b43: Fix unaligned 32bit SHM-shared access
authorMichael Buesch <mb@bu3sch.de>
Fri, 31 Jul 2009 18:51:41 +0000 (20:51 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 4 Aug 2009 20:44:21 +0000 (16:44 -0400)
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 <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/b43/main.c

index f985938..a048de5 100644 (file)
@@ -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