summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-12 21:32:00 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-12 21:32:00 -0700
commite4dad07102ea55ff15353e415ba4edc89953e67c (patch)
treec20a8a4832058dea8f520d8a2245be8f5ea0afc9
parentb42897ce287f1b242ac217de88e325101c0138f2 (diff)
Add skeleton "generic IO mapping" infrastructure.
Jeff wants to use this to clean up SATA and some network drivers.
-rw-r--r--arch/alpha/Kconfig4
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/i386/Kconfig4
-rw-r--r--arch/ia64/Kconfig4
-rw-r--r--arch/ppc/Kconfig4
-rw-r--r--arch/ppc64/Kconfig4
-rw-r--r--arch/x86_64/Kconfig4
-rw-r--r--include/asm-generic/iomap.h44
-rw-r--r--include/asm-i386/io.h2
-rw-r--r--include/asm-ppc64/io.h2
-rw-r--r--lib/Makefile1
-rw-r--r--lib/iomap.c110
12 files changed, 187 insertions, 0 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 541bd7965909..0e4855419a72 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -32,6 +32,10 @@ config GENERIC_ISA_DMA
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
source "init/Kconfig"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 95aa273cdacf..aa709d12ef58 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -63,6 +63,10 @@ config GENERIC_BUST_SPINLOCK
config GENERIC_ISA_DMA
bool
+config GENERIC_IOMAP
+ bool
+ default y
+
source "init/Kconfig"
menu "System Type"
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 18c722a8e656..597a9969169e 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -29,6 +29,10 @@ config GENERIC_ISA_DMA
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
source "init/Kconfig"
menu "Processor type and features"
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 4459907b0a8a..aa742c601da2 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -38,6 +38,10 @@ config EFI
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
choice
prompt "System type"
default IA64_GENERIC
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 46139ac97563..81d55092fde0 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -35,6 +35,10 @@ config GENERIC_NVRAM
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
source "init/Kconfig"
menu "Processor"
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index c11f5cc5605a..706c53f58d0f 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -24,6 +24,10 @@ config GENERIC_ISA_DMA
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
config HAVE_DEC_LOCK
bool
default y
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index a131337b9dac..6f55f43975c1 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -78,6 +78,10 @@ config GENERIC_ISA_DMA
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
source "init/Kconfig"
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
new file mode 100644
index 000000000000..cbd9e7f03a2a
--- /dev/null
+++ b/include/asm-generic/iomap.h
@@ -0,0 +1,44 @@
+#ifndef __GENERIC_IO_H
+#define __GENERIC_IO_H
+
+#include <linux/linkage.h>
+
+/*
+ * These are the "generic" interfaces for doing new-style
+ * memory-mapped or PIO accesses. Architectures may do
+ * their own arch-optimized versions, these just act as
+ * wrappers around the old-style IO register access functions:
+ * read[bwl]/write[bwl]/in[bwl]/out[bwl]
+ *
+ * Don't include this directly, include it from <asm/io.h>.
+ */
+
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines just encode the PIO/MMIO as part of the
+ * cookie, and coldly assume that the MMIO IO mappings are not
+ * in the low address range. Architectures for which this is not
+ * true can't use this generic implementation.
+ */
+extern unsigned int fastcall ioread8(void __iomem *);
+extern unsigned int fastcall ioread16(void __iomem *);
+extern unsigned int fastcall ioread32(void __iomem *);
+
+extern void fastcall iowrite8(u8, void __iomem *);
+extern void fastcall iowrite16(u16, void __iomem *);
+extern void fastcall iowrite32(u32, void __iomem *);
+
+/* Create a virtual mapping cookie for an IO port range */
+extern void __iomem *ioport_map(unsigned int port, unsigned int nr);
+extern void ioport_unmap(void __iomem *);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
+#endif
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 20a26b98ec6e..083e3b8f8c7f 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -45,6 +45,8 @@
#ifdef __KERNEL__
+#include <asm-generic/iomap.h>
+
#include <linux/vmalloc.h>
/**
diff --git a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
index 33c2dfff9815..1e9cd557352e 100644
--- a/include/asm-ppc64/io.h
+++ b/include/asm-ppc64/io.h
@@ -18,6 +18,8 @@
#include <asm/memory.h>
#include <asm/delay.h>
+#include <asm-generic/iomap.h>
+
#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 *)(p), (a), (c))
#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 *)(p), (a), (c))
#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 *)(p), (a), (c))
diff --git a/lib/Makefile b/lib/Makefile
index b62c9ef212ed..bcd6e855e747 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,6 +10,7 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+lib-$(CONFIG_GENERIC_IOMAP) += iomap.o
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
lib-y += dec_and_lock.o
diff --git a/lib/iomap.c b/lib/iomap.c
new file mode 100644
index 000000000000..0873451ac21b
--- /dev/null
+++ b/lib/iomap.c
@@ -0,0 +1,110 @@
+/*
+ * Implement the default iomap interfaces
+ */
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines don't assume any hardware mappings, and just
+ * encode the PIO/MMIO as part of the cookie. They coldly assume that
+ * the MMIO IO mappings are not in the low address range.
+ *
+ * Architectures for which this is not true can't use this generic
+ * implementation and should do their own copy.
+ *
+ * We encode the physical PIO addresses (0-0xffff) into the
+ * pointer by offsetting them with a constant (0x10000) and
+ * assuming that all the low addresses are always PIO. That means
+ * we can do some sanity checks on the low bits, and don't
+ * need to just take things for granted.
+ */
+#define PIO_OFFSET 0x10000
+#define PIO_MASK 0x0ffff
+#define PIO_RESERVED 0x40000
+
+/*
+ * Ugly macros are a way of life.
+ */
+#define VERIFY_PIO(port) BUG_ON((port & ~PIO_MASK) != PIO_OFFSET)
+
+#define IO_COND(addr, is_pio, is_mmio) do { \
+ unsigned long port = (unsigned long __force)addr; \
+ if (port < PIO_RESERVED) { \
+ VERIFY_PIO(port); \
+ port &= PIO_MASK; \
+ is_pio; \
+ } else { \
+ is_mmio; \
+ } \
+} while (0)
+
+unsigned int fastcall ioread8(void __iomem *addr)
+{
+ IO_COND(addr, return inb(port), return readb(addr));
+}
+unsigned int fastcall ioread16(void __iomem *addr)
+{
+ IO_COND(addr, return inw(port), return readw(addr));
+}
+unsigned int fastcall ioread32(void __iomem *addr)
+{
+ IO_COND(addr, return inl(port), return readl(addr));
+}
+
+void fastcall iowrite8(u8 val, void __iomem *addr)
+{
+ IO_COND(addr, outb(val,port), writeb(val, addr));
+}
+void fastcall iowrite16(u16 val, void __iomem *addr)
+{
+ IO_COND(addr, outw(val,port), writew(val, addr));
+}
+void fastcall iowrite32(u32 val, void __iomem *addr)
+{
+ IO_COND(addr, outl(val,port), writel(val, addr));
+}
+
+/* Create a virtual mapping cookie for an IO port range */
+void __iomem *ioport_map(unsigned int port, unsigned int nr)
+{
+ if (port > PIO_MASK)
+ return NULL;
+ return (void __iomem *) (unsigned long) (port + PIO_OFFSET);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+ /* Nothing to do */
+}
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+ unsigned long start = pci_resource_start(dev, bar);
+ unsigned long len = pci_resource_len(dev, bar);
+ unsigned long flags = pci_resource_flags(dev, bar);
+
+ if (!len || !start)
+ return NULL;
+ if (maxlen && len > maxlen)
+ len = maxlen;
+ if (flags & IORESOURCE_IO)
+ return ioport_map(start, len);
+ if (flags & IORESOURCE_MEM) {
+ if (flags & IORESOURCE_CACHEABLE)
+ return ioremap(start, len);
+ return ioremap_nocache(start, len);
+ }
+ /* What? */
+ return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+ IO_COND(addr, /* nothing */, iounmap(addr));
+}