diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f9c14c66434e..1e31e0bca744 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -1550,6 +1550,30 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, | |||
1550 | kfree(probe_resp_data); | 1550 | kfree(probe_resp_data); |
1551 | } | 1551 | } |
1552 | 1552 | ||
1553 | static void b43_upload_beacon0(struct b43_wldev *dev) | ||
1554 | { | ||
1555 | struct b43_wl *wl = dev->wl; | ||
1556 | |||
1557 | if (wl->beacon0_uploaded) | ||
1558 | return; | ||
1559 | b43_write_beacon_template(dev, 0x68, 0x18); | ||
1560 | /* FIXME: Probe resp upload doesn't really belong here, | ||
1561 | * but we don't use that feature anyway. */ | ||
1562 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | ||
1563 | &__b43_ratetable[3]); | ||
1564 | wl->beacon0_uploaded = 1; | ||
1565 | } | ||
1566 | |||
1567 | static void b43_upload_beacon1(struct b43_wldev *dev) | ||
1568 | { | ||
1569 | struct b43_wl *wl = dev->wl; | ||
1570 | |||
1571 | if (wl->beacon1_uploaded) | ||
1572 | return; | ||
1573 | b43_write_beacon_template(dev, 0x468, 0x1A); | ||
1574 | wl->beacon1_uploaded = 1; | ||
1575 | } | ||
1576 | |||
1553 | static void handle_irq_beacon(struct b43_wldev *dev) | 1577 | static void handle_irq_beacon(struct b43_wldev *dev) |
1554 | { | 1578 | { |
1555 | struct b43_wl *wl = dev->wl; | 1579 | struct b43_wl *wl = dev->wl; |
@@ -1575,24 +1599,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1575 | return; | 1599 | return; |
1576 | } | 1600 | } |
1577 | 1601 | ||
1578 | if (!beacon0_valid) { | 1602 | if (unlikely(wl->beacon_templates_virgin)) { |
1579 | if (!wl->beacon0_uploaded) { | 1603 | /* We never uploaded a beacon before. |
1580 | b43_write_beacon_template(dev, 0x68, 0x18); | 1604 | * Upload both templates now, but only mark one valid. */ |
1581 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | 1605 | wl->beacon_templates_virgin = 0; |
1582 | &__b43_ratetable[3]); | 1606 | b43_upload_beacon0(dev); |
1583 | wl->beacon0_uploaded = 1; | 1607 | b43_upload_beacon1(dev); |
1584 | } | ||
1585 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | 1608 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
1586 | cmd |= B43_MACCMD_BEACON0_VALID; | 1609 | cmd |= B43_MACCMD_BEACON0_VALID; |
1587 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | 1610 | b43_write32(dev, B43_MMIO_MACCMD, cmd); |
1588 | } else if (!beacon1_valid) { | 1611 | } else { |
1589 | if (!wl->beacon1_uploaded) { | 1612 | if (!beacon0_valid) { |
1590 | b43_write_beacon_template(dev, 0x468, 0x1A); | 1613 | b43_upload_beacon0(dev); |
1591 | wl->beacon1_uploaded = 1; | 1614 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
1615 | cmd |= B43_MACCMD_BEACON0_VALID; | ||
1616 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1617 | } else if (!beacon1_valid) { | ||
1618 | b43_upload_beacon1(dev); | ||
1619 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | ||
1620 | cmd |= B43_MACCMD_BEACON1_VALID; | ||
1621 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1592 | } | 1622 | } |
1593 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | ||
1594 | cmd |= B43_MACCMD_BEACON1_VALID; | ||
1595 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | ||
1596 | } | 1623 | } |
1597 | } | 1624 | } |
1598 | 1625 | ||
@@ -4172,6 +4199,9 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4172 | wl->filter_flags = 0; | 4199 | wl->filter_flags = 0; |
4173 | wl->radiotap_enabled = 0; | 4200 | wl->radiotap_enabled = 0; |
4174 | b43_qos_clear(wl); | 4201 | b43_qos_clear(wl); |
4202 | wl->beacon0_uploaded = 0; | ||
4203 | wl->beacon1_uploaded = 0; | ||
4204 | wl->beacon_templates_virgin = 1; | ||
4175 | 4205 | ||
4176 | /* First register RFkill. | 4206 | /* First register RFkill. |
4177 | * LEDs that are registered later depend on it. */ | 4207 | * LEDs that are registered later depend on it. */ |
@@ -4338,7 +4368,9 @@ static void b43_chip_reset(struct work_struct *work) | |||
4338 | goto out; | 4368 | goto out; |
4339 | } | 4369 | } |
4340 | } | 4370 | } |
4341 | out: | 4371 | out: |
4372 | if (err) | ||
4373 | wl->current_dev = NULL; /* Failed to init the dev. */ | ||
4342 | mutex_unlock(&wl->mutex); | 4374 | mutex_unlock(&wl->mutex); |
4343 | if (err) | 4375 | if (err) |
4344 | b43err(wl, "Controller restart FAILED\n"); | 4376 | b43err(wl, "Controller restart FAILED\n"); |
@@ -4479,9 +4511,11 @@ static void b43_one_core_detach(struct ssb_device *dev) | |||
4479 | struct b43_wldev *wldev; | 4511 | struct b43_wldev *wldev; |
4480 | struct b43_wl *wl; | 4512 | struct b43_wl *wl; |
4481 | 4513 | ||
4514 | /* Do not cancel ieee80211-workqueue based work here. | ||
4515 | * See comment in b43_remove(). */ | ||
4516 | |||
4482 | wldev = ssb_get_drvdata(dev); | 4517 | wldev = ssb_get_drvdata(dev); |
4483 | wl = wldev->wl; | 4518 | wl = wldev->wl; |
4484 | cancel_work_sync(&wldev->restart_work); | ||
4485 | b43_debugfs_remove_device(wldev); | 4519 | b43_debugfs_remove_device(wldev); |
4486 | b43_wireless_core_detach(wldev); | 4520 | b43_wireless_core_detach(wldev); |
4487 | list_del(&wldev->list); | 4521 | list_del(&wldev->list); |
@@ -4666,6 +4700,10 @@ static void b43_remove(struct ssb_device *dev) | |||
4666 | struct b43_wl *wl = ssb_get_devtypedata(dev); | 4700 | struct b43_wl *wl = ssb_get_devtypedata(dev); |
4667 | struct b43_wldev *wldev = ssb_get_drvdata(dev); | 4701 | struct b43_wldev *wldev = ssb_get_drvdata(dev); |
4668 | 4702 | ||
4703 | /* We must cancel any work here before unregistering from ieee80211, | ||
4704 | * as the ieee80211 unreg will destroy the workqueue. */ | ||
4705 | cancel_work_sync(&wldev->restart_work); | ||
4706 | |||
4669 | B43_WARN_ON(!wl); | 4707 | B43_WARN_ON(!wl); |
4670 | if (wl->current_dev == wldev) | 4708 | if (wl->current_dev == wldev) |
4671 | ieee80211_unregister_hw(wl->hw); | 4709 | ieee80211_unregister_hw(wl->hw); |