aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-12-13 21:10:10 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 23:03:17 -0500
commit1beb6a7d6cbed3ac03500ce9b5b9bb632c512039 (patch)
tree727aa76da5a82fca449dadf3cebbadc414ad6555 /arch/powerpc/sysdev/mpic.c
parentcd0c7f06803be06a5cf4564aa5a900f4b6aea603 (diff)
[PATCH] powerpc: Experimental support for new G5 Macs (#2)
This adds some very basic support for the new machines, including the Quad G5 (tested), and other new dual core based machines and iMac G5 iSight (untested). This is still experimental ! There is no thermal control yet, there is no proper handing of MSIs, etc.. but it boots, I have all 4 cores up on my machine. Compared to the previous version of this patch, this one adds DART IOMMU support for the U4 chipset and thus should work fine on setups with more than 2Gb of RAM. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c199
1 files changed, 160 insertions, 39 deletions
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