Commit 140c1729a221dc6eacfcbf2a073dbf00fad13e43

Authored by Ralf Baechle
1 parent 4c1569949a

[MIPS] Iomap implementation.

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>

Showing 6 changed files with 287 additions and 81 deletions Side-by-side Diff

arch/mips/lib/Makefile
... ... @@ -5,7 +5,8 @@
5 5 lib-y += csum_partial.o memcpy.o memset.o promlib.o \
6 6 strlen_user.o strncpy_user.o strnlen_user.o uncached.o
7 7  
8   -obj-y += iomap.o
  8 +obj-y += iomap.o
  9 +obj-$(CONFIG_PCI) += iomap-pci.o
9 10  
10 11 # libgcc-style stuff needed in the kernel
11 12 lib-y += ashldi3.o ashrdi3.o lshrdi3.o
arch/mips/lib/iomap-pci.c
  1 +/*
  2 + * Implement the default iomap interfaces
  3 + *
  4 + * (C) Copyright 2004 Linus Torvalds
  5 + * (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
  6 + * (C) Copyright 2007 MIPS Technologies, Inc.
  7 + * written by Ralf Baechle <ralf@linux-mips.org>
  8 + */
  9 +#include <linux/pci.h>
  10 +#include <linux/module.h>
  11 +#include <asm/io.h>
  12 +
  13 +static void __iomem *ioport_map_pci(struct pci_dev *dev,
  14 + unsigned long port, unsigned int nr)
  15 +{
  16 + struct pci_controller *ctrl = dev->bus->sysdata;
  17 + unsigned long base = ctrl->io_map_base;
  18 +
  19 + /* This will eventually become a BUG_ON but for now be gentle */
  20 + if (unlikely(!ctrl->io_map_base)) {
  21 + struct pci_bus *bus = dev->bus;
  22 + char name[8];
  23 +
  24 + while (bus->parent)
  25 + bus = bus->parent;
  26 +
  27 + ctrl->io_map_base = base = mips_io_port_base;
  28 +
  29 + sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
  30 + printk(KERN_WARNING "io_map_base of root PCI bus %s unset. "
  31 + "Trying to continue but you better\nfix this issue or "
  32 + "report it to linux-mips@linux-mips.org or your "
  33 + "vendor.\n", name);
  34 +#ifdef CONFIG_PCI_DOMAINS
  35 + panic("To avoid data corruption io_map_base MUST be set with "
  36 + "multiple PCI domains.");
  37 +#endif
  38 + }
  39 +
  40 + return (void __iomem *) (ctrl->io_map_base + port);
  41 +}
  42 +
  43 +/*
  44 + * Create a virtual mapping cookie for a PCI BAR (memory or IO)
  45 + */
  46 +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
  47 +{
  48 + unsigned long start = pci_resource_start(dev, bar);
  49 + unsigned long len = pci_resource_len(dev, bar);
  50 + unsigned long flags = pci_resource_flags(dev, bar);
  51 +
  52 + if (!len || !start)
  53 + return NULL;
  54 + if (maxlen && len > maxlen)
  55 + len = maxlen;
  56 + if (flags & IORESOURCE_IO)
  57 + return ioport_map_pci(dev, start, len);
  58 + if (flags & IORESOURCE_MEM) {
  59 + if (flags & IORESOURCE_CACHEABLE)
  60 + return ioremap(start, len);
  61 + return ioremap_nocache(start, len);
  62 + }
  63 + /* What? */
  64 + return NULL;
  65 +}
  66 +
  67 +EXPORT_SYMBOL(pci_iomap);
  68 +
  69 +void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
  70 +{
  71 + iounmap(addr);
  72 +}
  73 +
  74 +EXPORT_SYMBOL(pci_iounmap);
arch/mips/lib/iomap.c
1 1 /*
2   - * iomap.c, Memory Mapped I/O routines for MIPS architecture.
  2 + * Implement the default iomap interfaces
3 3 *
4   - * This code is based on lib/iomap.c, by Linus Torvalds.
  4 + * (C) Copyright 2004 Linus Torvalds
  5 + * (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
  6 + * (C) Copyright 2007 MIPS Technologies, Inc.
  7 + * written by Ralf Baechle <ralf@linux-mips.org>
  8 + */
  9 +#include <linux/pci.h>
  10 +#include <linux/module.h>
  11 +#include <asm/io.h>
  12 +
  13 +/*
  14 + * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
  15 + * access or a MMIO access, these functions don't care. The info is
  16 + * encoded in the hardware mapping set up by the mapping functions
  17 + * (or the cookie itself, depending on implementation and hw).
5 18 *
6   - * Copyright (C) 2004-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
  19 + * The generic routines don't assume any hardware mappings, and just
  20 + * encode the PIO/MMIO as part of the cookie. They coldly assume that
  21 + * the MMIO IO mappings are not in the low address range.
7 22 *
8   - * This program is free software; you can redistribute it and/or modify
9   - * it under the terms of the GNU General Public License as published by
10   - * the Free Software Foundation; either version 2 of the License, or
11   - * (at your option) any later version.
12   - *
13   - * This program is distributed in the hope that it will be useful,
14   - * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   - * GNU General Public License for more details.
17   - *
18   - * You should have received a copy of the GNU General Public License
19   - * along with this program; if not, write to the Free Software
20   - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23 + * Architectures for which this is not true can't use this generic
  24 + * implementation and should do their own copy.
21 25 */
22   -#include <linux/ioport.h>
23   -#include <linux/module.h>
24   -#include <linux/pci.h>
25 26  
26   -#include <asm/io.h>
  27 +#define PIO_MASK 0x0ffffUL
27 28  
28   -void __iomem *ioport_map(unsigned long port, unsigned int nr)
  29 +unsigned int ioread8(void __iomem *addr)
29 30 {
30   - unsigned long end;
  31 + return readb(addr);
  32 +}
31 33  
32   - end = port + nr - 1UL;
33   - if (ioport_resource.start > port ||
34   - ioport_resource.end < end || port > end)
35   - return NULL;
  34 +EXPORT_SYMBOL(ioread8);
36 35  
37   - return (void __iomem *)(mips_io_port_base + port);
  36 +unsigned int ioread16(void __iomem *addr)
  37 +{
  38 + return readw(addr);
38 39 }
39 40  
40   -void ioport_unmap(void __iomem *addr)
  41 +EXPORT_SYMBOL(ioread16);
  42 +
  43 +unsigned int ioread16be(void __iomem *addr)
41 44 {
  45 + return be16_to_cpu(__raw_readw(addr));
42 46 }
43   -EXPORT_SYMBOL(ioport_map);
44   -EXPORT_SYMBOL(ioport_unmap);
45 47  
46   -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
  48 +EXPORT_SYMBOL(ioread16be);
  49 +
  50 +unsigned int ioread32(void __iomem *addr)
47 51 {
48   - unsigned long start, len, flags;
  52 + return readl(addr);
  53 +}
49 54  
50   - if (dev == NULL)
51   - return NULL;
  55 +EXPORT_SYMBOL(ioread32);
52 56  
53   - start = pci_resource_start(dev, bar);
54   - len = pci_resource_len(dev, bar);
55   - if (!start || !len)
56   - return NULL;
  57 +unsigned int ioread32be(void __iomem *addr)
  58 +{
  59 + return be32_to_cpu(__raw_readl(addr));
  60 +}
57 61  
58   - if (maxlen != 0 && len > maxlen)
59   - len = maxlen;
  62 +EXPORT_SYMBOL(ioread32be);
