aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c247
1 files changed, 180 insertions, 67 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 58d1cc2023c8..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>
@@ -45,7 +48,11 @@ static struct mpic *mpic_primary;
45static DEFINE_SPINLOCK(mpic_lock); 48static DEFINE_SPINLOCK(mpic_lock);
46 49
47#ifdef CONFIG_PPC32 /* XXX for now */ 50#ifdef CONFIG_PPC32 /* XXX for now */
48#define distribute_irqs CONFIG_IRQ_ALL_CPUS 51#ifdef CONFIG_IRQ_ALL_CPUS
52#define distribute_irqs (1)
53#else
54#define distribute_irqs (0)
55#endif
49#endif 56#endif
50 57
51/* 58/*
@@ -164,70 +171,129 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
164/* 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)
165 * 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.
166 */ 173 */
167static 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)
168{ 175{
169 if (source_no >= 128 || !mpic->fixups) 176 if (source >= 128 || !mpic->fixups)
170 return 0; 177 return 0;
171 return mpic->fixups[source_no].base != NULL; 178 return mpic->fixups[source].base != NULL;
172} 179}
173 180
174static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) 181
182static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
175{ 183{
176 struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; 184 struct mpic_irq_fixup *fixup = &mpic->fixups[source];
177 u32 tmp;
178 185
179 spin_lock(&mpic->fixup_lock); 186 if (fixup->applebase) {
180 writeb(0x11 + 2 * fixup->irq, fixup->base); 187 unsigned int soff = (fixup->index >> 3) & ~3;
181 tmp = readl(fixup->base + 2); 188 unsigned int mask = 1U << (fixup->index & 0x1f);
182 writel(tmp | 0x80000000ul, fixup->base + 2); 189 writel(mask, fixup->applebase + soff);
183 /* config writes shouldn't be posted but let's be safe ... */ 190 } else {
184 (void)readl(fixup->base + 2); 191 spin_lock(&mpic->fixup_lock);
185 spin_unlock(&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 }
186} 196}
187 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;
188 204
189static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) 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)
190{ 223{
191 int i, irq; 224 struct mpic_irq_fixup *fixup = &mpic->fixups[source];
225 unsigned long flags;
192 u32 tmp; 226 u32 tmp;
193 227
194 printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); 228 if (fixup->base == NULL)
229 return;
195 230
196 for (i=0; i < 24; i++) { 231 DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
197 writeb(0x10 + 2*i, devbase + 0xf2); 232
198 tmp = readl(devbase + 0xf4); 233 /* Disable */
199 if ((tmp & 0x1) || !(tmp & 0x20)) 234 spin_lock_irqsave(&mpic->fixup_lock, flags);
200 continue; 235 writeb(0x10 + 2 * fixup->index, fixup->base + 2);
201 irq = (tmp >> 16) & 0xff; 236 tmp = readl(fixup->base + 4);
202 mpic->fixups[irq].irq = i; 237 tmp &= ~1U;
203 mpic->fixups[irq].base = devbase + 0xf2; 238 writel(tmp, fixup->base + 4);
204 } 239 spin_unlock_irqrestore(&mpic->fixup_lock, flags);
205} 240}
206 241
207static void __init mpic_amd8131_read_irq(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)
208{ 244{
209 int i, irq; 245 int i, irq, n;
246 u8 __iomem *base;
210 u32 tmp; 247 u32 tmp;
248 u8 pos;
249
250 for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
251 pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
252 u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
253 if (id == PCI_CAP_ID_HT_IRQCONF) {
254 id = readb(devbase + pos + 3);
255 if (id == 0x80)
256 break;
257 }
258 }
259 if (pos == 0)
260 return;
211 261
212 printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); 262 base = devbase + pos;
263 writeb(0x01, base + 2);
264 n = (readl(base + 4) >> 16) & 0xff;
213 265
214 for (i=0; i < 4; i++) { 266 printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x"
215 writeb(0x10 + 2*i, devbase + 0xba); 267 " has %d irqs\n",
216 tmp = readl(devbase + 0xbc); 268 devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
217 if ((tmp & 0x1) || !(tmp & 0x20)) 269
218 continue; 270 for (i = 0; i <= n; i++) {
271 writeb(0x10 + 2 * i, base + 2);
272 tmp = readl(base + 4);
219 irq = (tmp >> 16) & 0xff; 273 irq = (tmp >> 16) & 0xff;
220 mpic->fixups[irq].irq = i; 274 DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
221 mpic->fixups[irq].base = devbase + 0xba; 275 /* mask it , will be unmasked later */
276 tmp |= 0x1;
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;
222 } 287 }
223} 288}
224 289
225static void __init mpic_scan_ioapics(struct mpic *mpic) 290
291static void __init mpic_scan_ht_pics(struct mpic *mpic)
226{ 292{
227 unsigned int devfn; 293 unsigned int devfn;
228 u8 __iomem *cfgspace; 294 u8 __iomem *cfgspace;
229 295
230 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");
231 297
232 /* Allocate fixups array */ 298 /* Allocate fixups array */
233 mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); 299 mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
@@ -237,21 +303,20 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
237 /* Init spinlock */ 303 /* Init spinlock */
238 spin_lock_init(&mpic->fixup_lock); 304 spin_lock_init(&mpic->fixup_lock);
239 305
240 /* Map u3 config space. We assume all IO-APICs are on the primary bus 306 /* Map U3 config space. We assume all IO-APICs are on the primary bus
241 * and slot will never be above "0xf" so we only need to map 32k 307 * so we only need to map 64kB.
242 */ 308 */
243 cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); 309 cfgspace = ioremap(0xf2000000, 0x10000);
244 BUG_ON(cfgspace == NULL); 310 BUG_ON(cfgspace == NULL);
245 311
246 /* 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
247 * vendor ID and device ID only, that's plenty enough 313 * type, vendor ID and device ID only, that's plenty enough
248 */ 314 */
249 for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { 315 for (devfn = 0; devfn < 0x100; devfn++) {
250 u8 __iomem *devbase = cfgspace + (devfn << 8); 316 u8 __iomem *devbase = cfgspace + (devfn << 8);
251 u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 317 u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
252 u32 l = readl(devbase + PCI_VENDOR_ID); 318 u32 l = readl(devbase + PCI_VENDOR_ID);
253 u16 vendor_id, device_id; 319 u16 s;
254 int multifunc = 0;
255 320
256 DBG("devfn %x, l: %x\n", devfn, l); 321 DBG("devfn %x, l: %x\n", devfn, l);
257 322
@@ -259,22 +324,16 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
259 if (l == 0xffffffff || l == 0x00000000 || 324 if (l == 0xffffffff || l == 0x00000000 ||
260 l == 0x0000ffff || l == 0xffff0000) 325 l == 0x0000ffff || l == 0xffff0000)
261 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;
331
332 mpic_scan_ht_pic(mpic, devbase, devfn, l);
262 333
263 /* Check if it's a multifunction device (only really used
264 * to function 0 though
265 */
266 multifunc = !!(hdr_type & 0x80);
267 vendor_id = l & 0xffff;
268 device_id = (l >> 16) & 0xffff;
269
270 /* If a known device, go to fixup setup code */
271 if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460)
272 mpic_amd8111_read_irq(mpic, devbase);
273 if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450)
274 mpic_amd8131_read_irq(mpic, devbase);
275 next: 334 next:
276 /* next device, if function 0 */ 335 /* next device, if function 0 */
277 if ((PCI_FUNC(devfn) == 0) && !multifunc) 336 if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0)
278 devfn += 7; 337 devfn += 7;
279 } 338 }
280} 339}
@@ -371,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq)
371 break; 430 break;
372 } 431 }
373 } 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;
374} 458}
375 459
376static void mpic_disable_irq(unsigned int irq) 460static void mpic_disable_irq(unsigned int irq)
@@ -394,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq)
394 } 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));
395} 479}
396 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
397static void mpic_end_irq(unsigned int irq) 495static void mpic_end_irq(unsigned int irq)
398{ 496{
399 struct mpic *mpic = mpic_from_irq(irq); 497 struct mpic *mpic = mpic_from_irq(irq);
400 498
499#ifdef DEBUG_IRQ
401 DBG("%s: end_irq: %d\n", mpic->name, irq); 500 DBG("%s: end_irq: %d\n", mpic->name, irq);
402 501#endif
403 /* 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
404 * should only lower the priority, the MPIC should have properly 503 * should only lower the priority, the MPIC should have properly
405 * latched another edge interrupt coming in anyway 504 * latched another edge interrupt coming in anyway
@@ -408,8 +507,9 @@ static void mpic_end_irq(unsigned int irq)
408#ifdef CONFIG_MPIC_BROKEN_U3 507#ifdef CONFIG_MPIC_BROKEN_U3
409 if (mpic->flags & MPIC_BROKEN_U3) { 508 if (mpic->flags & MPIC_BROKEN_U3) {
410 unsigned int src = irq - mpic->irq_offset; 509 unsigned int src = irq - mpic->irq_offset;
411 if (mpic_is_ht_interrupt(mpic, src)) 510 if (mpic_is_ht_interrupt(mpic, src) &&
412 mpic_apic_end_irq(mpic, src); 511 (irq_desc[irq].status & IRQ_LEVEL))
512 mpic_ht_end_irq(mpic, src);
413 } 513 }
414#endif /* CONFIG_MPIC_BROKEN_U3 */ 514#endif /* CONFIG_MPIC_BROKEN_U3 */
415 515
@@ -490,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
490 mpic->name = name; 590 mpic->name = name;
491 591
492 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;
493 mpic->hc_irq.enable = mpic_enable_irq; 595 mpic->hc_irq.enable = mpic_enable_irq;
494 mpic->hc_irq.disable = mpic_disable_irq; 596 mpic->hc_irq.disable = mpic_disable_irq;
495 mpic->hc_irq.end = mpic_end_irq; 597 mpic->hc_irq.end = mpic_end_irq;
@@ -658,10 +760,10 @@ void __init mpic_init(struct mpic *mpic)
658 mpic->irq_count = mpic->num_sources; 760 mpic->irq_count = mpic->num_sources;
659 761
660#ifdef CONFIG_MPIC_BROKEN_U3 762#ifdef CONFIG_MPIC_BROKEN_U3
661 /* Do the ioapic fixups on U3 broken mpic */ 763 /* Do the HT PIC fixups on U3 broken mpic */
662 DBG("MPIC flags: %x\n", mpic->flags); 764 DBG("MPIC flags: %x\n", mpic->flags);
663 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 765 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
664 mpic_scan_ioapics(mpic); 766 mpic_scan_ht_pics(mpic);
665#endif /* CONFIG_MPIC_BROKEN_U3 */ 767#endif /* CONFIG_MPIC_BROKEN_U3 */
666 768
667 for (i = 0; i < mpic->num_sources; i++) { 769 for (i = 0; i < mpic->num_sources; i++) {
@@ -848,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
848 950
849 BUG_ON(mpic == NULL); 951 BUG_ON(mpic == NULL);
850 952
953#ifdef DEBUG_IPI
851 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
852 956
853 mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, 957 mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
854 mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 958 mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
@@ -859,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
859 u32 irq; 963 u32 irq;
860 964
861 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
862 DBG("%s: get_one_irq(): %d\n", mpic->name, irq); 967 DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
863 968#endif
864 if (mpic->cascade && irq == mpic->cascade_vec) { 969 if (mpic->cascade && irq == mpic->cascade_vec) {
970#ifdef DEBUG_LOW
865 DBG("%s: cascading ...\n", mpic->name); 971 DBG("%s: cascading ...\n", mpic->name);
972#endif
866 irq = mpic->cascade(regs, mpic->cascade_data); 973 irq = mpic->cascade(regs, mpic->cascade_data);
867 mpic_eoi(mpic); 974 mpic_eoi(mpic);
868 return irq; 975 return irq;
869 } 976 }
870 if (unlikely(irq == MPIC_VEC_SPURRIOUS)) 977 if (unlikely(irq == MPIC_VEC_SPURRIOUS))
871 return -1; 978 return -1;
872 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
873 return irq + mpic->irq_offset; 983 return irq + mpic->irq_offset;
984 }
985#ifdef DEBUG_IPI
874 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
875 return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; 988 return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
876} 989}
877 990