ath9k_htc: Handle pending URBs properly
When doing a channel change, the pending URBs have to be killed properly on calling htc_stop(). This fixes the probe response timeout seen when sending UDP traffic at a high rate and running background scan at the same time. Cc: stable <stable@kernel.org> Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
ee832d3e9e
commit
ff8f59b5bb
@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
|
|||||||
case -ENODEV:
|
case -ENODEV:
|
||||||
case -ESHUTDOWN:
|
case -ESHUTDOWN:
|
||||||
/*
|
/*
|
||||||
* The URB has been killed, free the SKBs
|
* The URB has been killed, free the SKBs.
|
||||||
* and return.
|
|
||||||
*/
|
*/
|
||||||
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
|
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
|
||||||
return;
|
|
||||||
|
/*
|
||||||
|
* If the URBs are being flushed, no need to add this
|
||||||
|
* URB to the free list.
|
||||||
|
*/
|
||||||
|
spin_lock(&hif_dev->tx.tx_lock);
|
||||||
|
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
|
||||||
|
spin_unlock(&hif_dev->tx.tx_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spin_unlock(&hif_dev->tx.tx_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the stop() case, this URB has to be added to
|
||||||
|
* the free list.
|
||||||
|
*/
|
||||||
|
goto add_free;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if TX has been stopped */
|
/*
|
||||||
|
* Check if TX has been stopped, this is needed because
|
||||||
|
* this CB could have been invoked just after the TX lock
|
||||||
|
* was released in hif_stop() and kill_urb() hasn't been
|
||||||
|
* called yet.
|
||||||
|
*/
|
||||||
spin_lock(&hif_dev->tx.tx_lock);
|
spin_lock(&hif_dev->tx.tx_lock);
|
||||||
if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
|
if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
|
||||||
spin_unlock(&hif_dev->tx.tx_lock);
|
spin_unlock(&hif_dev->tx.tx_lock);
|
||||||
@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
|
|||||||
static void hif_usb_stop(void *hif_handle, u8 pipe_id)
|
static void hif_usb_stop(void *hif_handle, u8 pipe_id)
|
||||||
{
|
{
|
||||||
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
|
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
|
||||||
|
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
|
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
|
||||||
@ -321,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
|
|||||||
hif_dev->tx.tx_skb_cnt = 0;
|
hif_dev->tx.tx_skb_cnt = 0;
|
||||||
hif_dev->tx.flags |= HIF_USB_TX_STOP;
|
hif_dev->tx.flags |= HIF_USB_TX_STOP;
|
||||||
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
|
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
|
||||||
|
|
||||||
|
/* The pending URBs have to be canceled. */
|
||||||
|
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
|
||||||
|
&hif_dev->tx.tx_pending, list) {
|
||||||
|
usb_kill_urb(tx_buf->urb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
|
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
|
||||||
@ -587,6 +614,7 @@ free:
|
|||||||
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
|
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
|
||||||
{
|
{
|
||||||
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
|
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
|
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
|
||||||
&hif_dev->tx.tx_buf, list) {
|
&hif_dev->tx.tx_buf, list) {
|
||||||
@ -597,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
|
|||||||
kfree(tx_buf);
|
kfree(tx_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
|
||||||
|
hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
|
||||||
|
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
|
||||||
|
|
||||||
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
|
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
|
||||||
&hif_dev->tx.tx_pending, list) {
|
&hif_dev->tx.tx_pending, list) {
|
||||||
usb_kill_urb(tx_buf->urb);
|
usb_kill_urb(tx_buf->urb);
|
||||||
|
@ -64,6 +64,7 @@ struct tx_buf {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define HIF_USB_TX_STOP BIT(0)
|
#define HIF_USB_TX_STOP BIT(0)
|
||||||
|
#define HIF_USB_TX_FLUSH BIT(1)
|
||||||
|
|
||||||
struct hif_usb_tx {
|
struct hif_usb_tx {
|
||||||
u8 flags;
|
u8 flags;
|
||||||
|
Loading…
Reference in New Issue
Block a user