60 63  
61   - flags = pci_resource_flags(dev, bar);
62   - if (flags & IORESOURCE_IO)
63   - return ioport_map(start, len);
64   - if (flags & IORESOURCE_MEM) {
65   - if (flags & IORESOURCE_CACHEABLE)
66   - return ioremap_cachable(start, len);
67   - return ioremap_nocache(start, len);
  64 +void iowrite8(u8 val, void __iomem *addr)
  65 +{
  66 + writeb(val, addr);
  67 +}
  68 +
  69 +EXPORT_SYMBOL(iowrite8);
  70 +
  71 +void iowrite16(u16 val, void __iomem *addr)
  72 +{
  73 + writew(val, addr);
  74 +}
  75 +
  76 +EXPORT_SYMBOL(iowrite16);
  77 +
  78 +void iowrite16be(u16 val, void __iomem *addr)
  79 +{
  80 + __raw_writew(cpu_to_be16(val), addr);
  81 +}
  82 +
  83 +EXPORT_SYMBOL(iowrite16be);
  84 +
  85 +void iowrite32(u32 val, void __iomem *addr)
  86 +{
  87 + writel(val, addr);
  88 +}
  89 +
  90 +EXPORT_SYMBOL(iowrite32);
  91 +
  92 +void iowrite32be(u32 val, void __iomem *addr)
  93 +{
  94 + __raw_writel(cpu_to_be32(val), addr);
  95 +}
  96 +
  97 +EXPORT_SYMBOL(iowrite32be);
  98 +
  99 +/*
  100 + * These are the "repeat MMIO read/write" functions.
  101 + * Note the "__raw" accesses, since we don't want to
  102 + * convert to CPU byte order. We write in "IO byte
  103 + * order" (we also don't have IO barriers).
  104 + */
  105 +static inline void mmio_insb(void __iomem *addr, u8 *dst, int count)
  106 +{
  107 + while (--count >= 0) {
  108 + u8 data = __raw_readb(addr);
  109 + *dst = data;
  110 + dst++;
68 111 }
  112 +}
69 113  
70   - return NULL;
  114 +static inline void mmio_insw(void __iomem *addr, u16 *dst, int count)
  115 +{
  116 + while (--count >= 0) {
  117 + u16 data = __raw_readw(addr);
  118 + *dst = data;
  119 + dst++;
  120 + }
71 121 }
72 122  
73   -void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
  123 +static inline void mmio_insl(void __iomem *addr, u32 *dst, int count)
74 124 {
75   - iounmap(addr);
  125 + while (--count >= 0) {
  126 + u32 data = __raw_readl(addr);
  127 + *dst = data;
  128 + dst++;
  129 + }
76 130 }
77   -EXPORT_SYMBOL(pci_iomap);
78   -EXPORT_SYMBOL(pci_iounmap);
  131 +
  132 +static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count)
  133 +{
  134 + while (--count >= 0) {
  135 + __raw_writeb(*src, addr);
  136 + src++;
  137 + }
  138 +}
  139 +
  140 +static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count)
  141 +{
  142 + while (--count >= 0) {
  143 + __raw_writew(*src, addr);
  144 + src++;
  145 + }
  146 +}
  147 +
  148 +static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count)
  149 +{
  150 + while (--count >= 0) {
  151 + __raw_writel(*src, addr);
  152 + src++;
  153 + }
  154 +}
  155 +
  156 +void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
  157 +{
  158 + mmio_insb(addr, dst, count);
  159 +}
  160 +
  161 +EXPORT_SYMBOL(ioread8_rep);
  162 +
  163 +void ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
  164 +{
  165 + mmio_insw(addr, dst, count);
  166 +}
  167 +
  168 +EXPORT_SYMBOL(ioread16_rep);
  169 +
  170 +void ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
  171 +{
  172 + mmio_insl(addr, dst, count);
  173 +}
  174 +
  175 +EXPORT_SYMBOL(ioread32_rep);
  176 +
  177 +void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
  178 +{
  179 + mmio_outsb(addr, src, count);
  180 +}
  181 +
  182 +EXPORT_SYMBOL(iowrite8_rep);
  183 +
  184 +void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
  185 +{
  186 + mmio_outsw(addr, src, count);
  187 +}
  188 +
  189 +EXPORT_SYMBOL(iowrite16_rep);
  190 +
  191 +void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
  192 +{
  193 + mmio_outsl(addr, src, count);
  194 +}
  195 +
  196 +EXPORT_SYMBOL(iowrite32_rep);
  197 +
  198 +/*
  199 + * Create a virtual mapping cookie for an IO port range
  200 + *
  201 + * This uses the same mapping are as the in/out family which has to be setup
  202 + * by the platform initialization code.
  203 + *
  204 + * Just to make matters somewhat more interesting on MIPS systems with
  205 + * multiple host bridge each will have it's own ioport address space.
  206 + */
  207 +static void __iomem *ioport_map_legacy(unsigned long port, unsigned int nr)
  208 +{
  209 + return (void __iomem *) (mips_io_port_base + port);
  210 +}
  211 +
  212 +void __iomem *ioport_map(unsigned long port, unsigned int nr)
  213 +{
  214 + if (port > PIO_MASK)
  215 + return NULL;
  216 +
  217 + return ioport_map_legacy(port, nr);
  218 +}
  219 +
  220 +EXPORT_SYMBOL(ioport_map);
  221 +
  222 +void ioport_unmap(void __iomem *addr)
  223 +{
  224 + /* Nothing to do */
  225 +}
  226 +
  227 +EXPORT_SYMBOL(ioport_unmap);
