diff options
| author | Johannes Berg <johannes@sipsolutions.net> | 2007-05-02 02:33:41 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2007-05-07 06:31:13 -0400 |
| commit | 3669e930481d6dd510718279cd4bacb15ca3ae91 (patch) | |
| tree | e7b733835e934e0ad045d89dd7d9f3e6d23e762f | |
| parent | 71bf08b6c083df4ee97874d895f911529f4150dd (diff) | |
[POWERPC] MPIC sys_device & suspend/resume
This adds mpic to the system devices and implements suspend
and resume for them. This is necessary to get interrupts for
modules back to where they were before a suspend to disk.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/powerpc/sysdev/mpic.c | 96 | ||||
| -rw-r--r-- | include/asm-powerpc/mpic.h | 15 |
2 files changed, 110 insertions, 1 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 57b1208ef1c3..e88bbd5ec4c8 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
| @@ -354,6 +354,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
| 354 | tmp |= 0x22; | 354 | tmp |= 0x22; |
| 355 | writel(tmp, fixup->base + 4); | 355 | writel(tmp, fixup->base + 4); |
| 356 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 356 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
| 357 | |||
| 358 | #ifdef CONFIG_PM | ||
| 359 | /* use the lowest bit inverted to the actual HW, | ||
| 360 | * set if this fixup was enabled, clear otherwise */ | ||
| 361 | mpic->save_data[source].fixup_data = tmp | 1; | ||
| 362 | #endif | ||
| 357 | } | 363 | } |
| 358 | 364 | ||
| 359 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | 365 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, |
| @@ -375,6 +381,12 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
| 375 | tmp |= 1; | 381 | tmp |= 1; |
| 376 | writel(tmp, fixup->base + 4); | 382 | writel(tmp, fixup->base + 4); |
| 377 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 383 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
| 384 | |||
| 385 | #ifdef CONFIG_PM | ||
| 386 | /* use the lowest bit inverted to the actual HW, | ||
| 387 | * set if this fixup was enabled, clear otherwise */ | ||
| 388 | mpic->save_data[source].fixup_data = tmp & ~1; | ||
| 389 | #endif | ||
| 378 | } | 390 | } |
| 379 | 391 | ||
| 380 | static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, | 392 | static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, |
| @@ -1143,7 +1155,7 @@ void __init mpic_init(struct mpic *mpic) | |||
| 1143 | /* Do the HT PIC fixups on U3 broken mpic */ | 1155 | /* Do the HT PIC fixups on U3 broken mpic */ |
| 1144 | DBG("MPIC flags: %x\n", mpic->flags); | 1156 | DBG("MPIC flags: %x\n", mpic->flags); |
| 1145 | if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) | 1157 | if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) |
| 1146 | mpic_scan_ht_pics(mpic); | 1158 | mpic_scan_ht_pics(mpic); |
| 1147 | 1159 | ||
| 1148 | for (i = 0; i < mpic->num_sources; i++) { | 1160 | for (i = 0; i < mpic->num_sources; i++) { |
| 1149 | /* start with vector = source number, and masked */ | 1161 | /* start with vector = source number, and masked */ |
| @@ -1167,6 +1179,12 @@ void __init mpic_init(struct mpic *mpic) | |||
| 1167 | 1179 | ||
| 1168 | /* Set current processor priority to 0 */ | 1180 | /* Set current processor priority to 0 */ |
| 1169 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); | 1181 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); |
| 1182 | |||
| 1183 | #ifdef CONFIG_PM | ||
| 1184 | /* allocate memory to save mpic state */ | ||
| 1185 | mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save)); | ||
| 1186 | BUG_ON(mpic->save_data == NULL); | ||
| 1187 | #endif | ||
| 1170 | } | 1188 | } |
| 1171 | 1189 | ||
| 1172 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) | 1190 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) |
| @@ -1420,3 +1438,79 @@ void __devinit smp_mpic_setup_cpu(int cpu) | |||
| 1420 | mpic_setup_this_cpu(); | 1438 | mpic_setup_this_cpu(); |
| 1421 | } | 1439 | } |
| 1422 | #endif /* CONFIG_SMP */ | 1440 | #endif /* CONFIG_SMP */ |
| 1441 | |||
| 1442 | #ifdef CONFIG_PM | ||
| 1443 | static int mpic_suspend(struct sys_device *dev, pm_message_t state) | ||
| 1444 | { | ||
| 1445 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
| 1446 | int i; | ||
| 1447 | |||
| 1448 | for (i = 0; i < mpic->num_sources; i++) { | ||
| 1449 | mpic->save_data[i].vecprio = | ||
| 1450 | mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); | ||
| 1451 | mpic->save_data[i].dest = | ||
| 1452 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | return 0; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | static int mpic_resume(struct sys_device *dev) | ||
| 1459 | { | ||
| 1460 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
| 1461 | int i; | ||
| 1462 | |||
| 1463 | for (i = 0; i < mpic->num_sources; i++) { | ||
| 1464 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), | ||
| 1465 | mpic->save_data[i].vecprio); | ||
| 1466 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), | ||
| 1467 | mpic->save_data[i].dest); | ||
| 1468 | |||
| 1469 | #ifdef CONFIG_MPIC_U3_HT_IRQS | ||
| 1470 | { | ||
| 1471 | struct mpic_irq_fixup *fixup = &mpic->fixups[i]; | ||
| 1472 | |||
| 1473 | if (fixup->base) { | ||
| 1474 | /* we use the lowest bit in an inverted meaning */ | ||
| 1475 | if ((mpic->save_data[i].fixup_data & 1) == 0) | ||
| 1476 | continue; | ||
| 1477 | |||
| 1478 | /* Enable and configure */ | ||
| 1479 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | ||
| 1480 | |||
| 1481 | writel(mpic->save_data[i].fixup_data & ~1, | ||
| 1482 | fixup->base + 4); | ||
| 1483 | } | ||
| 1484 | } | ||
| 1485 | #endif | ||
| 1486 | } /* end for loop */ | ||
| 1487 | |||
| 1488 | return 0; | ||
| 1489 | } | ||
| 1490 | #endif | ||
| 1491 | |||
| 1492 | static struct sysdev_class mpic_sysclass = { | ||
| 1493 | #ifdef CONFIG_PM | ||
| 1494 | .resume = mpic_resume, | ||
| 1495 | .suspend = mpic_suspend, | ||
| 1496 | #endif | ||
| 1497 | set_kset_name("mpic"), | ||
| 1498 | }; | ||
| 1499 | |||
| 1500 | static int mpic_init_sys(void) | ||
| 1501 | { | ||
| 1502 | struct mpic *mpic = mpics; | ||
| 1503 | int error, id = 0; | ||
| 1504 | |||
| 1505 | error = sysdev_class_register(&mpic_sysclass); | ||
| 1506 | |||
| 1507 | while (mpic && !error) { | ||
| 1508 | mpic->sysdev.cls = &mpic_sysclass; | ||
| 1509 | mpic->sysdev.id = id++; | ||
| 1510 | error = sysdev_register(&mpic->sysdev); | ||
| 1511 | mpic = mpic->next; | ||
| 1512 | } | ||
| 1513 | return error; | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | device_initcall(mpic_init_sys); | ||
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index e4d5fc5362a0..22c85c4f5b29 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #ifdef __KERNEL__ | 3 | #ifdef __KERNEL__ |
| 4 | 4 | ||
| 5 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
| 6 | #include <linux/sysdev.h> | ||
| 6 | #include <asm/dcr.h> | 7 | #include <asm/dcr.h> |
| 7 | 8 | ||
| 8 | /* | 9 | /* |
| @@ -228,6 +229,14 @@ struct mpic_reg_bank { | |||
| 228 | #endif /* CONFIG_PPC_DCR */ | 229 | #endif /* CONFIG_PPC_DCR */ |
| 229 | }; | 230 | }; |
| 230 | 231 | ||
| 232 | struct mpic_irq_save { | ||
| 233 | u32 vecprio, | ||
| 234 | dest; | ||
| 235 | #ifdef CONFIG_MPIC_U3_HT_IRQS | ||
| 236 | u32 fixup_data; | ||
| 237 | #endif | ||
| 238 | }; | ||
| 239 | |||
| 231 | /* The instance data of a given MPIC */ | 240 | /* The instance data of a given MPIC */ |
| 232 | struct mpic | 241 | struct mpic |
| 233 | { | 242 | { |
| @@ -294,6 +303,12 @@ struct mpic | |||
| 294 | 303 | ||
| 295 | /* link */ | 304 | /* link */ |
| 296 | struct mpic *next; | 305 | struct mpic *next; |
| 306 | |||
| 307 | struct sys_device sysdev; | ||
| 308 | |||
| 309 | #ifdef CONFIG_PM | ||
| 310 | struct mpic_irq_save *save_data; | ||
| 311 | #endif | ||
| 297 | }; | 312 | }; |
| 298 | 313 | ||
| 299 | /* | 314 | /* |
