diff options
author | Ishizaki Kou <kou.ishizaki@toshiba.co.jp> | 2008-04-24 05:21:10 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-04-24 07:08:12 -0400 |
commit | 7cfb62a2e820b6032c08835dbd996d8518af14a3 (patch) | |
tree | fdcd728c96ca020214452f11ae8600525e9d3773 /arch/powerpc/platforms/cell/spider-pci.c | |
parent | 36f8a2c4c61e3559a95190e457b431c6900859b4 (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>
Diffstat (limited to 'arch/powerpc/platforms/cell/spider-pci.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pci.c | 184 |
1 files changed, 184 insertions, 0 deletions
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 | |||
34 | struct spiderpci_iowa_private { | ||
35 | void __iomem *regs; | ||
36 | }; | ||
37 | |||
38 | static 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) \ | ||
49 | static 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) \ | ||
57 | static 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 | |||
64 | SPIDER_PCI_MMIO_READ(readb, u8) | ||
65 | SPIDER_PCI_MMIO_READ(readw, u16) | ||
66 | SPIDER_PCI_MMIO_READ(readl, u32) | ||
67 | SPIDER_PCI_MMIO_READ(readq, u64) | ||
68 | SPIDER_PCI_MMIO_READ(readw_be, u16) | ||
69 | SPIDER_PCI_MMIO_READ(readl_be, u32) | ||
70 | SPIDER_PCI_MMIO_READ(readq_be, u64) | ||
71 | SPIDER_PCI_MMIO_READ_STR(readsb) | ||
72 | SPIDER_PCI_MMIO_READ_STR(readsw) | ||
73 | SPIDER_PCI_MMIO_READ_STR(readsl) | ||
74 | |||
75 | static 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 | |||
82 | static 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 | |||
125 | int __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 | |||
161 | error: | ||
162 | kfree(priv); | ||
163 | bus->private = NULL; | ||
164 | |||
165 | if (regs) | ||
166 | iounmap(regs); | ||
167 | |||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | struct 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 | |||