aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/Makefile6
-rw-r--r--arch/powerpc/platforms/celleb/Makefile3
-rw-r--r--arch/powerpc/platforms/celleb/io-workarounds.c280
-rw-r--r--arch/powerpc/platforms/celleb/pci.c41
-rw-r--r--arch/powerpc/platforms/celleb/pci.h18
-rw-r--r--arch/powerpc/platforms/celleb/scc_epci.c59
-rw-r--r--arch/powerpc/platforms/celleb/setup.c2
7 files changed, 52 insertions, 357 deletions
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 20966b709604..81c26f32453e 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -27,3 +27,9 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
27 spufs/ 27 spufs/
28 28
29obj-$(CONFIG_PCI_MSI) += axon_msi.o 29obj-$(CONFIG_PCI_MSI) += axon_msi.o
30
31
32# celleb stuff
33ifeq ($(CONFIG_PPC_CELLEB),y)
34obj-y += io-workarounds.o spider-pci.o
35endif
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile
index 889d43f715ea..6d51a3c00713 100644
--- a/arch/powerpc/platforms/celleb/Makefile
+++ b/arch/powerpc/platforms/celleb/Makefile
@@ -1,7 +1,6 @@
1obj-y += interrupt.o iommu.o setup.o \ 1obj-y += interrupt.o iommu.o setup.o \
2 htab.o beat.o hvCall.o pci.o \ 2 htab.o beat.o hvCall.o pci.o \
3 scc_epci.o scc_uhc.o \ 3 scc_epci.o scc_uhc.o
4 io-workarounds.o
5 4
6obj-$(CONFIG_SMP) += smp.o 5obj-$(CONFIG_SMP) += smp.o
7obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o 6obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o
diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c
deleted file mode 100644
index 423339be1bac..000000000000
--- a/arch/powerpc/platforms/celleb/io-workarounds.c
+++ /dev/null
@@ -1,280 +0,0 @@
1/*
2 * Support for Celleb io workarounds
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This file is based to arch/powerpc/platform/cell/io-workarounds.c
7 *
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 along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#undef DEBUG
24
25#include <linux/of.h>
26#include <linux/of_device.h>
27#include <linux/irq.h>
28
29#include <asm/io.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
32#include <asm/pci-bridge.h>
33#include <asm/ppc-pci.h>
34
35#include "pci.h"
36
37#define MAX_CELLEB_PCI_BUS 4
38
39void *celleb_dummy_page_va;
40
41static struct celleb_pci_bus {
42 struct pci_controller *phb;
43 void (*dummy_read)(struct pci_controller *);
44} celleb_pci_busses[MAX_CELLEB_PCI_BUS];
45
46static int celleb_pci_count = 0;
47
48static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr,
49 unsigned long paddr)
50{
51 int i, j;
52 struct resource *res;
53
54 for (i = 0; i < celleb_pci_count; i++) {
55 struct celleb_pci_bus *bus = &celleb_pci_busses[i];
56 struct pci_controller *phb = bus->phb;
57 if (paddr)
58 for (j = 0; j < 3; j++) {
59 res = &phb->mem_resources[j];
60 if (paddr >= res->start && paddr <= res->end)
61 return bus;
62 }
63 res = &phb->io_resource;
64 if (vaddr && vaddr >= res->start && vaddr <= res->end)
65 return bus;
66 }
67 return NULL;
68}
69
70static void celleb_io_flush(const PCI_IO_ADDR addr)
71{
72 struct celleb_pci_bus *bus;
73 int token;
74
75 token = PCI_GET_ADDR_TOKEN(addr);
76
77 if (token && token <= celleb_pci_count)
78 bus = &celleb_pci_busses[token - 1];
79 else {
80 unsigned long vaddr, paddr;
81 pte_t *ptep;
82
83 vaddr = (unsigned long)PCI_FIX_ADDR(addr);
84 if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
85 return;
86
87 ptep = find_linux_pte(init_mm.pgd, vaddr);
88 if (ptep == NULL)
89 paddr = 0;
90 else
91 paddr = pte_pfn(*ptep) << PAGE_SHIFT;
92 bus = celleb_pci_find(vaddr, paddr);
93
94 if (bus == NULL)
95 return;
96 }
97
98 if (bus->dummy_read)
99 bus->dummy_read(bus->phb);
100}
101
102static u8 celleb_readb(const PCI_IO_ADDR addr)
103{
104 u8 val;
105 val = __do_readb(addr);
106 celleb_io_flush(addr);
107 return val;
108}
109
110static u16 celleb_readw(const PCI_IO_ADDR addr)
111{
112 u16 val;
113 val = __do_readw(addr);
114 celleb_io_flush(addr);
115 return val;
116}
117
118static u32 celleb_readl(const PCI_IO_ADDR addr)
119{
120 u32 val;
121 val = __do_readl(addr);
122 celleb_io_flush(addr);
123 return val;
124}
125
126static u64 celleb_readq(const PCI_IO_ADDR addr)
127{
128 u64 val;
129 val = __do_readq(addr);
130 celleb_io_flush(addr);
131 return val;
132}
133
134static u16 celleb_readw_be(const PCI_IO_ADDR addr)
135{
136 u16 val;
137 val = __do_readw_be(addr);
138 celleb_io_flush(addr);
139 return val;
140}
141
142static u32 celleb_readl_be(const PCI_IO_ADDR addr)
143{
144 u32 val;
145 val = __do_readl_be(addr);
146 celleb_io_flush(addr);
147 return val;
148}
149
150static u64 celleb_readq_be(const PCI_IO_ADDR addr)
151{
152 u64 val;
153 val = __do_readq_be(addr);
154 celleb_io_flush(addr);
155 return val;
156}
157
158static void celleb_readsb(const PCI_IO_ADDR addr,
159 void *buf, unsigned long count)
160{
161 __do_readsb(addr, buf, count);
162 celleb_io_flush(addr);
163}
164
165static void celleb_readsw(const PCI_IO_ADDR addr,
166 void *buf, unsigned long count)
167{
168 __do_readsw(addr, buf, count);
169 celleb_io_flush(addr);
170}
171
172static void celleb_readsl(const PCI_IO_ADDR addr,
173 void *buf, unsigned long count)
174{
175 __do_readsl(addr, buf, count);
176 celleb_io_flush(addr);
177}
178
179static void celleb_memcpy_fromio(void *dest,
180 const PCI_IO_ADDR src,
181 unsigned long n)
182{
183 __do_memcpy_fromio(dest, src, n);
184 celleb_io_flush(src);
185}
186
187static void __iomem *celleb_ioremap(unsigned long addr,
188 unsigned long size,
189 unsigned long flags)
190{
191 struct celleb_pci_bus *bus;
192 void __iomem *res = __ioremap(addr, size, flags);
193 int busno;
194
195 bus = celleb_pci_find(0, addr);
196 if (bus != NULL) {
197 busno = bus - celleb_pci_busses;
198 PCI_SET_ADDR_TOKEN(res, busno + 1);
199 }
200 return res;
201}
202
203static void celleb_iounmap(volatile void __iomem *addr)
204{
205 return __iounmap(PCI_FIX_ADDR(addr));
206}
207
208static struct ppc_pci_io celleb_pci_io __initdata = {
209 .readb = celleb_readb,
210 .readw = celleb_readw,
211 .readl = celleb_readl,
212 .readq = celleb_readq,
213 .readw_be = celleb_readw_be,
214 .readl_be = celleb_readl_be,
215 .readq_be = celleb_readq_be,
216 .readsb = celleb_readsb,
217 .readsw = celleb_readsw,
218 .readsl = celleb_readsl,
219 .memcpy_fromio = celleb_memcpy_fromio,
220};
221
222void __init celleb_pci_add_one(struct pci_controller *phb,
223 void (*dummy_read)(struct pci_controller *))
224{
225 struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count];
226 struct device_node *np = phb->dn;
227
228 if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) {
229 printk(KERN_ERR "Too many pci bridges, workarounds"
230 " disabled for %s\n", np->full_name);
231 return;
232 }
233
234 celleb_pci_count++;
235
236 bus->phb = phb;
237 bus->dummy_read = dummy_read;
238}
239
240static struct of_device_id celleb_pci_workaround_match[] __initdata = {
241 {
242 .name = "pci-pseudo",
243 .data = fake_pci_workaround_init,
244 }, {
245 .name = "epci",
246 .data = epci_workaround_init,
247 }, {
248 },
249};
250
251int __init celleb_pci_workaround_init(void)
252{
253 struct pci_controller *phb;
254 struct device_node *node;
255 const struct of_device_id *match;
256 void (*init_func)(struct pci_controller *);
257
258 celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
259 if (!celleb_dummy_page_va) {
260 printk(KERN_ERR "Celleb: dummy read disabled. "
261 "Alloc celleb_dummy_page_va failed\n");
262 return 1;
263 }
264
265 list_for_each_entry(phb, &hose_list, list_node) {
266 node = phb->dn;
267 match = of_match_node(celleb_pci_workaround_match, node);
268
269 if (match) {
270 init_func = match->data;
271 (*init_func)(phb);
272 }
273 }
274
275 ppc_pci_io = celleb_pci_io;
276 ppc_md.ioremap = celleb_ioremap;
277 ppc_md.iounmap = celleb_iounmap;
278
279 return 0;
280}
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index 51b390d34e4d..539d2cc59542 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -41,6 +41,7 @@
41#include <asm/pci-bridge.h> 41#include <asm/pci-bridge.h>
42#include <asm/ppc-pci.h> 42#include <asm/ppc-pci.h>
43 43
44#include "../cell/io-workarounds.h"
44#include "pci.h" 45#include "pci.h"
45#include "interrupt.h" 46#include "interrupt.h"
46 47
@@ -457,33 +458,39 @@ static int __init celleb_setup_fake_pci(struct device_node *dev,
457 return 0; 458 return 0;
458} 459}
459 460
460void __init fake_pci_workaround_init(struct pci_controller *phb) 461static struct celleb_phb_spec celleb_fake_pci_spec __initdata = {
461{ 462 .setup = celleb_setup_fake_pci,
462 /** 463};
463 * We will add fake pci bus to scc_pci_bus for the purpose to improve
464 * I/O Macro performance. But device-tree and device drivers
465 * are not ready to use address with a token.
466 */
467
468 /* celleb_pci_add_one(phb, NULL); */
469}
470 464
471static struct of_device_id celleb_phb_match[] __initdata = { 465static struct of_device_id celleb_phb_match[] __initdata = {
472 { 466 {
473 .name = "pci-pseudo", 467 .name = "pci-pseudo",
474 .data = celleb_setup_fake_pci, 468 .data = &celleb_fake_pci_spec,
475 }, { 469 }, {
476 .name = "epci", 470 .name = "epci",
477 .data = celleb_setup_epci, 471 .data = &celleb_epci_spec,
478 }, { 472 }, {
479 }, 473 },
480}; 474};
481 475
476static int __init celleb_io_workaround_init(struct pci_controller *phb,
477 struct celleb_phb_spec *phb_spec)
478{
479 if (phb_spec->ops) {
480 iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init,
481 phb_spec->iowa_data);
482 io_workaround_init();
483 }
484
485 return 0;
486}
487
482int __init celleb_setup_phb(struct pci_controller *phb) 488int __init celleb_setup_phb(struct pci_controller *phb)
483{ 489{
484 struct device_node *dev = phb->dn; 490 struct device_node *dev = phb->dn;
485 const struct of_device_id *match; 491 const struct of_device_id *match;
486 int (*setup_func)(struct device_node *, struct pci_controller *); 492 struct celleb_phb_spec *phb_spec;
493 int rc;
487 494
488 match = of_match_node(celleb_phb_match, dev); 495 match = of_match_node(celleb_phb_match, dev);
489 if (!match) 496 if (!match)
@@ -492,8 +499,12 @@ int __init celleb_setup_phb(struct pci_controller *phb)
492 phb_set_bus_ranges(dev, phb); 499 phb_set_bus_ranges(dev, phb);
493 phb->buid = 1; 500 phb->buid = 1;
494 501
495 setup_func = match->data; 502 phb_spec = match->data;
496 return (*setup_func)(dev, phb); 503 rc = (*phb_spec->setup)(dev, phb);
504 if (rc)
505 return 1;
506
507 return celleb_io_workaround_init(phb, phb_spec);
497} 508}
498 509
499int celleb_pci_probe_mode(struct pci_bus *bus) 510int celleb_pci_probe_mode(struct pci_bus *bus)
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h
index 5d5544ffeddb..cabb3a108c31 100644
--- a/arch/powerpc/platforms/celleb/pci.h
+++ b/arch/powerpc/platforms/celleb/pci.h
@@ -27,16 +27,18 @@
27#include <asm/prom.h> 27#include <asm/prom.h>
28#include <asm/ppc-pci.h> 28#include <asm/ppc-pci.h>
29 29
30#include "../cell/io-workarounds.h"
31
32struct celleb_phb_spec {
33 int (*setup)(struct device_node *, struct pci_controller *);
34 struct ppc_pci_io *ops;
35 int (*iowa_init)(struct iowa_bus *, void *);
36 void *iowa_data;
37};
38
30extern int celleb_setup_phb(struct pci_controller *); 39extern int celleb_setup_phb(struct pci_controller *);
31extern int celleb_pci_probe_mode(struct pci_bus *); 40extern int celleb_pci_probe_mode(struct pci_bus *);
32 41
33extern int celleb_setup_epci(struct device_node *, struct pci_controller *); 42extern struct celleb_phb_spec celleb_epci_spec;
34
35extern void *celleb_dummy_page_va;
36extern int __init celleb_pci_workaround_init(void);
37extern void __init celleb_pci_add_one(struct pci_controller *,
38 void (*)(struct pci_controller *));
39extern void fake_pci_workaround_init(struct pci_controller *);
40extern void epci_workaround_init(struct pci_controller *);
41 43
42#endif /* _CELLEB_PCI_H */ 44#endif /* _CELLEB_PCI_H */
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
index a999b393f6f6..b126739834ac 100644
--- a/arch/powerpc/platforms/celleb/scc_epci.c
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -43,10 +43,6 @@
43 43
44#define iob() __asm__ __volatile__("eieio; sync":::"memory") 44#define iob() __asm__ __volatile__("eieio; sync":::"memory")
45 45
46struct epci_private {
47 dma_addr_t dummy_page_da;
48};
49
50static inline PCI_IO_ADDR celleb_epci_get_epci_base( 46static inline PCI_IO_ADDR celleb_epci_get_epci_base(
51 struct pci_controller *hose) 47 struct pci_controller *hose)
52{ 48{
@@ -71,42 +67,6 @@ static inline PCI_IO_ADDR celleb_epci_get_epci_cfg(
71 return hose->cfg_data; 67 return hose->cfg_data;
72} 68}
73 69
74static void scc_epci_dummy_read(struct pci_controller *hose)
75{
76 PCI_IO_ADDR epci_base;
77 u32 val;
78
79 epci_base = celleb_epci_get_epci_base(hose);
80
81 val = in_be32(epci_base + SCC_EPCI_WATRP);
82 iosync();
83
84 return;
85}
86
87void __init epci_workaround_init(struct pci_controller *hose)
88{
89 PCI_IO_ADDR epci_base;
90 PCI_IO_ADDR reg;
91 struct epci_private *private = hose->private_data;
92
93 BUG_ON(!private);
94
95 private->dummy_page_da = dma_map_single(hose->parent,
96 celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE);
97 if (private->dummy_page_da == DMA_ERROR_CODE) {
98 printk(KERN_ERR "EPCI: dummy read disabled. "
99 "Map dummy page failed.\n");
100 return;
101 }
102
103 celleb_pci_add_one(hose, scc_epci_dummy_read);
104 epci_base = celleb_epci_get_epci_base(hose);
105
106 reg = epci_base + SCC_EPCI_DUMYRADR;
107 out_be32(reg, private->dummy_page_da);
108}
109
110static inline void clear_and_disable_master_abort_interrupt( 70static inline void clear_and_disable_master_abort_interrupt(
111 struct pci_controller *hose) 71 struct pci_controller *hose)
112{ 72{
@@ -425,8 +385,8 @@ static int __init celleb_epci_init(struct pci_controller *hose)
425 return 0; 385 return 0;
426} 386}
427 387
428int __init celleb_setup_epci(struct device_node *node, 388static int __init celleb_setup_epci(struct device_node *node,
429 struct pci_controller *hose) 389 struct pci_controller *hose)
430{ 390{
431 struct resource r; 391 struct resource r;
432 392
@@ -462,20 +422,12 @@ int __init celleb_setup_epci(struct device_node *node,
462 r.start, (unsigned long)hose->cfg_data, 422 r.start, (unsigned long)hose->cfg_data,
463 (r.end - r.start + 1)); 423 (r.end - r.start + 1));
464 424
465 hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL);
466 if (hose->private_data == NULL) {
467 printk(KERN_ERR "EPCI: no memory for private data.\n");
468 goto error;
469 }
470
471 hose->ops = &celleb_epci_ops; 425 hose->ops = &celleb_epci_ops;
472 celleb_epci_init(hose); 426 celleb_epci_init(hose);
473 427
474 return 0; 428 return 0;
475 429
476error: 430error:
477 kfree(hose->private_data);
478
479 if (hose->cfg_addr) 431 if (hose->cfg_addr)
480 iounmap(hose->cfg_addr); 432 iounmap(hose->cfg_addr);
481 433
@@ -483,3 +435,10 @@ error:
483 iounmap(hose->cfg_data); 435 iounmap(hose->cfg_data);
484 return 1; 436 return 1;
485} 437}
438
439struct celleb_phb_spec celleb_epci_spec __initdata = {
440 .setup = celleb_setup_epci,
441 .ops = &spiderpci_ops,
442 .iowa_init = &spiderpci_iowa_init,
443 .iowa_data = (void *)0,
444};
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index f27ae1e3fb58..ff8209e61e84 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -114,8 +114,6 @@ static int __init celleb_publish_devices(void)
114 /* Publish OF platform devices for southbridge IOs */ 114 /* Publish OF platform devices for southbridge IOs */
115 of_platform_bus_probe(NULL, celleb_bus_ids, NULL); 115 of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
116 116
117 celleb_pci_workaround_init();
118
119 return 0; 117 return 0;
120} 118}
121machine_device_initcall(celleb_beat, celleb_publish_devices); 119machine_device_initcall(celleb_beat, celleb_publish_devices);