[MIPS] Iomap implementation.
authorRalf Baechle <ralf@linux-mips.org>
Thu, 7 Dec 2006 14:35:43 +0000 (15:35 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Sun, 18 Feb 2007 21:31:34 +0000 (21:31 +0000)
This implementation has support for the concept of one separate ioport
address space by PCI domain.  A pointer to the virtual address where
the port space of a domain has been mapped has been added to struct
pci_controller and systems should be fixed to fill in this value. For
single domain systems this will be the same value as passed to
set_io_port_base().

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/lib/Makefile
arch/mips/lib/iomap-pci.c [new file with mode: 0644]
arch/mips/lib/iomap.c
arch/mips/pci/pci.c
include/asm-mips/io.h
include/asm-mips/pci.h

index 5ad501b30b430f387f219c575d4f7fbe9c8c517e..9e5d985936b32b9b3c3ccaf01de8db2885b78e62 100644 (file)
@@ -5,7 +5,8 @@
 lib-y  += csum_partial.o memcpy.o memset.o promlib.o \
           strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
-obj-y  += iomap.o
+obj-y                  += iomap.o
+obj-$(CONFIG_PCI)      += iomap-pci.o
 
 # libgcc-style stuff needed in the kernel
 lib-y += ashldi3.o ashrdi3.o lshrdi3.o
diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c
new file mode 100644 (file)
index 0000000..c11b249
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Implement the default iomap interfaces
+ *
+ * (C) Copyright 2004 Linus Torvalds
+ * (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
+ * (C) Copyright 2007 MIPS Technologies, Inc.
+ *     written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+static void __iomem *ioport_map_pci(struct pci_dev *dev,
+                                     unsigned long port, unsigned int nr)
+{
+       struct pci_controller *ctrl = dev->bus->sysdata;
+       unsigned long base = ctrl->io_map_base;
+
+       /* This will eventually become a BUG_ON but for now be gentle */
+       if (unlikely(!ctrl->io_map_base)) {
+               struct pci_bus *bus = dev->bus;
+               char name[8];
+
+               while (bus->parent)
+                       bus = bus->parent;
+
+               ctrl->io_map_base = base = mips_io_port_base;
+
+               sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
+               printk(KERN_WARNING "io_map_base of root PCI bus %s unset.  "
+                      "Trying to continue but you better\nfix this issue or "
+                      "report it to linux-mips@linux-mips.org or your "
+                      "vendor.\n", name);
+#ifdef CONFIG_PCI_DOMAINS
+               panic("To avoid data corruption io_map_base MUST be set with "
+                     "multiple PCI domains.");
+#endif
+       }
+
+       return (void __iomem *) (ctrl->io_map_base + port);
+}
+
+/*
+ * 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_pci(dev, start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       /* What? */
+       return NULL;
+}
+
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+       iounmap(addr);
+}
+
+EXPORT_SYMBOL(pci_iounmap);
index f4ac5bbcd81f17441a559c471d4615497514f5f8..d51d5cb0a4a937db84f5952afac2ea264b64faaf 100644 (file)
 /*
- *  iomap.c, Memory Mapped I/O routines for MIPS architecture.
+ * Implement the default iomap interfaces
  *
- *  This code is based on lib/iomap.c, by Linus Torvalds.
- *
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * (C) Copyright 2004 Linus Torvalds
+ * (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
+ * (C) Copyright 2007 MIPS Technologies, Inc.
+ *     written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/pci.h>
+#include <linux/module.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).
  *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ * 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.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Architectures for which this is not true can't use this generic
+ * implementation and should do their own copy.
  */
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/pci.h>
 
-#include <asm/io.h>
+#define PIO_MASK       0x0ffffUL
 
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
+unsigned int ioread8(void __iomem *addr)
 {
-       unsigned long end;
+       return readb(addr);
+}
 
-       end = port + nr - 1UL;
-       if (ioport_resource.start > port ||
-           ioport_resource.end < end || port > end)
-               return NULL;
+EXPORT_SYMBOL(ioread8);
 
-       return (void __iomem *)(mips_io_port_base + port);
+unsigned int ioread16(void __iomem *addr)
+{
+       return readw(addr);
 }
 
-void ioport_unmap(void __iomem *addr)
+EXPORT_SYMBOL(ioread16);
+
+unsigned int ioread16be(void __iomem *addr)
 {
+       return be16_to_cpu(__raw_readw(addr));
 }
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+EXPORT_SYMBOL(ioread16be);
+
+unsigned int ioread32(void __iomem *addr)
 {
-       unsigned long start, len, flags;
+       return readl(addr);
+}
 
-       if (dev == NULL)
-               return NULL;
+EXPORT_SYMBOL(ioread32);
 
-       start = pci_resource_start(dev, bar);
-       len = pci_resource_len(dev, bar);
-       if (!start || !len)
-               return NULL;
+unsigned int ioread32be(void __iomem *addr)
+{
+       return be32_to_cpu(__raw_readl(addr));
+}
 
-       if (maxlen != 0 && len > maxlen)
-               len = maxlen;
+EXPORT_SYMBOL(ioread32be);
+
+void iowrite8(u8 val, void __iomem *addr)
+{
+       writeb(val, addr);
+}
 
