diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
commit | 7a6362800cb7d1d618a697a650c7aaed3eb39320 (patch) | |
tree | 087f9bc6c13ef1fad4b392c5cf9325cd28fa8523 /drivers/net/wireless/wl1251/tx.c | |
parent | 6445ced8670f37cfc2c5e24a9de9b413dbfc788d (diff) | |
parent | ceda86a108671294052cbf51660097b6534672f5 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1480 commits)
bonding: enable netpoll without checking link status
xfrm: Refcount destination entry on xfrm_lookup
net: introduce rx_handler results and logic around that
bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
bonding: wrap slave state work
net: get rid of multiple bond-related netdevice->priv_flags
bonding: register slave pointer for rx_handler
be2net: Bump up the version number
be2net: Copyright notice change. Update to Emulex instead of ServerEngines
e1000e: fix kconfig for crc32 dependency
netfilter ebtables: fix xt_AUDIT to work with ebtables
xen network backend driver
bonding: Improve syslog message at device creation time
bonding: Call netif_carrier_off after register_netdevice
bonding: Incorrect TX queue offset
net_sched: fix ip_tos2prio
xfrm: fix __xfrm_route_forward()
be2net: Fix UDP packet detected status in RX compl
Phonet: fix aligned-mode pipe socket buffer header reserve
netxen: support for GbE port settings
...
Fix up conflicts in drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
with the staging updates.
Diffstat (limited to 'drivers/net/wireless/wl1251/tx.c')
-rw-r--r-- | drivers/net/wireless/wl1251/tx.c | 74 |
1 files changed, 32 insertions, 42 deletions
diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c index 554b4f9a3d3e..28121c590a2b 100644 --- a/drivers/net/wireless/wl1251/tx.c +++ b/drivers/net/wireless/wl1251/tx.c | |||
@@ -213,16 +213,30 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, | |||
213 | wl1251_debug(DEBUG_TX, "skb offset %d", offset); | 213 | wl1251_debug(DEBUG_TX, "skb offset %d", offset); |
214 | 214 | ||
215 | /* check whether the current skb can be used */ | 215 | /* check whether the current skb can be used */ |
216 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | 216 | if (skb_cloned(skb) || (skb_tailroom(skb) < offset)) { |
217 | unsigned char *src = skb->data; | 217 | struct sk_buff *newskb = skb_copy_expand(skb, 0, 3, |
218 | GFP_KERNEL); | ||
219 | |||
220 | if (unlikely(newskb == NULL)) { | ||
221 | wl1251_error("Can't allocate skb!"); | ||
222 | return -EINVAL; | ||
223 | } | ||
218 | 224 | ||
219 | /* align the buffer on a 4-byte boundary */ | 225 | tx_hdr = (struct tx_double_buffer_desc *) newskb->data; |
226 | |||
227 | dev_kfree_skb_any(skb); | ||
228 | wl->tx_frames[tx_hdr->id] = skb = newskb; | ||
229 | |||
230 | offset = (4 - (long)skb->data) & 0x03; | ||
231 | wl1251_debug(DEBUG_TX, "new skb offset %d", offset); | ||
232 | } | ||
233 | |||
234 | /* align the buffer on a 4-byte boundary */ | ||
235 | if (offset) { | ||
236 | unsigned char *src = skb->data; | ||
220 | skb_reserve(skb, offset); | 237 | skb_reserve(skb, offset); |
221 | memmove(skb->data, src, skb->len); | 238 | memmove(skb->data, src, skb->len); |
222 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | 239 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; |
223 | } else { | ||
224 | wl1251_info("No handler, fixme!"); | ||
225 | return -EINVAL; | ||
226 | } | 240 | } |
227 | } | 241 | } |
228 | 242 | ||
@@ -368,7 +382,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, | |||
368 | { | 382 | { |
369 | struct ieee80211_tx_info *info; | 383 | struct ieee80211_tx_info *info; |
370 | struct sk_buff *skb; | 384 | struct sk_buff *skb; |
371 | int hdrlen, ret; | 385 | int hdrlen; |
372 | u8 *frame; | 386 | u8 *frame; |
373 | 387 | ||
374 | skb = wl->tx_frames[result->id]; | 388 | skb = wl->tx_frames[result->id]; |
@@ -407,40 +421,12 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, | |||
407 | ieee80211_tx_status(wl->hw, skb); | 421 | ieee80211_tx_status(wl->hw, skb); |
408 | 422 | ||
409 | wl->tx_frames[result->id] = NULL; | 423 | wl->tx_frames[result->id] = NULL; |
410 | |||
411 | if (wl->tx_queue_stopped) { | ||
412 | wl1251_debug(DEBUG_TX, "cb: queue was stopped"); | ||
413 | |||
414 | skb = skb_dequeue(&wl->tx_queue); | ||
415 | |||
416 | /* The skb can be NULL because tx_work might have been | ||
417 | scheduled before the queue was stopped making the | ||
418 | queue empty */ | ||
419 | |||
420 | if (skb) { | ||
421 | ret = wl1251_tx_frame(wl, skb); | ||
422 | if (ret == -EBUSY) { | ||
423 | /* firmware buffer is still full */ | ||
424 | wl1251_debug(DEBUG_TX, "cb: fw buffer " | ||
425 | "still full"); | ||
426 | skb_queue_head(&wl->tx_queue, skb); | ||
427 | return; | ||
428 | } else if (ret < 0) { | ||
429 | dev_kfree_skb(skb); | ||
430 | return; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | wl1251_debug(DEBUG_TX, "cb: waking queues"); | ||
435 | ieee80211_wake_queues(wl->hw); | ||
436 | wl->tx_queue_stopped = false; | ||
437 | } | ||
438 | } | 424 | } |
439 | 425 | ||
440 | /* Called upon reception of a TX complete interrupt */ | 426 | /* Called upon reception of a TX complete interrupt */ |
441 | void wl1251_tx_complete(struct wl1251 *wl) | 427 | void wl1251_tx_complete(struct wl1251 *wl) |
442 | { | 428 | { |
443 | int i, result_index, num_complete = 0; | 429 | int i, result_index, num_complete = 0, queue_len; |
444 | struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; | 430 | struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; |
445 | unsigned long flags; | 431 | unsigned long flags; |
446 | 432 | ||
@@ -471,18 +457,22 @@ void wl1251_tx_complete(struct wl1251 *wl) | |||
471 | } | 457 | } |
472 | } | 458 | } |
473 | 459 | ||
474 | if (wl->tx_queue_stopped | 460 | queue_len = skb_queue_len(&wl->tx_queue); |
475 | && | ||
476 | skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){ | ||
477 | 461 | ||
478 | /* firmware buffer has space, restart queues */ | 462 | if ((num_complete > 0) && (queue_len > 0)) { |
463 | /* firmware buffer has space, reschedule tx_work */ | ||
464 | wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work"); | ||
465 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
466 | } | ||
467 | |||
468 | if (wl->tx_queue_stopped && | ||
469 | queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) { | ||
470 | /* tx_queue has space, restart queues */ | ||
479 | wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); | 471 | wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); |
480 | spin_lock_irqsave(&wl->wl_lock, flags); | 472 | spin_lock_irqsave(&wl->wl_lock, flags); |
481 | ieee80211_wake_queues(wl->hw); | 473 | ieee80211_wake_queues(wl->hw); |
482 | wl->tx_queue_stopped = false; | 474 | wl->tx_queue_stopped = false; |
483 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 475 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
484 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
485 | |||
486 | } | 476 | } |
487 | 477 | ||
488 | /* Every completed frame needs to be acknowledged */ | 478 | /* Every completed frame needs to be acknowledged */ |