From 1855ba7812dbd294fcfc083dc7d3b14d3b1f38db Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 18 Apr 2008 20:51:41 +0200 Subject: b43: Workaround invalid bluetooth settings This adds a workaround for invalid bluetooth SPROM settings on ASUS PCI cards. This will stop the microcode from poking with the BT GPIO line. This fixes data transmission on this device, as the BT GPIO line is used for something TX related on this device (probably the power amplifier or the radio). This also adds a modparam knob to help debugging this in the future, as more devices with this bug may show up. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/b43') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cf5c046c9fa..4bc053ffc37 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -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), @@ -3708,6 +3712,8 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev) struct ssb_sprom *sprom = &dev->dev->bus->sprom; u32 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 +3725,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) @@ -4416,6 +4424,8 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) 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 +4433,14 @@ 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 (pdev->vendor == PCI_VENDOR_ID_BROADCOM && + pdev->device == 0x4318 && + pdev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK && + pdev->subsystem_device == 0x100F) + bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST; + } } static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) -- cgit v1.2.3 From a259d6a45b915e00e8c6085e35fea7b61e3008a8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 18 Apr 2008 21:06:37 +0200 Subject: b43: Fix HostFlags data types The HostFlags are a bitmask of 48bit. So we must use an u64 datatype to hold all bits. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 5 +++-- drivers/net/wireless/b43/phy.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/b43') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4bc053ffc37..a90e902f4b3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3710,7 +3710,7 @@ 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; @@ -3860,7 +3860,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); diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 575c5436ebd..de024dc0371 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -2043,7 +2043,7 @@ int b43_phy_init(struct b43_wldev *dev) void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) { struct b43_phy *phy = &dev->phy; - u32 hf; + u64 hf; u16 tmp; int autodiv = 0; -- cgit v1.2.3 From 9fc38458355525f801cd2ab403ac89850489a05e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 19 Apr 2008 16:53:00 +0200 Subject: b43: Add more btcoexist workarounds This adds more workarounds for devices with broken BT bits. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/b43') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a90e902f4b3..94a0cdeb39a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4423,6 +4423,12 @@ 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; @@ -4436,10 +4442,9 @@ static void b43_sprom_fixup(struct ssb_bus *bus) bus->sprom.boardflags_lo |= B43_BFL_PACTRL; if (bus->bustype == SSB_BUSTYPE_PCI) { pdev = bus->host_pci; - if (pdev->vendor == PCI_VENDOR_ID_BROADCOM && - pdev->device == 0x4318 && - pdev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK && - pdev->subsystem_device == 0x100F) + 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; } } -- cgit v1.2.3 From 1033b3ea11820ea1fb1b877207bd6724e9aaedc3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 23 Apr 2008 19:13:01 +0200 Subject: b43: Workaround DMA quirks Some mainboards/CPUs don't allow DMA masks bigger than a certain limit. Some VIA crap^h^h^h^hdevices have an upper limit of 0xFFFFFFFF. So in this case a 64-bit b43 device would always fail to acquire the mask. Implement a workaround to fallback to lower DMA mask, as we can always also support a lower mask. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 47 +++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/b43') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 21c886a9a1d..6dcbb3c87e7 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -980,6 +980,42 @@ void b43_dma_free(struct b43_wldev *dev) destroy_ring(dma, tx_ring_mcast); } +static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) +{ + u64 orig_mask = mask; + bool fallback = 0; + int err; + + /* Try to set the DMA mask. If it fails, try falling back to a + * lower mask, as we can always also support a lower one. */ + while (1) { + err = ssb_dma_set_mask(dev->dev, mask); + if (!err) + break; + if (mask == DMA_64BIT_MASK) { + mask = DMA_32BIT_MASK; + fallback = 1; + continue; + } + if (mask == DMA_32BIT_MASK) { + mask = DMA_30BIT_MASK; + fallback = 1; + continue; + } + b43err(dev->wl, "The machine/kernel does not support " + "the required %u-bit DMA mask\n", + (unsigned int)dma_mask_to_engine_type(orig_mask)); + return -EOPNOTSUPP; + } + if (fallback) { + b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n", + (unsigned int)dma_mask_to_engine_type(orig_mask), + (unsigned int)dma_mask_to_engine_type(mask)); + } + + return 0; +} + int b43_dma_init(struct b43_wldev *dev) { struct b43_dma *dma = &dev->dma; @@ -989,14 +1025,9 @@ int b43_dma_init(struct b43_wldev *dev) dmamask = supported_dma_mask(dev); type = dma_mask_to_engine_type(dmamask); - err = ssb_dma_set_mask(dev->dev, dmamask); - if (err) { - b43err(dev->wl, "The machine/kernel does not support " - "the required DMA mask (0x%08X%08X)\n", - (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(dmamask & 0x00000000FFFFFFFFULL)); - return -EOPNOTSUPP; - } + err = b43_dma_set_mask(dev, dmamask); + if (err) + return err; err = -ENOMEM; /* setup TX DMA channels. */ -- cgit v1.2.3