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

Commit ff8f59b5 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville
Browse files

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: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ee832d3e
Loading
Loading
Loading
Loading
+36 −4
Original line number Diff line number Diff line
@@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
	case -ENODEV:
	case -ESHUTDOWN:
		/*
		 * The URB has been killed, free the SKBs
		 * and return.
		 * The URB has been killed, free the SKBs.
		 */
		ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);

		/*
		 * 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:
		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);
	if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
		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)
{
	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;

	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.flags |= HIF_USB_TX_STOP;
	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,
@@ -587,6 +614,7 @@ free:
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
{
	struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
	unsigned long flags;

	list_for_each_entry_safe(tx_buf, tx_buf_tmp,
				 &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);
	}

	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,
				 &hif_dev->tx.tx_pending, list) {
		usb_kill_urb(tx_buf->urb);
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ struct tx_buf {
};

#define HIF_USB_TX_STOP  BIT(0)
#define HIF_USB_TX_FLUSH BIT(1)

struct hif_usb_tx {
	u8 flags;