aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-02-22 01:38:31 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-09 15:03:01 -0500
commitffb591cd0e32d817bdbd359dead3baa770b999f8 (patch)
treeeb4ff124e93543fce011e634de3c3c0ac677ca2a /drivers/net/wireless
parent93c5bb68c89eff0cd41afce8ac932d12cc9d7ae8 (diff)
wl1271: Improvements to the TX path
- Fix a TX result overflow problem that was present in the TX path and visible with at least linksys AP's (probably any AP with high throughput capability.) - Optimize TX by writing FW trigger for a group of TX frames instead of each and every frame. - Slightly optimize the TX path code. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c8
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c38
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h2
4 files changed, 29 insertions, 23 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 10135c94e20e..cc974eae009e 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -396,10 +396,10 @@ struct wl1271 {
396 /* Accounting for allocated / available TX blocks on HW */ 396 /* Accounting for allocated / available TX blocks on HW */
397 u32 tx_blocks_freed[NUM_TX_QUEUES]; 397 u32 tx_blocks_freed[NUM_TX_QUEUES];
398 u32 tx_blocks_available; 398 u32 tx_blocks_available;
399 u8 tx_results_count; 399 u32 tx_results_count;
400 400
401 /* Transmitted TX packets counter for chipset interface */ 401 /* Transmitted TX packets counter for chipset interface */
402 int tx_packets_count; 402 u32 tx_packets_count;
403 403
404 /* Time-offset between host and chipset clocks */ 404 /* Time-offset between host and chipset clocks */
405 int time_offset; 405 int time_offset;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 310f58c66231..5cc778f658b9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -453,14 +453,12 @@ static void wl1271_irq_work(struct work_struct *work)
453 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); 453 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
454 454
455 if (intr & WL1271_ACX_INTR_DATA) { 455 if (intr & WL1271_ACX_INTR_DATA) {
456 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
457 wl->tx_results_count;
458
459 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); 456 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
460 457
461 /* check for tx results */ 458 /* check for tx results */
462 if (tx_res_cnt) 459 if (wl->fw_status->tx_results_counter !=
463 wl1271_tx_complete(wl, tx_res_cnt); 460 (wl->tx_results_count & 0xff))
461 wl1271_tx_complete(wl);
464 462
465 wl1271_rx(wl, wl->fw_status); 463 wl1271_rx(wl, wl->fw_status);
466 } 464 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 2b7dd9b76fe1..2e057b0e3257 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -169,7 +169,6 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
169 169
170 /* write packet new counter into the write access register */ 170 /* write packet new counter into the write access register */
171 wl->tx_packets_count++; 171 wl->tx_packets_count++;
172 wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
173 172
174 desc = (struct wl1271_tx_hw_descr *) skb->data; 173 desc = (struct wl1271_tx_hw_descr *) skb->data;
175 wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", 174 wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -244,6 +243,7 @@ void wl1271_tx_work(struct work_struct *work)
244 struct sk_buff *skb; 243 struct sk_buff *skb;
245 bool woken_up = false; 244 bool woken_up = false;
246 u32 sta_rates = 0; 245 u32 sta_rates = 0;
246 u32 prev_tx_packets_count;
247 int ret; 247 int ret;
248 248
249 /* check if the rates supported by the AP have changed */ 249 /* check if the rates supported by the AP have changed */
@@ -260,6 +260,8 @@ void wl1271_tx_work(struct work_struct *work)
260 if (unlikely(wl->state == WL1271_STATE_OFF)) 260 if (unlikely(wl->state == WL1271_STATE_OFF))
261 goto out; 261 goto out;
262 262
263 prev_tx_packets_count = wl->tx_packets_count;
264
263 /* if rates have changed, re-configure the rate policy */ 265 /* if rates have changed, re-configure the rate policy */
264 if (unlikely(sta_rates)) { 266 if (unlikely(sta_rates)) {
265 wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); 267 wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
@@ -270,7 +272,7 @@ void wl1271_tx_work(struct work_struct *work)
270 if (!woken_up) { 272 if (!woken_up) {
271 ret = wl1271_ps_elp_wakeup(wl, false); 273 ret = wl1271_ps_elp_wakeup(wl, false);
272 if (ret < 0) 274 if (ret < 0)
273 goto out; 275 goto out_ack;
274 woken_up = true; 276 woken_up = true;
275 } 277 }
276 278
@@ -282,10 +284,10 @@ void wl1271_tx_work(struct work_struct *work)
282 ieee80211_stop_queues(wl->hw); 284 ieee80211_stop_queues(wl->hw);
283 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); 285 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
284 skb_queue_head(&wl->tx_queue, skb); 286 skb_queue_head(&wl->tx_queue, skb);
285 goto out; 287 goto out_ack;
286 } else if (ret < 0) { 288 } else if (ret < 0) {
287 dev_kfree_skb(skb); 289 dev_kfree_skb(skb);
288 goto out; 290 goto out_ack;
289 } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, 291 } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
290 &wl->flags)) { 292 &wl->flags)) {
291 /* firmware buffer has space, restart queues */ 293 /* firmware buffer has space, restart queues */
@@ -295,6 +297,11 @@ void wl1271_tx_work(struct work_struct *work)
295 } 297 }
296 } 298 }
297 299
300out_ack:
301 /* interrupt the firmware with the new packets */
302 if (prev_tx_packets_count != wl->tx_packets_count)
303 wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
304
298out: 305out:
299 if (woken_up) 306 if (woken_up)
300 wl1271_ps_elp_sleep(wl); 307 wl1271_ps_elp_sleep(wl);
@@ -311,7 +318,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
311 int id = result->id; 318 int id = result->id;
312 319
313 /* check for id legality */ 320 /* check for id legality */
314 if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) { 321 if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
315 wl1271_warning("TX result illegal id: %d", id); 322 wl1271_warning("TX result illegal id: %d", id);
316 return; 323 return;
317 } 324 }
@@ -366,10 +373,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
366} 373}
367 374
368/* Called upon reception of a TX complete interrupt */ 375/* Called upon reception of a TX complete interrupt */
369void wl1271_tx_complete(struct wl1271 *wl, u32 count) 376void wl1271_tx_complete(struct wl1271 *wl)
370{ 377{
371 struct wl1271_acx_mem_map *memmap = 378 struct wl1271_acx_mem_map *memmap =
372 (struct wl1271_acx_mem_map *)wl->target_mem_map; 379 (struct wl1271_acx_mem_map *)wl->target_mem_map;
380 u32 count, fw_counter;
373 u32 i; 381 u32 i;
374 382
375 wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 383 wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
@@ -377,12 +385,18 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
377 /* read the tx results from the chipset */ 385 /* read the tx results from the chipset */
378 wl1271_read(wl, le32_to_cpu(memmap->tx_result), 386 wl1271_read(wl, le32_to_cpu(memmap->tx_result),
379 wl->tx_res_if, sizeof(*wl->tx_res_if), false); 387 wl->tx_res_if, sizeof(*wl->tx_res_if), false);
388 fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
389
390 /* write host counter to chipset (to ack) */
391 wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
392 offsetof(struct wl1271_tx_hw_res_if,
393 tx_result_host_counter), fw_counter);
394
395 count = fw_counter - wl->tx_results_count;
380 396
381 /* verify that the result buffer is not getting overrun */ 397 /* verify that the result buffer is not getting overrun */
382 if (count > TX_HW_RESULT_QUEUE_LEN) { 398 if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
383 wl1271_warning("TX result overflow from chipset: %d", count); 399 wl1271_warning("TX result overflow from chipset: %d", count);
384 count = TX_HW_RESULT_QUEUE_LEN;
385 }
386 400
387 /* process the results */ 401 /* process the results */
388 for (i = 0; i < count; i++) { 402 for (i = 0; i < count; i++) {
@@ -395,12 +409,6 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
395 409
396 wl->tx_results_count++; 410 wl->tx_results_count++;
397 } 411 }
398
399 /* write host counter to chipset (to ack) */
400 wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
401 offsetof(struct wl1271_tx_hw_res_if,
402 tx_result_host_counter),
403 le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
404} 412}
405 413
406/* caller must hold wl->mutex */ 414/* caller must hold wl->mutex */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 17e405a09caa..ca92bd811292 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -160,7 +160,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
160} 160}
161 161
162void wl1271_tx_work(struct work_struct *work); 162void wl1271_tx_work(struct work_struct *work);
163void wl1271_tx_complete(struct wl1271 *wl, u32 count); 163void wl1271_tx_complete(struct wl1271 *wl);
164void wl1271_tx_flush(struct wl1271 *wl); 164void wl1271_tx_flush(struct wl1271 *wl);
165 165
166#endif 166#endif