aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r--drivers/net/wireless/b43/main.c70
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
1553static 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
1567static 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
1553static void handle_irq_beacon(struct b43_wldev *dev) 1577static 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: 4371out:
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);