]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/acpi/boot.c
x86: fix C1E && nx6325 stability problem
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / acpi / boot.c
index 276ec058f68394ae00da5cd1426dfcb4080f2ad8..e1f01394b681ab71e61a00570d6c04285c0ca2ae 100644 (file)
@@ -83,6 +83,8 @@ int acpi_lapic;
 int acpi_ioapic;
 int acpi_strict;
 
+static int disable_irq0_through_ioapic __initdata;
+
 u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
 int acpi_skip_timer_override __initdata;
@@ -242,12 +244,19 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
 
 static void __cpuinit acpi_register_lapic(int id, u8 enabled)
 {
+       unsigned int ver = 0;
+
        if (!enabled) {
                ++disabled_cpus;
                return;
        }
 
-       generic_processor_info(id, 0);
+#ifdef CONFIG_X86_32
+       if (boot_cpu_physical_apicid != -1U)
+               ver = apic_version[boot_cpu_physical_apicid];
+#endif
+
+       generic_processor_info(id, ver);
 }
 
 static int __init
@@ -505,8 +514,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
         * Make sure all (legacy) PCI IRQs are set as level-triggered.
         */
        if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
-               extern void eisa_set_level_irq(unsigned int irq);
-
                if (triggering == ACPI_LEVEL_SENSITIVE)
                        eisa_set_level_irq(gsi);
        }
@@ -765,8 +772,13 @@ static void __init acpi_register_lapic_address(unsigned long address)
        mp_lapic_addr = address;
 
        set_fixmap_nocache(FIX_APIC_BASE, address);
-       if (boot_cpu_physical_apicid == -1U)
+       if (boot_cpu_physical_apicid == -1U) {
                boot_cpu_physical_apicid  = GET_APIC_ID(read_apic_id());
+#ifdef CONFIG_X86_32
+               apic_version[boot_cpu_physical_apicid] =
+                        GET_APIC_VERSION(apic_read(APIC_LVR));
+#endif
+       }
 }
 
 static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
@@ -848,7 +860,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
 #ifdef CONFIG_X86_IO_APIC
 #define MP_ISA_BUS             0
 
-#if defined(CONFIG_X86_ES7000) || defined(CONFIG_X86_GENERICARCH)
+#ifdef CONFIG_X86_ES7000
 extern int es7000_plat;
 #endif
 
@@ -948,10 +960,41 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
        nr_ioapics++;
 }
 
