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.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