Commit 97236a06 authored by Luciano Coelho's avatar Luciano Coelho

wlcore: move handling from hardirq to the irq thread function

Spin locks and completions are expensive in hard IRQ context and cause
problems with RT kernels.  In RT kernels, both spin locks and
completions can schedule(), so we can't use them in hard irq context.

Move handling code into the irq thread function to avoid that.
Reported-by: default avatarGregoire Gentil <gregoire@alwaysinnovating.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent da7aa280
...@@ -651,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) ...@@ -651,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie)
unsigned long flags; unsigned long flags;
struct wl1271 *wl = cookie; struct wl1271 *wl = cookie;
/* complete the ELP completion */
spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
if (wl->elp_compl) {
complete(wl->elp_compl);
wl->elp_compl = NULL;
}
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");
disable_irq_nosync(wl->irq);
pm_wakeup_event(wl->dev, 0);
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED;
}
spin_unlock_irqrestore(&wl->wl_lock, flags);
/* TX might be handled here, avoid redundant work */ /* TX might be handled here, avoid redundant work */
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work); cancel_work_sync(&wl->tx_work);
...@@ -5998,35 +6017,6 @@ int wlcore_free_hw(struct wl1271 *wl) ...@@ -5998,35 +6017,6 @@ int wlcore_free_hw(struct wl1271 *wl)
} }
EXPORT_SYMBOL_GPL(wlcore_free_hw); EXPORT_SYMBOL_GPL(wlcore_free_hw);
static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
{
struct wl1271 *wl = cookie;
unsigned long flags;
wl1271_debug(DEBUG_IRQ, "IRQ");
/* complete the ELP completion */
spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
if (wl->elp_compl) {
complete(wl->elp_compl);
wl->elp_compl = NULL;
}
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");
disable_irq_nosync(wl->irq);
pm_wakeup_event(wl->dev, 0);
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED;
}
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_WAKE_THREAD;
}
static void wlcore_nvs_cb(const struct firmware *fw, void *context) static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{ {
struct wl1271 *wl = context; struct wl1271 *wl = context;
...@@ -6068,9 +6058,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) ...@@ -6068,9 +6058,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
else else
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq, ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
irqflags, irqflags, pdev->name, wl);
pdev->name, wl);
if (ret < 0) { if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret); wl1271_error("request_irq() failed: %d", ret);
goto out_free_nvs; goto out_free_nvs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment