]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/b43/main.c
Merge branch 'for-2.6.26' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
[linux-2.6] / drivers / net / wireless / b43 / main.c
index cf5c046c9fa8e2539cf109239d578897b6afb6f3..8fdba9415c04f2da1d8099d8165613f3ae21be96 100644 (file)
@@ -84,6 +84,10 @@ int b43_modparam_qos = 1;
 module_param_named(qos, b43_modparam_qos, int, 0444);
 MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
 
+static int modparam_btcoex = 1;
+module_param_named(btcoex, modparam_btcoex, int, 0444);
+MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)");
+
 
 static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -725,6 +729,7 @@ static void b43_synchronize_irq(struct b43_wldev *dev)
  */
 void b43_dummy_transmission(struct b43_wldev *dev)
 {
+       struct b43_wl *wl = dev->wl;
        struct b43_phy *phy = &dev->phy;
        unsigned int i, max_loop;
        u16 value;
@@ -751,6 +756,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)
                return;
        }
 
+       spin_lock_irq(&wl->irq_lock);
+       write_lock(&wl->tx_lock);
+
        for (i = 0; i < 5; i++)
                b43_ram_write(dev, i * 4, buffer[i]);
 
@@ -791,6 +799,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)
        }
        if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
                b43_radio_write16(dev, 0x0051, 0x0037);
+
+       write_unlock(&wl->tx_lock);
+       spin_unlock_irq(&wl->irq_lock);
 }
 
 static void key_write(struct b43_wldev *dev,
@@ -2167,7 +2178,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
                                goto err_format;
                        array_size -= sizeof(iv->data.d32);
 
-                       value = be32_to_cpu(get_unaligned(&iv->data.d32));
+                       value = get_unaligned_be32(&iv->data.d32);
                        b43_write32(dev, offset, value);
 
                        iv = (const struct b43_iv *)((const uint8_t *)iv +
@@ -2804,10 +2815,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data)
        return (sizeof(u16));
 }
 
-static void b43_rng_exit(struct b43_wl *wl, bool suspended)
+static void b43_rng_exit(struct b43_wl *wl)
 {
        if (wl->rng_initialized)
-               __hwrng_unregister(&wl->rng, suspended);
+               hwrng_unregister(&wl->rng);
 }
 
 static int b43_rng_init(struct b43_wl *wl)
@@ -2836,24 +2847,31 @@ static int b43_op_tx(struct ieee80211_hw *hw,
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
-       int err = -ENODEV;
+       unsigned long flags;
+       int err;
 
        if (unlikely(skb->len < 2 + 2 + 6)) {
                /* Too short, this can't be a valid frame. */
-               return -EINVAL;
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
        }
        B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-
        if (unlikely(!dev))
-               goto out;
-       if (unlikely(b43_status(dev) < B43_STAT_STARTED))
-               goto out;
-       /* TX is done without a global lock. */
-       if (b43_using_pio_transfers(dev))
-               err = b43_pio_tx(dev, skb, ctl);
-       else
-               err = b43_dma_tx(dev, skb, ctl);
-out:
+               return NETDEV_TX_BUSY;
+
+       /* Transmissions on seperate queues can run concurrently. */
+       read_lock_irqsave(&wl->tx_lock, flags);
+
+       err = -ENODEV;
+       if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+               if (b43_using_pio_transfers(dev))
+                       err = b43_pio_tx(dev, skb, ctl);
+               else
+                       err = b43_dma_tx(dev, skb, ctl);
+       }
+
+       read_unlock_irqrestore(&wl->tx_lock, flags);
+
        if (unlikely(err))
                return NETDEV_TX_BUSY;
        return NETDEV_TX_OK;
@@ -3472,7 +3490,9 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        b43_synchronize_irq(dev);
 
+       write_lock_irqsave(&wl->tx_lock, flags);
        b43_set_status(dev, B43_STAT_INITIALIZED);
+       write_unlock_irqrestore(&wl->tx_lock, flags);
 
        b43_pio_stop(dev);
        mutex_unlock(&wl->mutex);
@@ -3481,8 +3501,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
        cancel_delayed_work_sync(&dev->periodic_work);
        mutex_lock(&wl->mutex);
 
-       ieee80211_stop_queues(wl->hw);  //FIXME this could cause a deadlock, as mac80211 seems buggy.
-
        b43_mac_suspend(dev);
        free_irq(dev->dev->irq, dev);
        b43dbg(wl, "Wireless interface stopped\n");
@@ -3706,8 +3724,10 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
        struct ssb_sprom *sprom = &dev->dev->bus->sprom;
-       u32 hf;
+       u64 hf;
 
+       if (!modparam_btcoex)
+               return;
        if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
                return;
        if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
@@ -3719,11 +3739,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
        else
                hf |= B43_HF_BTCOEX;
        b43_hf_write(dev, hf);
-       //TODO
 }
 
 static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
-{                              //TODO
+{
+       if (!modparam_btcoex)
+               return;
+       //TODO
 }
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
@@ -3824,7 +3846,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 
        if (!dev->suspend_in_progress) {
                b43_leds_exit(dev);
-               b43_rng_exit(dev->wl, false);
+               b43_rng_exit(dev->wl);
        }
        b43_dma_free(dev);
        b43_pio_free(dev);
@@ -3852,7 +3874,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        struct ssb_sprom *sprom = &bus->sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
-       u32 hf, tmp;
+       u64 hf;
+       u32 tmp;
 
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
 
@@ -4317,6 +4340,14 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                err = -EOPNOTSUPP;
                goto err_powerdown;
        }
+       if (1 /* disable A-PHY */) {
+               /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
+               if (dev->phy.type != B43_PHYTYPE_N) {
+                       have_2ghz_phy = 1;
+                       have_5ghz_phy = 0;
+               }
+       }
+
        dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
@@ -4414,8 +4445,16 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
        return err;
 }
 
+#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice)                ( \
+       (pdev->vendor == PCI_VENDOR_ID_##_vendor) &&                    \
+       (pdev->device == _device) &&                                    \
+       (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) &&       \
+       (pdev->subsystem_device == _subdevice)                          )
+
 static void b43_sprom_fixup(struct ssb_bus *bus)
 {
+       struct pci_dev *pdev;
+
        /* boardflags workarounds */
        if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
            bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
@@ -4423,6 +4462,13 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
        if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
            bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
                bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
+       if (bus->bustype == SSB_BUSTYPE_PCI) {
+               pdev = bus->host_pci;
+               if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
+                   IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
+                   IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
+                       bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
+       }
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
@@ -4466,6 +4512,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        memset(wl, 0, sizeof(*wl));
        wl->hw = hw;
        spin_lock_init(&wl->irq_lock);
+       rwlock_init(&wl->tx_lock);
        spin_lock_init(&wl->leds_lock);
        spin_lock_init(&wl->shm_lock);
        mutex_init(&wl->mutex);
@@ -4589,7 +4636,7 @@ static int b43_resume(struct ssb_device *dev)
                err = b43_wireless_core_start(wldev);
                if (err) {
                        b43_leds_exit(wldev);
-                       b43_rng_exit(wldev->wl, true);
+                       b43_rng_exit(wldev->wl);
                        b43_wireless_core_exit(wldev);
                        b43err(wl, "Resume failed at core start\n");
                        goto out;