Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e73eb62 authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by John W. Linville
Browse files

wl1271: Implement looped IRQ handling



This patch implements looped IRQ handling. In essence, if a new interrupt is
asserted by the FW while the host is processing the previous one, the host
will directly proceed processing the new IRQ without leaving the handling
function.

Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4aa05917
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -371,6 +371,8 @@ struct wl1271 {
#define WL1271_FLAG_IN_ELP             (6)
#define WL1271_FLAG_PSM                (7)
#define WL1271_FLAG_PSM_REQUESTED      (8)
#define WL1271_FLAG_IRQ_PENDING        (9)
#define WL1271_FLAG_IRQ_RUNNING       (10)
	unsigned long flags;

	struct wl1271_partition_set part;
+47 −29
Original line number Diff line number Diff line
@@ -406,10 +406,14 @@ static void wl1271_fw_status(struct wl1271 *wl,
		le32_to_cpu(status->fw_localtime);
}

#define WL1271_IRQ_MAX_LOOPS 10

static void wl1271_irq_work(struct work_struct *work)
{
	int ret;
	u32 intr;
	int loopcount = WL1271_IRQ_MAX_LOOPS;
	unsigned long flags;
	struct wl1271 *wl =
		container_of(work, struct wl1271, irq_work);

@@ -417,22 +421,39 @@ static void wl1271_irq_work(struct work_struct *work)

	wl1271_debug(DEBUG_IRQ, "IRQ work");

	if (wl->state == WL1271_STATE_OFF)
	if (unlikely(wl->state == WL1271_STATE_OFF))
		goto out;

	ret = wl1271_ps_elp_wakeup(wl, true);
	if (ret < 0)
		goto out;

	spin_lock_irqsave(&wl->wl_lock, flags);
	while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
		clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
		spin_unlock_irqrestore(&wl->wl_lock, flags);
		loopcount--;

		wl1271_fw_status(wl, wl->fw_status);
		intr = le32_to_cpu(wl->fw_status->intr);
		if (!intr) {
			wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
		goto out_sleep;
			continue;
		}

		intr &= WL1271_INTR_MASK;

		if (intr & WL1271_ACX_INTR_DATA) {
			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");

			/* check for tx results */
			if (wl->fw_status->tx_results_counter !=
			    (wl->tx_results_count & 0xff))
				wl1271_tx_complete(wl);

			wl1271_rx(wl, wl->fw_status);
		}

		if (intr & WL1271_ACX_INTR_EVENT_A) {
			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
			wl1271_event_handle(wl, 0);
@@ -450,18 +471,15 @@ static void wl1271_irq_work(struct work_struct *work)
		if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");

	if (intr & WL1271_ACX_INTR_DATA) {
		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");

		/* check for tx results */
		if (wl->fw_status->tx_results_counter !=
		    (wl->tx_results_count & 0xff))
			wl1271_tx_complete(wl);

		wl1271_rx(wl, wl->fw_status);
		spin_lock_irqsave(&wl->wl_lock, flags);
	}

out_sleep:
	if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
		ieee80211_queue_work(wl->hw, &wl->irq_work);
	else
		clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
	spin_unlock_irqrestore(&wl->wl_lock, flags);

	wl1271_ps_elp_sleep(wl);

out:
+3 −1
Original line number Diff line number Diff line
@@ -75,7 +75,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
		wl->elp_compl = NULL;
	}

	if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
		ieee80211_queue_work(wl->hw, &wl->irq_work);
	set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
	spin_unlock_irqrestore(&wl->wl_lock, flags);

	return IRQ_HANDLED;
+3 −1
Original line number Diff line number Diff line
@@ -324,7 +324,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
		wl->elp_compl = NULL;
	}

	if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
		ieee80211_queue_work(wl->hw, &wl->irq_work);
	set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
	spin_unlock_irqrestore(&wl->wl_lock, flags);

	return IRQ_HANDLED;