diff options
Diffstat (limited to 'include/asm-mips/io.h')
-rw-r--r-- | include/asm-mips/io.h | 164 |
1 files changed, 109 insertions, 55 deletions
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index 039845f2e6b..3061870b7f6 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -25,7 +25,9 @@ #include <asm/page.h> #include <asm/pgtable-bits.h> #include <asm/processor.h> +#include <asm/string.h> +#include <ioremap.h> #include <mangle-port.h> /* @@ -34,7 +36,7 @@ #undef CONF_SLOWDOWN_IO /* - * Raw operations are never swapped in software. Otoh values that raw + * Raw operations are never swapped in software. OTOH values that raw * operations are working on may or may not have been swapped by the bus * hardware. An example use would be for flash memory that's used for * execute in place. @@ -43,45 +45,53 @@ # define __raw_ioswabw(x) (x) # define __raw_ioswabl(x) (x) # define __raw_ioswabq(x) (x) +# define ____raw_ioswabq(x) (x) /* * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware; * less sane hardware forces software to fiddle with this... + * + * Regardless, if the host bus endianness mismatches that of PCI/ISA, then + * you can't have the numerical value of data and byte addresses within + * multibyte quantities both preserved at the same time. Hence two + * variations of functions: non-prefixed ones that preserve the value + * and prefixed ones that preserve byte addresses. The latters are + * typically used for moving raw data between a peripheral and memory (cf. + * string I/O functions), hence the "mem_" prefix. */ #if defined(CONFIG_SWAP_IO_SPACE) # define ioswabb(x) (x) +# define mem_ioswabb(x) (x) # ifdef CONFIG_SGI_IP22 /* * IP22 seems braindead enough to swap 16bits values in hardware, but * not 32bits. Go figure... Can't tell without documentation. */ # define ioswabw(x) (x) +# define mem_ioswabw(x) le16_to_cpu(x) # else # define ioswabw(x) le16_to_cpu(x) +# define mem_ioswabw(x) (x) # endif # define ioswabl(x) le32_to_cpu(x) +# define mem_ioswabl(x) (x) # define ioswabq(x) le64_to_cpu(x) +# define mem_ioswabq(x) (x) #else # define ioswabb(x) (x) +# define mem_ioswabb(x) (x) # define ioswabw(x) (x) +# define mem_ioswabw(x) cpu_to_le16(x) # define ioswabl(x) (x) +# define mem_ioswabl(x) cpu_to_le32(x) # define ioswabq(x) (x) +# define mem_ioswabq(x) cpu_to_le32(x) #endif -/* - * Native bus accesses never swapped. - */ -#define bus_ioswabb(x) (x) -#define bus_ioswabw(x) (x) -#define bus_ioswabl(x) (x) -#define bus_ioswabq(x) (x) - -#define __bus_ioswabq bus_ioswabq - #define IO_SPACE_LIMIT 0xffff /* @@ -194,12 +204,14 @@ extern unsigned long isa_slot_offset; */ #define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) -extern void * __ioremap(phys_t offset, phys_t size, unsigned long flags); +extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags); extern void __iounmap(volatile void __iomem *addr); -static inline void * __ioremap_mode(phys_t offset, unsigned long size, +static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, unsigned long flags) { +#define __IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL)) + if (cpu_has_64bit_addresses) { u64 base = UNCAC_BASE; @@ -209,10 +221,30 @@ static inline void * __ioremap_mode(phys_t offset, unsigned long size, */ if (flags == _CACHE_UNCACHED) base = (u64) IO_BASE; - return (void *) (unsigned long) (base + offset); + return (void __iomem *) (unsigned long) (base + offset); + } else if (__builtin_constant_p(offset) && + __builtin_constant_p(size) && __builtin_constant_p(flags)) { + phys_t phys_addr, last_addr; + + phys_addr = fixup_bigphys_addr(offset, size); + + /* Don't allow wraparound or zero size. */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Map uncached objects in the low 512MB of address + * space using KSEG1. + */ + if (__IS_LOW512(phys_addr) && __IS_LOW512(last_addr) && + flags == _CACHE_UNCACHED) + return (void __iomem *)CKSEG1ADDR(phys_addr); } return __ioremap(offset, size, flags); + +#undef __IS_LOW512 } /* @@ -264,12 +296,16 @@ static inline void * __ioremap_mode(phys_t offset, unsigned long size, static inline void iounmap(volatile void __iomem *addr) { - if (cpu_has_64bit_addresses) +#define __IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1) + + if (cpu_has_64bit_addresses || + (__builtin_constant_p(addr) && __IS_KSEG1(addr))) return; __iounmap(addr); -} +#undef __IS_KSEG1 +} #define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \ \ @@ -319,7 +355,8 @@ static inline type pfx##read##bwlq(volatile void __iomem *mem) \ else if (cpu_has_64bits) { \ unsigned long __flags; \ \ - local_irq_save(__flags); \ + if (irq) \ + local_irq_save(__flags); \ __asm__ __volatile__( \ ".set mips3" "\t\t# __readq" "\n\t" \ "ld %L0, %1" "\n\t" \ @@ -328,7 +365,8 @@ static inline type pfx##read##bwlq(volatile void __iomem *mem) \ ".set mips0" "\n" \ : "=r" (__val) \ : "m" (*__mem)); \ - local_irq_restore(__flags); \ + if (irq) \ + local_irq_restore(__flags); \ } else { \ __val = 0; \ BUG(); \ @@ -349,11 +387,11 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ \ __val = pfx##ioswab##bwlq(val); \ \ - if (sizeof(type) != sizeof(u64)) { \ - *__addr = __val; \ - slow; \ - } else \ - BUILD_BUG(); \ + /* Really, we want this to be atomic */ \ + BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \ + \ + *__addr = __val; \ + slow; \ } \ \ static inline type pfx##in##bwlq##p(unsigned long port) \ @@ -364,13 +402,10 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ port = __swizzle_addr_##bwlq(port); \ __addr = (void *)(mips_io_port_base + port); \ \ - if (sizeof(type) != sizeof(u64)) { \ - __val = *__addr; \ - slow; \ - } else { \ - __val = 0; \ - BUILD_BUG(); \ - } \ + BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \ + \ + __val = *__addr; \ + slow; \ \ return pfx##ioswab##bwlq(__val); \ } @@ -379,27 +414,35 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ \ __BUILD_MEMORY_SINGLE(bus, bwlq, type, 1) -#define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - \ -__BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \ -__BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO) - -#define BUILDIO(bwlq, type) \ +#define BUILDIO_MEM(bwlq, type) \ \ -__BUILD_MEMORY_PFX(, bwlq, type) \ __BUILD_MEMORY_PFX(__raw_, bwlq, type) \ -__BUILD_MEMORY_PFX(bus_, bwlq, type) \ -__BUILD_IOPORT_PFX(, bwlq, type) \ -__BUILD_IOPORT_PFX(__raw_, bwlq, type) +__BUILD_MEMORY_PFX(, bwlq, type) \ +__BUILD_MEMORY_PFX(mem_, bwlq, type) \ + +BUILDIO_MEM(b, u8) +BUILDIO_MEM(w, u16) +BUILDIO_MEM(l, u32) +BUILDIO_MEM(q, u64) + +#define __BUILD_IOPORT_PFX(bus, bwlq, type) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO) + +#define BUILDIO_IOPORT(bwlq, type) \ + __BUILD_IOPORT_PFX(, bwlq, type) \ + __BUILD_IOPORT_PFX(mem_, bwlq, type) + +BUILDIO_IOPORT(b, u8) +BUILDIO_IOPORT(w, u16) +BUILDIO_IOPORT(l, u32) +#ifdef CONFIG_64BIT +BUILDIO_IOPORT(q, u64) +#endif #define __BUILDIO(bwlq, type) \ \ -__BUILD_MEMORY_SINGLE(__bus_, bwlq, type, 0) - -BUILDIO(b, u8) -BUILDIO(w, u16) -BUILDIO(l, u32) -BUILDIO(q, u64) +__BUILD_MEMORY_SINGLE(____raw_, bwlq, type, 0) __BUILDIO(q, u64) @@ -422,7 +465,7 @@ static inline void writes##bwlq(volatile void __iomem *mem, void *addr, \ volatile type *__addr = addr; \ \ while (count--) { \ - __raw_write##bwlq(*__addr, mem); \ + mem_write##bwlq(*__addr, mem); \ __addr++; \ } \ } \ @@ -433,20 +476,20 @@ static inline void reads##bwlq(volatile void __iomem *mem, void *addr, \ volatile type *__addr = addr; \ \ while (count--) { \ - *__addr = __raw_read##bwlq(mem); \ + *__addr = mem_read##bwlq(mem); \ __addr++; \ } \ } #define __BUILD_IOPORT_STRING(bwlq, type) \ \ -static inline void outs##bwlq(unsigned long port, void *addr, \ +static inline void outs##bwlq(unsigned long port, const void *addr, \ unsigned int count) \ { \ - volatile type *__addr = addr; \ + const volatile type *__addr = addr; \ \ while (count--) { \ - __raw_out##bwlq(*__addr, port); \ + mem_out##bwlq(*__addr, port); \ __addr++; \ } \ } \ @@ -457,7 +500,7 @@ static inline void ins##bwlq(unsigned long port, void *addr, \ volatile type *__addr = addr; \ \ while (count--) { \ - *__addr = __raw_in##bwlq(port); \ + *__addr = mem_in##bwlq(port); \ __addr++; \ } \ } @@ -470,15 +513,26 @@ __BUILD_IOPORT_STRING(bwlq, type) BUILDSTRING(b, u8) BUILDSTRING(w, u16) BUILDSTRING(l, u32) +#ifdef CONFIG_64BIT BUILDSTRING(q, u64) +#endif /* Depends on MIPS II instruction set */ #define mmiowb() asm volatile ("sync" ::: "memory") -#define memset_io(a,b,c) memset((void *)(a),(b),(c)) -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) +static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) +{ + memset((void __force *) addr, val, count); +} +static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count) +{ + memcpy(dst, (void __force *) src, count); +} +static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count) +{ + memcpy((void __force *) dst, src, count); +} /* * Memory Mapped I/O |