Commit 3669e930 authored by Johannes Berg's avatar Johannes Berg Committed by Paul Mackerras

[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: default avatarJohannes Berg <johannes@sipsolutions.net>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 71bf08b6
...@@ -354,6 +354,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, ...@@ -354,6 +354,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
tmp |= 0x22; tmp |= 0x22;
writel(tmp, fixup->base + 4); writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags); spin_unlock_irqrestore(&mpic->fixup_lock, flags);
#ifdef CONFIG_PM
/* use the lowest bit inverted to the actual HW,
* set if this fixup was enabled, clear otherwise */
mpic->save_data[source].fixup_data = tmp | 1;
#endif
} }
static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, 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,6 +381,12 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
tmp |= 1; tmp |= 1;
writel(tmp, fixup->base + 4); writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags); spin_unlock_irqrestore(&mpic->fixup_lock, flags);
#ifdef CONFIG_PM
/* use the lowest bit inverted to the actual HW,
* set if this fixup was enabled, clear otherwise */
mpic->save_data[source].fixup_data = tmp & ~1;
#endif
} }
static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
...@@ -1167,6 +1179,12 @@ void __init mpic_init(struct mpic *mpic) ...@@ -1167,6 +1179,12 @@ void __init mpic_init(struct mpic *mpic)
/* Set current processor priority to 0 */ /* Set current processor priority to 0 */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
#ifdef CONFIG_PM
/* allocate memory to save mpic state */
mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
BUG_ON(mpic->save_data == NULL);
#endif
} }
void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 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,3 +1438,79 @@ void __devinit smp_mpic_setup_cpu(int cpu)
mpic_setup_this_cpu(); mpic_setup_this_cpu();
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
#ifdef CONFIG_PM
static int mpic_suspend(struct sys_device *dev, pm_message_t state)
{
struct mpic *mpic = container_of(dev, struct mpic, sysdev);
int i;
for (i = 0; i < mpic->num_sources; i++) {
mpic->save_data[i].vecprio =
mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI));
mpic->save_data[i].dest =
mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
}
return 0;
}
static int mpic_resume(struct sys_device *dev)
{
struct mpic *mpic = container_of(dev, struct mpic, sysdev);
int i;
for (i = 0; i < mpic->num_sources; i++) {
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI),
mpic->save_data[i].vecprio);
mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
mpic->save_data[i].dest);
#ifdef CONFIG_MPIC_U3_HT_IRQS
{
struct mpic_irq_fixup *fixup = &mpic->fixups[i];
if (fixup->base) {
/* we use the lowest bit in an inverted meaning */
if ((mpic->save_data[i].fixup_data & 1) == 0)
continue;
/* Enable and configure */
writeb(0x10 + 2 * fixup->index, fixup->base + 2);
writel(mpic->save_data[i].fixup_data & ~1,
fixup->base + 4);
}
}
#endif
} /* end for loop */
return 0;
}
#endif
static struct sysdev_class mpic_sysclass = {
#ifdef CONFIG_PM
.resume = mpic_resume,
.suspend = mpic_suspend,
#endif
set_kset_name("mpic"),
};
static int mpic_init_sys(void)
{
struct mpic *mpic = mpics;
int error, id = 0;
error = sysdev_class_register(&mpic_sysclass);
while (mpic && !error) {
mpic->sysdev.cls = &mpic_sysclass;
mpic->sysdev.id = id++;
error = sysdev_register(&mpic->sysdev);
mpic = mpic->next;
}
return error;
}
device_initcall(mpic_init_sys);
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/sysdev.h>
#include <asm/dcr.h> #include <asm/dcr.h>
/* /*
...@@ -228,6 +229,14 @@ struct mpic_reg_bank { ...@@ -228,6 +229,14 @@ struct mpic_reg_bank {
#endif /* CONFIG_PPC_DCR */ #endif /* CONFIG_PPC_DCR */
}; };
struct mpic_irq_save {
u32 vecprio,
dest;
#ifdef CONFIG_MPIC_U3_HT_IRQS
u32 fixup_data;
#endif
};
/* The instance data of a given MPIC */ /* The instance data of a given MPIC */
struct mpic struct mpic
{ {
...@@ -294,6 +303,12 @@ struct mpic ...@@ -294,6 +303,12 @@ struct mpic
/* link */ /* link */
struct mpic *next; struct mpic *next;
struct sys_device sysdev;
#ifdef CONFIG_PM
struct mpic_irq_save *save_data;
#endif
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment