X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Fi8259.c;h=7873d9ba88146b5fc2231ccc62b5970ccf6ea656;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=c52b859c92173de45c874f9f6859bba8d6a3d658;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index c52b859c9..7873d9ba8 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -130,7 +130,7 @@ void (*interrupt[NR_IRQS])(void) = { * moves to arch independent land */ -spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(i8259A_lock); static void end_8259A_irq (unsigned int irq) { @@ -148,7 +148,7 @@ static void end_8259A_irq (unsigned int irq) #define shutdown_8259A_irq disable_8259A_irq -void mask_and_ack_8259A(unsigned int); +static void mask_and_ack_8259A(unsigned int); static unsigned int startup_8259A_irq(unsigned int irq) { @@ -272,7 +272,7 @@ static inline int i8259A_irq_real(unsigned int irq) * first, _then_ send the EOI, and the order of EOI * to the two 8259s is important! */ -void mask_and_ack_8259A(unsigned int irq) +static void mask_and_ack_8259A(unsigned int irq) { unsigned int irqmask = 1 << irq; unsigned long flags; @@ -329,7 +329,7 @@ spurious_8259A_irq: * lets ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { - printk("spurious 8259A interrupt: IRQ%d.\n", irq); + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } atomic_inc(&irq_err_count); @@ -342,7 +342,7 @@ spurious_8259A_irq: } } -void __init init_8259A(int auto_eoi) +void init_8259A(int auto_eoi) { unsigned long flags; @@ -385,6 +385,57 @@ void __init init_8259A(int auto_eoi) spin_unlock_irqrestore(&i8259A_lock, flags); } +static char irq_trigger[2]; +/** + * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ + */ +static void restore_ELCR(char *trigger) +{ + outb(trigger[0], 0x4d0); + outb(trigger[1], 0x4d1); +} + +static void save_ELCR(char *trigger) +{ + /* IRQ 0,1,2,8,13 are marked as reserved */ + trigger[0] = inb(0x4d0) & 0xF8; + trigger[1] = inb(0x4d1) & 0xDE; +} + +static int i8259A_resume(struct sys_device *dev) +{ + init_8259A(0); + restore_ELCR(irq_trigger); + return 0; +} + +static int i8259A_suspend(struct sys_device *dev, pm_message_t state) +{ + save_ELCR(irq_trigger); + return 0; +} + +static struct sysdev_class i8259_sysdev_class = { + set_kset_name("i8259"), + .suspend = i8259A_suspend, + .resume = i8259A_resume, +}; + +static struct sys_device device_i8259A = { + .id = 0, + .cls = &i8259_sysdev_class, +}; + +static int __init i8259A_init_sysfs(void) +{ + int error = sysdev_class_register(&i8259_sysdev_class); + if (!error) + error = sysdev_register(&device_i8259A); + return error; +} + +device_initcall(i8259A_init_sysfs); + /* * IRQ2 is cascade interrupt to second interrupt controller */ @@ -425,6 +476,8 @@ void error_interrupt(void); void reschedule_interrupt(void); void call_function_interrupt(void); void invalidate_interrupt(void); +void thermal_interrupt(void); +void i8254_timer_resume(void); static void setup_timer(void) { @@ -441,6 +494,11 @@ static int timer_resume(struct sys_device *dev) return 0; } +void i8254_timer_resume(void) +{ + setup_timer(); +} + static struct sysdev_class timer_sysclass = { set_kset_name("timer"), .resume = timer_resume, @@ -499,6 +557,7 @@ void __init init_IRQ(void) /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); #endif + set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); #ifdef CONFIG_X86_LOCAL_APIC /* self generated IPI for local APIC timer */