diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 106 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.h | 1 |
2 files changed, 49 insertions, 58 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 3091bb3cef9..cee5febb8a4 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -93,14 +93,24 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, | |||
93 | return ret; | 93 | return ret; |
94 | } | 94 | } |
95 | 95 | ||
96 | static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, | ||
97 | struct sk_buff_head *list) | ||
98 | { | ||
99 | struct sk_buff *skb; | ||
100 | |||
101 | while ((skb = __skb_dequeue(list)) != NULL) { | ||
102 | dev_kfree_skb_any(skb); | ||
103 | TX_STAT_INC(skb_dropped); | ||
104 | } | ||
105 | } | ||
106 | |||
96 | static void hif_usb_tx_cb(struct urb *urb) | 107 | static void hif_usb_tx_cb(struct urb *urb) |
97 | { | 108 | { |
98 | struct tx_buf *tx_buf = (struct tx_buf *) urb->context; | 109 | struct tx_buf *tx_buf = (struct tx_buf *) urb->context; |
99 | struct hif_device_usb *hif_dev = tx_buf->hif_dev; | 110 | struct hif_device_usb *hif_dev = tx_buf->hif_dev; |
100 | struct sk_buff *skb; | 111 | struct sk_buff *skb; |
101 | bool drop, flush; | ||
102 | 112 | ||
103 | if (!hif_dev) | 113 | if (!hif_dev || !tx_buf) |
104 | return; | 114 | return; |
105 | 115 | ||
106 | switch (urb->status) { | 116 | switch (urb->status) { |
@@ -108,57 +118,47 @@ static void hif_usb_tx_cb(struct urb *urb) | |||
108 | break; | 118 | break; |
109 | case -ENOENT: | 119 | case -ENOENT: |
110 | case -ECONNRESET: | 120 | case -ECONNRESET: |
111 | break; | ||
112 | case -ENODEV: | 121 | case -ENODEV: |
113 | case -ESHUTDOWN: | 122 | case -ESHUTDOWN: |
123 | /* | ||
124 | * The URB has been killed, free the SKBs | ||
125 | * and return. | ||
126 | */ | ||
127 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | ||
114 | return; | 128 | return; |
115 | default: | 129 | default: |
116 | break; | 130 | break; |
117 | } | 131 | } |
118 | 132 | ||
119 | if (tx_buf) { | 133 | /* Check if TX has been stopped */ |
120 | spin_lock(&hif_dev->tx.tx_lock); | 134 | spin_lock(&hif_dev->tx.tx_lock); |
121 | drop = !!(hif_dev->tx.flags & HIF_USB_TX_STOP); | 135 | if (hif_dev->tx.flags & HIF_USB_TX_STOP) { |
122 | flush = !!(hif_dev->tx.flags & HIF_USB_TX_FLUSH); | ||
123 | spin_unlock(&hif_dev->tx.tx_lock); | ||
124 | |||
125 | while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { | ||
126 | if (!drop && !flush) { | ||
127 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | ||
128 | skb, 1); | ||
129 | TX_STAT_INC(skb_completed); | ||
130 | } else { | ||
131 | dev_kfree_skb_any(skb); | ||
132 | TX_STAT_INC(skb_dropped); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (flush) | ||
137 | return; | ||
138 | |||
139 | tx_buf->len = tx_buf->offset = 0; | ||
140 | __skb_queue_head_init(&tx_buf->skb_queue); | ||
141 | |||
142 | spin_lock(&hif_dev->tx.tx_lock); | ||
143 | list_del(&tx_buf->list); | ||
144 | list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | ||
145 | hif_dev->tx.tx_buf_cnt++; | ||
146 | if (!drop) | ||
147 | __hif_usb_tx(hif_dev); /* Check for pending SKBs */ | ||
148 | TX_STAT_INC(buf_completed); | ||
149 | spin_unlock(&hif_dev->tx.tx_lock); | 136 | spin_unlock(&hif_dev->tx.tx_lock); |
150 | } | 137 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); |
151 | } | 138 | goto add_free; |
152 | 139 | } | |
153 | static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, | 140 | spin_unlock(&hif_dev->tx.tx_lock); |
154 | struct sk_buff_head *list) | 141 | |
155 | { | 142 | /* Complete the queued SKBs. */ |
156 | struct sk_buff *skb; | 143 | while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { |
157 | 144 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | |
158 | while ((skb = __skb_dequeue(list)) != NULL) { | 145 | skb, 1); |
159 | dev_kfree_skb_any(skb); | 146 | TX_STAT_INC(skb_completed); |
160 | TX_STAT_INC(skb_dropped); | 147 | } |
161 | } | 148 | |
149 | add_free: | ||
150 | /* Re-initialize the SKB queue */ | ||
151 | tx_buf->len = tx_buf->offset = 0; | ||
152 | __skb_queue_head_init(&tx_buf->skb_queue); | ||
153 | |||
154 | /* Add this TX buffer to the free list */ | ||
155 | spin_lock(&hif_dev->tx.tx_lock); | ||
156 | list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | ||
157 | hif_dev->tx.tx_buf_cnt++; | ||
158 | if (!(hif_dev->tx.flags & HIF_USB_TX_STOP)) | ||
159 | __hif_usb_tx(hif_dev); /* Check for pending SKBs */ | ||
160 | TX_STAT_INC(buf_completed); | ||
161 | spin_unlock(&hif_dev->tx.tx_lock); | ||
162 | } | 162 | } |
163 | 163 | ||
164 | /* TX lock has to be taken */ | 164 | /* TX lock has to be taken */ |
@@ -178,8 +178,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) | |||
178 | return 0; | 178 | return 0; |
179 | 179 | ||
180 | tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list); | 180 | tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list); |
181 | list_del(&tx_buf->list); | 181 | list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending); |
182 | list_add_tail(&tx_buf->list, &hif_dev->tx.tx_pending); | ||
183 | hif_dev->tx.tx_buf_cnt--; | 182 | hif_dev->tx.tx_buf_cnt--; |
184 | 183 | ||
185 | tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); | 184 | tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); |
@@ -548,20 +547,17 @@ free: | |||
548 | 547 | ||
549 | static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) | 548 | static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) |
550 | { | 549 | { |
551 | unsigned long flags; | ||
552 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; | 550 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; |
553 | 551 | ||
554 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) { | 552 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, |
553 | &hif_dev->tx.tx_buf, list) { | ||
554 | usb_kill_urb(tx_buf->urb); | ||
555 | list_del(&tx_buf->list); | 555 | list_del(&tx_buf->list); |
556 | usb_free_urb(tx_buf->urb); | 556 | usb_free_urb(tx_buf->urb); |
557 | kfree(tx_buf->buf); | 557 | kfree(tx_buf->buf); |
558 | kfree(tx_buf); | 558 | kfree(tx_buf); |
559 | } | 559 | } |
560 | 560 | ||
561 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
562 | hif_dev->tx.flags |= HIF_USB_TX_FLUSH; | ||
563 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
564 | |||
565 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, | 561 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, |
566 | &hif_dev->tx.tx_pending, list) { | 562 | &hif_dev->tx.tx_pending, list) { |
567 | usb_kill_urb(tx_buf->urb); | 563 | usb_kill_urb(tx_buf->urb); |
@@ -570,10 +566,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) | |||
570 | kfree(tx_buf->buf); | 566 | kfree(tx_buf->buf); |
571 | kfree(tx_buf); | 567 | kfree(tx_buf); |
572 | } | 568 | } |
573 | |||
574 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
575 | hif_dev->tx.flags &= ~HIF_USB_TX_FLUSH; | ||
576 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
577 | } | 569 | } |
578 | 570 | ||
579 | static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) | 571 | static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 7d49a8af420..0aca49b6fcb 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h | |||
@@ -61,7 +61,6 @@ struct tx_buf { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | #define HIF_USB_TX_STOP BIT(0) | 63 | #define HIF_USB_TX_STOP BIT(0) |
64 | #define HIF_USB_TX_FLUSH BIT(1) | ||
65 | 64 | ||
66 | struct hif_usb_tx { | 65 | struct hif_usb_tx { |
67 | u8 flags; | 66 | u8 flags; |