diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-01-05 10:12:45 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-01-05 10:13:24 -0500 |
commit | 1032c736e81cdf490ae62f86da7efe67c3c3e61d (patch) | |
tree | a0c3919849f97dbbc5ea7c6a9ac1d7a639e44a73 /drivers/net/wireless/b43legacy/main.c | |
parent | 117ff42fd43e92d24c6aa6f3e4f0f1e1edada140 (diff) | |
parent | cb00ec382b57d35b955c085198cd54a0c1fcdc94 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/b43legacy/dma.c
Diffstat (limited to 'drivers/net/wireless/b43legacy/main.c')
-rw-r--r-- | drivers/net/wireless/b43legacy/main.c | 86 |
1 files changed, 67 insertions, 19 deletions
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 200138cdb030..75e70bce40f6 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -2440,30 +2440,64 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) | |||
2440 | return err; | 2440 | return err; |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | static void b43legacy_tx_work(struct work_struct *work) | ||
2444 | { | ||
2445 | struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl, | ||
2446 | tx_work); | ||
2447 | struct b43legacy_wldev *dev; | ||
2448 | struct sk_buff *skb; | ||
2449 | int queue_num; | ||
2450 | int err = 0; | ||
2451 | |||
2452 | mutex_lock(&wl->mutex); | ||
2453 | dev = wl->current_dev; | ||
2454 | if (unlikely(!dev || b43legacy_status(dev) < B43legacy_STAT_STARTED)) { | ||
2455 | mutex_unlock(&wl->mutex); | ||
2456 | return; | ||
2457 | } | ||
2458 | |||
2459 | for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) { | ||
2460 | while (skb_queue_len(&wl->tx_queue[queue_num])) { | ||
2461 | skb = skb_dequeue(&wl->tx_queue[queue_num]); | ||
2462 | if (b43legacy_using_pio(dev)) | ||
2463 | err = b43legacy_pio_tx(dev, skb); | ||
2464 | else | ||
2465 | err = b43legacy_dma_tx(dev, skb); | ||
2466 | if (err == -ENOSPC) { | ||
2467 | wl->tx_queue_stopped[queue_num] = 1; | ||
2468 | ieee80211_stop_queue(wl->hw, queue_num); | ||
2469 | skb_queue_head(&wl->tx_queue[queue_num], skb); | ||
2470 | break; | ||
2471 | } | ||
2472 | if (unlikely(err)) | ||
2473 | dev_kfree_skb(skb); /* Drop it */ | ||
2474 | err = 0; | ||
2475 | } | ||
2476 | |||
2477 | if (!err) | ||
2478 | wl->tx_queue_stopped[queue_num] = 0; | ||
2479 | } | ||
2480 | |||
2481 | mutex_unlock(&wl->mutex); | ||
2482 | } | ||
2483 | |||
2443 | static void b43legacy_op_tx(struct ieee80211_hw *hw, | 2484 | static void b43legacy_op_tx(struct ieee80211_hw *hw, |
2444 | struct sk_buff *skb) | 2485 | struct sk_buff *skb) |
2445 | { | 2486 | { |
2446 | struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | 2487 | struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); |
2447 | struct b43legacy_wldev *dev = wl->current_dev; | ||
2448 | int err = -ENODEV; | ||
2449 | unsigned long flags; | ||
2450 | 2488 | ||
2451 | if (unlikely(!dev)) | 2489 | if (unlikely(skb->len < 2 + 2 + 6)) { |
2452 | goto out; | 2490 | /* Too short, this can't be a valid frame. */ |
2453 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) | ||
2454 | goto out; | ||
2455 | /* DMA-TX is done without a global lock. */ | ||
2456 | if (b43legacy_using_pio(dev)) { | ||
2457 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2458 | err = b43legacy_pio_tx(dev, skb); | ||
2459 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2460 | } else | ||
2461 | err = b43legacy_dma_tx(dev, skb); | ||
2462 | out: | ||
2463 | if (unlikely(err)) { | ||
2464 | /* Drop the packet. */ | ||
2465 | dev_kfree_skb_any(skb); | 2491 | dev_kfree_skb_any(skb); |
2492 | return; | ||
2466 | } | 2493 | } |
2494 | B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
2495 | |||
2496 | skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); | ||
2497 | if (!wl->tx_queue_stopped[skb->queue_mapping]) | ||
2498 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
2499 | else | ||
2500 | ieee80211_stop_queue(wl->hw, skb->queue_mapping); | ||
2467 | } | 2501 | } |
2468 | 2502 | ||
2469 | static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, | 2503 | static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, |
@@ -2879,6 +2913,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) | |||
2879 | { | 2913 | { |
2880 | struct b43legacy_wl *wl = dev->wl; | 2914 | struct b43legacy_wl *wl = dev->wl; |
2881 | unsigned long flags; | 2915 | unsigned long flags; |
2916 | int queue_num; | ||
2882 | 2917 | ||
2883 | if (b43legacy_status(dev) < B43legacy_STAT_STARTED) | 2918 | if (b43legacy_status(dev) < B43legacy_STAT_STARTED) |
2884 | return; | 2919 | return; |
@@ -2898,11 +2933,16 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) | |||
2898 | /* Must unlock as it would otherwise deadlock. No races here. | 2933 | /* Must unlock as it would otherwise deadlock. No races here. |
2899 | * Cancel the possibly running self-rearming periodic work. */ | 2934 | * Cancel the possibly running self-rearming periodic work. */ |
2900 | cancel_delayed_work_sync(&dev->periodic_work); | 2935 | cancel_delayed_work_sync(&dev->periodic_work); |
2936 | cancel_work_sync(&wl->tx_work); | ||
2901 | mutex_lock(&wl->mutex); | 2937 | mutex_lock(&wl->mutex); |
2902 | 2938 | ||
2903 | ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */ | 2939 | /* Drain all TX queues. */ |
2940 | for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) { | ||
2941 | while (skb_queue_len(&wl->tx_queue[queue_num])) | ||
2942 | dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num])); | ||
2943 | } | ||
2904 | 2944 | ||
2905 | b43legacy_mac_suspend(dev); | 2945 | b43legacy_mac_suspend(dev); |
2906 | free_irq(dev->dev->irq, dev); | 2946 | free_irq(dev->dev->irq, dev); |
2907 | b43legacydbg(wl, "Wireless interface stopped\n"); | 2947 | b43legacydbg(wl, "Wireless interface stopped\n"); |
2908 | } | 2948 | } |
@@ -3748,6 +3788,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) | |||
3748 | struct ieee80211_hw *hw; | 3788 | struct ieee80211_hw *hw; |
3749 | struct b43legacy_wl *wl; | 3789 | struct b43legacy_wl *wl; |
3750 | int err = -ENOMEM; | 3790 | int err = -ENOMEM; |
3791 | int queue_num; | ||
3751 | 3792 | ||
3752 | b43legacy_sprom_fixup(dev->bus); | 3793 | b43legacy_sprom_fixup(dev->bus); |
3753 | 3794 | ||
@@ -3782,6 +3823,13 @@ static int b43legacy_wireless_init(struct ssb_device *dev) | |||
3782 | mutex_init(&wl->mutex); | 3823 | mutex_init(&wl->mutex); |
3783 | INIT_LIST_HEAD(&wl->devlist); | 3824 | INIT_LIST_HEAD(&wl->devlist); |
3784 | INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); | 3825 | INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); |
3826 | INIT_WORK(&wl->tx_work, b43legacy_tx_work); | ||
3827 | |||
3828 | /* Initialize queues and flags. */ | ||
3829 | for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) { | ||
3830 | skb_queue_head_init(&wl->tx_queue[queue_num]); | ||
3831 | wl->tx_queue_stopped[queue_num] = 0; | ||
3832 | } | ||
3785 | 3833 | ||
3786 | ssb_set_devtypedata(dev, wl); | 3834 | ssb_set_devtypedata(dev, wl); |
3787 | b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n", | 3835 | b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n", |