diff options
author | Michael Buesch <mb@bu3sch.de> | 2009-07-31 14:51:41 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-04 16:44:21 -0400 |
commit | f62ae6cd887a184d6923037d588b5b2466aa2a97 (patch) | |
tree | 9017155281a2948f43235439438002779935cb38 /drivers/net/wireless/b43/main.c | |
parent | 88d89526a671ba008f59456161b0c513cdfb5d5a (diff) |
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 <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 31 |
1 files 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) | |||
395 | /* Unaligned access */ | 395 | /* Unaligned access */ |
396 | b43_shm_control_word(dev, routing, offset >> 2); | 396 | b43_shm_control_word(dev, routing, offset >> 2); |
397 | ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); | 397 | ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); |
398 | ret <<= 16; | ||
399 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); | 398 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); |
400 | ret |= b43_read16(dev, B43_MMIO_SHM_DATA); | 399 | ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16; |
401 | 400 | ||
402 | goto out; | 401 | goto out; |
403 | } | 402 | } |
@@ -464,9 +463,10 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value | |||
464 | /* Unaligned access */ | 463 | /* Unaligned access */ |
465 | b43_shm_control_word(dev, routing, offset >> 2); | 464 | b43_shm_control_word(dev, routing, offset >> 2); |
466 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, | 465 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, |
467 | (value >> 16) & 0xffff); | 466 | value & 0xFFFF); |
468 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); | 467 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); |
469 | b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); | 468 | b43_write16(dev, B43_MMIO_SHM_DATA, |
469 | (value >> 16) & 0xFFFF); | ||
470 | return; | 470 | return; |
471 | } | 471 | } |
472 | offset >>= 2; | 472 | offset >>= 2; |
@@ -2931,9 +2931,10 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) | |||
2931 | /* Check if communication with the device works correctly. */ | 2931 | /* Check if communication with the device works correctly. */ |
2932 | static int b43_validate_chipaccess(struct b43_wldev *dev) | 2932 | static int b43_validate_chipaccess(struct b43_wldev *dev) |
2933 | { | 2933 | { |
2934 | u32 v, backup; | 2934 | u32 v, backup0, backup4; |
2935 | 2935 | ||
2936 | backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); | 2936 | backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0); |
2937 | backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4); | ||
2937 | 2938 | ||
2938 | /* Check for read/write and endianness problems. */ | 2939 | /* Check for read/write and endianness problems. */ |
2939 | b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); | 2940 | b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); |
@@ -2943,7 +2944,23 @@ static int b43_validate_chipaccess(struct b43_wldev *dev) | |||
2943 | if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) | 2944 | if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) |
2944 | goto error; | 2945 | goto error; |
2945 | 2946 | ||
2946 | b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); | 2947 | /* Check if unaligned 32bit SHM_SHARED access works properly. |
2948 | * However, don't bail out on failure, because it's noncritical. */ | ||
2949 | b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122); | ||
2950 | b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344); | ||
2951 | b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566); | ||
2952 | b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788); | ||
2953 | if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344) | ||
2954 | b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n"); | ||
2955 | b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD); | ||
2956 | if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 || | ||
2957 | b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD || | ||
2958 | b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB || | ||
2959 | b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788) | ||
2960 | b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n"); | ||
2961 | |||
2962 | b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0); | ||
2963 | b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4); | ||
2947 | 2964 | ||
2948 | if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { | 2965 | if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { |
2949 | /* The 32bit register shadows the two 16bit registers | 2966 | /* The 32bit register shadows the two 16bit registers |