[PATCH v3 1/3] asm-generic/io.h: Implement generic {read,write}s*()

Thierry Reding thierry.reding at gmail.com
Wed Jul 16 04:01:22 PDT 2014


From: Thierry Reding <treding at nvidia.com>

Currently driver writers need to use io{read,write}{8,16,32}_rep() when
accessing FIFO registers portably. This is bad for two reasons: it is
inconsistent with how other registers are accessed using the standard
{read,write}{b,w,l}() functions, which can lead to confusion. On some
architectures the io{read,write}*() functions also need to perform some
extra checks to determine whether an address is memory-mapped or refers
to I/O space. Drivers which can be expected to never use I/O can safely
use the {read,write}s{b,w,l,q}(), just like they use their non-string
variants and there's no need for these extra checks.

This patch implements generic versions of readsb(), readsw(), readsl(),
readsq(), writesb(), writesw(), writesl() and writesq(). Variants of
these string functions for I/O accesses (ins*() and outs*() as well as
ioread*_rep() and iowrite*_rep()) are now implemented in terms of the
new functions.

Going forward, {read,write}{,s}{b,w,l,q}() should be used consistently
by drivers for devices that will only ever be memory-mapped and hence
don't need to access I/O space, whereas io{read,write}{8,16,32}_rep()
should be used by drivers for devices that can be either memory-mapped
or I/O-mapped.

While at it, also make sure that any of the functions provided as
fallback for architectures that don't override them can't be overridden
subsequently.

This is compile- and runtime-tested on 32-bit and 64-bit ARM and compile
tested on Microblaze, s390, SPARC and Xtensa. For ARC, Blackfin, Metag,
OpenRISC, Score and Unicore32 which also use asm-generic/io.h I couldn't
find or build a cross-compiler that would run on my system. But by code
inspection they shouldn't break with this patch.

Signed-off-by: Thierry Reding <treding at nvidia.com>
---
Changes in v3:
- allow architectures to override io{read,write}{16,32}be()
- explain the reasons for this change in the commit message

Changes in v2:
- respect IO_SPACE_LIMIT in ioport_map()

 include/asm-generic/io.h | 294 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 211 insertions(+), 83 deletions(-)

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 975e1cc75edb..b2ea16b4264b 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -32,6 +32,7 @@
  * memory location directly.
  */
 #ifndef __raw_readb
+#define __raw_readb __raw_readb
 static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
 	return *(const volatile u8 __force *) addr;
@@ -39,6 +40,7 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
 #endif
 
 #ifndef __raw_readw
+#define __raw_readw __raw_readw
 static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
 	return *(const volatile u16 __force *) addr;
@@ -46,27 +48,35 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 #endif
 
 #ifndef __raw_readl
+#define __raw_readl __raw_readl
 static inline u32 __raw_readl(const volatile void __iomem *addr)
 {
 	return *(const volatile u32 __force *) addr;
 }
 #endif
 
+#ifndef readb
 #define readb __raw_readb
+#endif
 
+#ifndef readw
 #define readw readw
 static inline u16 readw(const volatile void __iomem *addr)
 {
 	return __le16_to_cpu(__raw_readw(addr));
 }
+#endif
 
+#ifndef readl
 #define readl readl
 static inline u32 readl(const volatile void __iomem *addr)
 {
 	return __le32_to_cpu(__raw_readl(addr));
 }
+#endif
 
 #ifndef __raw_writeb
