aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy/main.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-01-05 10:12:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-01-05 10:13:24 -0500
commit1032c736e81cdf490ae62f86da7efe67c3c3e61d (patch)
treea0c3919849f97dbbc5ea7c6a9ac1d7a639e44a73 /drivers/net/wireless/b43legacy/main.c
parent117ff42fd43e92d24c6aa6f3e4f0f1e1edada140 (diff)
parentcb00ec382b57d35b955c085198cd54a0c1fcdc94 (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.c86
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
2443static 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
2443static void b43legacy_op_tx(struct ieee80211_hw *hw, 2484static 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);
2462out:
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
2469static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, 2503static 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); 2945b43legacy_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",