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.c162
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
359static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, 367static 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
395static 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
431static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
432 unsigned int devfn)
433{
434 return;
435}
436#endif
437
380static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 438static 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
562static void mpic_unmask_irq(unsigned int irq) 621void 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
582static void mpic_mask_irq(unsigned int irq) 641void 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
603static void mpic_end_irq(unsigned int irq) 662void 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
736static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) 795int 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
1172void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1241void __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
1494static 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
1509static 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
1543static 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
1551static 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
1567device_initcall(mpic_init_sys);