diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 86 |
1 files changed, 64 insertions, 22 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 8fdba9415c04..fa4b0d8b74a2 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 | ||
@@ -4073,6 +4104,9 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4073 | wl->filter_flags = 0; | 4104 | wl->filter_flags = 0; |
4074 | wl->radiotap_enabled = 0; | 4105 | wl->radiotap_enabled = 0; |
4075 | b43_qos_clear(wl); | 4106 | b43_qos_clear(wl); |
4107 | wl->beacon0_uploaded = 0; | ||
4108 | wl->beacon1_uploaded = 0; | ||
4109 | wl->beacon_templates_virgin = 1; | ||
4076 | 4110 | ||
4077 | /* First register RFkill. | 4111 | /* First register RFkill. |
4078 | * LEDs that are registered later depend on it. */ | 4112 | * LEDs that are registered later depend on it. */ |
@@ -4241,7 +4275,9 @@ static void b43_chip_reset(struct work_struct *work) | |||
4241 | goto out; | 4275 | goto out; |
4242 | } | 4276 | } |
4243 | } | 4277 | } |
4244 | out: | 4278 | out: |
4279 | if (err) | ||
4280 | wl->current_dev = NULL; /* Failed to init the dev. */ | ||
4245 | mutex_unlock(&wl->mutex); | 4281 | mutex_unlock(&wl->mutex); |
4246 | if (err) | 4282 | if (err) |
4247 | b43err(wl, "Controller restart FAILED\n"); | 4283 | b43err(wl, "Controller restart FAILED\n"); |
@@ -4382,9 +4418,11 @@ static void b43_one_core_detach(struct ssb_device *dev) | |||
4382 | struct b43_wldev *wldev; | 4418 | struct b43_wldev *wldev; |
4383 | struct b43_wl *wl; | 4419 | struct b43_wl *wl; |
4384 | 4420 | ||
4421 | /* Do not cancel ieee80211-workqueue based work here. | ||
4422 | * See comment in b43_remove(). */ | ||
4423 | |||
4385 | wldev = ssb_get_drvdata(dev); | 4424 | wldev = ssb_get_drvdata(dev); |
4386 | wl = wldev->wl; | 4425 | wl = wldev->wl; |
4387 | cancel_work_sync(&wldev->restart_work); | ||
4388 | b43_debugfs_remove_device(wldev); | 4426 | b43_debugfs_remove_device(wldev); |
4389 | b43_wireless_core_detach(wldev); | 4427 | b43_wireless_core_detach(wldev); |
4390 | list_del(&wldev->list); | 4428 | list_del(&wldev->list); |
@@ -4569,6 +4607,10 @@ static void b43_remove(struct ssb_device *dev) | |||
4569 | struct b43_wl *wl = ssb_get_devtypedata(dev); | 4607 | struct b43_wl *wl = ssb_get_devtypedata(dev); |
4570 | struct b43_wldev *wldev = ssb_get_drvdata(dev); | 4608 | struct b43_wldev *wldev = ssb_get_drvdata(dev); |
4571 | 4609 | ||
4610 | /* We must cancel any work here before unregistering from ieee80211, | ||
4611 | * as the ieee80211 unreg will destroy the workqueue. */ | ||
4612 | cancel_work_sync(&wldev->restart_work); | ||
4613 | |||
4572 | B43_WARN_ON(!wl); | 4614 | B43_WARN_ON(!wl); |
4573 | if (wl->current_dev == wldev) | 4615 | if (wl->current_dev == wldev) |
4574 | ieee80211_unregister_hw(wl->hw); | 4616 | ieee80211_unregister_hw(wl->hw); |