Commit eb215c33 authored by Tony Lindgren's avatar Tony Lindgren Committed by Kalle Valo
Browse files

wlcore: Simplify runtime resume ELP path



We can simplify the runtime resume ELP path by always setting and
clearing the completion in runtime resume. This way we can test for
WL1271_FLAG_IRQ_RUNNING after the resume write to see if we need
completion at all.

And in wlcore_irq(), we need to take spinlock for running the
completion and for the pm_wakeup_event(). Spinlock is not needed
around the bitops flags check for WL1271_FLAG_SUSPENDED so the
spinlocked sections get shorter.

Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200702162951.45392-2-tony@atomide.com
parent 0ef0ace3
Loading
Loading
Loading
Loading
+15 −28
Original line number Diff line number Diff line
@@ -649,24 +649,26 @@ static irqreturn_t wlcore_irq(int irq, void *cookie)
	unsigned long flags;
	struct wl1271 *wl = cookie;

	set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);

	/* complete the ELP completion */
	if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) {
		spin_lock_irqsave(&wl->wl_lock, flags);
	set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
	if (wl->elp_compl) {
		if (wl->elp_compl)
			complete(wl->elp_compl);
		wl->elp_compl = NULL;
		spin_unlock_irqrestore(&wl->wl_lock, flags);
	}

	if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
		/* don't enqueue a work right now. mark it as pending */
		set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
		wl1271_debug(DEBUG_IRQ, "should not enqueue work");
		spin_lock_irqsave(&wl->wl_lock, flags);
		disable_irq_nosync(wl->irq);
		pm_wakeup_event(wl->dev, 0);
		spin_unlock_irqrestore(&wl->wl_lock, flags);
		goto out_handled;
	}
	spin_unlock_irqrestore(&wl->wl_lock, flags);

	/* TX might be handled here, avoid redundant work */
	set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
@@ -6732,7 +6734,6 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev)
	unsigned long flags;
	int ret;
	unsigned long start_time = jiffies;
	bool pending = false;
	bool recovery = false;

	/* Nothing to do if no ELP mode requested */
@@ -6742,49 +6743,35 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev)
	wl1271_debug(DEBUG_PSM, "waking up chip from elp");

	spin_lock_irqsave(&wl->wl_lock, flags);
	if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
		pending = true;
	else
	wl->elp_compl = &compl;
	spin_unlock_irqrestore(&wl->wl_lock, flags);

	ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
	if (ret < 0) {
		recovery = true;
		goto err;
	}

	if (!pending) {
	} else if (!test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) {
		ret = wait_for_completion_timeout(&compl,
			msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
		if (ret == 0) {
			wl1271_warning("ELP wakeup timeout!");

			/* Return no error for runtime PM for recovery */
			ret = 0;
			recovery = true;
			goto err;
		}
	}

	clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);

	wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
		     jiffies_to_msecs(jiffies - start_time));

	return 0;

err:
	spin_lock_irqsave(&wl->wl_lock, flags);
	wl->elp_compl = NULL;
	spin_unlock_irqrestore(&wl->wl_lock, flags);
	clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);

	if (recovery) {
		set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
		wl12xx_queue_recovery_work(wl);
	} else {
		wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
			     jiffies_to_msecs(jiffies - start_time));
	}

	return ret;
	return 0;
}

static const struct dev_pm_ops wlcore_pm_ops = {