diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 143 |
1 files changed, 106 insertions, 37 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 8c24cd72aaca..a70827793086 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -729,6 +729,7 @@ static void b43_synchronize_irq(struct b43_wldev *dev) | |||
729 | */ | 729 | */ |
730 | void b43_dummy_transmission(struct b43_wldev *dev) | 730 | void b43_dummy_transmission(struct b43_wldev *dev) |
731 | { | 731 | { |
732 | struct b43_wl *wl = dev->wl; | ||
732 | struct b43_phy *phy = &dev->phy; | 733 | struct b43_phy *phy = &dev->phy; |
733 | unsigned int i, max_loop; | 734 | unsigned int i, max_loop; |
734 | u16 value; | 735 | u16 value; |
@@ -755,6 +756,9 @@ void b43_dummy_transmission(struct b43_wldev *dev) | |||
755 | return; | 756 | return; |
756 | } | 757 | } |
757 | 758 | ||
759 | spin_lock_irq(&wl->irq_lock); | ||
760 | write_lock(&wl->tx_lock); | ||
761 | |||
758 | for (i = 0; i < 5; i++) | 762 | for (i = 0; i < 5; i++) |
759 | b43_ram_write(dev, i * 4, buffer[i]); | 763 | b43_ram_write(dev, i * 4, buffer[i]); |
760 | 764 | ||
@@ -795,6 +799,9 @@ void b43_dummy_transmission(struct b43_wldev *dev) | |||
795 | } | 799 | } |
796 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) | 800 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) |
797 | b43_radio_write16(dev, 0x0051, 0x0037); | 801 | b43_radio_write16(dev, 0x0051, 0x0037); |
802 | |||
803 | write_unlock(&wl->tx_lock); | ||
804 | spin_unlock_irq(&wl->irq_lock); | ||
798 | } | 805 | } |
799 | 806 | ||
800 | static void key_write(struct b43_wldev *dev, | 807 | static void key_write(struct b43_wldev *dev, |
@@ -1138,7 +1145,6 @@ static void b43_generate_noise_sample(struct b43_wldev *dev) | |||
1138 | b43_jssi_write(dev, 0x7F7F7F7F); | 1145 | b43_jssi_write(dev, 0x7F7F7F7F); |
1139 | b43_write32(dev, B43_MMIO_MACCMD, | 1146 | b43_write32(dev, B43_MMIO_MACCMD, |
1140 | b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); | 1147 | b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); |
1141 | B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); | ||
1142 | } | 1148 | } |
1143 | 1149 | ||
1144 | static void b43_calculate_link_quality(struct b43_wldev *dev) | 1150 | static void b43_calculate_link_quality(struct b43_wldev *dev) |
@@ -1147,7 +1153,6 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) | |||
1147 | 1153 | ||
1148 | if (dev->noisecalc.calculation_running) | 1154 | if (dev->noisecalc.calculation_running) |
1149 | return; | 1155 | return; |
1150 | dev->noisecalc.channel_at_start = dev->phy.channel; | ||
1151 | dev->noisecalc.calculation_running = 1; | 1156 | dev->noisecalc.calculation_running = 1; |
1152 | dev->noisecalc.nr_samples = 0; | 1157 | dev->noisecalc.nr_samples = 0; |
1153 | 1158 | ||
@@ -1164,9 +1169,16 @@ static void handle_irq_noise(struct b43_wldev *dev) | |||
1164 | 1169 | ||
1165 | /* Bottom half of Link Quality calculation. */ | 1170 | /* Bottom half of Link Quality calculation. */ |
1166 | 1171 | ||
1172 | /* Possible race condition: It might be possible that the user | ||
1173 | * changed to a different channel in the meantime since we | ||
1174 | * started the calculation. We ignore that fact, since it's | ||
1175 | * not really that much of a problem. The background noise is | ||
1176 | * an estimation only anyway. Slightly wrong results will get damped | ||
1177 | * by the averaging of the 8 sample rounds. Additionally the | ||
1178 | * value is shortlived. So it will be replaced by the next noise | ||
1179 | * calculation round soon. */ | ||
1180 | |||
1167 | B43_WARN_ON(!dev->noisecalc.calculation_running); | 1181 | B43_WARN_ON(!dev->noisecalc.calculation_running); |
1168 | if (dev->noisecalc.channel_at_start != phy->channel) | ||
1169 | goto drop_calculation; | ||
1170 | *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); | 1182 | *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); |
1171 | if (noise[0] == 0x7F || noise[1] == 0x7F || | 1183 | if (noise[0] == 0x7F || noise[1] == 0x7F || |
1172 | noise[2] == 0x7F || noise[3] == 0x7F) | 1184 | noise[2] == 0x7F || noise[3] == 0x7F) |
@@ -1207,11 +1219,10 @@ static void handle_irq_noise(struct b43_wldev *dev) | |||
1207 | average -= 48; | 1219 | average -= 48; |
1208 | 1220 | ||
1209 | dev->stats.link_noise = average; | 1221 | dev->stats.link_noise = average; |
1210 | drop_calculation: | ||
1211 | dev->noisecalc.calculation_running = 0; | 1222 | dev->noisecalc.calculation_running = 0; |
1212 | return; | 1223 | return; |
1213 | } | 1224 | } |
1214 | generate_new: | 1225 | generate_new: |
1215 | b43_generate_noise_sample(dev); | 1226 | b43_generate_noise_sample(dev); |
1216 | } | 1227 | } |
1217 | 1228 | ||
@@ -1537,6 +1548,30 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, | |||
1537 | kfree(probe_resp_data); | 1548 | kfree(probe_resp_data); |
1538 | } | 1549 | } |
1539 | 1550 | ||
1551 | static void b43_upload_beacon0(struct b43_wldev *dev) | ||
1552 | { | ||
1553 | struct b43_wl *wl = dev->wl; | ||
1554 | |||
1555 | if (wl->beacon0_uploaded) | ||
1556 | return; | ||
1557 | b43_write_beacon_template(dev, 0x68, 0x18); | ||
1558 | /* FIXME: Probe resp upload doesn't really belong here, | ||
1559 | * but we don't use that feature anyway. */ | ||
1560 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | ||
1561 | &__b43_ratetable[3]); | ||
1562 | wl->beacon0_uploaded = 1; | ||
1563 | } | ||
1564 | |||
1565 | static void b43_upload_beacon1(struct b43_wldev *dev) | ||
1566 | { | ||
1567 | struct b43_wl *wl = dev->wl; | ||
1568 | |||
1569 | if (wl->beacon1_uploaded) | ||
1570 | return; | ||
1571 | b43_write_beacon_template(dev, 0x468, 0x1A); | ||
1572 | wl->beacon1_uploaded = 1; | ||
1573 | } | ||
1574 | |||
1540 | static void handle_irq_beacon(struct b43_wldev *dev) | 1575 | static void handle_irq_beacon(struct b43_wldev *dev) |
1541 | { | 1576 | { |
1542 | struct b43_wl *wl = dev->wl; | 1577 | struct b43_wl *wl = dev->wl; |
@@ -1561,24 +1596,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1561 | return; | 1596 | return; |
1562 | } | 1597 | } |
1563 | 1598 | ||
1564 | if (!beacon0_valid) { | 1599 | if (unlikely(wl->beacon_templates_virgin)) { |
1565 | if (!wl->beacon0_uploaded) { | 1600 | /* We never uploaded a beacon before. |
1566 | b43_write_beacon_template(dev, 0x68, 0x18); | 1601 | * Upload both templates now, but only mark one valid. */ |
1567 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | 1602 | wl->beacon_templates_virgin = 0; |
1568 | &__b43_ratetable[3]); | 1603 | b43_upload_beacon0(dev); |
1569 | wl->beacon0_uploaded = 1; | 1604 | b43_upload_beacon1(dev); |
1570 | } | ||
1571 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | 1605 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
1572 | cmd |= B43_MACCMD_BEACON0_VALID; | 1606 | cmd |= B43_MACCMD_BEACON0_VALID; |
1573 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | 1607 | b43_write32(dev, B43_MMIO_MACCMD, cmd); |
1574 | } else if (!beacon1_valid) { | 1608 | } else { |
1575 | if (!wl->beacon1_uploaded) { | 1609 | if (!beacon0_valid) { |
1576 | b43_write_beacon_template(dev, 0x468, 0x1A); | 1610 | b43_upload_beacon0(dev); |
1577 | wl->beacon1_uploaded = 1; | 1611 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
1612 | cmd |= B43_MACCMD_BEACON0_VALID; | ||
1613 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1614 | } else if (!beacon1_valid) { | ||
1615 | b43_upload_beacon1(dev); | ||
1616 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | ||
1617 | cmd |= B43_MACCMD_BEACON1_VALID; | ||
1618 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1578 | } | 1619 | } |
1579 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | ||
1580 | cmd |= B43_MACCMD_BEACON1_VALID; | ||
1581 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1582 | } | 1620 | } |
1583 | } | 1621 | } |
1584 | 1622 | ||
@@ -2840,26 +2878,37 @@ static int b43_op_tx(struct ieee80211_hw *hw, | |||
2840 | { | 2878 | { |
2841 | struct b43_wl *wl = hw_to_b43_wl(hw); | 2879 | struct b43_wl *wl = hw_to_b43_wl(hw); |
2842 | struct b43_wldev *dev = wl->current_dev; | 2880 | struct b43_wldev *dev = wl->current_dev; |
2843 | int err = -ENODEV; | 2881 | unsigned long flags; |
2882 | int err; | ||
2844 | 2883 | ||
2845 | if (unlikely(skb->len < 2 + 2 + 6)) { | 2884 | if (unlikely(skb->len < 2 + 2 + 6)) { |
2846 | /* Too short, this can't be a valid frame. */ | 2885 | /* Too short, this can't be a valid frame. */ |
2847 | return -EINVAL; | 2886 | goto drop_packet; |
2848 | } | 2887 | } |
2849 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | 2888 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); |
2850 | |||
2851 | if (unlikely(!dev)) | 2889 | if (unlikely(!dev)) |
2852 | goto out; | 2890 | goto drop_packet; |
2853 | if (unlikely(b43_status(dev) < B43_STAT_STARTED)) | 2891 | |
2854 | goto out; | 2892 | /* Transmissions on seperate queues can run concurrently. */ |
2855 | /* TX is done without a global lock. */ | 2893 | read_lock_irqsave(&wl->tx_lock, flags); |
2856 | if (b43_using_pio_transfers(dev)) | 2894 | |
2857 | err = b43_pio_tx(dev, skb, ctl); | 2895 | err = -ENODEV; |
2858 | else | 2896 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { |
2859 | err = b43_dma_tx(dev, skb, ctl); | 2897 | if (b43_using_pio_transfers(dev)) |
2860 | out: | 2898 | err = b43_pio_tx(dev, skb, ctl); |
2899 | else | ||
2900 | err = b43_dma_tx(dev, skb, ctl); | ||
2901 | } | ||
2902 | |||
2903 | read_unlock_irqrestore(&wl->tx_lock, flags); | ||
2904 | |||
2861 | if (unlikely(err)) | 2905 | if (unlikely(err)) |
2862 | return NETDEV_TX_BUSY; | 2906 | goto drop_packet; |
2907 | return NETDEV_TX_OK; | ||
2908 | |||
2909 | drop_packet: | ||
2910 | /* We can not transmit this packet. Drop it. */ | ||
2911 | dev_kfree_skb_any(skb); | ||
2863 | return NETDEV_TX_OK; | 2912 | return NETDEV_TX_OK; |
2864 | } | 2913 | } |
2865 | 2914 | ||
@@ -3476,7 +3525,9 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) | |||
3476 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3525 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
3477 | b43_synchronize_irq(dev); | 3526 | b43_synchronize_irq(dev); |
3478 | 3527 | ||
3528 | write_lock_irqsave(&wl->tx_lock, flags); | ||
3479 | b43_set_status(dev, B43_STAT_INITIALIZED); | 3529 | b43_set_status(dev, B43_STAT_INITIALIZED); |
3530 | write_unlock_irqrestore(&wl->tx_lock, flags); | ||
3480 | 3531 | ||
3481 | b43_pio_stop(dev); | 3532 | b43_pio_stop(dev); |
3482 | mutex_unlock(&wl->mutex); | 3533 | mutex_unlock(&wl->mutex); |
@@ -3485,8 +3536,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) | |||
3485 | cancel_delayed_work_sync(&dev->periodic_work); | 3536 | cancel_delayed_work_sync(&dev->periodic_work); |
3486 | mutex_lock(&wl->mutex); | 3537 | mutex_lock(&wl->mutex); |
3487 | 3538 | ||
3488 | ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy. | ||
3489 | |||
3490 | b43_mac_suspend(dev); | 3539 | b43_mac_suspend(dev); |
3491 | free_irq(dev->dev->irq, dev); | 3540 | free_irq(dev->dev->irq, dev); |
3492 | b43dbg(wl, "Wireless interface stopped\n"); | 3541 | b43dbg(wl, "Wireless interface stopped\n"); |
@@ -4059,6 +4108,9 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4059 | wl->filter_flags = 0; | 4108 | wl->filter_flags = 0; |
4060 | wl->radiotap_enabled = 0; | 4109 | wl->radiotap_enabled = 0; |
4061 | b43_qos_clear(wl); | 4110 | b43_qos_clear(wl); |
4111 | wl->beacon0_uploaded = 0; | ||
4112 | wl->beacon1_uploaded = 0; | ||
4113 | wl->beacon_templates_virgin = 1; | ||
4062 | 4114 | ||
4063 | /* First register RFkill. | 4115 | /* First register RFkill. |
4064 | * LEDs that are registered later depend on it. */ | 4116 | * LEDs that are registered later depend on it. */ |
@@ -4227,7 +4279,9 @@ static void b43_chip_reset(struct work_struct *work) | |||
4227 | goto out; | 4279 | goto out; |
4228 | } | 4280 | } |
4229 | } | 4281 | } |
4230 | out: | 4282 | out: |
4283 | if (err) | ||
4284 | wl->current_dev = NULL; /* Failed to init the dev. */ | ||
4231 | mutex_unlock(&wl->mutex); | 4285 | mutex_unlock(&wl->mutex); |
4232 | if (err) | 4286 | if (err) |
4233 | b43err(wl, "Controller restart FAILED\n"); | 4287 | b43err(wl, "Controller restart FAILED\n"); |
@@ -4326,6 +4380,14 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) | |||
4326 | err = -EOPNOTSUPP; | 4380 | err = -EOPNOTSUPP; |
4327 | goto err_powerdown; | 4381 | goto err_powerdown; |
4328 | } | 4382 | } |
4383 | if (1 /* disable A-PHY */) { | ||
4384 | /* FIXME: For now we disable the A-PHY on multi-PHY devices. */ | ||
4385 | if (dev->phy.type != B43_PHYTYPE_N) { | ||
4386 | have_2ghz_phy = 1; | ||
4387 | have_5ghz_phy = 0; | ||
4388 | } | ||
4389 | } | ||
4390 | |||
4329 | dev->phy.gmode = have_2ghz_phy; | 4391 | dev->phy.gmode = have_2ghz_phy; |
4330 | tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; | 4392 | tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; |
4331 | b43_wireless_core_reset(dev, tmp); | 4393 | b43_wireless_core_reset(dev, tmp); |
@@ -4360,9 +4422,11 @@ static void b43_one_core_detach(struct ssb_device *dev) | |||
4360 | struct b43_wldev *wldev; | 4422 | struct b43_wldev *wldev; |
4361 | struct b43_wl *wl; | 4423 | struct b43_wl *wl; |
4362 | 4424 | ||
4425 | /* Do not cancel ieee80211-workqueue based work here. | ||
4426 | * See comment in b43_remove(). */ | ||
4427 | |||
4363 | wldev = ssb_get_drvdata(dev); | 4428 | wldev = ssb_get_drvdata(dev); |
4364 | wl = wldev->wl; | 4429 | wl = wldev->wl; |
4365 | cancel_work_sync(&wldev->restart_work); | ||
4366 | b43_debugfs_remove_device(wldev); | 4430 | b43_debugfs_remove_device(wldev); |
4367 | b43_wireless_core_detach(wldev); | 4431 | b43_wireless_core_detach(wldev); |
4368 | list_del(&wldev->list); | 4432 | list_del(&wldev->list); |
@@ -4490,6 +4554,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4490 | memset(wl, 0, sizeof(*wl)); | 4554 | memset(wl, 0, sizeof(*wl)); |
4491 | wl->hw = hw; | 4555 | wl->hw = hw; |
4492 | spin_lock_init(&wl->irq_lock); | 4556 | spin_lock_init(&wl->irq_lock); |
4557 | rwlock_init(&wl->tx_lock); | ||
4493 | spin_lock_init(&wl->leds_lock); | 4558 | spin_lock_init(&wl->leds_lock); |
4494 | spin_lock_init(&wl->shm_lock); | 4559 | spin_lock_init(&wl->shm_lock); |
4495 | mutex_init(&wl->mutex); | 4560 | mutex_init(&wl->mutex); |
@@ -4546,6 +4611,10 @@ static void b43_remove(struct ssb_device *dev) | |||
4546 | struct b43_wl *wl = ssb_get_devtypedata(dev); | 4611 | struct b43_wl *wl = ssb_get_devtypedata(dev); |
4547 | struct b43_wldev *wldev = ssb_get_drvdata(dev); | 4612 | struct b43_wldev *wldev = ssb_get_drvdata(dev); |
4548 | 4613 | ||
4614 | /* We must cancel any work here before unregistering from ieee80211, | ||
4615 | * as the ieee80211 unreg will destroy the workqueue. */ | ||
4616 | cancel_work_sync(&wldev->restart_work); | ||
4617 | |||
4549 | B43_WARN_ON(!wl); | 4618 | B43_WARN_ON(!wl); |
4550 | if (wl->current_dev == wldev) | 4619 | if (wl->current_dev == wldev) |
4551 | ieee80211_unregister_hw(wl->hw); | 4620 | ieee80211_unregister_hw(wl->hw); |