diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 162 |
1 files changed, 155 insertions, 7 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 0b84b7c775d8..4fd2bec89916 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <asm/mpic.h> | 36 | #include <asm/mpic.h> |
37 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
38 | 38 | ||
39 | #include "mpic.h" | ||
40 | |||
39 | #ifdef DEBUG | 41 | #ifdef DEBUG |
40 | #define DBG(fmt...) printk(fmt) | 42 | #define DBG(fmt...) printk(fmt) |
41 | #else | 43 | #else |
@@ -354,6 +356,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
354 | tmp |= 0x22; | 356 | tmp |= 0x22; |
355 | writel(tmp, fixup->base + 4); | 357 | writel(tmp, fixup->base + 4); |
356 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 358 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
359 | |||
360 | #ifdef CONFIG_PM | ||
361 | /* use the lowest bit inverted to the actual HW, | ||
362 | * set if this fixup was enabled, clear otherwise */ | ||
363 | mpic->save_data[source].fixup_data = tmp | 1; | ||
364 | #endif | ||
357 | } | 365 | } |
358 | 366 | ||
359 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | 367 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, |
@@ -375,8 +383,58 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
375 | tmp |= 1; | 383 | tmp |= 1; |
376 | writel(tmp, fixup->base + 4); | 384 | writel(tmp, fixup->base + 4); |
377 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 385 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
386 | |||
387 | #ifdef CONFIG_PM | ||
388 | /* use the lowest bit inverted to the actual HW, | ||
389 | * set if this fixup was enabled, clear otherwise */ | ||
390 | mpic->save_data[source].fixup_data = tmp & ~1; | ||
391 | #endif | ||
378 | } | 392 | } |
379 | 393 | ||
394 | #ifdef CONFIG_PCI_MSI | ||
395 | static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, | ||
396 | unsigned int devfn) | ||
397 | { | ||
398 | u8 __iomem *base; | ||
399 | u8 pos, flags; | ||
400 | u64 addr = 0; | ||
401 | |||
402 | for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; | ||
403 | pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { | ||
404 | u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); | ||
405 | if (id == PCI_CAP_ID_HT) { | ||
406 | id = readb(devbase + pos + 3); | ||
407 | if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | if (pos == 0) | ||
413 | return; | ||
414 | |||
415 | base = devbase + pos; | ||
416 | |||
417 | flags = readb(base + HT_MSI_FLAGS); | ||
418 | if (!(flags & HT_MSI_FLAGS_FIXED)) { | ||
419 | addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; | ||
420 | addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); | ||
421 | } | ||
422 | |||
423 | printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%lx\n", | ||
424 | PCI_SLOT(devfn), PCI_FUNC(devfn), | ||
425 | flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); | ||
426 | |||
427 | if (!(flags & HT_MSI_FLAGS_ENABLE)) | ||
428 | writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); | ||
429 | } | ||
430 | #else | ||
431 | static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, | ||
432 | unsigned int devfn) | ||
433 | { | ||
434 | return; | ||
435 | } | ||
436 | #endif | ||
437 | |||
380 | static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, | 438 | static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, |
381 | unsigned int devfn, u32 vdid) | 439 | unsigned int devfn, u32 vdid) |
382 | { | 440 | { |
@@ -468,6 +526,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) | |||
468 | goto next; | 526 | goto next; |
469 | 527 | ||
470 | mpic_scan_ht_pic(mpic, devbase, devfn, l); | 528 | mpic_scan_ht_pic(mpic, devbase, devfn, l); |
529 | mpic_scan_ht_msi(mpic, devbase, devfn); | ||
471 | 530 | ||
472 | next: | 531 | next: |
473 | /* next device, if function 0 */ | 532 | /* next device, if function 0 */ |
@@ -559,7 +618,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id) | |||
559 | */ | 618 | */ |
560 | 619 | ||
561 | 620 | ||
562 | static void mpic_unmask_irq(unsigned int irq) | 621 | void mpic_unmask_irq(unsigned int irq) |
563 | { | 622 | { |
564 | unsigned int loops = 100000; | 623 | unsigned int loops = 100000; |
565 | struct mpic *mpic = mpic_from_irq(irq); | 624 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -579,7 +638,7 @@ static void mpic_unmask_irq(unsigned int irq) | |||
579 | } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); | 638 | } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); |
580 | } | 639 | } |
581 | 640 | ||
582 | static void mpic_mask_irq(unsigned int irq) | 641 | void mpic_mask_irq(unsigned int irq) |
583 | { | 642 | { |
584 | unsigned int loops = 100000; | 643 | unsigned int loops = 100000; |
585 | struct mpic *mpic = mpic_from_irq(irq); | 644 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -600,7 +659,7 @@ static void mpic_mask_irq(unsigned int irq) | |||
600 | } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); | 659 | } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); |
601 | } | 660 | } |
602 | 661 | ||
603 | static void mpic_end_irq(unsigned int irq) | 662 | void mpic_end_irq(unsigned int irq) |
604 | { | 663 | { |
605 | struct mpic *mpic = mpic_from_irq(irq); | 664 | struct mpic *mpic = mpic_from_irq(irq); |
606 | 665 | ||
@@ -733,7 +792,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) | |||
733 | } | 792 | } |
734 | } | 793 | } |
735 | 794 | ||
736 | static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | 795 | int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) |
737 | { | 796 | { |
738 | struct mpic *mpic = mpic_from_irq(virq); | 797 | struct mpic *mpic = mpic_from_irq(virq); |
739 | unsigned int src = mpic_irq_to_hw(virq); | 798 | unsigned int src = mpic_irq_to_hw(virq); |
@@ -834,6 +893,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
834 | if (hw >= mpic->irq_count) | 893 | if (hw >= mpic->irq_count) |
835 | return -EINVAL; | 894 | return -EINVAL; |
836 | 895 | ||
896 | mpic_msi_reserve_hwirq(mpic, hw); | ||
897 | |||
837 | /* Default chip */ | 898 | /* Default chip */ |
838 | chip = &mpic->hc_irq; | 899 | chip = &mpic->hc_irq; |
839 | 900 | ||
@@ -1142,8 +1203,10 @@ void __init mpic_init(struct mpic *mpic) | |||
1142 | 1203 | ||
1143 | /* Do the HT PIC fixups on U3 broken mpic */ | 1204 | /* Do the HT PIC fixups on U3 broken mpic */ |
1144 | DBG("MPIC flags: %x\n", mpic->flags); | 1205 | DBG("MPIC flags: %x\n", mpic->flags); |
1145 | if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) | 1206 | if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { |
1146 | mpic_scan_ht_pics(mpic); | 1207 | mpic_scan_ht_pics(mpic); |
1208 | mpic_u3msi_init(mpic); | ||
1209 | } | ||
1147 | 1210 | ||
1148 | for (i = 0; i < mpic->num_sources; i++) { | 1211 | for (i = 0; i < mpic->num_sources; i++) { |
1149 | /* start with vector = source number, and masked */ | 1212 | /* start with vector = source number, and masked */ |
@@ -1167,6 +1230,12 @@ void __init mpic_init(struct mpic *mpic) | |||
1167 | 1230 | ||
1168 | /* Set current processor priority to 0 */ | 1231 | /* Set current processor priority to 0 */ |
1169 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); | 1232 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); |
1233 | |||
1234 | #ifdef CONFIG_PM | ||
1235 | /* allocate memory to save mpic state */ | ||
1236 | mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save)); | ||
1237 | BUG_ON(mpic->save_data == NULL); | ||
1238 | #endif | ||
1170 | } | 1239 | } |
1171 | 1240 | ||
1172 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) | 1241 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) |
@@ -1333,8 +1402,11 @@ unsigned int mpic_get_one_irq(struct mpic *mpic) | |||
1333 | #ifdef DEBUG_LOW | 1402 | #ifdef DEBUG_LOW |
1334 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); | 1403 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); |
1335 | #endif | 1404 | #endif |
1336 | if (unlikely(src == mpic->spurious_vec)) | 1405 | if (unlikely(src == mpic->spurious_vec)) { |
1406 | if (mpic->flags & MPIC_SPV_EOI) | ||
1407 | mpic_eoi(mpic); | ||
1337 | return NO_IRQ; | 1408 | return NO_IRQ; |
1409 | } | ||
1338 | return irq_linear_revmap(mpic->irqhost, src); | 1410 | return irq_linear_revmap(mpic->irqhost, src); |
1339 | } | 1411 | } |
1340 | 1412 | ||
@@ -1417,3 +1489,79 @@ void __devinit smp_mpic_setup_cpu(int cpu) | |||
1417 | mpic_setup_this_cpu(); | 1489 | mpic_setup_this_cpu(); |
1418 | } | 1490 | } |
1419 | #endif /* CONFIG_SMP */ | 1491 | #endif /* CONFIG_SMP */ |
1492 | |||
1493 | #ifdef CONFIG_PM | ||
1494 | static int mpic_suspend(struct sys_device *dev, pm_message_t state) | ||
1495 | { | ||
1496 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
1497 | int i; | ||
1498 | |||
1499 | for (i = 0; i < mpic->num_sources; i++) { | ||
1500 | mpic->save_data[i].vecprio = | ||
1501 | mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); | ||
1502 | mpic->save_data[i].dest = | ||
1503 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); | ||
1504 | } | ||
1505 | |||
1506 | return 0; | ||
1507 | } | ||
1508 | |||
1509 | static int mpic_resume(struct sys_device *dev) | ||
1510 | { | ||
1511 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
1512 | int i; | ||
1513 | |||
1514 | for (i = 0; i < mpic->num_sources; i++) { | ||
1515 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), | ||
1516 | mpic->save_data[i].vecprio); | ||
1517 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), | ||
1518 | mpic->save_data[i].dest); | ||
1519 | |||
1520 | #ifdef CONFIG_MPIC_U3_HT_IRQS | ||
1521 | { | ||
1522 | struct mpic_irq_fixup *fixup = &mpic->fixups[i]; | ||
1523 | |||
1524 | if (fixup->base) { | ||
1525 | /* we use the lowest bit in an inverted meaning */ | ||
1526 | if ((mpic->save_data[i].fixup_data & 1) == 0) | ||
1527 | continue; | ||
1528 | |||
1529 | /* Enable and configure */ | ||
1530 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | ||
1531 | |||
1532 | writel(mpic->save_data[i].fixup_data & ~1, | ||
1533 | fixup->base + 4); | ||
1534 | } | ||
1535 | } | ||
1536 | #endif | ||
1537 | } /* end for loop */ | ||
1538 | |||
1539 | return 0; | ||
1540 | } | ||
1541 | #endif | ||
1542 | |||
1543 | static struct sysdev_class mpic_sysclass = { | ||
1544 | #ifdef CONFIG_PM | ||
1545 | .resume = mpic_resume, | ||
1546 | .suspend = mpic_suspend, | ||
1547 | #endif | ||
1548 | set_kset_name("mpic"), | ||
1549 | }; | ||
1550 | |||
1551 | static int mpic_init_sys(void) | ||
1552 | { | ||
1553 | struct mpic *mpic = mpics; | ||
1554 | int error, id = 0; | ||
1555 | |||
1556 | error = sysdev_class_register(&mpic_sysclass); | ||
1557 | |||
1558 | while (mpic && !error) { | ||
1559 | mpic->sysdev.cls = &mpic_sysclass; | ||
1560 | mpic->sysdev.id = id++; | ||
1561 | error = sysdev_register(&mpic->sysdev); | ||
1562 | mpic = mpic->next; | ||
1563 | } | ||
1564 | return error; | ||
1565 | } | ||
1566 | |||
1567 | device_initcall(mpic_init_sys); | ||