Commit | Line | Data |
---|---|---|
7cfb62a2 IK |
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> | |
5a0e3ad6 | 25 | #include <linux/slab.h> |
7cfb62a2 IK |
26 | #include <linux/io.h> |
27 | ||
28 | #include <asm/ppc-pci.h> | |
29 | #include <asm/pci-bridge.h> | |
30 | ||
31 | #include "io-workarounds.h" | |
32 | ||
33 | #define SPIDER_PCI_DISABLE_PREFETCH | |
34 | ||
35 | struct spiderpci_iowa_private { | |
36 | void __iomem *regs; | |
37 | }; | |
38 | ||
39 | static void spiderpci_io_flush(struct iowa_bus *bus) | |
40 | { | |
41 | struct spiderpci_iowa_private *priv; | |
42 | u32 val; | |
43 | ||
44 | priv = bus->private; | |
45 | val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ); | |
46 | iosync(); | |
47 | } | |
48 | ||
49 | #define SPIDER_PCI_MMIO_READ(name, ret) \ | |
50 | static ret spiderpci_##name(const PCI_IO_ADDR addr) \ | |
51 | { \ | |
52 | ret val = __do_##name(addr); \ | |
53 | spiderpci_io_flush(iowa_mem_find_bus(addr)); \ | |
54 | return val; \ | |
55 | } | |
56 | ||
57 | #define SPIDER_PCI_MMIO_READ_STR(name) \ | |
58 | static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \ | |
59 | unsigned long count) \ | |
60 | { \ | |
61 | __do_##name(addr, buf, count); \ | |
62 | spiderpci_io_flush(iowa_mem_find_bus(addr)); \ | |
63 | } | |
64 | ||
65 | SPIDER_PCI_MMIO_READ(readb, u8) | |
66 | SPIDER_PCI_MMIO_READ(readw, u16) | |
67 | SPIDER_PCI_MMIO_READ(readl, u32) | |
68 | SPIDER_PCI_MMIO_READ(readq, u64) | |
69 | SPIDER_PCI_MMIO_READ(readw_be, u16) | |
70 | SPIDER_PCI_MMIO_READ(readl_be, u32) | |
71 | SPIDER_PCI_MMIO_READ(readq_be, u64) | |
72 | SPIDER_PCI_MMIO_READ_STR(readsb) | |
73 | SPIDER_PCI_MMIO_READ_STR(readsw) | |
74 | SPIDER_PCI_MMIO_READ_STR(readsl) | |
75 | ||
76 | static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src, | |
77 | unsigned long n) | |
78 | { | |
79 | __do_memcpy_fromio(dest, src, n); | |
80 | spiderpci_io_flush(iowa_mem_find_bus(src)); | |
81 | } | |
82 | ||
83 | static int __init spiderpci_pci_setup_chip(struct pci_controller *phb, | |
84 | void __iomem *regs) | |
85 | { | |
86 | void *dummy_page_va; | |
87 | dma_addr_t dummy_page_da; | |
88 | ||
89 | #ifdef SPIDER_PCI_DISABLE_PREFETCH | |
90 | u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT); | |
91 | pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val); | |
92 | out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); | |
93 | #endif /* SPIDER_PCI_DISABLE_PREFETCH */ | |
94 | ||
95 | /* setup dummy read */ | |
96 | /* | |
97 | * On CellBlade, we can't know that which XDR memory is used by | |
98 | * kmalloc() to allocate dummy_page_va. | |
99 | * In order to imporve the performance, the XDR which is used to | |
100 | * allocate dummy_page_va is the nearest the spider-pci. | |
101 | * We have to select the CBE which is the nearest the spider-pci | |
102 | * to allocate memory from the best XDR, but I don't know that | |
103 | * how to do. | |
104 | * | |
105 | * Celleb does not have this problem, because it has only one XDR. | |
106 | */ | |
107 | dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
108 | if (!dummy_page_va) { | |
109 | pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n"); | |
110 | return -1; | |
111 | } | |
112 | ||
113 | dummy_page_da = dma_map_single(phb->parent, dummy_page_va, | |
114 | PAGE_SIZE, DMA_FROM_DEVICE); | |
8d8bb39b | 115 | if (dma_mapping_error(phb->parent, dummy_page_da)) { |
7cfb62a2 IK |
116 | pr_err("SPIDER-IOWA:Map dummy page filed.\n"); |
117 | kfree(dummy_page_va); | |
118 | return -1; | |
119 | } | |
120 | ||
121 | out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da); | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) | |
127 | { | |
128 | void __iomem *regs = NULL; | |
129 | struct spiderpci_iowa_private *priv; | |
130 | struct device_node *np = bus->phb->dn; | |
131 | struct resource r; | |
132 | unsigned long offset = (unsigned long)data; | |
133 | ||
134 | pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n", | |
135 | np->full_name); | |
136 | ||
137 | priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL); | |
138 | if (!priv) { | |
139 | pr_err("SPIDERPCI-IOWA:" | |
140 | "Can't allocate struct spiderpci_iowa_private"); | |
141 | return -1; | |
142 | } | |
143 | ||
144 | if (of_address_to_resource(np, 0, &r)) { | |
145 | pr_err("SPIDERPCI-IOWA:Can't get resource.\n"); | |
146 | goto error; | |
147 | } | |
148 | ||
149 | regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE); | |
150 | if (!regs) { | |
151 | pr_err("SPIDERPCI-IOWA:ioremap failed.\n"); | |
152 | goto error; | |
153 | } | |
154 | priv->regs = regs; | |
155 | bus->private = priv; | |
156 | ||
157 | if (spiderpci_pci_setup_chip(bus->phb, regs)) | |
158 | goto error; | |
159 | ||
160 | return 0; | |
161 | ||
162 | error: | |
163 | kfree(priv); | |
164 | bus->private = NULL; | |
165 | ||
166 | if (regs) | |
167 | iounmap(regs); | |
168 | ||
169 | return -1; | |
170 | } | |
171 | ||
172 | struct ppc_pci_io spiderpci_ops = { | |
173 | .readb = spiderpci_readb, | |
174 | .readw = spiderpci_readw, | |
175 | .readl = spiderpci_readl, | |
176 | .readq = spiderpci_readq, | |
177 | .readw_be = spiderpci_readw_be, | |
178 | .readl_be = spiderpci_readl_be, | |
179 | .readq_be = spiderpci_readq_be, | |
180 | .readsb = spiderpci_readsb, | |
181 | .readsw = spiderpci_readsw, | |
182 | .readsl = spiderpci_readsl, | |
183 | .memcpy_fromio = spiderpci_memcpy_fromio, | |
184 | }; | |
185 |