diff options
author | Michael Buesch <mb@bu3sch.de> | 2009-09-04 16:53:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-09-08 16:31:06 -0400 |
commit | f5d40eedb32aa9a0e226d468e1f89fb676824694 (patch) | |
tree | 8fb9fce1dd10b71fd940cbb22cbbf12887fe2d4b /drivers/net/wireless/b43/main.c | |
parent | 36dbd9548e92268127b0c31b0e121e63e9207108 (diff) |
b43: Remove TX spinlock
This removes the TX spinlock and defers TX to a workqueue to allow
locking wl->mutex instead and to allow sleeping for register accesses.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Tested-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 75 |
1 files changed, 38 insertions, 37 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 80b688441ffe..fca2fe947d7d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -690,7 +690,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) | |||
690 | */ | 690 | */ |
691 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | 691 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) |
692 | { | 692 | { |
693 | struct b43_wl *wl = dev->wl; | ||
694 | struct b43_phy *phy = &dev->phy; | 693 | struct b43_phy *phy = &dev->phy; |
695 | unsigned int i, max_loop; | 694 | unsigned int i, max_loop; |
696 | u16 value; | 695 | u16 value; |
@@ -710,8 +709,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
710 | buffer[0] = 0x000B846E; | 709 | buffer[0] = 0x000B846E; |
711 | } | 710 | } |
712 | 711 | ||
713 | write_lock_irq(&wl->tx_lock); | ||
714 | |||
715 | for (i = 0; i < 5; i++) | 712 | for (i = 0; i < 5; i++) |
716 | b43_ram_write(dev, i * 4, buffer[i]); | 713 | b43_ram_write(dev, i * 4, buffer[i]); |
717 | 714 | ||
@@ -767,8 +764,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
767 | } | 764 | } |
768 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) | 765 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) |
769 | b43_radio_write16(dev, 0x0051, 0x0037); | 766 | b43_radio_write16(dev, 0x0051, 0x0037); |
770 | |||
771 | write_unlock_irq(&wl->tx_lock); | ||
772 | } | 767 | } |
773 | 768 | ||
774 | static void key_write(struct b43_wldev *dev, | 769 | static void key_write(struct b43_wldev *dev, |
@@ -3098,42 +3093,49 @@ static int b43_rng_init(struct b43_wl *wl) | |||
3098 | return err; | 3093 | return err; |
3099 | } | 3094 | } |
3100 | 3095 | ||
3101 | static int b43_op_tx(struct ieee80211_hw *hw, | 3096 | static void b43_tx_work(struct work_struct *work) |
3102 | struct sk_buff *skb) | ||
3103 | { | 3097 | { |
3104 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3098 | struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); |
3105 | struct b43_wldev *dev = wl->current_dev; | 3099 | struct b43_wldev *dev; |
3106 | unsigned long flags; | 3100 | struct sk_buff *skb; |
3107 | int err; | 3101 | int err = 0; |
3108 | 3102 | ||
3109 | if (unlikely(skb->len < 2 + 2 + 6)) { | 3103 | mutex_lock(&wl->mutex); |
3110 | /* Too short, this can't be a valid frame. */ | 3104 | dev = wl->current_dev; |
3111 | goto drop_packet; | 3105 | if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { |
3106 | mutex_unlock(&wl->mutex); | ||
3107 | return; | ||
3112 | } | 3108 | } |
3113 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3114 | if (unlikely(!dev)) | ||
3115 | goto drop_packet; | ||
3116 | 3109 | ||
3117 | /* Transmissions on seperate queues can run concurrently. */ | 3110 | while (skb_queue_len(&wl->tx_queue)) { |
3118 | read_lock_irqsave(&wl->tx_lock, flags); | 3111 | skb = skb_dequeue(&wl->tx_queue); |
3119 | 3112 | ||
3120 | err = -ENODEV; | ||
3121 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { | ||
3122 | if (b43_using_pio_transfers(dev)) | 3113 | if (b43_using_pio_transfers(dev)) |
3123 | err = b43_pio_tx(dev, skb); | 3114 | err = b43_pio_tx(dev, skb); |
3124 | else | 3115 | else |
3125 | err = b43_dma_tx(dev, skb); | 3116 | err = b43_dma_tx(dev, skb); |
3117 | if (unlikely(err)) | ||
3118 | dev_kfree_skb(skb); /* Drop it */ | ||
3126 | } | 3119 | } |
3127 | 3120 | ||
3128 | read_unlock_irqrestore(&wl->tx_lock, flags); | 3121 | mutex_unlock(&wl->mutex); |
3122 | } | ||
3129 | 3123 | ||
3130 | if (unlikely(err)) | 3124 | static int b43_op_tx(struct ieee80211_hw *hw, |
3131 | goto drop_packet; | 3125 | struct sk_buff *skb) |
3132 | return NETDEV_TX_OK; | 3126 | { |
3127 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3128 | |||
3129 | if (unlikely(skb->len < 2 + 2 + 6)) { | ||
3130 | /* Too short, this can't be a valid frame. */ | ||
3131 | dev_kfree_skb_any(skb); | ||
3132 | return NETDEV_TX_OK; | ||
3133 | } | ||
3134 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3135 | |||
3136 | skb_queue_tail(&wl->tx_queue, skb); | ||
3137 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
3133 | 3138 | ||
3134 | drop_packet: | ||
3135 | /* We can not transmit this packet. Drop it. */ | ||
3136 | dev_kfree_skb_any(skb); | ||
3137 | return NETDEV_TX_OK; | 3139 | return NETDEV_TX_OK; |
3138 | } | 3140 | } |
3139 | 3141 | ||
@@ -3686,18 +3688,12 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3686 | u8 algorithm; | 3688 | u8 algorithm; |
3687 | u8 index; | 3689 | u8 index; |
3688 | int err; | 3690 | int err; |
3689 | unsigned long flags; | ||
3690 | static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 3691 | static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
3691 | 3692 | ||
3692 | if (modparam_nohwcrypt) | 3693 | if (modparam_nohwcrypt) |
3693 | return -ENOSPC; /* User disabled HW-crypto */ | 3694 | return -ENOSPC; /* User disabled HW-crypto */ |
3694 | 3695 | ||
3695 | mutex_lock(&wl->mutex); | 3696 | mutex_lock(&wl->mutex); |
3696 | write_lock_irqsave(&wl->tx_lock, flags); | ||
3697 | /* mutex -> Every config operation must take it. | ||
3698 | * tx_lock -> We modify the dev->key array, which is accessed | ||
3699 | * in the TX handler. | ||
3700 | */ | ||
3701 | 3697 | ||
3702 | dev = wl->current_dev; | 3698 | dev = wl->current_dev; |
3703 | err = -ENODEV; | 3699 | err = -ENODEV; |
@@ -3789,7 +3785,6 @@ out_unlock: | |||
3789 | sta ? sta->addr : bcast_addr); | 3785 | sta ? sta->addr : bcast_addr); |
3790 | b43_dump_keymemory(dev); | 3786 | b43_dump_keymemory(dev); |
3791 | } | 3787 | } |
3792 | write_unlock_irqrestore(&wl->tx_lock, flags); | ||
3793 | mutex_unlock(&wl->mutex); | 3788 | mutex_unlock(&wl->mutex); |
3794 | 3789 | ||
3795 | return err; | 3790 | return err; |
@@ -3846,9 +3841,10 @@ redo: | |||
3846 | if (!dev || b43_status(dev) < B43_STAT_STARTED) | 3841 | if (!dev || b43_status(dev) < B43_STAT_STARTED) |
3847 | return dev; | 3842 | return dev; |
3848 | 3843 | ||
3849 | /* Disable periodic work. Unlock to avoid deadlocks. */ | 3844 | /* Cancel work. Unlock to avoid deadlocks. */ |
3850 | mutex_unlock(&wl->mutex); | 3845 | mutex_unlock(&wl->mutex); |
3851 | cancel_delayed_work_sync(&dev->periodic_work); | 3846 | cancel_delayed_work_sync(&dev->periodic_work); |
3847 | cancel_work_sync(&wl->tx_work); | ||
3852 | mutex_lock(&wl->mutex); | 3848 | mutex_lock(&wl->mutex); |
3853 | dev = wl->current_dev; | 3849 | dev = wl->current_dev; |
3854 | if (!dev || b43_status(dev) < B43_STAT_STARTED) { | 3850 | if (!dev || b43_status(dev) < B43_STAT_STARTED) { |
@@ -3883,6 +3879,10 @@ redo: | |||
3883 | } | 3879 | } |
3884 | B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); | 3880 | B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); |
3885 | 3881 | ||
3882 | /* Drain the TX queue */ | ||
3883 | while (skb_queue_len(&wl->tx_queue)) | ||
3884 | dev_kfree_skb(skb_dequeue(&wl->tx_queue)); | ||
3885 | |||
3886 | b43_pio_stop(dev); | 3886 | b43_pio_stop(dev); |
3887 | b43_mac_suspend(dev); | 3887 | b43_mac_suspend(dev); |
3888 | free_irq(dev->dev->irq, dev); | 3888 | free_irq(dev->dev->irq, dev); |
@@ -4866,7 +4866,6 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4866 | 4866 | ||
4867 | /* Initialize struct b43_wl */ | 4867 | /* Initialize struct b43_wl */ |
4868 | wl->hw = hw; | 4868 | wl->hw = hw; |
4869 | rwlock_init(&wl->tx_lock); | ||
4870 | spin_lock_init(&wl->leds_lock); | 4869 | spin_lock_init(&wl->leds_lock); |
4871 | spin_lock_init(&wl->shm_lock); | 4870 | spin_lock_init(&wl->shm_lock); |
4872 | mutex_init(&wl->mutex); | 4871 | mutex_init(&wl->mutex); |
@@ -4874,6 +4873,8 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4874 | INIT_LIST_HEAD(&wl->devlist); | 4873 | INIT_LIST_HEAD(&wl->devlist); |
4875 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); | 4874 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); |
4876 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); | 4875 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); |
4876 | INIT_WORK(&wl->tx_work, b43_tx_work); | ||
4877 | skb_queue_head_init(&wl->tx_queue); | ||
4877 | 4878 | ||
4878 | ssb_set_devtypedata(dev, wl); | 4879 | ssb_set_devtypedata(dev, wl); |
4879 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", | 4880 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", |