+#define __raw_writeb __raw_writeb
 static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
 {
 	*(volatile u8 __force *) addr = b;
@@ -74,6 +84,7 @@ static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
 #endif
 
 #ifndef __raw_writew
+#define __raw_writew __raw_writew
 static inline void __raw_writew(u16 b, volatile void __iomem *addr)
 {
 	*(volatile u16 __force *) addr = b;
@@ -81,78 +92,225 @@ static inline void __raw_writew(u16 b, volatile void __iomem *addr)
 #endif
 
 #ifndef __raw_writel
+#define __raw_writel __raw_writel
 static inline void __raw_writel(u32 b, volatile void __iomem *addr)
 {
 	*(volatile u32 __force *) addr = b;
 }
 #endif
 
+#ifndef writeb
 #define writeb __raw_writeb
+#endif
+
+#ifndef writew
 #define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
+#endif
+
+#ifndef writel
 #define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
+#endif
 
 #ifdef CONFIG_64BIT
 #ifndef __raw_readq
+#define __raw_readq __raw_readq
 static inline u64 __raw_readq(const volatile void __iomem *addr)
 {
 	return *(const volatile u64 __force *) addr;
 }
 #endif
 
+#ifndef readq
 #define readq readq
 static inline u64 readq(const volatile void __iomem *addr)
 {
 	return __le64_to_cpu(__raw_readq(addr));
 }
+#endif
 
 #ifndef __raw_writeq
+#define __raw_writeq __raw_writeq
 static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
 {
 	*(volatile u64 __force *) addr = b;
 }
 #endif
 
+#ifndef writeq
 #define writeq(b, addr) __raw_writeq(__cpu_to_le64(b), addr)
+#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef readsb
+#define readsb readsb
+static inline void readsb(const void __iomem *addr, void *buffer, int count)
+{
+	if (count) {
+		u8 *buf = buffer;
+		do {
+			u8 x = __raw_readb(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef readsw
+#define readsw readsw
+static inline void readsw(const void __iomem *addr, void *buffer, int count)
+{
+	if (count) {
+		u16 *buf = buffer;
+		do {
+			u16 x = __raw_readw(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef readsl
+#define readsl readsl
+static inline void readsl(const void __iomem *addr, void *buffer, int count)
+{
+	if (count) {
+		u32 *buf = buffer;
+		do {
+			u32 x = __raw_readl(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef writesb
+#define writesb writesb
+static inline void writesb(void __iomem *addr, const void *buffer, int count)
+{
+	if (count) {
+		const u8 *buf = buffer;
+		do {
+			__raw_writeb(*buf++, addr);
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef writesw
+#define writesw writesw
+static inline void writesw(void __iomem *addr, const void *buffer, int count)
+{
+	if (count) {
+		const u16 *buf = buffer;
+		do {
+			__raw_writew(*buf++, addr);
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef writesl
+#define writesl writesl
+static inline void writesl(void __iomem *addr, const void *buffer, int count)
+{
+	if (count) {
+		const u32 *buf = buffer;
+		do {
+			__raw_writel(*buf++, addr);
+		} while (--count);
+	}
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef readsq
+#define readsq readsq
+static inline void readsq(const void __iomem *addr, void *buffer, int count)
+{
+	if (count) {
+		u64 *buf = buffer;
+		do {
+			u64 x = __raw_readq(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+#endif
+
+#ifndef writesq
+#define writesq writesq
+static inline void writesq(void __iomem *addr, const void *buffer, int count)
+{
+	if (count) {
+		const u64 *buf = buffer;
+		do {
+			__raw_writeq(*buf++, addr);
+		} while (--count);
+	}
+}
+#endif
 #endif /* CONFIG_64BIT */
 
 #ifndef PCI_IOBASE
 #define PCI_IOBASE ((void __iomem *) 0)
 #endif
 
+#ifndef IO_SPACE_LIMIT
+#define IO_SPACE_LIMIT 0xffff
+#endif
+
 /*****************************************************************************/
 /*
  * traditional input/output functions
  */
 
+#ifndef inb
+#define inb inb
 static inline u8 inb(unsigned long addr)
 {
-	return readb(addr + PCI_IOBASE);
+	return readb(PCI_IOBASE + addr);
 }
+#endif
 
+#ifndef inw
+#define inw inw
 static inline u16 inw(unsigned long addr)
 {
-	return readw(addr + PCI_IOBASE);
+	return readw(PCI_IOBASE + addr);
 }
+#endif
 
+#ifndef inl
+#define inl inl
 static inline u32 inl(unsigned long addr)
 {
-	return readl(addr + PCI_IOBASE);
+	return readl(PCI_IOBASE + addr);
 }
+#endif
 
+#ifndef outb
+#define outb outb
 static inline void outb(u8 b, unsigned long addr)
 {
-	writeb(b, addr + PCI_IOBASE);
+	writeb(b, PCI_IOBASE + addr);
 }
+#endif
 
+#ifndef outw
+#define outw outw
 static inline void outw(u16 b, unsigned long addr)
 {
-	writew(b, addr + PCI_IOBASE);
+	writew(b, PCI_IOBASE + addr);
 }
+#endif
 
+#ifndef outl
+#define outl outl
 static inline void outl(u32 b, unsigned long addr)
 {
-	writel(b, addr + PCI_IOBASE);
+	writel(b, PCI_IOBASE + addr);
 }
+#endif
 
 #define inb_p(addr)	inb(addr)
 #define inw_p(addr)	inw(addr)
@@ -162,112 +320,71 @@ static inline void outl(u32 b, unsigned long addr)
 #define outl_p(x, addr)	outl((x), (addr))
 
 #ifndef insb
-static inline void insb(unsigned long addr, void *buffer, int count)
-{
-	if (count) {
-		u8 *buf = buffer;
-		do {
-			u8 x = __raw_readb(addr + PCI_IOBASE);
-			*buf++ = x;
-		} while (--count);
-	}
-}
+#define insb(addr, buffer, count) readsb(PCI_IOBASE + addr, buffer, count)
 #endif
 
 #ifndef insw
-static inline void insw(unsigned long addr, void *buffer, int count)
-{
-	if (count) {
-		u16 *buf = buffer;
-		do {
-			u16 x = __raw_readw(addr + PCI_IOBASE);
-			*buf++ = x;
-		} while (--count);
-	}
-}
+#define insw(addr, buffer, count) readsw(PCI_IOBASE + addr, buffer, count)
 #endif
 
 #ifndef insl
-static inline void insl(unsigned long addr, void *buffer, int count)
-{
-	if (count) {
-		u32 *buf = buffer;
-		do {
-			u32 x = __raw_readl(addr + PCI_IOBASE);
-			*buf++ = x;
-		} while (--count);
-	}
-}
+#define insl(addr, buffer, count) readsl(PCI_IOBASE + addr, buffer, count)
 #endif
 
 #ifndef outsb
-static inline void outsb(unsigned long addr, const void *buffer, int count)
-{
-	if (count) {
-		const u8 *buf = buffer;
-		do {
-			__raw_writeb(*buf++, addr + PCI_IOBASE);
-		} while (--count);
-	}
-}
+#define outsb(addr, buffer, count) writesb(PCI_IOBASE + addr, buffer, count)
 #endif
 
 #ifndef outsw
-static inline void outsw(unsigned long addr, const void *buffer, int count)
-{
-	if (count) {
-		const u16 *buf = buffer;
-		do {
-			__raw_writew(*buf++, addr + PCI_IOBASE);
-		} while (--count);
-	}
-}
+#define outsw(addr, buffer, count) writesw(PCI_IOBASE + addr, buffer, count)
 #endif
 
 #ifndef outsl
-static inline void outsl(unsigned long addr, const void *buffer, int count)
-{
-	if (count) {
-		const u32 *buf = buffer;
-		do {
-			__raw_writel(*buf++, addr + PCI_IOBASE);
-		} while (--count);
-	}
-}
+#define outsl(addr, buffer, count) writesl(PCI_IOBASE + addr, buffer, count)
 #endif
 
+#define insb_p(port,to,len)	insb(port,to,len)
+#define insw_p(port,to,len)	insw(port,to,len)
+#define insl_p(port,to,len)	insl(port,to,len)
+
+#define outsb_p(port,from,len)	outsb(port,from,len)
+#define outsw_p(port,from,len)	outsw(port,from,len)
+#define outsl_p(port,from,len)	outsl(port,from,len)
+
 #ifndef CONFIG_GENERIC_IOMAP
 #define ioread8(addr)		readb(addr)
 #define ioread16(addr)		readw(addr)
-#define ioread16be(addr)	__be16_to_cpu(__raw_readw(addr))
 #define ioread32(addr)		readl(addr)
+
+#ifndef ioread16be
+#define ioread16be(addr)	__be16_to_cpu(__raw_readw(addr))
+#endif
+
+#ifndef ioread32be
 #define ioread32be(addr)	__be32_to_cpu(__raw_readl(addr))
+#endif
 
 #define iowrite8(v, addr)	writeb((v), (addr))
 #define iowrite16(v, addr)	writew((v), (addr))
-#define iowrite16be(v, addr)	__raw_writew(__cpu_to_be16(v), addr)
 #define iowrite32(v, addr)	writel((v), (addr))
-#define iowrite32be(v, addr)	__raw_writel(__cpu_to_be32(v), addr)
 
-#define ioread8_rep(p, dst, count) \
-	insb((unsigned long) (p), (dst), (count))
-#define ioread16_rep(p, dst, count) \
-	insw((unsigned long) (p), (dst), (count))
-#define ioread32_rep(p, dst, count) \
-	insl((unsigned long) (p), (dst), (count))
-
-#define iowrite8_rep(p, src, count) \
-	outsb((unsigned long) (p), (src), (count))
-#define iowrite16_rep(p, src, count) \
-	outsw((unsigned long) (p), (src), (count))
-#define iowrite32_rep(p, src, count) \
-	outsl((unsigned long) (p), (src), (count))
-#endif /* CONFIG_GENERIC_IOMAP */
+#ifndef iowrite16be
+#define iowrite16be(v, addr)	__raw_writew(__cpu_to_be16(v), addr)
+#endif
 
-#ifndef IO_SPACE_LIMIT
-#define IO_SPACE_LIMIT 0xffff
+#ifndef iowrite32be
+#define iowrite32be(v, addr)	__raw_writel(__cpu_to_be32(v), addr)
 #endif
 
+#define ioread8_rep(p, dst, count) readsb(p, dst, count)
+#define ioread16_rep(p, dst, count) readsw(p, dst, count)
+#define ioread32_rep(p, dst, count) readsl(p, dst, count)
+
+#define iowrite8_rep(p, src, count) writesb(p, src, count)
+#define iowrite16_rep(p, src, count) writesw(p, src, count)
+#define iowrite32_rep(p, src, count) writesl(p, src, count)
+#endif /* CONFIG_GENERIC_IOMAP */
+
 #ifdef __KERNEL__
 
 #include <linux/vmalloc.h>
@@ -278,6 +395,7 @@ struct pci_dev;
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 
 #ifndef pci_iounmap
+#define pci_iounmap pci_iounmap
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
 {
 }
@@ -289,11 +407,15 @@ static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
  * These are pretty trivial
  */
 #ifndef virt_to_phys
+#define virt_to_phys virt_to_phys
 static inline unsigned long virt_to_phys(volatile void *address)
 {
 	return __pa((unsigned long)address);
 }
+#endif
 
+#ifndef phys_to_virt
+#define phys_to_virt phys_to_virt
 static inline void *phys_to_virt(unsigned long address)
 {
 	return __va(address);
@@ -329,14 +451,20 @@ static inline void iounmap(void __iomem *addr)
 
 #ifdef CONFIG_HAS_IOPORT_MAP
 #ifndef CONFIG_GENERIC_IOMAP
+#ifndef ioport_map
+#define ioport_map ioport_map
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
-	return (void __iomem *) port;
+	return PCI_IOBASE + (port & IO_SPACE_LIMIT);
 }
+#endif
 
+#ifndef ioport_unmap
+#define ioport_unmap ioport_unmap
 static inline void ioport_unmap(void __iomem *p)
 {
 }
+#endif
 #else /* CONFIG_GENERIC_IOMAP */
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *p);
-- 
2.0.1




More information about the linux-arm-kernel mailing list