-       flags = pci_resource_flags(dev, bar);
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap_cachable(start, len);
-               return ioremap_nocache(start, len);
+EXPORT_SYMBOL(iowrite8);
+
+void iowrite16(u16 val, void __iomem *addr)
+{
+       writew(val, addr);
+}
+
+EXPORT_SYMBOL(iowrite16);
+
+void iowrite16be(u16 val, void __iomem *addr)
+{
+       __raw_writew(cpu_to_be16(val), addr);
+}
+
+EXPORT_SYMBOL(iowrite16be);
+
+void iowrite32(u32 val, void __iomem *addr)
+{
+       writel(val, addr);
+}
+
+EXPORT_SYMBOL(iowrite32);
+
+void iowrite32be(u32 val, void __iomem *addr)
+{
+       __raw_writel(cpu_to_be32(val), addr);
+}
+
+EXPORT_SYMBOL(iowrite32be);
+
+/*
+ * These are the "repeat MMIO read/write" functions.
+ * Note the "__raw" accesses, since we don't want to
+ * convert to CPU byte order. We write in "IO byte
+ * order" (we also don't have IO barriers).
+ */
+static inline void mmio_insb(void __iomem *addr, u8 *dst, int count)
+{
+       while (--count >= 0) {
+               u8 data = __raw_readb(addr);
+               *dst = data;
+               dst++;
        }
+}
 
-       return NULL;
+static inline void mmio_insw(void __iomem *addr, u16 *dst, int count)
+{
+       while (--count >= 0) {
+               u16 data = __raw_readw(addr);
+               *dst = data;
+               dst++;
+       }
 }
 
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+static inline void mmio_insl(void __iomem *addr, u32 *dst, int count)
 {
-       iounmap(addr);
+       while (--count >= 0) {
+               u32 data = __raw_readl(addr);
+               *dst = data;
+               dst++;
+       }
 }
-EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
+
+static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writeb(*src, addr);
+               src++;
+       }
+}
+
+static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writew(*src, addr);
+               src++;
+       }
+}
+
+static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writel(*src, addr);
+               src++;
+       }
+}
+
+void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       mmio_insb(addr, dst, count);
+}
+
+EXPORT_SYMBOL(ioread8_rep);
+
+void ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       mmio_insw(addr, dst, count);
+}
+
+EXPORT_SYMBOL(ioread16_rep);
+
+void ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       mmio_insl(addr, dst, count);
+}
+
+EXPORT_SYMBOL(ioread32_rep);
+
+void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       mmio_outsb(addr, src, count);
+}
+
+EXPORT_SYMBOL(iowrite8_rep);
+
+void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       mmio_outsw(addr, src, count);
+}
+
+EXPORT_SYMBOL(iowrite16_rep);
+
+void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       mmio_outsl(addr, src, count);
+}
+
+EXPORT_SYMBOL(iowrite32_rep);
+
+/*
+ * Create a virtual mapping cookie for an IO port range
+ *
+ * This uses the same mapping are as the in/out family which has to be setup
+ * by the platform initialization code.
+ *
+ * Just to make matters somewhat more interesting on MIPS systems with
+ * multiple host bridge each will have it's own ioport address space.
+ */
+static void __iomem *ioport_map_legacy(unsigned long port, unsigned int nr)
+{
+       return (void __iomem *) (mips_io_port_base + port);
+}
+
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       if (port > PIO_MASK)
+               return NULL;
+
+       return ioport_map_legacy(port, nr);
+}
+
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+       /* Nothing to do */
+}
+
+EXPORT_SYMBOL(ioport_unmap);
index 5ace368657ad691a352ca4dfa237a3bde96d8c00..697a7e48cb8d1498f2572b72dd5838ed287eccb4 100644 (file)
@@ -79,6 +79,14 @@ void __init register_pci_controller(struct pci_controller *hose)
 {
        *hose_tail = hose;
        hose_tail = &hose->next;
+
+       /*
+        * Do not panic here but later - this might hapen before console init.
+        */
+       if (!hose->io_map_base) {
+               printk(KERN_WARNING
+                      "registering PCI controller with io_map_base unset\n");
+       }
 }
 
 /* Most MIPS systems have straight-forward swizzling needs.  */
index b6a2eb8166287c8b72b4e14e5157006254f50d3a..92ec2618560c984355e653d33d5dc935e5e1488c 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm-generic/iomap.h>
 #include <asm/page.h>
 #include <asm/pgtable-bits.h>
 #include <asm/processor.h>
@@ -517,34 +518,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
        memcpy((void __force *) dst, src, count);
 }
 
-/*
- * Memory Mapped I/O
- */
-#define ioread8(addr)          readb(addr)
-#define ioread16(addr)         readw(addr)
-#define ioread32(addr)         readl(addr)
-
-#define iowrite8(b,addr)       writeb(b,addr)
-#define iowrite16(w,addr)      writew(w,addr)
-#define iowrite32(l,addr)      writel(l,addr)
-
-#define ioread8_rep(a,b,c)     readsb(a,b,c)
-#define ioread16_rep(a,b,c)    readsw(a,b,c)
-#define ioread32_rep(a,b,c)    readsl(a,b,c)
-
-#define iowrite8_rep(a,b,c)    writesb(a,b,c)
-#define iowrite16_rep(a,b,c)   writesw(a,b,c)
-#define iowrite32_rep(a,b,c)   writesl(a,b,c)
-
-/* Create a virtual mapping cookie for an IO port range */
-extern void __iomem *ioport_map(unsigned long 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 *);
-
 /*
  * ISA space is 'always mapped' on currently supported MIPS systems, no need
  * to explicitly ioremap() it. The fact that the ISA IO space is mapped
index 7f0f120ca07c23b6d42e2bdee1c3081095bf4c07..3eea3ba0fca5ec7f2353a0555c0dc47c2800637d 100644 (file)
@@ -32,6 +32,7 @@ struct pci_controller {
        unsigned long mem_offset;
        struct resource *io_resource;
        unsigned long io_offset;
+       unsigned long io_map_base;
 
        unsigned int index;
        /* For compatibility with current (as of July 2003) pciutils