| 1 | From 4f214b1ead0af7439921637645cb63f378516175 Mon Sep 17 00:00:00 2001 |
| 2 | From: Hauke Mehrtens <hauke@hauke-m.de> |
| 3 | Date: Sat, 21 Jan 2012 18:48:38 +0100 |
| 4 | Subject: [PATCH 33/34] b43: add workaround for b43 on pcie bus of bcm4716. |
| 5 | |
| 6 | bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder |
| 7 | transactions. As a fix, a read after write is performed on certain |
| 8 | places in the code. Older chips and the newer 5357 family don't require |
| 9 | this fix. |
| 10 | This code is based on the brcmsmac driver. |
| 11 | |
| 12 | Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> |
| 13 | --- |
| 14 | drivers/net/wireless/b43/b43.h | 26 ++++++++++++++++++++++++++ |
| 15 | drivers/net/wireless/b43/bus.h | 10 ++++++++++ |
| 16 | drivers/net/wireless/b43/phy_common.c | 6 ++++++ |
| 17 | drivers/net/wireless/b43/phy_n.c | 10 +++++----- |
| 18 | 4 files changed, 47 insertions(+), 5 deletions(-) |
| 19 | |
| 20 | --- a/drivers/net/wireless/b43/b43.h |
| 21 | +++ b/drivers/net/wireless/b43/b43.h |
| 22 | @@ -1044,6 +1044,32 @@ static inline bool b43_using_pio_transfe |
| 23 | return dev->__using_pio_transfers; |
| 24 | } |
| 25 | |
| 26 | +/* |
| 27 | + * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder |
| 28 | + * transactions. As a fix, a read after write is performed on certain places |
| 29 | + * in the code. Older chips and the newer 5357 family don't require this fix. |
| 30 | + */ |
| 31 | +#ifdef CONFIG_BCM47XX_BCMA |
| 32 | +#include <asm/mach-bcm47xx/bcm47xx.h> |
| 33 | +static inline void b43_wflush16(struct b43_wldev *dev, u16 offset, u16 value) |
| 34 | +{ |
| 35 | + if (b43_bus_host_is_pci(dev->dev) && |
| 36 | + bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA && |
| 37 | + (bcm47xx_bus.bcma.bus.chipinfo.id == 0x4716 || |
| 38 | + bcm47xx_bus.bcma.bus.chipinfo.id == 0x5300)) { |
| 39 | + b43_write16(dev, offset, value); |
| 40 | + b43_read16(dev, offset); |
| 41 | + } else { |
| 42 | + b43_write16(dev, offset, value); |
| 43 | + } |
| 44 | +} |
| 45 | +#else |
| 46 | +static inline void b43_wflush16(struct b43_wldev *dev, u16 offset, u16 value) |
| 47 | +{ |
| 48 | + b43_write16(dev, offset, value); |
| 49 | +} |
| 50 | +#endif |
| 51 | + |
| 52 | /* Message printing */ |
| 53 | __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...); |
| 54 | __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...); |
| 55 | --- a/drivers/net/wireless/b43/bus.h |
| 56 | +++ b/drivers/net/wireless/b43/bus.h |
| 57 | @@ -60,6 +60,16 @@ static inline bool b43_bus_host_is_sdio( |
| 58 | return (dev->bus_type == B43_BUS_SSB && |
| 59 | dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO); |
| 60 | } |
| 61 | +static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev) |
| 62 | +{ |
| 63 | + if (dev->bus_type == B43_BUS_SSB) |
| 64 | + return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI); |
| 65 | +#ifdef CONFIG_B43_BCMA |
| 66 | + if (dev->bus_type == B43_BUS_BCMA) |
| 67 | + return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI); |
| 68 | +#endif |
| 69 | + return false; |
| 70 | +} |
| 71 | |
| 72 | struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core); |
| 73 | struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev); |
| 74 | --- a/drivers/net/wireless/b43/phy_common.c |
| 75 | +++ b/drivers/net/wireless/b43/phy_common.c |
| 76 | @@ -251,6 +251,12 @@ void b43_phy_write(struct b43_wldev *dev |
| 77 | { |
| 78 | assert_mac_suspended(dev); |
| 79 | dev->phy.ops->phy_write(dev, reg, value); |
| 80 | +#ifdef CONFIG_BCM47XX |
| 81 | + if (b43_bus_host_is_pci(dev->dev) && reg == 0x72) { |
| 82 | + b43_read16(dev, B43_MMIO_PHY_VER); |
| 83 | + return; |
| 84 | + } |
| 85 | +#endif |
| 86 | if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) { |
| 87 | b43_read16(dev, B43_MMIO_PHY_VER); |
| 88 | dev->phy.writes_counter = 0; |
| 89 | --- a/drivers/net/wireless/b43/phy_n.c |
| 90 | +++ b/drivers/net/wireless/b43/phy_n.c |
| 91 | @@ -4837,14 +4837,14 @@ static inline void check_phyreg(struct b |
| 92 | static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) |
| 93 | { |
| 94 | check_phyreg(dev, reg); |
| 95 | - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 96 | + b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 97 | return b43_read16(dev, B43_MMIO_PHY_DATA); |
| 98 | } |
| 99 | |
| 100 | static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) |
| 101 | { |
| 102 | check_phyreg(dev, reg); |
| 103 | - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 104 | + b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 105 | b43_write16(dev, B43_MMIO_PHY_DATA, value); |
| 106 | } |
| 107 | |
| 108 | @@ -4852,7 +4852,7 @@ static void b43_nphy_op_maskset(struct b |
| 109 | u16 set) |
| 110 | { |
| 111 | check_phyreg(dev, reg); |
| 112 | - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 113 | + b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg); |
| 114 | b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set); |
| 115 | } |
| 116 | |
| 117 | @@ -4863,7 +4863,7 @@ static u16 b43_nphy_op_radio_read(struct |
| 118 | /* N-PHY needs 0x100 for read access */ |
| 119 | reg |= 0x100; |
| 120 | |
| 121 | - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); |
| 122 | + b43_wflush16(dev, B43_MMIO_RADIO_CONTROL, reg); |
| 123 | return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); |
| 124 | } |
| 125 | |
| 126 | @@ -4872,7 +4872,7 @@ static void b43_nphy_op_radio_write(stru |
| 127 | /* Register 1 is a 32-bit register. */ |
| 128 | B43_WARN_ON(reg == 1); |
| 129 | |
| 130 | - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); |
| 131 | + b43_wflush16(dev, B43_MMIO_RADIO_CONTROL, reg); |
| 132 | b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); |
| 133 | } |
| 134 | |
| 135 | |