From f62ae6cd887a184d6923037d588b5b2466aa2a97 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 31 Jul 2009 20:51:41 +0200 Subject: [PATCH] b43: Fix unaligned 32bit SHM-shared access This fixes unaligned 32bit SHM-shared read/write access. The low and high 16 bits were swapped. It also adds a testcase for this to the chipaccess validation. (Thanks to Albert Herranz for tracking down this bug.) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f985938962e3..a048de5fcc73 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -395,9 +395,8 @@ u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); - ret <<= 16; b43_shm_control_word(dev, routing, (offset >> 2) + 1); - ret |= b43_read16(dev, B43_MMIO_SHM_DATA); + ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16; goto out; } @@ -464,9 +463,10 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, - (value >> 16) & 0xffff); + value & 0xFFFF); b43_shm_control_word(dev, routing, (offset >> 2) + 1); - b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); + b43_write16(dev, B43_MMIO_SHM_DATA, + (value >> 16) & 0xFFFF); return; } offset >>= 2; @@ -2931,9 +2931,10 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) /* Check if communication with the device works correctly. */ static int b43_validate_chipaccess(struct b43_wldev *dev) { - u32 v, backup; + u32 v, backup0, backup4; - backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4); /* Check for read/write and endianness problems. */ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); @@ -2943,7 +2944,23 @@ static int b43_validate_chipaccess(struct b43_wldev *dev) if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) goto error; - b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); + /* Check if unaligned 32bit SHM_SHARED access works properly. + * However, don't bail out on failure, because it's noncritical. */ + b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122); + b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344); + b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566); + b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788); + if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344) + b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n"); + b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD); + if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 || + b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD || + b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB || + b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788) + b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n"); + + b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0); + b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4); if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { /* The 32bit register shadows the two 16bit registers -- 2.20.1