Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / x86_64 / kernel / i8259.c
index c52b859..5ecd34a 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
+#include <linux/bitops.h>
 
 #include <asm/acpi.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/hw_irq.h>
-#include <asm/bitops.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
 
-#include <linux/irq.h>
-
 /*
  * Common place to define all x86 IRQ vectors
  *
@@ -130,13 +127,13 @@ 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)
 {
        if (irq > 256) { 
                char var;
-               printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, current->thread_info); 
+               printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current));
 
                BUG(); 
        }
@@ -148,7 +145,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)
 { 
@@ -157,14 +154,13 @@ static unsigned int startup_8259A_irq(unsigned int irq)
 }
 
 static struct hw_interrupt_type i8259A_irq_type = {
-       "XT-PIC",
-       startup_8259A_irq,
-       shutdown_8259A_irq,
-       enable_8259A_irq,
-       disable_8259A_irq,
-       mask_and_ack_8259A,
-       end_8259A_irq,
-       NULL
+       .typename = "XT-PIC",
+       .startup = startup_8259A_irq,
+       .shutdown = shutdown_8259A_irq,
+       .enable = enable_8259A_irq,
+       .disable = disable_8259A_irq,
+       .ack = mask_and_ack_8259A,
+       .end = end_8259A_irq,
 };
 
 /*
@@ -272,7 +268,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 +325,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 +338,7 @@ spurious_8259A_irq:
        }
 }
 
-void __init init_8259A(int auto_eoi)
+void init_8259A(int auto_eoi)
 {
        unsigned long flags;
 
@@ -385,6 +381,69 @@ 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 int i8259A_shutdown(struct sys_device *dev)
+{
+       /* Put the i8259A into a quiescent state that
+        * the kernel initialization code can get it
+        * out of.
+        */
+       outb(0xff, 0x21);       /* mask all of 8259A-1 */
+       outb(0xff, 0xA1);       /* mask all of 8259A-1 */
+       return 0;
+}
+
+static struct sysdev_class i8259_sysdev_class = {
+       set_kset_name("i8259"),
+       .suspend = i8259A_suspend,
+       .resume = i8259A_resume,
+       .shutdown = i8259A_shutdown,
+};
+
+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
  */
@@ -424,9 +483,19 @@ void spurious_interrupt(void);
 void error_interrupt(void);
 void reschedule_interrupt(void);
 void call_function_interrupt(void);
-void invalidate_interrupt(void);
-
-static void setup_timer(void)
+void invalidate_interrupt0(void);
+void invalidate_interrupt1(void);
+void invalidate_interrupt2(void);
+void invalidate_interrupt3(void);
+void invalidate_interrupt4(void);
+void invalidate_interrupt5(void);
+void invalidate_interrupt6(void);
+void invalidate_interrupt7(void);
+void thermal_interrupt(void);
+void threshold_interrupt(void);
+void i8254_timer_resume(void);
+
+static void setup_timer_hardware(void)
 {
        outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
        udelay(10);
@@ -437,12 +506,17 @@ static void setup_timer(void)
 
 static int timer_resume(struct sys_device *dev)
 {
-       setup_timer();
+       setup_timer_hardware();
        return 0;
 }
 
+void i8254_timer_resume(void)
+{
+       setup_timer_hardware();
+}
+
 static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer"),
+       set_kset_name("timer_pit"),
        .resume         = timer_resume,
 };
 
@@ -475,10 +549,9 @@ void __init init_IRQ(void)
                int vector = FIRST_EXTERNAL_VECTOR + i;
                if (i >= NR_IRQS)
                        break;
-               if (vector != IA32_SYSCALL_VECTOR && vector != KDB_VECTOR) { 
+               if (vector != IA32_SYSCALL_VECTOR)
                        set_intr_gate(vector, interrupt[i]);
        }
-       }
 
 #ifdef CONFIG_SMP
        /*
@@ -493,12 +566,21 @@ void __init init_IRQ(void)
         */
        set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
-       /* IPI for invalidation */
-       set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+       /* IPIs for invalidation */
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
 
        /* IPI for generic function call */
        set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 #endif 
+       set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+       set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* self generated IPI for local APIC timer */
@@ -513,7 +595,7 @@ void __init init_IRQ(void)
         * Set the clock to HZ Hz, we already have a valid
         * vector now:
         */
-       setup_timer();
+       setup_timer_hardware();
 
        if (!acpi_ioapic)
                setup_irq(2, &irq2);