aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-04-23 00:58:09 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-26 14:21:16 -0400
commitc11d8f89d3b785f3ef987c2d9ee1bfea6f8b3d0f (patch)
tree021e219b44265384aca9c7e8ef34066aa889ea49
parentd4cde88c1c025ffa18150ec29e80e456f2a5c65a (diff)
ath9k_htc: Simplify TX URB management
This patch simplifies URB management for transmission, by removing the 'FLUSH' variable (which is not needed, since we can determine if the URB has been killed by looking at the URB status), and also handling the STOP case properly. Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c106
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h1
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
96static 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
96static void hif_usb_tx_cb(struct urb *urb) 107static 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 }
153static 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
149add_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
549static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) 548static 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
579static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) 571static 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
66struct hif_usb_tx { 65struct hif_usb_tx {
67 u8 flags; 66 u8 flags;