Commit 140c1729a221dc6eacfcbf2a073dbf00fad13e43
1 parent
4c1569949a
Exists in
master
and in
7 other branches
[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); |
arch/mips/pci/pci.c
... | ... | @@ -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