From c47c360b48598a572a32e0853b68b5256f3b1e0a Mon Sep 17 00:00:00 2001 From: proski Date: Sun, 8 Jun 2008 01:28:58 +0000 Subject: [PATCH] Be very careful about using ioread32be() and iowrite32() They appeared: - in generic code and PARISC - in 2.6.12 - in PPC64 - in 2.6.14 - in merged PowerPC - in 2.6.15 (when the merge occurred) - in MIPS - in 2.6.21 Improve comments and indentation, as the logic is getting more complex. git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3712 0192ed92-7a03-0410-a25b-9323aeb14dbd --- ath_hal/ah_os.h | 87 ++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/ath_hal/ah_os.h b/ath_hal/ah_os.h index 79efdd5..c522ff4 100644 --- a/ath_hal/ah_os.h +++ b/ath_hal/ah_os.h @@ -151,19 +151,27 @@ extern void *__ahdecl ath_hal_memcpy(void *, const void *, size_t); #endif /* AH_BYTE_ORDER */ /* - * Some big-endian architectures don't set CONFIG_GENERIC_IOMAP, but fail to - * implement iowrite32be and ioread32be. Provide compatibility macros when - * it's needed. + * The HAL programs big-endian platforms to use byte-swapped hardware registers. + * This is done to avoid the byte swapping needed to access PCI devices. * - * As of Linux 2.6.24, only MIPS, PARISC and PowerPC implement iowrite32be and - * ioread32be as functions. + * Many big-endian architectures provide I/O functions that avoid byte swapping. + * We use them when possible. Otherwise, we provide replacements. The downside + * or the replacements is that we may be byte-swapping data twice, so we try to + * avoid it. * - * The downside or the replacement macros it that we may be byte-swapping data - * for the second time, so the native implementations should be preferred. + * We use raw access for Linux prior to 2.6.12. For newer version, we need to + * use ioread32() and iowrite32(), which would take care of indirect access to + * the registers. */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) && \ - !defined(CONFIG_GENERIC_IOMAP) && (AH_BYTE_ORDER == AH_BIG_ENDIAN) && \ - !defined(__mips__) && !defined(__hppa__) && !defined(__powerpc__) + (AH_BYTE_ORDER == AH_BIG_ENDIAN) && \ + !defined(CONFIG_GENERIC_IOMAP) && \ + !defined(CONFIG_PARICS) && \ + !(defined(CONFIG_PPC64) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14))) && \ + !defined(CONFIG_PPC_MERGE) && \ + !(defined(CONFIG_MIPS) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))) # ifndef iowrite32be # define iowrite32be(_val, _addr) iowrite32(swab32((_val)), (_addr)) # endif @@ -177,54 +185,53 @@ extern void *__ahdecl ath_hal_memcpy(void *, const void *, size_t); * debugging is enabled (AH_DEBUG) or it's explicitly requested for the target. * * The hardware registers use little-endian byte order natively. Big-endian - * systems are configured by HAL to enable hardware byte-swap of register reads - * and writes at reset. This avoid the need to byte-swap the data in software. - * However, the registers in a certain area from 0x4000 to 0x4fff (PCI clock - * domain registers) are not byte swapped! + * systems are configured by HAL to byte-swap of register reads and writes. + * However, the registers in the areas 0x4000-0x4fff and 0x7000-0x7fff are not + * byte swapped! * * Since Linux I/O primitives default to little-endian operations, we only * need to suppress byte-swapping on big-endian systems outside the area used * by the PCI clock domain registers. */ #if (AH_BYTE_ORDER == AH_BIG_ENDIAN) -#define is_reg_le(__reg) ((0x4000 <= (__reg) && (__reg) < 0x5000) || \ - (0x7000 <= (__reg) && (__reg) < 0x8000)) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) -#define _OS_REG_WRITE(_ah, _reg, _val) do { \ +# define is_reg_le(__reg) ((0x4000 <= (__reg) && (__reg) < 0x5000) || \ + (0x7000 <= (__reg) && (__reg) < 0x8000)) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) +# define _OS_REG_WRITE(_ah, _reg, _val) do { \ is_reg_le(_reg) ? \ - iowrite32((_val), (_ah)->ah_sh + (_reg)) : \ - iowrite32be((_val), (_ah)->ah_sh + (_reg)); \ + iowrite32((_val), (_ah)->ah_sh + (_reg)) : \ + iowrite32be((_val), (_ah)->ah_sh + (_reg)); \ } while (0) -#define _OS_REG_READ(_ah, _reg) \ +# define _OS_REG_READ(_ah, _reg) \ (is_reg_le(_reg) ? \ - ioread32((_ah)->ah_sh + (_reg)) : \ - ioread32be((_ah)->ah_sh + (_reg))) -#else -#define _OS_REG_WRITE(_ah, _reg, _val) do { \ - writel(is_reg_le(_reg) ? \ - (_val) : cpu_to_le32(_val), \ - (_ah)->ah_sh + (_reg)); \ + ioread32((_ah)->ah_sh + (_reg)) : \ + ioread32be((_ah)->ah_sh + (_reg))) +# else /* Linux < 2.6.12 */ +# define _OS_REG_WRITE(_ah, _reg, _val) do { \ + writel(is_reg_le(_reg) ? \ + (_val) : cpu_to_le32(_val), \ + (_ah)->ah_sh + (_reg)); \ } while (0) -#define _OS_REG_READ(_ah, _reg) \ +# define _OS_REG_READ(_ah, _reg) \ (is_reg_le(_reg) ? \ - readl((_ah)->ah_sh + (_reg)) : \ - cpu_to_le32(readl((_ah)->ah_sh + (_reg)))) -#endif /* KERNEL_VERSION(2,6,12) */ -#else /* AH_BYTE_ORDER != AH_BIG_ENDIAN */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) -#define _OS_REG_WRITE(_ah, _reg, _val) do { \ + readl((_ah)->ah_sh + (_reg)) : \ + cpu_to_le32(readl((_ah)->ah_sh + (_reg)))) +# endif /* Linux < 2.6.12 */ +#else /* Little endian */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) +# define _OS_REG_WRITE(_ah, _reg, _val) do { \ iowrite32((_val), (_ah)->ah_sh + (_reg)); \ } while (0) -#define _OS_REG_READ(_ah, _reg) \ +# define _OS_REG_READ(_ah, _reg) \ ioread32((_ah)->ah_sh + (_reg)) -#else -#define _OS_REG_WRITE(_ah, _reg, _val) do { \ +# else /* Linux < 2.6.12 */ +# define _OS_REG_WRITE(_ah, _reg, _val) do { \ writel((_val), (_ah)->ah_sh + (_reg)); \ } while (0) -#define _OS_REG_READ(_ah, _reg) \ +# define _OS_REG_READ(_ah, _reg) \ readl((_ah)->ah_sh + (_reg)) -#endif /* KERNEL_VERSION(2,6,12) */ -#endif /* AH_BYTE_ORDER != AH_BIG_ENDIAN */ +# endif /* Linux < 2.6.12 */ +#endif /* Little endian */ #define HAL_DEBUG_OFF 0 /* Show register accesses */