[PATCH] ath9k_htc: add adaptive usb receive flow control to repair soft lockup with monitor mode
From: Yuwei Zheng yuweizh...@139.com In the environment with heavy wifi traffic, set the ar9271 into monitor mode, will trigger a deadloop panic. The ath9k_hif_usb_rx_cb function excute on the interrupt context, and ath9k_rx_tasklet excute on the soft irq context. In other words, the ath9k_hif_usb_rx_cb have more chance to excute than ath9k_rx_tasklet. So in the worst condition, the rx.rxbuf receive list is always full, and the do {}while(true) loop will not be break. The kernel get a soft lockup panic. [59011.007210] BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:30609] [59011.030560] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.804486] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.858522] Kernel panic - not syncing: softlockup: hung tasks [59014.038891] Exception stack(0xdf4bbc38 to 0xdf4bbc80) [59014.046834] bc20: de57b950 6113 [59014.059579] bc40: bb32bb32 6113 de57b948 de57b500 dc7bb440 df4bbcd0 [59014.072337] bc60: de57b950 6113 df4bbcd0 df4bbc80 c04c259d c04c25a0 6133 [59014.085233] [c04c28db] (__irq_svc+0x3b/0x5c) from [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) [59014.100437] [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) from [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) [59014.118267] [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) from [c0036d23] (tasklet_action+0x3b/0x98) [59014.134132] [c0036d23] (tasklet_action+0x3b/0x98) from [c0036709] (__do_softirq+0x99/0x16c) [59014.147784] [c0036709] (__do_softirq+0x99/0x16c) from [c00369f7] (irq_exit+0x5b/0x5c) [59014.160653] [c00369f7] (irq_exit+0x5b/0x5c) from [c000cfc3] (handle_IRQ+0x37/0x78) [59014.173124] [c000cfc3] (handle_IRQ+0x37/0x78) from [c00085df] (omap3_intc_handle_irq+0x5f/0x68) [59014.187225] [c00085df] (omap3_intc_handle_irq+0x5f/0x68) from [c04c28db](__irq_svc+0x3b/0x5c) This bug can be see with low performance board, such as uniprocessor beagle bone board. Signed-off-by: Yuwei Zheng yuweizh...@139.com --- drivers/net/wireless/ath/ath9k/hif_usb.c | 75 +++--- drivers/net/wireless/ath/ath9k/hif_usb.h | 9 drivers/net/wireless/ath/ath9k/htc.h | 19 +++ drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 53 ++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 44 +++ 5 files changed, 193 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b..d05cc0b 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -640,6 +640,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) struct hif_device_usb *hif_dev = usb_get_intfdata(usb_ifnum_to_if(urb-dev, 0)); int ret; + int delay; if (!skb) return; @@ -658,7 +659,6 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) default: goto resubmit; } - if (likely(urb-actual_length != 0)) { skb_put(skb, urb-actual_length); ath9k_hif_usb_rx_stream(hif_dev, skb); @@ -667,12 +667,22 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); - - usb_anchor_urb(urb, hif_dev-rx_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free; + spin_lock(hif_dev-aurfc_lock); + if (atomic_read(hif_dev-aurfc_submit_delay) 0 + hif_dev-aurfc_active == 1) { + usb_anchor_urb(urb, hif_dev-rx_delayed_submitted); + delay = atomic_read(hif_dev-aurfc_submit_delay); + schedule_delayed_work(hif_dev-aurfc_delayed_work, + msecs_to_jiffies(delay)); + spin_unlock(hif_dev-aurfc_lock); + } else { + spin_unlock(hif_dev-aurfc_lock); + usb_anchor_urb(urb, hif_dev-rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } } return; @@ -818,9 +828,51 @@ err: return -ENOMEM; } +static void aurfc_submit_handler(struct work_struct *work) +{ + struct hif_device_usb *hif_dev = + container_of(work, +struct hif_device_usb, +aurfc_delayed_work.work); + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int ret; + int loop_times = 0; + + AURFC_STAT_INC(aurfc_called); + while (true) { + loop_times++; + if (loop_times MAX_RX_URB_NUM) + atomic_add(AURFC_STEP, +
[PATCH] ath9k_htc: add adaptive usb receive flow control to repair soft lockup with monitor mode
From: Yuwei Zheng yuweizh...@139.com In the environment with heavy wifi traffic, set the ar9271 into monitor mode, will trigger a deadloop panic. The ath9k_hif_usb_rx_cb function excute on the interrupt context, and ath9k_rx_tasklet excute on the soft irq context. In other words, the ath9k_hif_usb_rx_cb have more chance to excute than ath9k_rx_tasklet. So in the worst condition, the rx.rxbuf receive list is always full, and the do {}while(true) loop will not be break. The kernel get a soft lockup panic. [59011.007210] BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:30609] [59011.030560] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.804486] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.858522] Kernel panic - not syncing: softlockup: hung tasks [59014.038891] Exception stack(0xdf4bbc38 to 0xdf4bbc80) [59014.046834] bc20: de57b950 6113 [59014.059579] bc40: bb32bb32 6113 de57b948 de57b500 dc7bb440 df4bbcd0 [59014.072337] bc60: de57b950 6113 df4bbcd0 df4bbc80 c04c259d c04c25a0 6133 [59014.085233] [c04c28db] (__irq_svc+0x3b/0x5c) from [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) [59014.100437] [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) from [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) [59014.118267] [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) from [c0036d23] (tasklet_action+0x3b/0x98) [59014.134132] [c0036d23] (tasklet_action+0x3b/0x98) from [c0036709] (__do_softirq+0x99/0x16c) [59014.147784] [c0036709] (__do_softirq+0x99/0x16c) from [c00369f7] (irq_exit+0x5b/0x5c) [59014.160653] [c00369f7] (irq_exit+0x5b/0x5c) from [c000cfc3] (handle_IRQ+0x37/0x78) [59014.173124] [c000cfc3] (handle_IRQ+0x37/0x78) from [c00085df] (omap3_intc_handle_irq+0x5f/0x68) [59014.187225] [c00085df] (omap3_intc_handle_irq+0x5f/0x68) from [c04c28db](__irq_svc+0x3b/0x5c) This bug can be see with low performance board, such as uniprocessor beagle bone board. Signed-off-by: Yuwei Zheng yuweizh...@139.com --- drivers/net/wireless/ath/ath9k/hif_usb.c | 74 +++--- drivers/net/wireless/ath/ath9k/hif_usb.h | 9 drivers/net/wireless/ath/ath9k/htc.h | 19 +++ drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 53 ++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 44 +++ 5 files changed, 192 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b..90ee568 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -640,6 +640,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) struct hif_device_usb *hif_dev = usb_get_intfdata(usb_ifnum_to_if(urb-dev, 0)); int ret; + int delay; if (!skb) return; @@ -658,7 +659,6 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) default: goto resubmit; } - if (likely(urb-actual_length != 0)) { skb_put(skb, urb-actual_length); ath9k_hif_usb_rx_stream(hif_dev, skb); @@ -667,12 +667,22 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); - - usb_anchor_urb(urb, hif_dev-rx_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free; + spin_lock(hif_dev-aurfc_lock); + if (atomic_read(hif_dev-aurfc_submit_delay) 0 + hif_dev-aurfc_active == 1) { + usb_anchor_urb(urb, hif_dev-rx_delayed_submitted); + delay = atomic_read(hif_dev-aurfc_submit_delay); + schedule_delayed_work(hif_dev-aurfc_delayed_work, + msecs_to_jiffies(delay)); + spin_unlock(hif_dev-aurfc_lock); + } else { + spin_unlock(hif_dev-aurfc_lock); + usb_anchor_urb(urb, hif_dev-rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } } return; @@ -818,9 +828,50 @@ err: return -ENOMEM; } +static void aurfc_submit_handler(struct work_struct *work) +{ + struct hif_device_usb *hif_dev = + container_of(work, +struct hif_device_usb, +aurfc_delayed_work.work); + + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int ret; + int loop_times = 0; + + while (true) { + loop_times++; + if (loop_times MAX_RX_URB_NUM) + atomic_add(AURFC_STEP, +
[PATCH] ath9k_htc: add adaptive usb flow control to repair soft lockup with monitor mode
From: Yuwei Zheng yuweizh...@139.com In the environment with heavy wifi traffic, set the ar9271 into monitor mode, will trigger a deadloop panic. The ath9k_hif_usb_rx_cb function excute on the interrupt context, and ath9k_rx_tasklet excute on the soft irq context. In other words, the ath9k_hif_usb_rx_cb have more chance to excute than ath9k_rx_tasklet. So in the worst condition, the rx.rxbuf receive list is always full, and the do {}while(true) loop will not be break. The kernel get a soft lockup panic. [59011.007210] BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:30609] [59011.030560] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.804486] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.858522] Kernel panic - not syncing: softlockup: hung tasks [59014.038891] Exception stack(0xdf4bbc38 to 0xdf4bbc80) [59014.046834] bc20: de57b950 6113 [59014.059579] bc40: bb32bb32 6113 de57b948 de57b500 dc7bb440 df4bbcd0 [59014.072337] bc60: de57b950 6113 df4bbcd0 df4bbc80 c04c259d c04c25a0 6133 [59014.085233] [c04c28db] (__irq_svc+0x3b/0x5c) from [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) [59014.100437] [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) from [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) [59014.118267] [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) from [c0036d23] (tasklet_action+0x3b/0x98) [59014.134132] [c0036d23] (tasklet_action+0x3b/0x98) from [c0036709] (__do_softirq+0x99/0x16c) [59014.147784] [c0036709] (__do_softirq+0x99/0x16c) from [c00369f7] (irq_exit+0x5b/0x5c) [59014.160653] [c00369f7] (irq_exit+0x5b/0x5c) from [c000cfc3] (handle_IRQ+0x37/0x78) [59014.173124] [c000cfc3] (handle_IRQ+0x37/0x78) from [c00085df] (omap3_intc_handle_irq+0x5f/0x68) [59014.187225] [c00085df] (omap3_intc_handle_irq+0x5f/0x68) from [c04c28db](__irq_svc+0x3b/0x5c) This bug can be see with low performance board, such as uniprocessor beagle bone board. Signed-off-by: Yuwei Zheng zhengyu...@360.cn Signed-off-by: Yuwei Zheng yuweizh...@139.com --- drivers/net/wireless/ath/ath9k/hif_usb.c | 61 +++--- drivers/net/wireless/ath/ath9k/hif_usb.h | 6 +++ drivers/net/wireless/ath/ath9k/htc.h | 18 drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 46 +++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 25 +++ 5 files changed, 149 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b..718bbd6 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -640,6 +640,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) struct hif_device_usb *hif_dev = usb_get_intfdata(usb_ifnum_to_if(urb-dev, 0)); int ret; + int delay; if (!skb) return; @@ -658,7 +659,6 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) default: goto resubmit; } - if (likely(urb-actual_length != 0)) { skb_put(skb, urb-actual_length); ath9k_hif_usb_rx_stream(hif_dev, skb); @@ -667,12 +667,18 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); - - usb_anchor_urb(urb, hif_dev-rx_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free; + if (atomic_read(hif_dev-rx_urb_submit_delay) 0) { + usb_anchor_urb(urb, hif_dev-rx_delayed_submitted); + delay = atomic_read(hif_dev-rx_urb_submit_delay); + schedule_delayed_work(hif_dev-rx_submit_delayed_work, + usecs_to_jiffies(delay)); + } else { + usb_anchor_urb(urb, hif_dev-rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } } return; @@ -818,9 +824,43 @@ err: return -ENOMEM; } +static void rx_urb_delayed_submit_handler(struct work_struct *work) +{ + struct hif_device_usb *hif_dev = + container_of(work, +struct hif_device_usb, +rx_submit_delayed_work.work); + + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int ret; + int loop_times = 0; + + while (true) { + loop_times++; + if (loop_times (MAX_RX_URB_NUM)) + atomic_add(ARC_RX_STEP, hif_dev-rx_urb_submit_delay); + + urb = usb_get_from_anchor(hif_dev-rx_delayed_submitted); + if (urb) { + skb = (struct
[PATCH] ath9k_htc: add adaptive rate control to repair soft lockup with monitor mode
From: Yuwei Zheng yuweizh...@139.com In the environment with heavy wifi traffic, set the ar9271 into monitor mode, will trigger a deadloop panic. The ath9k_hif_usb_rx_cb function excute on the interrupt context, and ath9k_rx_tasklet excute on the soft irq context. In other words, the ath9k_hif_usb_rx_cb have more chance to excute than ath9k_rx_tasklet. So in the worst condition, the rx.rxbuf receive list is always full, and the do {}while(true) loop will not be break. The kernel get a soft lockup panic. [59011.007210] BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:30609] [59011.030560] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.804486] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.858522] Kernel panic - not syncing: softlockup: hung tasks [59014.038891] Exception stack(0xdf4bbc38 to 0xdf4bbc80) [59014.046834] bc20: de57b950 6113 [59014.059579] bc40: bb32bb32 6113 de57b948 de57b500 dc7bb440 df4bbcd0 [59014.072337] bc60: de57b950 6113 df4bbcd0 df4bbc80 c04c259d c04c25a0 6133 [59014.085233] [c04c28db] (__irq_svc+0x3b/0x5c) from [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) [59014.100437] [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) from [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) [59014.118267] [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) from [c0036d23] (tasklet_action+0x3b/0x98) [59014.134132] [c0036d23] (tasklet_action+0x3b/0x98) from [c0036709] (__do_softirq+0x99/0x16c) [59014.147784] [c0036709] (__do_softirq+0x99/0x16c) from [c00369f7] (irq_exit+0x5b/0x5c) [59014.160653] [c00369f7] (irq_exit+0x5b/0x5c) from [c000cfc3] (handle_IRQ+0x37/0x78) [59014.173124] [c000cfc3] (handle_IRQ+0x37/0x78) from [c00085df] (omap3_intc_handle_irq+0x5f/0x68) [59014.187225] [c00085df] (omap3_intc_handle_irq+0x5f/0x68) from [c04c28db](__irq_svc+0x3b/0x5c) This bug can be see with low performance board, such as uniprocessor beagle bone board. Signed-off-by: Yuwei Zheng zhengyu...@360.cn Signed-off-by: Yuwei Zheng yuweizh...@139.com --- drivers/net/wireless/ath/ath9k/hif_usb.c | 61 +++--- drivers/net/wireless/ath/ath9k/hif_usb.h | 6 +++ drivers/net/wireless/ath/ath9k/htc.h | 18 drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 46 +++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 25 +++ 5 files changed, 149 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b..9166f10 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -640,6 +640,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) struct hif_device_usb *hif_dev = usb_get_intfdata(usb_ifnum_to_if(urb-dev, 0)); int ret; + int delay; if (!skb) return; @@ -658,7 +659,6 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) default: goto resubmit; } - if (likely(urb-actual_length != 0)) { skb_put(skb, urb-actual_length); ath9k_hif_usb_rx_stream(hif_dev, skb); @@ -667,12 +667,18 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); - - usb_anchor_urb(urb, hif_dev-rx_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free; + if (atomic_read(hif_dev-rx_urb_submit_delay) 0) { + usb_anchor_urb(urb, hif_dev-rx_delayed_submitted); + delay = atomic_read(hif_dev-rx_urb_submit_delay); + schedule_delayed_work(hif_dev-rx_submit_delayed_work, + usecs_to_jiffies(delay)); + } else { + usb_anchor_urb(urb, hif_dev-rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } } return; @@ -818,9 +824,43 @@ err: return -ENOMEM; } +static void rx_urb_delayed_submit_handler(struct work_struct *work) +{ + struct hif_device_usb *hif_dev = + container_of(work, +struct hif_device_usb, +rx_submit_delayed_work.work); + + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int ret; + int loop_times = 0; + + while (true) { + loop_times++; + if (loop_times (MAX_RX_URB_NUM)) + atomic_add(ARC_RX_STEP, hif_dev-rx_urb_submit_delay); + + urb = usb_get_from_anchor(hif_dev-rx_delayed_submitted); + if (urb) { + skb = (struct sk_buff
[PATCH] Repair soft lockup with monitor mode of ath9k_htc card
From: Yuwei Zheng yuweizh...@139.com In the environment with heavy wifi traffic, set the ar9271 into monitor mode, will trigger a deadloop panic. The ath9k_hif_usb_rx_cb function excute on the interrupt context, and ath9k_rx_tasklet excute on the soft irq context. In other words, the ath9k_hif_usb_rx_cb have more chance to excute than ath9k_rx_tasklet. So in the worst condition, the rx.rxbuf receive list is always full, and the do {}while(true) loop will not be break. The kernel get a soft lockup panic. [59011.007210] BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:30609] [59011.030560] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.804486] BUG: scheduling while atomic: kworker/0:0/30609/0x40010100 [59013.858522] Kernel panic - not syncing: softlockup: hung tasks [59014.038891] Exception stack(0xdf4bbc38 to 0xdf4bbc80) [59014.046834] bc20: de57b950 6113 [59014.059579] bc40: bb32bb32 6113 de57b948 de57b500 dc7bb440 df4bbcd0 [59014.072337] bc60: de57b950 6113 df4bbcd0 df4bbc80 c04c259d c04c25a0 6133 [59014.085233] [c04c28db] (__irq_svc+0x3b/0x5c) from [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) [59014.100437] [c04c25a0] (_raw_spin_unlock_irqrestore+0xc/0x10) from [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) [59014.118267] [bf9c2089] (ath9k_rx_tasklet+0x290/0x490 [ath9k_htc]) from [c0036d23] (tasklet_action+0x3b/0x98) [59014.134132] [c0036d23] (tasklet_action+0x3b/0x98) from [c0036709] (__do_softirq+0x99/0x16c) [59014.147784] [c0036709] (__do_softirq+0x99/0x16c) from [c00369f7] (irq_exit+0x5b/0x5c) [59014.160653] [c00369f7] (irq_exit+0x5b/0x5c) from [c000cfc3] (handle_IRQ+0x37/0x78) [59014.173124] [c000cfc3] (handle_IRQ+0x37/0x78) from [c00085df] (omap3_intc_handle_irq+0x5f/0x68) [59014.187225] [c00085df] (omap3_intc_handle_irq+0x5f/0x68) from [c04c28db](__irq_svc+0x3b/0x5c) This bug can be see with low performance board, such as uniprocessor beagle bone board. Signed-off-by: Yuwei Zheng zhengyu...@360.cn Signed-off-by: Yuwei Zheng yuweizh...@139.com --- drivers/net/wireless/ath/ath9k/hif_usb.c | 58 ++ drivers/net/wireless/ath/ath9k/hif_usb.h | 5 +++ drivers/net/wireless/ath/ath9k/htc.h | 13 ++ drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 49 ++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 26 5 files changed, 144 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b..18c6f0e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -658,7 +658,6 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) default: goto resubmit; } - if (likely(urb-actual_length != 0)) { skb_put(skb, urb-actual_length); ath9k_hif_usb_rx_stream(hif_dev, skb); @@ -667,12 +666,18 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); - - usb_anchor_urb(urb, hif_dev-rx_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free; + if (atomic_read(hif_dev-rx_urb_submit_delay) 0) { + usb_anchor_urb(urb, hif_dev-rx_delayed_submitted); + ret = tasklet_hrtimer_start(hif_dev-rx_submit_timer, + ktime_set(0, atomic_read(hif_dev-rx_urb_submit_delay)*1000), + HRTIMER_MODE_REL); + } else { + usb_anchor_urb(urb, hif_dev-rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } } return; @@ -818,9 +823,39 @@ err: return -ENOMEM; } +static enum hrtimer_restart rx_urb_submit_timer_handler(struct hrtimer *me) +{ + struct tasklet_hrtimer *thr = + container_of(me, struct tasklet_hrtimer, timer); + struct hif_device_usb *hif_dev = + container_of(thr, struct hif_device_usb, rx_submit_timer); + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int ret; + + while (true) { + urb = usb_get_from_anchor(hif_dev-rx_delayed_submitted); + if (urb != NULL) { + skb = (struct sk_buff *)urb-context; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret != -EBUSY) { + usb_unanchor_urb(urb); + dev_kfree_skb_any(skb); + urb-context = NULL; + } + } else { +