... ... @@ -79,6 +79,14 @@
79 79 {
80 80 *hose_tail = hose;
81 81 hose_tail = &hose->next;
  82 +
  83 + /*
  84 + * Do not panic here but later - this might hapen before console init.
  85 + */
  86 + if (!hose->io_map_base) {
  87 + printk(KERN_WARNING
  88 + "registering PCI controller with io_map_base unset\n");
  89 + }
82 90 }
83 91  
84 92 /* Most MIPS systems have straight-forward swizzling needs. */
include/asm-mips/io.h
... ... @@ -20,6 +20,7 @@
20 20 #include <asm/byteorder.h>
21 21 #include <asm/cpu.h>
22 22 #include <asm/cpu-features.h>
  23 +#include <asm-generic/iomap.h>
23 24 #include <asm/page.h>
24 25 #include <asm/pgtable-bits.h>
25 26 #include <asm/processor.h>
... ... @@ -516,34 +517,6 @@
516 517 {
517 518 memcpy((void __force *) dst, src, count);
518 519 }
519   -
520   -/*
521   - * Memory Mapped I/O
522   - */
523   -#define ioread8(addr) readb(addr)
524   -#define ioread16(addr) readw(addr)
525   -#define ioread32(addr) readl(addr)
526   -
527   -#define iowrite8(b,addr) writeb(b,addr)
528   -#define iowrite16(w,addr) writew(w,addr)
529   -#define iowrite32(l,addr) writel(l,addr)
530   -
531   -#define ioread8_rep(a,b,c) readsb(a,b,c)
532   -#define ioread16_rep(a,b,c) readsw(a,b,c)
533   -#define ioread32_rep(a,b,c) readsl(a,b,c)
534   -
535   -#define iowrite8_rep(a,b,c) writesb(a,b,c)
536   -#define iowrite16_rep(a,b,c) writesw(a,b,c)
537   -#define iowrite32_rep(a,b,c) writesl(a,b,c)
538   -
539   -/* Create a virtual mapping cookie for an IO port range */
540   -extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
541   -extern void ioport_unmap(void __iomem *);
542   -
543   -/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
544   -struct pci_dev;
545   -extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
546   -extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
547 520  
548 521 /*
549 522 * ISA space is 'always mapped' on currently supported MIPS systems, no need
include/asm-mips/pci.h
... ... @@ -32,6 +32,7 @@
32 32 unsigned long mem_offset;
33 33 struct resource *io_resource;
34 34 unsigned long io_offset;
  35 + unsigned long io_map_base;
35 36  
36 37 unsigned int index;
37 38 /* For compatibility with current (as of July 2003) pciutils