+static void assign_to_mp_irq(struct mp_config_intsrc *m,
+                                   struct mp_config_intsrc *mp_irq)
+{
+       memcpy(mp_irq, m, sizeof(struct mp_config_intsrc));
+}
+
+static int mp_irq_cmp(struct mp_config_intsrc *mp_irq,
+                               struct mp_config_intsrc *m)
+{
+       return memcmp(mp_irq, m, sizeof(struct mp_config_intsrc));
+}
+
+static void save_mp_irq(struct mp_config_intsrc *m)
+{
+       int i;
+
+       for (i = 0; i < mp_irq_entries; i++) {
+               if (!mp_irq_cmp(&mp_irqs[i], m))
+                       return;
+       }
+
+       assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
+       if (++mp_irq_entries == MAX_IRQ_SOURCES)
+               panic("Max # of irq sources exceeded!!\n");
+}
+
 void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
 {
-       int ioapic = -1;
-       int pin = -1;
+       int ioapic;
+       int pin;
+       struct mp_config_intsrc mp_irq;
+
+       /* Skip the 8254 timer interrupt (IRQ 0) if requested.  */
+       if (bus_irq == 0 && disable_irq0_through_ioapic)
+               return;
 
        /*
         * Convert 'gsi' to 'ioapic.pin'.
@@ -969,24 +1012,23 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
        if ((bus_irq == 0) && (trigger == 3))
                trigger = 1;
 
-       mp_irqs[mp_irq_entries].mp_type = MP_INTSRC;
-       mp_irqs[mp_irq_entries].mp_irqtype = mp_INT;
-       mp_irqs[mp_irq_entries].mp_irqflag = (trigger << 2) | polarity;
-       mp_irqs[mp_irq_entries].mp_srcbus = MP_ISA_BUS;
-       mp_irqs[mp_irq_entries].mp_srcbusirq = bus_irq; /* IRQ */
-       mp_irqs[mp_irq_entries].mp_dstapic =
-                       mp_ioapics[ioapic].mp_apicid;   /* APIC ID */
-       mp_irqs[mp_irq_entries].mp_dstirq = pin;        /* INTIN# */
-
-       if (++mp_irq_entries == MAX_IRQ_SOURCES)
-               panic("Max # of irq sources exceeded!!\n");
+       mp_irq.mp_type = MP_INTSRC;
+       mp_irq.mp_irqtype = mp_INT;
+       mp_irq.mp_irqflag = (trigger << 2) | polarity;
+       mp_irq.mp_srcbus = MP_ISA_BUS;
+       mp_irq.mp_srcbusirq = bus_irq;  /* IRQ */
+       mp_irq.mp_dstapic = mp_ioapics[ioapic].mp_apicid; /* APIC ID */
+       mp_irq.mp_dstirq = pin; /* INTIN# */
 
+       save_mp_irq(&mp_irq);
 }
 
 void __init mp_config_acpi_legacy_irqs(void)
 {
-       int i = 0;
-       int ioapic = -1;
+       int i;
+       int ioapic;
+       unsigned int dstapic;
+       struct mp_config_intsrc mp_irq;
 
 #if defined (CONFIG_MCA) || defined (CONFIG_EISA)
        /*
@@ -997,7 +1039,7 @@ void __init mp_config_acpi_legacy_irqs(void)
        set_bit(MP_ISA_BUS, mp_bus_not_pci);
        Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
 
-#if defined(CONFIG_X86_ES7000) || defined(CONFIG_X86_GENERICARCH)
+#ifdef CONFIG_X86_ES7000
        /*
         * Older generations of ES7000 have no legacy identity mappings
         */
@@ -1011,11 +1053,7 @@ void __init mp_config_acpi_legacy_irqs(void)
        ioapic = mp_find_ioapic(0);
        if (ioapic < 0)
                return;
-
-       mp_irqs[mp_irq_entries].mp_type = MP_INTSRC;
-       mp_irqs[mp_irq_entries].mp_irqflag = 0; /* Conforming */
-       mp_irqs[mp_irq_entries].mp_srcbus = MP_ISA_BUS;
-       mp_irqs[mp_irq_entries].mp_dstapic = mp_ioapics[ioapic].mp_apicid;
+       dstapic = mp_ioapics[ioapic].mp_apicid;
 
        /*
         * Use the default configuration for the IRQs 0-15.  Unless
@@ -1024,6 +1062,10 @@ void __init mp_config_acpi_legacy_irqs(void)
        for (i = 0; i < 16; i++) {
                int idx;
 
+               /* Skip the 8254 timer interrupt (IRQ 0) if requested.  */
+               if (i == 0 && disable_irq0_through_ioapic)
+                       continue;
+
                for (idx = 0; idx < mp_irq_entries; idx++) {
                        struct mp_config_intsrc *irq = mp_irqs + idx;
 
@@ -1033,9 +1075,8 @@ void __init mp_config_acpi_legacy_irqs(void)
                                break;
 
                        /* Do we already have a mapping for this IOAPIC pin */
-                       if ((irq->mp_dstapic ==
-                               mp_irqs[mp_irq_entries].mp_dstapic) &&
-                           (irq->mp_dstirq == i))
+                       if (irq->mp_dstapic == dstapic &&
+                           irq->mp_dstirq == i)
                                break;
                }
 
@@ -1044,12 +1085,15 @@ void __init mp_config_acpi_legacy_irqs(void)
                        continue;       /* IRQ already used */
                }
 
-               mp_irqs[mp_irq_entries].mp_irqtype = mp_INT;
-               mp_irqs[mp_irq_entries].mp_srcbusirq = i;       /* Identity mapped */
-               mp_irqs[mp_irq_entries].mp_dstirq = i;
+               mp_irq.mp_type = MP_INTSRC;
+               mp_irq.mp_irqflag = 0;  /* Conforming */
+               mp_irq.mp_srcbus = MP_ISA_BUS;
+               mp_irq.mp_dstapic = dstapic;
+               mp_irq.mp_irqtype = mp_INT;
+               mp_irq.mp_srcbusirq = i; /* Identity mapped */
+               mp_irq.mp_dstirq = i;
 
-               if (++mp_irq_entries == MAX_IRQ_SOURCES)
-                       panic("Max # of irq sources exceeded!!\n");
+               save_mp_irq(&mp_irq);
        }
 }
 
@@ -1154,6 +1198,32 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
        return gsi;
 }
 
