aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIshizaki Kou <kou.ishizaki@toshiba.co.jp>2008-04-24 05:21:10 -0400
committerPaul Mackerras <paulus@samba.org>2008-04-24 07:08:12 -0400
commit7cfb62a2e820b6032c08835dbd996d8518af14a3 (patch)
treefdcd728c96ca020214452f11ae8600525e9d3773
parent36f8a2c4c61e3559a95190e457b431c6900859b4 (diff)
[POWERPC] cell: Generalize io-workarounds code
This splits cell io-workaround code into spider-pci dependent code and a generic part, and also moves io-workarounds initialization into cell_setup_phb. Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/of_platform.c2
-rw-r--r--arch/powerpc/platforms/cell/Makefile3
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c358
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.h49
-rw-r--r--arch/powerpc/platforms/cell/setup.c43
-rw-r--r--arch/powerpc/platforms/cell/spider-pci.c184
-rw-r--r--include/asm-powerpc/io-defs.h101
-rw-r--r--include/asm-powerpc/io.h8
8 files changed, 433 insertions, 315 deletions
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index fb698d47082d..e79ad8afda07 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -275,6 +275,8 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
275 275
276 /* Scan the bus */ 276 /* Scan the bus */
277 scan_phb(phb); 277 scan_phb(phb);
278 if (phb->bus == NULL)
279 return -ENXIO;
278 280
279 /* Claim resources. This might need some rework as well depending 281 /* Claim resources. This might need some rework as well depending
280 * wether we are doing probe-only or not, like assigning unassigned 282 * wether we are doing probe-only or not, like assigning unassigned
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index c89964c6fb1f..20966b709604 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,6 +1,7 @@
1obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \ 1obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
2 cbe_regs.o spider-pic.o \ 2 cbe_regs.o spider-pic.o \
3 pervasive.o pmu.o io-workarounds.o 3 pervasive.o pmu.o io-workarounds.o \
4 spider-pci.o
4obj-$(CONFIG_CBE_RAS) += ras.o 5obj-$(CONFIG_CBE_RAS) += ras.o
5 6
6obj-$(CONFIG_CBE_THERM) += cbe_thermal.o 7obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 979d4b67efb4..3b84e8be314c 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -1,6 +1,9 @@
1/* 1/*
2 * Support PCI IO workaround
3 *
2 * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org> 4 * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
3 * IBM, Corp. 5 * IBM, Corp.
6 * (C) Copyright 2007-2008 TOSHIBA CORPORATION
4 * 7 *
5 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -9,335 +12,174 @@
9#undef DEBUG 12#undef DEBUG
10 13
11#include <linux/kernel.h> 14#include <linux/kernel.h>
12#include <linux/mm.h> 15
13#include <linux/pci.h>
14#include <asm/io.h> 16#include <asm/io.h>
15#include <asm/machdep.h> 17#include <asm/machdep.h>
16#include <asm/pci-bridge.h> 18#include <asm/pgtable.h>
17#include <asm/ppc-pci.h> 19#include <asm/ppc-pci.h>
18 20
21#include "io-workarounds.h"
19 22
20#define SPIDER_PCI_REG_BASE 0xd000 23#define IOWA_MAX_BUS 8
21#define SPIDER_PCI_VCI_CNTL_STAT 0x0110
22#define SPIDER_PCI_DUMMY_READ 0x0810
23#define SPIDER_PCI_DUMMY_READ_BASE 0x0814
24 24
25/* Undefine that to re-enable bogus prefetch 25static struct iowa_bus iowa_busses[IOWA_MAX_BUS];
26 * 26static unsigned int iowa_bus_count;
27 * Without that workaround, the chip will do bogus prefetch past
28 * page boundary from system memory. This setting will disable that,
29 * though the documentation is unclear as to the consequences of doing
30 * so, either purely performances, or possible misbehaviour... It's not
31 * clear wether the chip can handle unaligned accesses at all without
32 * prefetching enabled.
33 *
34 * For now, things appear to be behaving properly with that prefetching
35 * disabled and IDE, possibly because IDE isn't doing any unaligned
36 * access.
37 */
38#define SPIDER_DISABLE_PREFETCH
39 27
40#define MAX_SPIDERS 3 28static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
29{
30 int i, j;
31 struct resource *res;
32 unsigned long vstart, vend;
41 33
42static struct spider_pci_bus { 34 for (i = 0; i < iowa_bus_count; i++) {
43 void __iomem *regs; 35 struct iowa_bus *bus = &iowa_busses[i];
44 unsigned long mmio_start; 36 struct pci_controller *phb = bus->phb;
45 unsigned long mmio_end;
46 unsigned long pio_vstart;
47 unsigned long pio_vend;
48} spider_pci_busses[MAX_SPIDERS];
49static int spider_pci_count;
50 37
51static struct spider_pci_bus *spider_pci_find(unsigned long vaddr, 38 if (vaddr) {
52 unsigned long paddr) 39 vstart = (unsigned long)phb->io_base_virt;
53{ 40 vend = vstart + phb->pci_io_size - 1;
54 int i; 41 if ((vaddr >= vstart) && (vaddr <= vend))
55 42 return bus;
56 for (i = 0; i < spider_pci_count; i++) { 43 }
57 struct spider_pci_bus *bus = &spider_pci_busses[i]; 44
58 if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end) 45 if (paddr)
59 return bus; 46 for (j = 0; j < 3; j++) {
60 if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend) 47 res = &phb->mem_resources[j];
61 return bus; 48 if (paddr >= res->start && paddr <= res->end)
49 return bus;
50 }
62 } 51 }
52
63 return NULL; 53 return NULL;
64} 54}
65 55
66static void spider_io_flush(const volatile void __iomem *addr) 56struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
67{ 57{
68 struct spider_pci_bus *bus; 58 struct iowa_bus *bus;
69 int token; 59 int token;
70 60
71 /* Get platform token (set by ioremap) from address */
72 token = PCI_GET_ADDR_TOKEN(addr); 61 token = PCI_GET_ADDR_TOKEN(addr);
73 62
74 /* Fast path if we have a non-0 token, it indicates which bus we 63 if (token && token <= iowa_bus_count)
75 * are on. 64 bus = &iowa_busses[token - 1];
76 *
77 * If the token is 0, that means either that the ioremap was done
78 * before we initialized this layer, or it's a PIO operation. We
79 * fallback to a low path in this case. Hopefully, internal devices
80 * which are ioremap'ed early should use in_XX/out_XX functions
81 * instead of the PCI ones and thus not suffer from the slowdown.
82 *
83 * Also note that currently, the workaround will not work for areas
84 * that are not mapped with PTEs (bolted in the hash table). This
85 * is the case for ioremaps done very early at boot (before
86 * mem_init_done) and includes the mapping of the ISA IO space.
87 *
88 * Fortunately, none of the affected devices is expected to do DMA
89 * and thus there should be no problem in practice.
90 *
91 * In order to improve performances, we only do the PTE search for
92 * addresses falling in the PHB IO space area. That means it will
93 * not work for hotplug'ed PHBs but those don't exist with Spider.
94 */
95 if (token && token <= spider_pci_count)
96 bus = &spider_pci_busses[token - 1];
97 else { 65 else {
98 unsigned long vaddr, paddr; 66 unsigned long vaddr, paddr;
99 pte_t *ptep; 67 pte_t *ptep;
100 68
101 /* Fixup physical address */
102 vaddr = (unsigned long)PCI_FIX_ADDR(addr); 69 vaddr = (unsigned long)PCI_FIX_ADDR(addr);
70 if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
71 return NULL;
103 72
104 /* Check if it's in allowed range for PIO */
105 if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
106 return;
107
108 /* Try to find a PTE. If not, clear the paddr, we'll do
109 * a vaddr only lookup (PIO only)
110 */
111 ptep = find_linux_pte(init_mm.pgd, vaddr); 73 ptep = find_linux_pte(init_mm.pgd, vaddr);
112 if (ptep == NULL) 74 if (ptep == NULL)
113 paddr = 0; 75 paddr = 0;
114 else 76 else
115 paddr = pte_pfn(*ptep) << PAGE_SHIFT; 77 paddr = pte_pfn(*ptep) << PAGE_SHIFT;
78 bus = iowa_pci_find(vaddr, paddr);
116 79
117 bus = spider_pci_find(vaddr, paddr);
118 if (bus == NULL) 80 if (bus == NULL)
119 return; 81 return NULL;
120 } 82 }
121 83
122 /* Now do the workaround 84 return bus;
123 */
124 (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ);
125} 85}
126 86
127static u8 spider_readb(const volatile void __iomem *addr) 87struct iowa_bus *iowa_pio_find_bus(unsigned long port)
128{ 88{
129 u8 val = __do_readb(addr); 89 unsigned long vaddr = (unsigned long)pci_io_base + port;
130 spider_io_flush(addr); 90 return iowa_pci_find(vaddr, 0);
131 return val;
132} 91}
133 92
134static u16 spider_readw(const volatile void __iomem *addr)
135{
136 u16 val = __do_readw(addr);
137 spider_io_flush(addr);
138 return val;
139}
140 93
141static u32 spider_readl(const volatile void __iomem *addr) 94#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
142{ 95static ret iowa_##name at \
143 u32 val = __do_readl(addr); 96{ \
144 spider_io_flush(addr); 97 struct iowa_bus *bus; \
145 return val; 98 bus = iowa_##space##_find_bus(aa); \
99 if (bus && bus->ops && bus->ops->name) \
100 return bus->ops->name al; \
101 return __do_##name al; \
146} 102}
147 103
148static u64 spider_readq(const volatile void __iomem *addr) 104#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
149{ 105static void iowa_##name at \
150 u64 val = __do_readq(addr); 106{ \
151 spider_io_flush(addr); 107 struct iowa_bus *bus; \
152 return val; 108 bus = iowa_##space##_find_bus(aa); \
109 if (bus && bus->ops && bus->ops->name) { \
110 bus->ops->name al; \
111 return; \
112 } \
113 __do_##name al; \
153} 114}
154 115
155static u16 spider_readw_be(const volatile void __iomem *addr) 116#include <asm/io-defs.h>
156{
157 u16 val = __do_readw_be(addr);
158 spider_io_flush(addr);
159 return val;
160}
161 117
162static u32 spider_readl_be(const volatile void __iomem *addr) 118#undef DEF_PCI_AC_RET
163{ 119#undef DEF_PCI_AC_NORET
164 u32 val = __do_readl_be(addr);
165 spider_io_flush(addr);
166 return val;
167}
168 120
169static u64 spider_readq_be(const volatile void __iomem *addr) 121static struct ppc_pci_io __initdata iowa_pci_io = {
170{
171 u64 val = __do_readq_be(addr);
172 spider_io_flush(addr);
173 return val;
174}
175 122
176static void spider_readsb(const volatile void __iomem *addr, void *buf, 123#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name,
177 unsigned long count) 124#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name,
178{
179 __do_readsb(addr, buf, count);
180 spider_io_flush(addr);
181}
182 125
183static void spider_readsw(const volatile void __iomem *addr, void *buf, 126#include <asm/io-defs.h>
184 unsigned long count)
185{
186 __do_readsw(addr, buf, count);
187 spider_io_flush(addr);
188}
189 127
190static void spider_readsl(const volatile void __iomem *addr, void *buf, 128#undef DEF_PCI_AC_RET
191 unsigned long count) 129#undef DEF_PCI_AC_NORET
192{
193 __do_readsl(addr, buf, count);
194 spider_io_flush(addr);
195}
196
197static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src,
198 unsigned long n)
199{
200 __do_memcpy_fromio(dest, src, n);
201 spider_io_flush(src);
202}
203 130
131};
204 132
205static void __iomem * spider_ioremap(unsigned long addr, unsigned long size, 133static void __iomem *iowa_ioremap(unsigned long addr, unsigned long size,
206 unsigned long flags) 134 unsigned long flags)
207{ 135{
208 struct spider_pci_bus *bus; 136 struct iowa_bus *bus;
209 void __iomem *res = __ioremap(addr, size, flags); 137 void __iomem *res = __ioremap(addr, size, flags);
210 int busno; 138 int busno;
211 139
212 pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n", 140 bus = iowa_pci_find(0, addr);
213 addr, size, flags, res);
214
215 bus = spider_pci_find(0, addr);
216 if (bus != NULL) { 141 if (bus != NULL) {
217 busno = bus - spider_pci_busses; 142 busno = bus - iowa_busses;
218 pr_debug(" found bus %d, setting token\n", busno);
219 PCI_SET_ADDR_TOKEN(res, busno + 1); 143 PCI_SET_ADDR_TOKEN(res, busno + 1);
220 } 144 }
221 pr_debug(" result=0x%p\n", res);
222
223 return res; 145 return res;
224} 146}
225 147
226static void __init spider_pci_setup_chip(struct spider_pci_bus *bus) 148/* Regist new bus to support workaround */
227{ 149void __init iowa_register_bus(struct pci_controller *phb,
228#ifdef SPIDER_DISABLE_PREFETCH 150 struct ppc_pci_io *ops,
229 u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT); 151 int (*initfunc)(struct iowa_bus *, void *), void *data)
230 pr_debug(" PVCI_Control_Status was 0x%08x\n", val);
231 out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
232#endif
233
234 /* Configure the dummy address for the workaround */
235 out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000);
236}
237
238static void __init spider_pci_add_one(struct pci_controller *phb)
239{ 152{
240 struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count]; 153 struct iowa_bus *bus;
241 struct device_node *np = phb->dn; 154 struct device_node *np = phb->dn;
242 struct resource rsrc;
243 void __iomem *regs;
244 155
245 if (spider_pci_count >= MAX_SPIDERS) { 156 if (iowa_bus_count >= IOWA_MAX_BUS) {
246 printk(KERN_ERR "Too many spider bridges, workarounds" 157 pr_err("IOWA:Too many pci bridges, "
247 " disabled for %s\n", np->full_name); 158 "workarounds disabled for %s\n", np->full_name);
248 return; 159 return;
249 } 160 }
250 161
251 /* Get the registers for the beast */ 162 bus = &iowa_busses[iowa_bus_count];
252 if (of_address_to_resource(np, 0, &rsrc)) { 163 bus->phb = phb;
253 printk(KERN_ERR "Failed to get registers for spider %s" 164 bus->ops = ops;
254 " workarounds disabled\n", np->full_name);
255 return;
256 }
257 165
258 /* Mask out some useless bits in there to get to the base of the 166 if (initfunc)
259 * spider chip 167 if ((*initfunc)(bus, data))
260 */ 168 return;
261 rsrc.start &= ~0xfffffffful;
262
263 /* Map them */
264 regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000);
265 if (regs == NULL) {
266 printk(KERN_ERR "Failed to map registers for spider %s"
267 " workarounds disabled\n", np->full_name);
268 return;
269 }
270
271 spider_pci_count++;
272
273 /* We assume spiders only have one MMIO resource */
274 bus->mmio_start = phb->mem_resources[0].start;
275 bus->mmio_end = phb->mem_resources[0].end + 1;
276
277 bus->pio_vstart = (unsigned long)phb->io_base_virt;
278 bus->pio_vend = bus->pio_vstart + phb->pci_io_size;
279
280 bus->regs = regs;
281
282 printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name);
283 169
284 pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n", 170 iowa_bus_count++;
285 bus->mmio_start, bus->mmio_end);
286 pr_debug(" pio (V) = 0x%016lx..0x%016lx\n",
287 bus->pio_vstart, bus->pio_vend);
288 pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n",
289 rsrc.start + SPIDER_PCI_REG_BASE, bus->regs);
290 171
291 spider_pci_setup_chip(bus); 172 pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name);
292} 173}
293 174
294static struct ppc_pci_io __initdata spider_pci_io = { 175/* enable IO workaround */
295 .readb = spider_readb, 176void __init io_workaround_init(void)
296 .readw = spider_readw,
297 .readl = spider_readl,
298 .readq = spider_readq,
299 .readw_be = spider_readw_be,
300 .readl_be = spider_readl_be,
301 .readq_be = spider_readq_be,
302 .readsb = spider_readsb,
303 .readsw = spider_readsw,
304 .readsl = spider_readsl,
305 .memcpy_fromio = spider_memcpy_fromio,
306};
307
308static int __init spider_pci_workaround_init(void)
309{ 177{
310 struct pci_controller *phb; 178 static int io_workaround_inited;
311
312 /* Find spider bridges. We assume they have been all probed
313 * in setup_arch(). If that was to change, we would need to
314 * update this code to cope with dynamically added busses
315 */
316 list_for_each_entry(phb, &hose_list, list_node) {
317 struct device_node *np = phb->dn;
318 const char *model = of_get_property(np, "model", NULL);
319
320 /* If no model property or name isn't exactly "pci", skip */
321 if (model == NULL || strcmp(np->name, "pci"))
322 continue;
323 /* If model is not "Spider", skip */
324 if (strcmp(model, "Spider"))
325 continue;
326 spider_pci_add_one(phb);
327 }
328
329 /* No Spider PCI found, exit */
330 if (spider_pci_count == 0)
331 return 0;
332 179
333 /* Setup IO callbacks. We only setup MMIO reads. PIO reads will 180 if (io_workaround_inited)
334 * fallback to MMIO reads (though without a token, thus slower) 181 return;
335 */ 182 ppc_pci_io = iowa_pci_io;
336 ppc_pci_io = spider_pci_io; 183 ppc_md.ioremap = iowa_ioremap;
337 184 io_workaround_inited = 1;
338 /* Setup ioremap callback */
339 ppc_md.ioremap = spider_ioremap;
340
341 return 0;
342} 185}
343machine_arch_initcall(cell, spider_pci_workaround_init);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h
new file mode 100644
index 000000000000..79d8ed3d510f
--- /dev/null
+++ b/arch/powerpc/platforms/cell/io-workarounds.h
@@ -0,0 +1,49 @@
1/*
2 * Support PCI IO workaround
3 *
4 * (C) Copyright 2007-2008 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef _IO_WORKAROUNDS_H
22#define _IO_WORKAROUNDS_H
23
24#include <linux/io.h>
25#include <asm/pci-bridge.h>
26
27/* Bus info */
28struct iowa_bus {
29 struct pci_controller *phb;
30 struct ppc_pci_io *ops;
31 void *private;
32};
33
34void __init io_workaround_init(void);
35void __init iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
36 int (*)(struct iowa_bus *, void *), void *);
37struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR);
38struct iowa_bus *iowa_pio_find_bus(unsigned long);
39
40extern struct ppc_pci_io spiderpci_ops;
41extern int spiderpci_iowa_init(struct iowa_bus *, void *);
42
43#define SPIDER_PCI_REG_BASE 0xd000
44#define SPIDER_PCI_REG_SIZE 0x1000
45#define SPIDER_PCI_VCI_CNTL_STAT 0x0110
46#define SPIDER_PCI_DUMMY_READ 0x0810
47#define SPIDER_PCI_DUMMY_READ_BASE 0x0814
48
49#endif /* _IO_WORKAROUNDS_H */
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 5c531e8f9f6f..ab721b50fbba 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -57,6 +57,7 @@
57#include "interrupt.h" 57#include "interrupt.h"
58#include "pervasive.h" 58#include "pervasive.h"
59#include "ras.h" 59#include "ras.h"
60#include "io-workarounds.h"
60 61
61#ifdef DEBUG 62#ifdef DEBUG
62#define DBG(fmt...) udbg_printf(fmt) 63#define DBG(fmt...) udbg_printf(fmt)
@@ -117,13 +118,50 @@ static void cell_fixup_pcie_rootcomplex(struct pci_dev *dev)
117} 118}
118DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex); 119DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex);
119 120
121static int __devinit cell_setup_phb(struct pci_controller *phb)
122{
123 const char *model;
124 struct device_node *np;
125
126 int rc = rtas_setup_phb(phb);
127 if (rc)
128 return rc;
129
130 np = phb->dn;
131 model = of_get_property(np, "model", NULL);
132 if (model == NULL || strcmp(np->name, "pci"))
133 return 0;
134
135 /* Setup workarounds for spider */
136 if (strcmp(model, "Spider"))
137 return 0;
138
139 iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init,
140 (void *)SPIDER_PCI_REG_BASE);
141 io_workaround_init();
142
143 return 0;
144}
145
120static int __init cell_publish_devices(void) 146static int __init cell_publish_devices(void)
121{ 147{
148 struct device_node *root = of_find_node_by_path("/");
149 struct device_node *np;
122 int node; 150 int node;
123 151
124 /* Publish OF platform devices for southbridge IOs */ 152 /* Publish OF platform devices for southbridge IOs */
125 of_platform_bus_probe(NULL, NULL, NULL); 153 of_platform_bus_probe(NULL, NULL, NULL);
126 154
155 /* On spider based blades, we need to manually create the OF
156 * platform devices for the PCI host bridges
157 */
158 for_each_child_of_node(root, np) {
159 if (np->type == NULL || (strcmp(np->type, "pci") != 0 &&
160 strcmp(np->type, "pciex") != 0))
161 continue;
162 of_platform_device_create(np, NULL, NULL);
163 }
164
127 /* There is no device for the MIC memory controller, thus we create 165 /* There is no device for the MIC memory controller, thus we create
128 * a platform device for it to attach the EDAC driver to. 166 * a platform device for it to attach the EDAC driver to.
129 */ 167 */
@@ -132,6 +170,7 @@ static int __init cell_publish_devices(void)
132 continue; 170 continue;
133 platform_device_register_simple("cbe-mic", node, NULL, 0); 171 platform_device_register_simple("cbe-mic", node, NULL, 0);
134 } 172 }
173
135 return 0; 174 return 0;
136} 175}
137machine_subsys_initcall(cell, cell_publish_devices); 176machine_subsys_initcall(cell, cell_publish_devices);
@@ -213,7 +252,7 @@ static void __init cell_setup_arch(void)
213 252
214 /* Find and initialize PCI host bridges */ 253 /* Find and initialize PCI host bridges */
215 init_pci_config_tokens(); 254 init_pci_config_tokens();
216 find_and_init_phbs(); 255
217 cbe_pervasive_init(); 256 cbe_pervasive_init();
218#ifdef CONFIG_DUMMY_CONSOLE 257#ifdef CONFIG_DUMMY_CONSOLE
219 conswitchp = &dummy_con; 258 conswitchp = &dummy_con;
@@ -249,7 +288,7 @@ define_machine(cell) {
249 .calibrate_decr = generic_calibrate_decr, 288 .calibrate_decr = generic_calibrate_decr,
250 .progress = cell_progress, 289 .progress = cell_progress,
251 .init_IRQ = cell_init_irq, 290 .init_IRQ = cell_init_irq,
252 .pci_setup_phb = rtas_setup_phb, 291 .pci_setup_phb = cell_setup_phb,
253#ifdef CONFIG_KEXEC 292#ifdef CONFIG_KEXEC
254 .machine_kexec = default_machine_kexec, 293 .machine_kexec = default_machine_kexec,
255 .machine_kexec_prepare = default_machine_kexec_prepare, 294 .machine_kexec_prepare = default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c
new file mode 100644
index 000000000000..418b605ac35a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spider-pci.c
@@ -0,0 +1,184 @@
1/*
2 * IO workarounds for PCI on Celleb/Cell platform
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#undef DEBUG
22
23#include <linux/kernel.h>
24#include <linux/of_platform.h>
25#include <linux/io.h>
26
27#include <asm/ppc-pci.h>
28#include <asm/pci-bridge.h>
29
30#include "io-workarounds.h"
31
32#define SPIDER_PCI_DISABLE_PREFETCH
33
34struct spiderpci_iowa_private {
35 void __iomem *regs;
36};
37
38static void spiderpci_io_flush(struct iowa_bus *bus)
39{
40 struct spiderpci_iowa_private *priv;
41 u32 val;
42
43 priv = bus->private;
44 val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ);
45 iosync();
46}
47
48#define SPIDER_PCI_MMIO_READ(name, ret) \
49static ret spiderpci_##name(const PCI_IO_ADDR addr) \
50{ \
51 ret val = __do_##name(addr); \
52 spiderpci_io_flush(iowa_mem_find_bus(addr)); \
53 return val; \
54}
55
56#define SPIDER_PCI_MMIO_READ_STR(name) \
57static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \
58 unsigned long count) \
59{ \
60 __do_##name(addr, buf, count); \
61 spiderpci_io_flush(iowa_mem_find_bus(addr)); \
62}
63
64SPIDER_PCI_MMIO_READ(readb, u8)
65SPIDER_PCI_MMIO_READ(readw, u16)
66SPIDER_PCI_MMIO_READ(readl, u32)
67SPIDER_PCI_MMIO_READ(readq, u64)
68SPIDER_PCI_MMIO_READ(readw_be, u16)
69SPIDER_PCI_MMIO_READ(readl_be, u32)
70SPIDER_PCI_MMIO_READ(readq_be, u64)
71SPIDER_PCI_MMIO_READ_STR(readsb)
72SPIDER_PCI_MMIO_READ_STR(readsw)
73SPIDER_PCI_MMIO_READ_STR(readsl)
74
75static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src,
76 unsigned long n)
77{
78 __do_memcpy_fromio(dest, src, n);
79 spiderpci_io_flush(iowa_mem_find_bus(src));
80}
81
82static int __init spiderpci_pci_setup_chip(struct pci_controller *phb,
83 void __iomem *regs)
84{
85 void *dummy_page_va;
86 dma_addr_t dummy_page_da;
87
88#ifdef SPIDER_PCI_DISABLE_PREFETCH
89 u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT);
90 pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val);
91 out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
92#endif /* SPIDER_PCI_DISABLE_PREFETCH */
93
94 /* setup dummy read */
95 /*
96 * On CellBlade, we can't know that which XDR memory is used by
97 * kmalloc() to allocate dummy_page_va.
98 * In order to imporve the performance, the XDR which is used to
99 * allocate dummy_page_va is the nearest the spider-pci.
100 * We have to select the CBE which is the nearest the spider-pci
101 * to allocate memory from the best XDR, but I don't know that
102 * how to do.
103 *
104 * Celleb does not have this problem, because it has only one XDR.
105 */
106 dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
107 if (!dummy_page_va) {
108 pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n");
109 return -1;
110 }
111
112 dummy_page_da = dma_map_single(phb->parent, dummy_page_va,
113 PAGE_SIZE, DMA_FROM_DEVICE);
114 if (dma_mapping_error(dummy_page_da)) {
115 pr_err("SPIDER-IOWA:Map dummy page filed.\n");
116 kfree(dummy_page_va);
117 return -1;
118 }
119
120 out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da);
121
122 return 0;
123}
124
125int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data)
126{
127 void __iomem *regs = NULL;
128 struct spiderpci_iowa_private *priv;
129 struct device_node *np = bus->phb->dn;
130 struct resource r;
131 unsigned long offset = (unsigned long)data;
132
133 pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n",
134 np->full_name);
135
136 priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL);
137 if (!priv) {
138 pr_err("SPIDERPCI-IOWA:"
139 "Can't allocate struct spiderpci_iowa_private");
140 return -1;
141 }
142
143 if (of_address_to_resource(np, 0, &r)) {
144 pr_err("SPIDERPCI-IOWA:Can't get resource.\n");
145 goto error;
146 }
147
148 regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE);
149 if (!regs) {
150 pr_err("SPIDERPCI-IOWA:ioremap failed.\n");
151 goto error;
152 }
153 priv->regs = regs;
154 bus->private = priv;
155
156 if (spiderpci_pci_setup_chip(bus->phb, regs))
157 goto error;
158
159 return 0;
160
161error:
162 kfree(priv);
163 bus->private = NULL;
164
165 if (regs)
166 iounmap(regs);
167
168 return -1;
169}
170
171struct ppc_pci_io spiderpci_ops = {
172 .readb = spiderpci_readb,
173 .readw = spiderpci_readw,
174 .readl = spiderpci_readl,
175 .readq = spiderpci_readq,
176 .readw_be = spiderpci_readw_be,
177 .readl_be = spiderpci_readl_be,
178 .readq_be = spiderpci_readq_be,
179 .readsb = spiderpci_readsb,
180 .readsw = spiderpci_readsw,
181 .readsl = spiderpci_readsl,
182 .memcpy_fromio = spiderpci_memcpy_fromio,
183};
184
diff --git a/include/asm-powerpc/io-defs.h b/include/asm-powerpc/io-defs.h
index 03691ab69217..44d7927aec69 100644
--- a/include/asm-powerpc/io-defs.h
+++ b/include/asm-powerpc/io-defs.h
@@ -1,59 +1,60 @@
1/* This file is meant to be include multiple times by other headers */ 1/* This file is meant to be include multiple times by other headers */
2/* last 2 argments are used by platforms/cell/io-workarounds.[ch] */
2 3
3DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr)) 4DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr), mem, addr)
4DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr)) 5DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr), mem, addr)
5DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr)) 6DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr), mem, addr)
6DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr)) 7DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr), mem, addr)
7DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr)) 8DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr), mem, addr)
8DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr)) 9DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
9DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr)) 10DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
10DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr)) 11DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
11DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr)) 12DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
12DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr)) 13DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
13 14
14#ifdef __powerpc64__ 15#ifdef __powerpc64__
15DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr)) 16DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr), mem, addr)
16DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr)) 17DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr), mem, addr)
17DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr)) 18DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
18DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr)) 19DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
19#endif /* __powerpc64__ */ 20#endif /* __powerpc64__ */
20 21
21DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port)) 22DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port), pio, port)
22DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port)) 23DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port), pio, port)
23DEF_PCI_AC_RET(inl, u32, (unsigned long port), (port)) 24DEF_PCI_AC_RET(inl, u32, (unsigned long port), (port), pio, port)
24DEF_PCI_AC_NORET(outb, (u8 val, unsigned long port), (val, port)) 25DEF_PCI_AC_NORET(outb, (u8 val, unsigned long port), (val, port), pio, port)
25DEF_PCI_AC_NORET(outw, (u16 val, unsigned long port), (val, port)) 26DEF_PCI_AC_NORET(outw, (u16 val, unsigned long port), (val, port), pio, port)
26DEF_PCI_AC_NORET(outl, (u32 val, unsigned long port), (val, port)) 27DEF_PCI_AC_NORET(outl, (u32 val, unsigned long port), (val, port), pio, port)
27 28
28DEF_PCI_AC_NORET(readsb, (const PCI_IO_ADDR a, void *b, unsigned long c), \ 29DEF_PCI_AC_NORET(readsb, (const PCI_IO_ADDR a, void *b, unsigned long c),
29 (a, b, c)) 30 (a, b, c), mem, a)
30DEF_PCI_AC_NORET(readsw, (const PCI_IO_ADDR a, void *b, unsigned long c), \ 31DEF_PCI_AC_NORET(readsw, (const PCI_IO_ADDR a, void *b, unsigned long c),
31 (a, b, c)) 32 (a, b, c), mem, a)
32DEF_PCI_AC_NORET(readsl, (const PCI_IO_ADDR a, void *b, unsigned long c), \ 33DEF_PCI_AC_NORET(readsl, (const PCI_IO_ADDR a, void *b, unsigned long c),
33 (a, b, c)) 34 (a, b, c), mem, a)
34DEF_PCI_AC_NORET(writesb, (PCI_IO_ADDR a, const void *b, unsigned long c), \ 35DEF_PCI_AC_NORET(writesb, (PCI_IO_ADDR a, const void *b, unsigned long c),
35 (a, b, c)) 36 (a, b, c), mem, a)
36DEF_PCI_AC_NORET(writesw, (PCI_IO_ADDR a, const void *b, unsigned long c), \ 37DEF_PCI_AC_NORET(writesw, (PCI_IO_ADDR a, const void *b, unsigned long c),
37 (a, b, c)) 38 (a, b, c), mem, a)
38DEF_PCI_AC_NORET(writesl, (PCI_IO_ADDR a, const void *b, unsigned long c), \ 39DEF_PCI_AC_NORET(writesl, (PCI_IO_ADDR a, const void *b, unsigned long c),
39 (a, b, c)) 40 (a, b, c), mem, a)
40 41
41DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c), \ 42DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c),
42 (p, b, c)) 43 (p, b, c), pio, p)
43DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c), \ 44DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c),
44 (p, b, c)) 45 (p, b, c), pio, p)
45DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c), \ 46DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c),
46 (p, b, c)) 47 (p, b, c), pio, p)
47DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c), \ 48DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c),
48 (p, b, c)) 49 (p, b, c), pio, p)
49DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c), \ 50DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c),
50 (p, b, c)) 51 (p, b, c), pio, p)
51DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c), \ 52DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c),
52 (p, b, c)) 53 (p, b, c), pio, p)
53 54
54DEF_PCI_AC_NORET(memset_io, (PCI_IO_ADDR a, int c, unsigned long n), \ 55DEF_PCI_AC_NORET(memset_io, (PCI_IO_ADDR a, int c, unsigned long n),
55 (a, c, n)) 56 (a, c, n), mem, a)
56DEF_PCI_AC_NORET(memcpy_fromio,(void *d,const PCI_IO_ADDR s,unsigned long n), \ 57DEF_PCI_AC_NORET(memcpy_fromio, (void *d, const PCI_IO_ADDR s, unsigned long n),
57 (d, s, n)) 58 (d, s, n), mem, s)
58DEF_PCI_AC_NORET(memcpy_toio,(PCI_IO_ADDR d,const void *s,unsigned long n), \ 59DEF_PCI_AC_NORET(memcpy_toio, (PCI_IO_ADDR d, const void *s, unsigned long n),
59 (d, s, n)) 60 (d, s, n), mem, d)
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 7be26f615755..afae0697e8ce 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -458,8 +458,8 @@ __do_out_asm(_rec_outl, "stwbrx")
458/* Structure containing all the hooks */ 458/* Structure containing all the hooks */
459extern struct ppc_pci_io { 459extern struct ppc_pci_io {
460 460
461#define DEF_PCI_AC_RET(name, ret, at, al) ret (*name) at; 461#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) ret (*name) at;
462#define DEF_PCI_AC_NORET(name, at, al) void (*name) at; 462#define DEF_PCI_AC_NORET(name, at, al, space, aa) void (*name) at;
463 463
464#include <asm/io-defs.h> 464#include <asm/io-defs.h>
465 465
@@ -469,7 +469,7 @@ extern struct ppc_pci_io {
469} ppc_pci_io; 469} ppc_pci_io;
470 470
471/* The inline wrappers */ 471/* The inline wrappers */
472#define DEF_PCI_AC_RET(name, ret, at, al) \ 472#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
473static inline ret name at \ 473static inline ret name at \
474{ \ 474{ \
475 if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ 475 if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \
@@ -477,7 +477,7 @@ static inline ret name at \
477 return __do_##name al; \ 477 return __do_##name al; \
478} 478}
479 479
480#define DEF_PCI_AC_NORET(name, at, al) \ 480#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
481static inline void name at \ 481static inline void name at \
482{ \ 482{ \
483 if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ 483 if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \