diff options
| author | Ishizaki Kou <kou.ishizaki@toshiba.co.jp> | 2008-04-24 05:24:13 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2008-04-24 07:08:13 -0400 |
| commit | 6ec859e1b21ab42bfc36bb3b51db275480165c8a (patch) | |
| tree | 299d0729340598d795559084a11c2fdfc61ce199 | |
| parent | 7cfb62a2e820b6032c08835dbd996d8518af14a3 (diff) | |
[POWERPC] celleb: Consolidate io-workarounds code
Now, we can use generic io-workarounds mechanism and the workaround
code for spider-pci. This changes Celleb PCI code to use spider-pci
code.
Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/powerpc/platforms/cell/Makefile | 6 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/Makefile | 3 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/io-workarounds.c | 280 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/pci.c | 41 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/pci.h | 18 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/scc_epci.c | 59 | ||||
| -rw-r--r-- | arch/powerpc/platforms/celleb/setup.c | 2 |
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 | ||
| 29 | obj-$(CONFIG_PCI_MSI) += axon_msi.o | 29 | obj-$(CONFIG_PCI_MSI) += axon_msi.o |
| 30 | |||
| 31 | |||
| 32 | # celleb stuff | ||
| 33 | ifeq ($(CONFIG_PPC_CELLEB),y) | ||
| 34 | obj-y += io-workarounds.o spider-pci.o | ||
| 35 | endif | ||
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 @@ | |||
| 1 | obj-y += interrupt.o iommu.o setup.o \ | 1 | obj-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 | ||
| 6 | obj-$(CONFIG_SMP) += smp.o | 5 | obj-$(CONFIG_SMP) += smp.o |
| 7 | obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o | 6 | obj-$(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 | |||
| 39 | void *celleb_dummy_page_va; | ||
| 40 | |||
| 41 | static 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 | |||
| 46 | static int celleb_pci_count = 0; | ||
| 47 | |||
| 48 | static 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 | |||
| 70 | static 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 | |||
| 102 | static 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 | |||
| 110 | static 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 | |||
| 118 | static 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 | |||
| 126 | static 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 | |||
| 134 | static 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 | |||
| 142 | static 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 | |||
| 150 | static 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 | |||
| 158 | static 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 | |||
| 165 | static 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 | |||
| 172 | static 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 | |||
| 179 | static 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 | |||
| 187 | static 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 | |||
| 203 | static void celleb_iounmap(volatile void __iomem *addr) | ||
| 204 | { | ||
| 205 | return __iounmap(PCI_FIX_ADDR(addr)); | ||
| 206 | } | ||
| 207 | |||
| 208 | static 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 | |||
| 222 | void __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 | |||
| 240 | static 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 | |||
| 251 | int __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 | ||
| 460 | void __init fake_pci_workaround_init(struct pci_controller *phb) | 461 | static 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 | ||
| 471 | static struct of_device_id celleb_phb_match[] __initdata = { | 465 | static 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 | ||
| 476 | static 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 | |||
| 482 | int __init celleb_setup_phb(struct pci_controller *phb) | 488 | int __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 | ||
| 499 | int celleb_pci_probe_mode(struct pci_bus *bus) | 510 | int 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 | |||
| 32 | struct 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 | |||
| 30 | extern int celleb_setup_phb(struct pci_controller *); | 39 | extern int celleb_setup_phb(struct pci_controller *); |
| 31 | extern int celleb_pci_probe_mode(struct pci_bus *); | 40 | extern int celleb_pci_probe_mode(struct pci_bus *); |
| 32 | 41 | ||
| 33 | extern int celleb_setup_epci(struct device_node *, struct pci_controller *); | 42 | extern struct celleb_phb_spec celleb_epci_spec; |
| 34 | |||
| 35 | extern void *celleb_dummy_page_va; | ||
| 36 | extern int __init celleb_pci_workaround_init(void); | ||
| 37 | extern void __init celleb_pci_add_one(struct pci_controller *, | ||
| 38 | void (*)(struct pci_controller *)); | ||
| 39 | extern void fake_pci_workaround_init(struct pci_controller *); | ||
| 40 | extern 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 | ||
| 46 | struct epci_private { | ||
| 47 | dma_addr_t dummy_page_da; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static inline PCI_IO_ADDR celleb_epci_get_epci_base( | 46 | static 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 | ||
| 74 | static 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 | |||
| 87 | void __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 | |||
| 110 | static inline void clear_and_disable_master_abort_interrupt( | 70 | static 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 | ||
| 428 | int __init celleb_setup_epci(struct device_node *node, | 388 | static 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 | ||
| 476 | error: | 430 | error: |
| 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 | |||
| 439 | struct 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 | } |
| 121 | machine_device_initcall(celleb_beat, celleb_publish_devices); | 119 | machine_device_initcall(celleb_beat, celleb_publish_devices); |
