aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/dart.h41
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c (renamed from arch/powerpc/sysdev/u3_iommu.c)173
-rw-r--r--arch/powerpc/sysdev/mpic.c199
4 files changed, 287 insertions, 128 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index b3e3636a57b0..14b9abde2d27 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,6 +4,6 @@ obj-$(CONFIG_PPC_I8259) += i8259.o
4obj-$(CONFIG_PPC_MPC106) += grackle.o 4obj-$(CONFIG_PPC_MPC106) += grackle.o
5obj-$(CONFIG_BOOKE) += dcr.o 5obj-$(CONFIG_BOOKE) += dcr.o
6obj-$(CONFIG_40x) += dcr.o 6obj-$(CONFIG_40x) += dcr.o
7obj-$(CONFIG_U3_DART) += u3_iommu.o 7obj-$(CONFIG_U3_DART) += dart_iommu.o
8obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o 8obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
9obj-$(CONFIG_83xx) += ipic.o 9obj-$(CONFIG_83xx) += ipic.o
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
index 33ed9ed7fc1e..c2d05763ccbe 100644
--- a/arch/powerpc/sysdev/dart.h
+++ b/arch/powerpc/sysdev/dart.h
@@ -20,29 +20,44 @@
20#define _POWERPC_SYSDEV_DART_H 20#define _POWERPC_SYSDEV_DART_H
21 21
22 22
23/* physical base of DART registers */
24#define DART_BASE 0xf8033000UL
25
26/* Offset from base to control register */ 23/* Offset from base to control register */
27#define DARTCNTL 0 24#define DART_CNTL 0
25
28/* Offset from base to exception register */ 26/* Offset from base to exception register */
29#define DARTEXCP 0x10 27#define DART_EXCP_U3 0x10
30/* Offset from base to TLB tag registers */ 28/* Offset from base to TLB tag registers */
31#define DARTTAG 0x1000 29#define DART_TAGS_U3 0x1000
32 30
31/* U4 registers */
32#define DART_BASE_U4 0x10
33#define DART_SIZE_U4 0x20
34#define DART_EXCP_U4 0x30
35#define DART_TAGS_U4 0x1000
33 36
34/* Control Register fields */ 37/* Control Register fields */
35 38
36/* base address of table (pfn) */ 39/* U3 registers */
37#define DARTCNTL_BASE_MASK 0xfffff 40#define DART_CNTL_U3_BASE_MASK 0xfffff
38#define DARTCNTL_BASE_SHIFT 12 41#define DART_CNTL_U3_BASE_SHIFT 12
42#define DART_CNTL_U3_FLUSHTLB 0x400
43#define DART_CNTL_U3_ENABLE 0x200
44#define DART_CNTL_U3_SIZE_MASK 0x1ff
45#define DART_CNTL_U3_SIZE_SHIFT 0
46
47/* U4 registers */
48#define DART_BASE_U4_BASE_MASK 0xffffff
49#define DART_BASE_U4_BASE_SHIFT 0
50#define DART_CNTL_U4_FLUSHTLB 0x20000000
51#define DART_CNTL_U4_ENABLE 0x80000000
52#define DART_SIZE_U4_SIZE_MASK 0x1fff
53#define DART_SIZE_U4_SIZE_SHIFT 0
54
55#define DART_REG(r) (dart + ((r) >> 2))
56#define DART_IN(r) (in_be32(DART_REG(r)))
57#define DART_OUT(r,v) (out_be32(DART_REG(r), (v)))
39 58
40#define DARTCNTL_FLUSHTLB 0x400
41#define DARTCNTL_ENABLE 0x200
42 59
43/* size of table in pages */ 60/* size of table in pages */
44#define DARTCNTL_SIZE_MASK 0x1ff
45#define DARTCNTL_SIZE_SHIFT 0
46 61
47 62
48/* DART table fields */ 63/* DART table fields */
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 5c1a26a6d00c..df0dbdee762a 100644
--- a/arch/powerpc/sysdev/u3_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -1,25 +1,27 @@
1/* 1/*
2 * arch/powerpc/sysdev/u3_iommu.c 2 * arch/powerpc/sysdev/dart_iommu.c
3 * 3 *
4 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation 4 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
5 * Copyright (C) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>,
6 * IBM Corporation
5 * 7 *
6 * Based on pSeries_iommu.c: 8 * Based on pSeries_iommu.c:
7 * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation 9 * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
8 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation 10 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
9 * 11 *
10 * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. 12 * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu.
13 *
11 * 14 *
12 *
13 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or 17 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version. 18 * (at your option) any later version.
17 * 19 *
18 * This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details. 23 * GNU General Public License for more details.
22 * 24 *
23 * You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software 26 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -57,21 +59,22 @@ static unsigned long dart_tablesize;
57static u32 *dart_vbase; 59static u32 *dart_vbase;
58 60
59/* Mapped base address for the dart */ 61/* Mapped base address for the dart */
60static unsigned int *dart; 62static unsigned int *__iomem dart;
61 63
62/* Dummy val that entries are set to when unused */ 64/* Dummy val that entries are set to when unused */
63static unsigned int dart_emptyval; 65static unsigned int dart_emptyval;
64 66
65static struct iommu_table iommu_table_u3; 67static struct iommu_table iommu_table_dart;
66static int iommu_table_u3_inited; 68static int iommu_table_dart_inited;
67static int dart_dirty; 69static int dart_dirty;
70static int dart_is_u4;
68 71
69#define DBG(...) 72#define DBG(...)
70 73
71static inline void dart_tlb_invalidate_all(void) 74static inline void dart_tlb_invalidate_all(void)
72{ 75{
73 unsigned long l = 0; 76 unsigned long l = 0;
74 unsigned int reg; 77 unsigned int reg, inv_bit;
75 unsigned long limit; 78 unsigned long limit;
76 79
77 DBG("dart: flush\n"); 80 DBG("dart: flush\n");
@@ -81,29 +84,28 @@ static inline void dart_tlb_invalidate_all(void)
81 * 84 *
82 * Gotcha: Sometimes, the DART won't detect that the bit gets 85 * Gotcha: Sometimes, the DART won't detect that the bit gets
83 * set. If so, clear it and set it again. 86 * set. If so, clear it and set it again.
84 */ 87 */
85 88
86 limit = 0; 89 limit = 0;
87 90
91 inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB;
88retry: 92retry:
89 reg = in_be32((unsigned int *)dart+DARTCNTL);
90 reg |= DARTCNTL_FLUSHTLB;
91 out_be32((unsigned int *)dart+DARTCNTL, reg);
92
93 l = 0; 93 l = 0;
94 while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && 94 reg = DART_IN(DART_CNTL);
95 l < (1L<<limit)) { 95 reg |= inv_bit;
96 DART_OUT(DART_CNTL, reg);
97
98 while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit))
96 l++; 99 l++;
97 } 100 if (l == (1L << limit)) {
98 if (l == (1L<<limit)) {
99 if (limit < 4) { 101 if (limit < 4) {
100 limit++; 102 limit++;
101 reg = in_be32((unsigned int *)dart+DARTCNTL); 103 reg = DART_IN(DART_CNTL);
102 reg &= ~DARTCNTL_FLUSHTLB; 104 reg &= ~inv_bit;
103 out_be32((unsigned int *)dart+DARTCNTL, reg); 105 DART_OUT(DART_CNTL, reg);
104 goto retry; 106 goto retry;
105 } else 107 } else
106 panic("U3-DART: TLB did not flush after waiting a long " 108 panic("DART: TLB did not flush after waiting a long "
107 "time. Buggy U3 ?"); 109 "time. Buggy U3 ?");
108 } 110 }
109} 111}
@@ -115,7 +117,7 @@ static void dart_flush(struct iommu_table *tbl)
115 dart_dirty = 0; 117 dart_dirty = 0;
116} 118}
117 119
118static void dart_build(struct iommu_table *tbl, long index, 120static void dart_build(struct iommu_table *tbl, long index,
119 long npages, unsigned long uaddr, 121 long npages, unsigned long uaddr,
120 enum dma_data_direction direction) 122 enum dma_data_direction direction)
121{ 123{
@@ -128,7 +130,7 @@ static void dart_build(struct iommu_table *tbl, long index,
128 npages <<= DART_PAGE_FACTOR; 130 npages <<= DART_PAGE_FACTOR;
129 131
130 dp = ((unsigned int*)tbl->it_base) + index; 132 dp = ((unsigned int*)tbl->it_base) + index;
131 133
132 /* On U3, all memory is contigous, so we can move this 134 /* On U3, all memory is contigous, so we can move this
133 * out of the loop. 135 * out of the loop.
134 */ 136 */
@@ -148,7 +150,7 @@ static void dart_build(struct iommu_table *tbl, long index,
148static void dart_free(struct iommu_table *tbl, long index, long npages) 150static void dart_free(struct iommu_table *tbl, long index, long npages)
149{ 151{
150 unsigned int *dp; 152 unsigned int *dp;
151 153
152 /* We don't worry about flushing the TLB cache. The only drawback of 154 /* We don't worry about flushing the TLB cache. The only drawback of
153 * not doing it is that we won't catch buggy device drivers doing 155 * not doing it is that we won't catch buggy device drivers doing
154 * bad DMAs, but then no 32-bit architecture ever does either. 156 * bad DMAs, but then no 32-bit architecture ever does either.
@@ -160,7 +162,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
160 npages <<= DART_PAGE_FACTOR; 162 npages <<= DART_PAGE_FACTOR;
161 163
162 dp = ((unsigned int *)tbl->it_base) + index; 164 dp = ((unsigned int *)tbl->it_base) + index;
163 165
164 while (npages--) 166 while (npages--)
165 *(dp++) = dart_emptyval; 167 *(dp++) = dart_emptyval;
166} 168}
@@ -168,20 +170,25 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
168 170
169static int dart_init(struct device_node *dart_node) 171static int dart_init(struct device_node *dart_node)
170{ 172{
171 unsigned int regword;
172 unsigned int i; 173 unsigned int i;
173 unsigned long tmp; 174 unsigned long tmp, base, size;
175 struct resource r;
174 176
175 if (dart_tablebase == 0 || dart_tablesize == 0) { 177 if (dart_tablebase == 0 || dart_tablesize == 0) {
176 printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); 178 printk(KERN_INFO "DART: table not allocated, using "
179 "direct DMA\n");
177 return -ENODEV; 180 return -ENODEV;
178 } 181 }
179 182
183 if (of_address_to_resource(dart_node, 0, &r))
184 panic("DART: can't get register base ! ");
185
180 /* Make sure nothing from the DART range remains in the CPU cache 186 /* Make sure nothing from the DART range remains in the CPU cache
181 * from a previous mapping that existed before the kernel took 187 * from a previous mapping that existed before the kernel took
182 * over 188 * over
183 */ 189 */
184 flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); 190 flush_dcache_phys_range(dart_tablebase,
191 dart_tablebase + dart_tablesize);
185 192
186 /* Allocate a spare page to map all invalid DART pages. We need to do 193 /* Allocate a spare page to map all invalid DART pages. We need to do
187 * that to work around what looks like a problem with the HT bridge 194 * that to work around what looks like a problem with the HT bridge
@@ -189,21 +196,16 @@ static int dart_init(struct device_node *dart_node)
189 */ 196 */
190 tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); 197 tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
191 if (!tmp) 198 if (!tmp)
192 panic("U3-DART: Cannot allocate spare page!"); 199 panic("DART: Cannot allocate spare page!");
193 dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK); 200 dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
201 DARTMAP_RPNMASK);
194 202
195 /* Map in DART registers. FIXME: Use device node to get base address */ 203 /* Map in DART registers */
196 dart = ioremap(DART_BASE, 0x7000); 204 dart = ioremap(r.start, r.end - r.start + 1);
197 if (dart == NULL) 205 if (dart == NULL)
198 panic("U3-DART: Cannot map registers!"); 206 panic("DART: Cannot map registers!");
199 207
200 /* Set initial control register contents: table base, 208 /* Map in DART table */
201 * table size and enable bit
202 */
203 regword = DARTCNTL_ENABLE |
204 ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
205 (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
206 << DARTCNTL_SIZE_SHIFT);
207 dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); 209 dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
208 210
209 /* Fill initial table */ 211 /* Fill initial table */
@@ -211,36 +213,50 @@ static int dart_init(struct device_node *dart_node)
211 dart_vbase[i] = dart_emptyval; 213 dart_vbase[i] = dart_emptyval;
212 214
213 /* Initialize DART with table base and enable it. */ 215 /* Initialize DART with table base and enable it. */
214 out_be32((unsigned int *)dart, regword); 216 base = dart_tablebase >> DART_PAGE_SHIFT;
217 size = dart_tablesize >> DART_PAGE_SHIFT;
218 if (dart_is_u4) {
219 BUG_ON(size & ~DART_SIZE_U4_SIZE_MASK);
220 DART_OUT(DART_BASE_U4, base);
221 DART_OUT(DART_SIZE_U4, size);
222 DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE);
223 } else {
224 BUG_ON(size & ~DART_CNTL_U3_SIZE_MASK);
225 DART_OUT(DART_CNTL,
226 DART_CNTL_U3_ENABLE |
227 (base << DART_CNTL_U3_BASE_SHIFT) |
228 (size << DART_CNTL_U3_SIZE_SHIFT));
229 }
215 230
216 /* Invalidate DART to get rid of possible stale TLBs */ 231 /* Invalidate DART to get rid of possible stale TLBs */
217 dart_tlb_invalidate_all(); 232 dart_tlb_invalidate_all();
218 233
219 printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); 234 printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n",
235 dart_is_u4 ? "U4" : "U3");
220 236
221 return 0; 237 return 0;
222} 238}
223 239
224static void iommu_table_u3_setup(void) 240static void iommu_table_dart_setup(void)
225{ 241{
226 iommu_table_u3.it_busno = 0; 242 iommu_table_dart.it_busno = 0;
227 iommu_table_u3.it_offset = 0; 243 iommu_table_dart.it_offset = 0;
228 /* it_size is in number of entries */ 244 /* it_size is in number of entries */
229 iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; 245 iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
230 246
231 /* Initialize the common IOMMU code */ 247 /* Initialize the common IOMMU code */
232 iommu_table_u3.it_base = (unsigned long)dart_vbase; 248 iommu_table_dart.it_base = (unsigned long)dart_vbase;
233 iommu_table_u3.it_index = 0; 249 iommu_table_dart.it_index = 0;
234 iommu_table_u3.it_blocksize = 1; 250 iommu_table_dart.it_blocksize = 1;
235 iommu_init_table(&iommu_table_u3); 251 iommu_init_table(&iommu_table_dart);
236 252
237 /* Reserve the last page of the DART to avoid possible prefetch 253 /* Reserve the last page of the DART to avoid possible prefetch
238 * past the DART mapped area 254 * past the DART mapped area
239 */ 255 */
240 set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map); 256 set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
241} 257}
242 258
243static void iommu_dev_setup_u3(struct pci_dev *dev) 259static void iommu_dev_setup_dart(struct pci_dev *dev)
244{ 260{
245 struct device_node *dn; 261 struct device_node *dn;
246 262
@@ -254,35 +270,39 @@ static void iommu_dev_setup_u3(struct pci_dev *dev)
254 dn = pci_device_to_OF_node(dev); 270 dn = pci_device_to_OF_node(dev);
255 271
256 if (dn) 272 if (dn)
257 PCI_DN(dn)->iommu_table = &iommu_table_u3; 273 PCI_DN(dn)->iommu_table = &iommu_table_dart;
258} 274}
259 275
260static void iommu_bus_setup_u3(struct pci_bus *bus) 276static void iommu_bus_setup_dart(struct pci_bus *bus)
261{ 277{
262 struct device_node *dn; 278 struct device_node *dn;
263 279
264 if (!iommu_table_u3_inited) { 280 if (!iommu_table_dart_inited) {
265 iommu_table_u3_inited = 1; 281 iommu_table_dart_inited = 1;
266 iommu_table_u3_setup(); 282 iommu_table_dart_setup();
267 } 283 }
268 284
269 dn = pci_bus_to_OF_node(bus); 285 dn = pci_bus_to_OF_node(bus);
270 286
271 if (dn) 287 if (dn)
272 PCI_DN(dn)->iommu_table = &iommu_table_u3; 288 PCI_DN(dn)->iommu_table = &iommu_table_dart;
273} 289}
274 290
275static void iommu_dev_setup_null(struct pci_dev *dev) { } 291static void iommu_dev_setup_null(struct pci_dev *dev) { }
276static void iommu_bus_setup_null(struct pci_bus *bus) { } 292static void iommu_bus_setup_null(struct pci_bus *bus) { }
277 293
278void iommu_init_early_u3(void) 294void iommu_init_early_dart(void)
279{ 295{
280 struct device_node *dn; 296 struct device_node *dn;
281 297
282 /* Find the DART in the device-tree */ 298 /* Find the DART in the device-tree */
283 dn = of_find_compatible_node(NULL, "dart", "u3-dart"); 299 dn = of_find_compatible_node(NULL, "dart", "u3-dart");
284 if (dn == NULL) 300 if (dn == NULL) {
285 return; 301 dn = of_find_compatible_node(NULL, "dart", "u4-dart");
302 if (dn == NULL)
303 goto bail;
304 dart_is_u4 = 1;
305 }
286 306
287 /* Setup low level TCE operations for the core IOMMU code */ 307 /* Setup low level TCE operations for the core IOMMU code */
288 ppc_md.tce_build = dart_build; 308 ppc_md.tce_build = dart_build;
@@ -290,24 +310,27 @@ void iommu_init_early_u3(void)
290 ppc_md.tce_flush = dart_flush; 310 ppc_md.tce_flush = dart_flush;
291 311
292 /* Initialize the DART HW */ 312 /* Initialize the DART HW */
293 if (dart_init(dn)) { 313 if (dart_init(dn) == 0) {
294 /* If init failed, use direct iommu and null setup functions */ 314 ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
295 ppc_md.iommu_dev_setup = iommu_dev_setup_null; 315 ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
296 ppc_md.iommu_bus_setup = iommu_bus_setup_null;
297
298 /* Setup pci_dma ops */
299 pci_direct_iommu_init();
300 } else {
301 ppc_md.iommu_dev_setup = iommu_dev_setup_u3;
302 ppc_md.iommu_bus_setup = iommu_bus_setup_u3;
303 316
304 /* Setup pci_dma ops */ 317 /* Setup pci_dma ops */
305 pci_iommu_init(); 318 pci_iommu_init();
319
320 return;
306 } 321 }
322
323 bail:
324 /* If init failed, use direct iommu and null setup functions */
325 ppc_md.iommu_dev_setup = iommu_dev_setup_null;
326 ppc_md.iommu_bus_setup = iommu_bus_setup_null;
327
328 /* Setup pci_dma ops */
329 pci_direct_iommu_init();
307} 330}
308 331
309 332
310void __init alloc_u3_dart_table(void) 333void __init alloc_dart_table(void)
311{ 334{
312 /* Only reserve DART space if machine has more than 2GB of RAM 335 /* Only reserve DART space if machine has more than 2GB of RAM
313 * or if requested with iommu=on on cmdline. 336 * or if requested with iommu=on on cmdline.
@@ -323,5 +346,5 @@ void __init alloc_u3_dart_table(void)
323 dart_tablebase = (unsigned long) 346 dart_tablebase = (unsigned long)
324 abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); 347 abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
325 348
326 printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); 349 printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
327} 350}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 9513ea78e6c1..4f26304d0263 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -13,6 +13,9 @@
13 */ 13 */
14 14
15#undef DEBUG 15#undef DEBUG
16#undef DEBUG_IPI
17#undef DEBUG_IRQ
18#undef DEBUG_LOW
16 19
17#include <linux/config.h> 20#include <linux/config.h>
18#include <linux/types.h> 21#include <linux/types.h>
@@ -168,35 +171,86 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
168/* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 171/* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
169 * to force the edge setting on the MPIC and do the ack workaround. 172 * to force the edge setting on the MPIC and do the ack workaround.
170 */ 173 */
171static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) 174static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
172{ 175{
173 if (source_no >= 128 || !mpic->fixups) 176 if (source >= 128 || !mpic->fixups)
174 return 0; 177 return 0;
175 return mpic->fixups[source_no].base != NULL; 178 return mpic->fixups[source].base != NULL;
176} 179}
177 180
178 181
179static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) 182static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
180{ 183{
181 struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; 184 struct mpic_irq_fixup *fixup = &mpic->fixups[source];
182 185
183 spin_lock(&mpic->fixup_lock); 186 if (fixup->applebase) {
184 writeb(0x11 + 2 * fixup->irq, fixup->base + 2); 187 unsigned int soff = (fixup->index >> 3) & ~3;
185 writel(fixup->data, fixup->base + 4); 188 unsigned int mask = 1U << (fixup->index & 0x1f);
186 spin_unlock(&mpic->fixup_lock); 189 writel(mask, fixup->applebase + soff);
190 } else {
191 spin_lock(&mpic->fixup_lock);
192 writeb(0x11 + 2 * fixup->index, fixup->base + 2);
193 writel(fixup->data, fixup->base + 4);
194 spin_unlock(&mpic->fixup_lock);
195 }
187} 196}
188 197
198static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
199 unsigned int irqflags)
200{
201 struct mpic_irq_fixup *fixup = &mpic->fixups[source];
202 unsigned long flags;
203 u32 tmp;
204
205 if (fixup->base == NULL)
206 return;
207
208 DBG("startup_ht_interrupt(%u, %u) index: %d\n",
209 source, irqflags, fixup->index);
210 spin_lock_irqsave(&mpic->fixup_lock, flags);
211 /* Enable and configure */
212 writeb(0x10 + 2 * fixup->index, fixup->base + 2);
213 tmp = readl(fixup->base + 4);
214 tmp &= ~(0x23U);
215 if (irqflags & IRQ_LEVEL)
216 tmp |= 0x22;
217 writel(tmp, fixup->base + 4);
218 spin_unlock_irqrestore(&mpic->fixup_lock, flags);
219}
220
221static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
222 unsigned int irqflags)
223{
224 struct mpic_irq_fixup *fixup = &mpic->fixups[source];
225 unsigned long flags;
226 u32 tmp;
227
228 if (fixup->base == NULL)
229 return;
230
231 DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
232
233 /* Disable */
234 spin_lock_irqsave(&mpic->fixup_lock, flags);
235 writeb(0x10 + 2 * fixup->index, fixup->base + 2);
236 tmp = readl(fixup->base + 4);
237 tmp &= ~1U;
238 writel(tmp, fixup->base + 4);
239 spin_unlock_irqrestore(&mpic->fixup_lock, flags);
240}
189 241
190static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) 242static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
243 unsigned int devfn, u32 vdid)
191{ 244{
192 int i, irq, n; 245 int i, irq, n;
246 u8 __iomem *base;
193 u32 tmp; 247 u32 tmp;
194 u8 pos; 248 u8 pos;
195 249
196 for (pos = readb(devbase + 0x34); pos; pos = readb(devbase + pos + 1)) { 250 for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
197 u8 id = readb(devbase + pos); 251 pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
198 252 u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
199 if (id == 0x08) { 253 if (id == PCI_CAP_ID_HT_IRQCONF) {
200 id = readb(devbase + pos + 3); 254 id = readb(devbase + pos + 3);
201 if (id == 0x80) 255 if (id == 0x80)
202 break; 256 break;
@@ -205,33 +259,41 @@ static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase)
205 if (pos == 0) 259 if (pos == 0)
206 return; 260 return;
207 261
208 printk(KERN_INFO "mpic: - Workarounds @ %p, pos = 0x%02x\n", devbase, pos); 262 base = devbase + pos;
263 writeb(0x01, base + 2);
264 n = (readl(base + 4) >> 16) & 0xff;
209 265
210 devbase += pos; 266 printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x"
211 267 " has %d irqs\n",
212 writeb(0x01, devbase + 2); 268 devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
213 n = (readl(devbase + 4) >> 16) & 0xff;
214 269
215 for (i = 0; i <= n; i++) { 270 for (i = 0; i <= n; i++) {
216 writeb(0x10 + 2 * i, devbase + 2); 271 writeb(0x10 + 2 * i, base + 2);
217 tmp = readl(devbase + 4); 272 tmp = readl(base + 4);
218 if ((tmp & 0x21) != 0x20)
219 continue;
220 irq = (tmp >> 16) & 0xff; 273 irq = (tmp >> 16) & 0xff;
221 mpic->fixups[irq].irq = i; 274 DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
222 mpic->fixups[irq].base = devbase; 275 /* mask it , will be unmasked later */
223 writeb(0x11 + 2 * i, devbase + 2); 276 tmp |= 0x1;
224 mpic->fixups[irq].data = readl(devbase + 4) | 0x80000000; 277 writel(tmp, base + 4);
278 mpic->fixups[irq].index = i;
279 mpic->fixups[irq].base = base;
280 /* Apple HT PIC has a non-standard way of doing EOIs */
281 if ((vdid & 0xffff) == 0x106b)
282 mpic->fixups[irq].applebase = devbase + 0x60;
283 else
284 mpic->fixups[irq].applebase = NULL;
285 writeb(0x11 + 2 * i, base + 2);
286 mpic->fixups[irq].data = readl(base + 4) | 0x80000000;
225 } 287 }
226} 288}
227 289
228 290
229static void __init mpic_scan_ioapics(struct mpic *mpic) 291static void __init mpic_scan_ht_pics(struct mpic *mpic)
230{ 292{
231 unsigned int devfn; 293 unsigned int devfn;
232 u8 __iomem *cfgspace; 294 u8 __iomem *cfgspace;
233 295
234 printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); 296 printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
235 297
236 /* Allocate fixups array */ 298 /* Allocate fixups array */
237 mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); 299 mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
@@ -247,13 +309,14 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
247 cfgspace = ioremap(0xf2000000, 0x10000); 309 cfgspace = ioremap(0xf2000000, 0x10000);
248 BUG_ON(cfgspace == NULL); 310 BUG_ON(cfgspace == NULL);
249 311
250 /* Now we scan all slots. We do a very quick scan, we read the header type, 312 /* Now we scan all slots. We do a very quick scan, we read the header
251 * vendor ID and device ID only, that's plenty enough 313 * type, vendor ID and device ID only, that's plenty enough
252 */ 314 */
253 for (devfn = 0; devfn < 0x100; devfn++) { 315 for (devfn = 0; devfn < 0x100; devfn++) {
254 u8 __iomem *devbase = cfgspace + (devfn << 8); 316 u8 __iomem *devbase = cfgspace + (devfn << 8);
255 u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 317 u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
256 u32 l = readl(devbase + PCI_VENDOR_ID); 318 u32 l = readl(devbase + PCI_VENDOR_ID);
319 u16 s;
257 320
258 DBG("devfn %x, l: %x\n", devfn, l); 321 DBG("devfn %x, l: %x\n", devfn, l);
259 322
@@ -261,8 +324,12 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
261 if (l == 0xffffffff || l == 0x00000000 || 324 if (l == 0xffffffff || l == 0x00000000 ||
262 l == 0x0000ffff || l == 0xffff0000) 325 l == 0x0000ffff || l == 0xffff0000)
263 goto next; 326 goto next;
327 /* Check if is supports capability lists */
328 s = readw(devbase + PCI_STATUS);
329 if (!(s & PCI_STATUS_CAP_LIST))
330 goto next;
264 331
265 mpic_scan_ioapic(mpic, devbase); 332 mpic_scan_ht_pic(mpic, devbase, devfn, l);
266 333
267 next: 334 next:
268 /* next device, if function 0 */ 335 /* next device, if function 0 */
@@ -363,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq)
363 break; 430 break;
364 } 431 }
365 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); 432 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
433
434#ifdef CONFIG_MPIC_BROKEN_U3
435 if (mpic->flags & MPIC_BROKEN_U3) {
436 unsigned int src = irq - mpic->irq_offset;
437 if (mpic_is_ht_interrupt(mpic, src) &&
438 (irq_desc[irq].status & IRQ_LEVEL))
439 mpic_ht_end_irq(mpic, src);
440 }
441#endif /* CONFIG_MPIC_BROKEN_U3 */
442}
443
444static unsigned int mpic_startup_irq(unsigned int irq)
445{
446#ifdef CONFIG_MPIC_BROKEN_U3
447 struct mpic *mpic = mpic_from_irq(irq);
448 unsigned int src = irq - mpic->irq_offset;
449
450 if (mpic_is_ht_interrupt(mpic, src))
451 mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
452
453#endif /* CONFIG_MPIC_BROKEN_U3 */
454
455 mpic_enable_irq(irq);
456
457 return 0;
366} 458}
367 459
368static void mpic_disable_irq(unsigned int irq) 460static void mpic_disable_irq(unsigned int irq)
@@ -386,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq)
386 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); 478 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
387} 479}
388 480
481static void mpic_shutdown_irq(unsigned int irq)
482{
483#ifdef CONFIG_MPIC_BROKEN_U3
484 struct mpic *mpic = mpic_from_irq(irq);
485 unsigned int src = irq - mpic->irq_offset;
486
487 if (mpic_is_ht_interrupt(mpic, src))
488 mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
489
490#endif /* CONFIG_MPIC_BROKEN_U3 */
491
492 mpic_disable_irq(irq);
493}
494
389static void mpic_end_irq(unsigned int irq) 495static void mpic_end_irq(unsigned int irq)
390{ 496{
391 struct mpic *mpic = mpic_from_irq(irq); 497 struct mpic *mpic = mpic_from_irq(irq);
392 498
499#ifdef DEBUG_IRQ
393 DBG("%s: end_irq: %d\n", mpic->name, irq); 500 DBG("%s: end_irq: %d\n", mpic->name, irq);
394 501#endif
395 /* We always EOI on end_irq() even for edge interrupts since that 502 /* We always EOI on end_irq() even for edge interrupts since that
396 * should only lower the priority, the MPIC should have properly 503 * should only lower the priority, the MPIC should have properly
397 * latched another edge interrupt coming in anyway 504 * latched another edge interrupt coming in anyway
@@ -400,8 +507,9 @@ static void mpic_end_irq(unsigned int irq)
400#ifdef CONFIG_MPIC_BROKEN_U3 507#ifdef CONFIG_MPIC_BROKEN_U3
401 if (mpic->flags & MPIC_BROKEN_U3) { 508 if (mpic->flags & MPIC_BROKEN_U3) {
402 unsigned int src = irq - mpic->irq_offset; 509 unsigned int src = irq - mpic->irq_offset;
403 if (mpic_is_ht_interrupt(mpic, src)) 510 if (mpic_is_ht_interrupt(mpic, src) &&
404 mpic_apic_end_irq(mpic, src); 511 (irq_desc[irq].status & IRQ_LEVEL))
512 mpic_ht_end_irq(mpic, src);
405 } 513 }
406#endif /* CONFIG_MPIC_BROKEN_U3 */ 514#endif /* CONFIG_MPIC_BROKEN_U3 */
407 515
@@ -482,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
482 mpic->name = name; 590 mpic->name = name;
483 591
484 mpic->hc_irq.typename = name; 592 mpic->hc_irq.typename = name;
593 mpic->hc_irq.startup = mpic_startup_irq;
594 mpic->hc_irq.shutdown = mpic_shutdown_irq;
485 mpic->hc_irq.enable = mpic_enable_irq; 595 mpic->hc_irq.enable = mpic_enable_irq;
486 mpic->hc_irq.disable = mpic_disable_irq; 596 mpic->hc_irq.disable = mpic_disable_irq;
487 mpic->hc_irq.end = mpic_end_irq; 597 mpic->hc_irq.end = mpic_end_irq;
@@ -650,10 +760,10 @@ void __init mpic_init(struct mpic *mpic)
650 mpic->irq_count = mpic->num_sources; 760 mpic->irq_count = mpic->num_sources;
651 761
652#ifdef CONFIG_MPIC_BROKEN_U3 762#ifdef CONFIG_MPIC_BROKEN_U3
653 /* Do the ioapic fixups on U3 broken mpic */ 763 /* Do the HT PIC fixups on U3 broken mpic */
654 DBG("MPIC flags: %x\n", mpic->flags); 764 DBG("MPIC flags: %x\n", mpic->flags);
655 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 765 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
656 mpic_scan_ioapics(mpic); 766 mpic_scan_ht_pics(mpic);
657#endif /* CONFIG_MPIC_BROKEN_U3 */ 767#endif /* CONFIG_MPIC_BROKEN_U3 */
658 768
659 for (i = 0; i < mpic->num_sources; i++) { 769 for (i = 0; i < mpic->num_sources; i++) {
@@ -840,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
840 950
841 BUG_ON(mpic == NULL); 951 BUG_ON(mpic == NULL);
842 952
953#ifdef DEBUG_IPI
843 DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); 954 DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
955#endif
844 956
845 mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, 957 mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
846 mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 958 mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
@@ -851,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
851 u32 irq; 963 u32 irq;
852 964
853 irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; 965 irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
966#ifdef DEBUG_LOW
854 DBG("%s: get_one_irq(): %d\n", mpic->name, irq); 967 DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
855 968#endif
856 if (mpic->cascade && irq == mpic->cascade_vec) { 969 if (mpic->cascade && irq == mpic->cascade_vec) {
970#ifdef DEBUG_LOW
857 DBG("%s: cascading ...\n", mpic->name); 971 DBG("%s: cascading ...\n", mpic->name);
972#endif
858 irq = mpic->cascade(regs, mpic->cascade_data); 973 irq = mpic->cascade(regs, mpic->cascade_data);
859 mpic_eoi(mpic); 974 mpic_eoi(mpic);
860 return irq; 975 return irq;
861 } 976 }
862 if (unlikely(irq == MPIC_VEC_SPURRIOUS)) 977 if (unlikely(irq == MPIC_VEC_SPURRIOUS))
863 return -1; 978 return -1;
864 if (irq < MPIC_VEC_IPI_0) 979 if (irq < MPIC_VEC_IPI_0) {
980#ifdef DEBUG_IRQ
981 DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
982#endif
865 return irq + mpic->irq_offset; 983 return irq + mpic->irq_offset;
984 }
985#ifdef DEBUG_IPI
866 DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); 986 DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
987#endif
867 return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; 988 return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
868} 989}
869 990