+int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin,
+                       u32 gsi, int triggering, int polarity)
+{
+#ifdef CONFIG_X86_MPPARSE
+       struct mp_config_intsrc mp_irq;
+       int ioapic;
+
+       if (!acpi_ioapic)
+               return 0;
+
+       /* print the entry should happen on mptable identically */
+       mp_irq.mp_type = MP_INTSRC;
+       mp_irq.mp_irqtype = mp_INT;
+       mp_irq.mp_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
+                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
+       mp_irq.mp_srcbus = number;
+       mp_irq.mp_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
+       ioapic = mp_find_ioapic(gsi);
+       mp_irq.mp_dstapic = mp_ioapic_routing[ioapic].apic_id;
+       mp_irq.mp_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base;
+
+       save_mp_irq(&mp_irq);
+#endif
+       return 0;
+}
+
 /*
  * Parse IOAPIC related entries in MADT
  * returns 0 on success, < 0 on error
@@ -1303,8 +1373,6 @@ static void __init acpi_process_madt(void)
        return;
 }
 
-#ifdef __i386__
-
 static int __init disable_acpi_irq(const struct dmi_system_id *d)
 {
        if (!acpi_force) {
@@ -1354,6 +1422,28 @@ static int __init force_acpi_ht(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * Don't register any I/O APIC entries for the 8254 timer IRQ.
+ */
+static int __init
+dmi_disable_irq0_through_ioapic(const struct dmi_system_id *d)
+{
+       pr_notice("%s detected: disabling IRQ 0 through I/O APIC\n", d->ident);
+       disable_irq0_through_ioapic = 1;
+       return 0;
+}
+
+/*
+ * Force ignoring BIOS IRQ0 pin2 override
+ */
+static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
+{
+       pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
+       acpi_skip_timer_override = 1;
+       force_mask_ioapic_irq_2();
+       return 0;
+}
+
 /*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact acpi-devel@sourceforge.net
@@ -1521,11 +1611,61 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
                     },
         },
+       /*
+        * HP laptops which use a DSDT reporting as HP/SB400/10000,
+        * which includes some code which overrides all temperature
+        * trip points to 16C if the INTIN2 input of the I/O APIC
+        * is enabled.  This input is incorrectly designated the
+        * ISA IRQ 0 via an interrupt source override even though
+        * it is wired to the output of the master 8259A and INTIN0
+        * is not connected at all.  Abandon any attempts to route
+        * IRQ 0 through the I/O APIC therefore.
+        */
+       {
+        .callback = dmi_disable_irq0_through_ioapic,
+        .ident = "HP NX6125 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
+                    },
+        },
+       {
+        .callback = dmi_disable_irq0_through_ioapic,
+        .ident = "HP NX6325 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+                    },
+        },
+       /*
+        * HP laptops which use a DSDT reporting as HP/SB400/10000,
+        * which includes some code which overrides all temperature
+        * trip points to 16C if the INTIN2 input of the I/O APIC
+        * is enabled.  This input is incorrectly designated the
+        * ISA IRQ 0 via an interrupt source override even though
+        * it is wired to the output of the master 8259A and INTIN0
+        * is not connected at all.  Force ignoring BIOS IRQ0 pin2
+        * override in that cases.
+        */
+       {
+        .callback = dmi_ignore_irq0_timer_override,
+        .ident = "HP NX6125 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
+                    },
+        },
+       {
+        .callback = dmi_ignore_irq0_timer_override,
+        .ident = "HP NX6325 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+                    },
+        },
        {}
 };
 
-#endif                         /* __i386__ */
-
 /*
  * acpi_boot_table_init() and acpi_boot_init()
  *  called from setup_arch(), always.
@@ -1553,9 +1693,7 @@ int __init acpi_boot_table_init(void)
 {
        int error;
 
-#ifdef __i386__
        dmi_check_system(acpi_dmi_table);
-#endif
 
        /*
         * If acpi_disabled, bail out
@@ -1680,6 +1818,20 @@ static int __init parse_pci(char *arg)
 }
 early_param("pci", parse_pci);
 
+int __init acpi_mps_check(void)
+{
+#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_X86_MPPARSE)
+/* mptable code is not built-in*/
+       if (acpi_disabled || acpi_noirq) {
+               printk(KERN_WARNING "MPS support code is not built-in.\n"
+                      "Using acpi=off or acpi=noirq or pci=noacpi "
+                      "may have problem\n");
+               return 1;
+       }
+#endif
+       return 0;
+}
+
 #ifdef CONFIG_X86_IO_APIC
 static int __init parse_acpi_skip_timer_override(char *arg)
 {