diff options
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r-- | drivers/net/wireless/b43/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 65 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 98 |
5 files changed, 109 insertions, 61 deletions
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index f51b2d9b085b..1fa043d1802c 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config B43 | 1 | config B43 |
2 | tristate "Broadcom 43xx wireless support (mac80211 stack)" | 2 | tristate "Broadcom 43xx wireless support (mac80211 stack)" |
3 | depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 | 3 | depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA |
4 | select SSB | 4 | select SSB |
5 | select FW_LOADER | 5 | select FW_LOADER |
6 | select HW_RANDOM | 6 | select HW_RANDOM |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 37783cdd301a..d3db298c05fc 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -630,7 +630,6 @@ struct b43_pio { | |||
630 | 630 | ||
631 | /* Context information for a noise calculation (Link Quality). */ | 631 | /* Context information for a noise calculation (Link Quality). */ |
632 | struct b43_noise_calculation { | 632 | struct b43_noise_calculation { |
633 | u8 channel_at_start; | ||
634 | bool calculation_running; | 633 | bool calculation_running; |
635 | u8 nr_samples; | 634 | u8 nr_samples; |
636 | s8 samples[8][4]; | 635 | s8 samples[8][4]; |
@@ -737,6 +736,7 @@ struct b43_wl { | |||
737 | struct ieee80211_tx_control beacon_txctl; | 736 | struct ieee80211_tx_control beacon_txctl; |
738 | bool beacon0_uploaded; | 737 | bool beacon0_uploaded; |
739 | bool beacon1_uploaded; | 738 | bool beacon1_uploaded; |
739 | bool beacon_templates_virgin; /* Never wrote the templates? */ | ||
740 | struct work_struct beacon_update_trigger; | 740 | struct work_struct beacon_update_trigger; |
741 | 741 | ||
742 | /* The current QOS parameters for the 4 queues. | 742 | /* The current QOS parameters for the 4 queues. |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 6dcbb3c87e72..e23f2f172bd7 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -795,24 +795,49 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
795 | { | 795 | { |
796 | struct b43_dmaring *ring; | 796 | struct b43_dmaring *ring; |
797 | int err; | 797 | int err; |
798 | int nr_slots; | ||
799 | dma_addr_t dma_test; | 798 | dma_addr_t dma_test; |
800 | 799 | ||
801 | ring = kzalloc(sizeof(*ring), GFP_KERNEL); | 800 | ring = kzalloc(sizeof(*ring), GFP_KERNEL); |
802 | if (!ring) | 801 | if (!ring) |
803 | goto out; | 802 | goto out; |
804 | ring->type = type; | ||
805 | 803 | ||
806 | nr_slots = B43_RXRING_SLOTS; | 804 | ring->nr_slots = B43_RXRING_SLOTS; |
807 | if (for_tx) | 805 | if (for_tx) |
808 | nr_slots = B43_TXRING_SLOTS; | 806 | ring->nr_slots = B43_TXRING_SLOTS; |
809 | 807 | ||
810 | ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta), | 808 | ring->meta = kcalloc(ring->nr_slots, sizeof(struct b43_dmadesc_meta), |
811 | GFP_KERNEL); | 809 | GFP_KERNEL); |
812 | if (!ring->meta) | 810 | if (!ring->meta) |
813 | goto err_kfree_ring; | 811 | goto err_kfree_ring; |
812 | |||
813 | ring->type = type; | ||
814 | ring->dev = dev; | ||
815 | ring->mmio_base = b43_dmacontroller_base(type, controller_index); | ||
816 | ring->index = controller_index; | ||
817 | if (type == B43_DMA_64BIT) | ||
818 | ring->ops = &dma64_ops; | ||
819 | else | ||
820 | ring->ops = &dma32_ops; | ||
814 | if (for_tx) { | 821 | if (for_tx) { |
815 | ring->txhdr_cache = kcalloc(nr_slots, | 822 | ring->tx = 1; |
823 | ring->current_slot = -1; | ||
824 | } else { | ||
825 | if (ring->index == 0) { | ||
826 | ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; | ||
827 | ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; | ||
828 | } else if (ring->index == 3) { | ||
829 | ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE; | ||
830 | ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET; | ||
831 | } else | ||
832 | B43_WARN_ON(1); | ||
833 | } | ||
834 | spin_lock_init(&ring->lock); | ||
835 | #ifdef CONFIG_B43_DEBUG | ||
836 | ring->last_injected_overflow = jiffies; | ||
837 | #endif | ||
838 | |||
839 | if (for_tx) { | ||
840 | ring->txhdr_cache = kcalloc(ring->nr_slots, | ||
816 | b43_txhdr_size(dev), | 841 | b43_txhdr_size(dev), |
817 | GFP_KERNEL); | 842 | GFP_KERNEL); |
818 | if (!ring->txhdr_cache) | 843 | if (!ring->txhdr_cache) |
@@ -828,7 +853,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
828 | b43_txhdr_size(dev), 1)) { | 853 | b43_txhdr_size(dev), 1)) { |
829 | /* ugh realloc */ | 854 | /* ugh realloc */ |
830 | kfree(ring->txhdr_cache); | 855 | kfree(ring->txhdr_cache); |
831 | ring->txhdr_cache = kcalloc(nr_slots, | 856 | ring->txhdr_cache = kcalloc(ring->nr_slots, |
832 | b43_txhdr_size(dev), | 857 | b43_txhdr_size(dev), |
833 | GFP_KERNEL | GFP_DMA); | 858 | GFP_KERNEL | GFP_DMA); |
834 | if (!ring->txhdr_cache) | 859 | if (!ring->txhdr_cache) |
@@ -853,32 +878,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
853 | DMA_TO_DEVICE); | 878 | DMA_TO_DEVICE); |
854 | } | 879 | } |
855 | 880 | ||
856 | ring->dev = dev; | ||
857 | ring->nr_slots = nr_slots; | ||
858 | ring->mmio_base = b43_dmacontroller_base(type, controller_index); | ||
859 | ring->index = controller_index; | ||
860 | if (type == B43_DMA_64BIT) | ||
861 | ring->ops = &dma64_ops; | ||
862 | else | ||
863 | ring->ops = &dma32_ops; | ||
864 | if (for_tx) { | ||
865 | ring->tx = 1; | ||
866 | ring->current_slot = -1; | ||
867 | } else { | ||
868 | if (ring->index == 0) { | ||
869 | ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; | ||
870 | ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; | ||
871 | } else if (ring->index == 3) { | ||
872 | ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE; | ||
873 | ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET; | ||
874 | } else | ||
875 | B43_WARN_ON(1); | ||
876 | } | ||
877 | spin_lock_init(&ring->lock); | ||
878 | #ifdef CONFIG_B43_DEBUG | ||
879 | ring->last_injected_overflow = jiffies; | ||
880 | #endif | ||
881 | |||
882 | err = alloc_ringmemory(ring); | 881 | err = alloc_ringmemory(ring); |
883 | if (err) | 882 | if (err) |
884 | goto err_kfree_txhdr_cache; | 883 | goto err_kfree_txhdr_cache; |
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 36a9c42df835..76f4c7bad8b8 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -72,6 +72,9 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, | |||
72 | struct b43_wldev *dev = led->dev; | 72 | struct b43_wldev *dev = led->dev; |
73 | bool radio_enabled; | 73 | bool radio_enabled; |
74 | 74 | ||
75 | if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) | ||
76 | return; | ||
77 | |||
75 | /* Checking the radio-enabled status here is slightly racy, | 78 | /* Checking the radio-enabled status here is slightly racy, |
76 | * but we want to avoid the locking overhead and we don't care | 79 | * but we want to avoid the locking overhead and we don't care |
77 | * whether the LED has the wrong state for a second. */ | 80 | * whether the LED has the wrong state for a second. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 8fdba9415c04..a70827793086 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -1145,7 +1145,6 @@ static void b43_generate_noise_sample(struct b43_wldev *dev) | |||
1145 | b43_jssi_write(dev, 0x7F7F7F7F); | 1145 | b43_jssi_write(dev, 0x7F7F7F7F); |
1146 | b43_write32(dev, B43_MMIO_MACCMD, | 1146 | b43_write32(dev, B43_MMIO_MACCMD, |
1147 | b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); | 1147 | b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); |
1148 | B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); | ||
1149 | } | 1148 | } |
1150 | 1149 | ||
1151 | static void b43_calculate_link_quality(struct b43_wldev *dev) | 1150 | static void b43_calculate_link_quality(struct b43_wldev *dev) |
@@ -1154,7 +1153,6 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) | |||
1154 | 1153 | ||
1155 | if (dev->noisecalc.calculation_running) | 1154 | if (dev->noisecalc.calculation_running) |
1156 | return; | 1155 | return; |
1157 | dev->noisecalc.channel_at_start = dev->phy.channel; | ||
1158 | dev->noisecalc.calculation_running = 1; | 1156 | dev->noisecalc.calculation_running = 1; |
1159 | dev->noisecalc.nr_samples = 0; | 1157 | dev->noisecalc.nr_samples = 0; |
1160 | 1158 | ||
@@ -1171,9 +1169,16 @@ static void handle_irq_noise(struct b43_wldev *dev) | |||
1171 | 1169 | ||
1172 | /* Bottom half of Link Quality calculation. */ | 1170 | /* Bottom half of Link Quality calculation. */ |
1173 | 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 | |||
1174 | B43_WARN_ON(!dev->noisecalc.calculation_running); | 1181 | B43_WARN_ON(!dev->noisecalc.calculation_running); |
1175 | if (dev->noisecalc.channel_at_start != phy->channel) | ||
1176 | goto drop_calculation; | ||
1177 | *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); | 1182 | *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); |
1178 | if (noise[0] == 0x7F || noise[1] == 0x7F || | 1183 | if (noise[0] == 0x7F || noise[1] == 0x7F || |
1179 | noise[2] == 0x7F || noise[3] == 0x7F) | 1184 | noise[2] == 0x7F || noise[3] == 0x7F) |
@@ -1214,11 +1219,10 @@ static void handle_irq_noise(struct b43_wldev *dev) | |||
1214 | average -= 48; | 1219 | average -= 48; |
1215 | 1220 | ||
1216 | dev->stats.link_noise = average; | 1221 | dev->stats.link_noise = average; |
1217 | drop_calculation: | ||
1218 | dev->noisecalc.calculation_running = 0; | 1222 | dev->noisecalc.calculation_running = 0; |
1219 | return; | 1223 | return; |
1220 | } | 1224 | } |
1221 | generate_new: | 1225 | generate_new: |
1222 | b43_generate_noise_sample(dev); | 1226 | b43_generate_noise_sample(dev); |
1223 | } | 1227 | } |
1224 | 1228 | ||
@@ -1544,6 +1548,30 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, | |||
1544 | kfree(probe_resp_data); | 1548 | kfree(probe_resp_data); |
1545 | } | 1549 | } |
1546 | 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 | |||
1547 | static void handle_irq_beacon(struct b43_wldev *dev) | 1575 | static void handle_irq_beacon(struct b43_wldev *dev) |
1548 | { | 1576 | { |
1549 | struct b43_wl *wl = dev->wl; | 1577 | struct b43_wl *wl = dev->wl; |
@@ -1568,24 +1596,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1568 | return; | 1596 | return; |
1569 | } | 1597 | } |
1570 | 1598 | ||
1571 | if (!beacon0_valid) { | 1599 | if (unlikely(wl->beacon_templates_virgin)) { |
1572 | if (!wl->beacon0_uploaded) { | 1600 | /* We never uploaded a beacon before. |
1573 | b43_write_beacon_template(dev, 0x68, 0x18); | 1601 | * Upload both templates now, but only mark one valid. */ |
1574 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | 1602 | wl->beacon_templates_virgin = 0; |
1575 | &__b43_ratetable[3]); | 1603 | b43_upload_beacon0(dev); |
1576 | wl->beacon0_uploaded = 1; | 1604 | b43_upload_beacon1(dev); |
1577 | } | ||
1578 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | 1605 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
1579 | cmd |= B43_MACCMD_BEACON0_VALID; | 1606 | cmd |= B43_MACCMD_BEACON0_VALID; |
1580 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | 1607 | b43_write32(dev, B43_MMIO_MACCMD, cmd); |
1581 | } else if (!beacon1_valid) { | 1608 | } else { |
1582 | if (!wl->beacon1_uploaded) { | 1609 | if (!beacon0_valid) { |
1583 | b43_write_beacon_template(dev, 0x468, 0x1A); | 1610 | b43_upload_beacon0(dev); |
1584 | 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); | ||
1585 | } | 1619 | } |
1586 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | ||
1587 | cmd |= B43_MACCMD_BEACON1_VALID; | ||
1588 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1589 | } | 1620 | } |
1590 | } | 1621 | } |
1591 | 1622 | ||
@@ -2852,12 +2883,11 @@ static int b43_op_tx(struct ieee80211_hw *hw, | |||
2852 | 2883 | ||
2853 | if (unlikely(skb->len < 2 + 2 + 6)) { | 2884 | if (unlikely(skb->len < 2 + 2 + 6)) { |
2854 | /* Too short, this can't be a valid frame. */ | 2885 | /* Too short, this can't be a valid frame. */ |
2855 | dev_kfree_skb_any(skb); | 2886 | goto drop_packet; |
2856 | return NETDEV_TX_OK; | ||
2857 | } | 2887 | } |
2858 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | 2888 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); |
2859 | if (unlikely(!dev)) | 2889 | if (unlikely(!dev)) |
2860 | return NETDEV_TX_BUSY; | 2890 | goto drop_packet; |
2861 | 2891 | ||
2862 | /* Transmissions on seperate queues can run concurrently. */ | 2892 | /* Transmissions on seperate queues can run concurrently. */ |
2863 | read_lock_irqsave(&wl->tx_lock, flags); | 2893 | read_lock_irqsave(&wl->tx_lock, flags); |
@@ -2873,7 +2903,12 @@ static int b43_op_tx(struct ieee80211_hw *hw, | |||
2873 | read_unlock_irqrestore(&wl->tx_lock, flags); | 2903 | read_unlock_irqrestore(&wl->tx_lock, flags); |
2874 | 2904 | ||
2875 | if (unlikely(err)) | 2905 | if (unlikely(err)) |
2876 | 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); | ||
2877 | return NETDEV_TX_OK; | 2912 | return NETDEV_TX_OK; |
2878 | } | 2913 | } |
2879 | 2914 | ||
@@ -4073,6 +4108,9 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4073 | wl->filter_flags = 0; | 4108 | wl->filter_flags = 0; |
4074 | wl->radiotap_enabled = 0; | 4109 | wl->radiotap_enabled = 0; |
4075 | 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; | ||
4076 | 4114 | ||
4077 | /* First register RFkill. | 4115 | /* First register RFkill. |
4078 | * LEDs that are registered later depend on it. */ | 4116 | * LEDs that are registered later depend on it. */ |
@@ -4241,7 +4279,9 @@ static void b43_chip_reset(struct work_struct *work) | |||
4241 | goto out; | 4279 | goto out; |
4242 | } | 4280 | } |
4243 | } | 4281 | } |
4244 | out: | 4282 | out: |
4283 | if (err) | ||
4284 | wl->current_dev = NULL; /* Failed to init the dev. */ | ||
4245 | mutex_unlock(&wl->mutex); | 4285 | mutex_unlock(&wl->mutex); |
4246 | if (err) | 4286 | if (err) |
4247 | b43err(wl, "Controller restart FAILED\n"); | 4287 | b43err(wl, "Controller restart FAILED\n"); |
@@ -4382,9 +4422,11 @@ static void b43_one_core_detach(struct ssb_device *dev) | |||
4382 | struct b43_wldev *wldev; | 4422 | struct b43_wldev *wldev; |
4383 | struct b43_wl *wl; | 4423 | struct b43_wl *wl; |
4384 | 4424 | ||
4425 | /* Do not cancel ieee80211-workqueue based work here. | ||
4426 | * See comment in b43_remove(). */ | ||
4427 | |||
4385 | wldev = ssb_get_drvdata(dev); | 4428 | wldev = ssb_get_drvdata(dev); |
4386 | wl = wldev->wl; | 4429 | wl = wldev->wl; |
4387 | cancel_work_sync(&wldev->restart_work); | ||
4388 | b43_debugfs_remove_device(wldev); | 4430 | b43_debugfs_remove_device(wldev); |
4389 | b43_wireless_core_detach(wldev); | 4431 | b43_wireless_core_detach(wldev); |
4390 | list_del(&wldev->list); | 4432 | list_del(&wldev->list); |
@@ -4569,6 +4611,10 @@ static void b43_remove(struct ssb_device *dev) | |||
4569 | struct b43_wl *wl = ssb_get_devtypedata(dev); | 4611 | struct b43_wl *wl = ssb_get_devtypedata(dev); |
4570 | struct b43_wldev *wldev = ssb_get_drvdata(dev); | 4612 | struct b43_wldev *wldev = ssb_get_drvdata(dev); |
4571 | 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 | |||
4572 | B43_WARN_ON(!wl); | 4618 | B43_WARN_ON(!wl); |
4573 | if (wl->current_dev == wldev) | 4619 | if (wl->current_dev == wldev) |
4574 | ieee80211_unregister_hw(wl->hw); | 4620 | ieee80211_unregister_hw(wl->hw); |