[PATCH] ath9k_htc: add adaptive usb receive flow control to repair soft lockup with monitor mode

2015-02-09 Thread yuweizheng
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

2015-02-06 Thread yuweizheng
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

2015-02-03 Thread yuweizheng
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

2015-02-03 Thread yuweizheng
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

2015-01-30 Thread yuweizheng
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 {
+