diff options
Diffstat (limited to 'arch/x86/kernel/acpi/boot.c')
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 407 |
1 files changed, 405 insertions, 2 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ff1a7b49a460..6516359922ba 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -83,6 +83,8 @@ int acpi_lapic; | |||
83 | int acpi_ioapic; | 83 | int acpi_ioapic; |
84 | int acpi_strict; | 84 | int acpi_strict; |
85 | 85 | ||
86 | static int disable_irq0_through_ioapic __initdata; | ||
87 | |||
86 | u8 acpi_sci_flags __initdata; | 88 | u8 acpi_sci_flags __initdata; |
87 | int acpi_sci_override_gsi __initdata; | 89 | int acpi_sci_override_gsi __initdata; |
88 | int acpi_skip_timer_override __initdata; | 90 | int acpi_skip_timer_override __initdata; |
@@ -338,8 +340,6 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e | |||
338 | 340 | ||
339 | #ifdef CONFIG_X86_IO_APIC | 341 | #ifdef CONFIG_X86_IO_APIC |
340 | 342 | ||
341 | struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS]; | ||
342 | |||
343 | static int __init | 343 | static int __init |
344 | acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) | 344 | acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) |
345 | { | 345 | { |
@@ -858,6 +858,372 @@ static int __init acpi_parse_madt_lapic_entries(void) | |||
858 | #endif /* CONFIG_X86_LOCAL_APIC */ | 858 | #endif /* CONFIG_X86_LOCAL_APIC */ |
859 | 859 | ||
860 | #ifdef CONFIG_X86_IO_APIC | 860 | #ifdef CONFIG_X86_IO_APIC |
861 | #define MP_ISA_BUS 0 | ||
862 | |||
863 | #ifdef CONFIG_X86_ES7000 | ||
864 | extern int es7000_plat; | ||
865 | #endif | ||
866 | |||
867 | static struct { | ||
868 | int apic_id; | ||
869 | int gsi_base; | ||
870 | int gsi_end; | ||
871 | DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); | ||
872 | } mp_ioapic_routing[MAX_IO_APICS]; | ||
873 | |||
874 | static int mp_find_ioapic(int gsi) | ||
875 | { | ||
876 | int i = 0; | ||
877 | |||
878 | /* Find the IOAPIC that manages this GSI. */ | ||
879 | for (i = 0; i < nr_ioapics; i++) { | ||
880 | if ((gsi >= mp_ioapic_routing[i].gsi_base) | ||
881 | && (gsi <= mp_ioapic_routing[i].gsi_end)) | ||
882 | return i; | ||
883 | } | ||
884 | |||
885 | printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); | ||
886 | return -1; | ||
887 | } | ||
888 | |||
889 | static u8 __init uniq_ioapic_id(u8 id) | ||
890 | { | ||
891 | #ifdef CONFIG_X86_32 | ||
892 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && | ||
893 | !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) | ||
894 | return io_apic_get_unique_id(nr_ioapics, id); | ||
895 | else | ||
896 | return id; | ||
897 | #else | ||
898 | int i; | ||
899 | DECLARE_BITMAP(used, 256); | ||
900 | bitmap_zero(used, 256); | ||
901 | for (i = 0; i < nr_ioapics; i++) { | ||
902 | struct mp_config_ioapic *ia = &mp_ioapics[i]; | ||
903 | __set_bit(ia->mp_apicid, used); | ||
904 | } | ||
905 | if (!test_bit(id, used)) | ||
906 | return id; | ||
907 | return find_first_zero_bit(used, 256); | ||
908 | #endif | ||
909 | } | ||
910 | |||
911 | static int bad_ioapic(unsigned long address) | ||
912 | { | ||
913 | if (nr_ioapics >= MAX_IO_APICS) { | ||
914 | printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " | ||
915 | "(found %d)\n", MAX_IO_APICS, nr_ioapics); | ||
916 | panic("Recompile kernel with bigger MAX_IO_APICS!\n"); | ||
917 | } | ||
918 | if (!address) { | ||
919 | printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" | ||
920 | " found in table, skipping!\n"); | ||
921 | return 1; | ||
922 | } | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | ||
927 | { | ||
928 | int idx = 0; | ||
929 | |||
930 | if (bad_ioapic(address)) | ||
931 | return; | ||
932 | |||
933 | idx = nr_ioapics; | ||
934 | |||
935 | mp_ioapics[idx].mp_type = MP_IOAPIC; | ||
936 | mp_ioapics[idx].mp_flags = MPC_APIC_USABLE; | ||
937 | mp_ioapics[idx].mp_apicaddr = address; | ||
938 | |||
939 | set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); | ||
940 | mp_ioapics[idx].mp_apicid = uniq_ioapic_id(id); | ||
941 | #ifdef CONFIG_X86_32 | ||
942 | mp_ioapics[idx].mp_apicver = io_apic_get_version(idx); | ||
943 | #else | ||
944 | mp_ioapics[idx].mp_apicver = 0; | ||
945 | #endif | ||
946 | /* | ||
947 | * Build basic GSI lookup table to facilitate gsi->io_apic lookups | ||
948 | * and to prevent reprogramming of IOAPIC pins (PCI GSIs). | ||
949 | */ | ||
950 | mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mp_apicid; | ||
951 | mp_ioapic_routing[idx].gsi_base = gsi_base; | ||
952 | mp_ioapic_routing[idx].gsi_end = gsi_base + | ||
953 | io_apic_get_redir_entries(idx); | ||
954 | |||
955 | printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, " | ||
956 | "GSI %d-%d\n", idx, mp_ioapics[idx].mp_apicid, | ||
957 | mp_ioapics[idx].mp_apicver, mp_ioapics[idx].mp_apicaddr, | ||
958 | mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end); | ||
959 | |||
960 | nr_ioapics++; | ||
961 | } | ||
962 | |||
963 | static void assign_to_mp_irq(struct mp_config_intsrc *m, | ||
964 | struct mp_config_intsrc *mp_irq) | ||
965 | { | ||
966 | memcpy(mp_irq, m, sizeof(struct mp_config_intsrc)); | ||
967 | } | ||
968 | |||
969 | static int mp_irq_cmp(struct mp_config_intsrc *mp_irq, | ||
970 | struct mp_config_intsrc *m) | ||
971 | { | ||
972 | return memcmp(mp_irq, m, sizeof(struct mp_config_intsrc)); | ||
973 | } | ||
974 | |||
975 | static void save_mp_irq(struct mp_config_intsrc *m) | ||
976 | { | ||
977 | int i; | ||
978 | |||
979 | for (i = 0; i < mp_irq_entries; i++) { | ||
980 | if (!mp_irq_cmp(&mp_irqs[i], m)) | ||
981 | return; | ||
982 | } | ||
983 | |||
984 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
985 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | ||
986 | panic("Max # of irq sources exceeded!!\n"); | ||
987 | } | ||
988 | |||
989 | void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) | ||
990 | { | ||
991 | int ioapic; | ||
992 | int pin; | ||
993 | struct mp_config_intsrc mp_irq; | ||
994 | |||
995 | /* Skip the 8254 timer interrupt (IRQ 0) if requested. */ | ||
996 | if (bus_irq == 0 && disable_irq0_through_ioapic) | ||
997 | return; | ||
998 | |||
999 | /* | ||
1000 | * Convert 'gsi' to 'ioapic.pin'. | ||
1001 | */ | ||
1002 | ioapic = mp_find_ioapic(gsi); | ||
1003 | if (ioapic < 0) | ||
1004 | return; | ||
1005 | pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
1006 | |||
1007 | /* | ||
1008 | * TBD: This check is for faulty timer entries, where the override | ||
1009 | * erroneously sets the trigger to level, resulting in a HUGE | ||
1010 | * increase of timer interrupts! | ||
1011 | */ | ||
1012 | if ((bus_irq == 0) && (trigger == 3)) | ||
1013 | trigger = 1; | ||
1014 | |||
1015 | mp_irq.mp_type = MP_INTSRC; | ||
1016 | mp_irq.mp_irqtype = mp_INT; | ||
1017 | mp_irq.mp_irqflag = (trigger << 2) | polarity; | ||
1018 | mp_irq.mp_srcbus = MP_ISA_BUS; | ||
1019 | mp_irq.mp_srcbusirq = bus_irq; /* IRQ */ | ||
1020 | mp_irq.mp_dstapic = mp_ioapics[ioapic].mp_apicid; /* APIC ID */ | ||
1021 | mp_irq.mp_dstirq = pin; /* INTIN# */ | ||
1022 | |||
1023 | save_mp_irq(&mp_irq); | ||
1024 | } | ||
1025 | |||
1026 | void __init mp_config_acpi_legacy_irqs(void) | ||
1027 | { | ||
1028 | int i; | ||
1029 | int ioapic; | ||
1030 | unsigned int dstapic; | ||
1031 | struct mp_config_intsrc mp_irq; | ||
1032 | |||
1033 | #if defined (CONFIG_MCA) || defined (CONFIG_EISA) | ||
1034 | /* | ||
1035 | * Fabricate the legacy ISA bus (bus #31). | ||
1036 | */ | ||
1037 | mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; | ||
1038 | #endif | ||
1039 | set_bit(MP_ISA_BUS, mp_bus_not_pci); | ||
1040 | Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); | ||
1041 | |||
1042 | #ifdef CONFIG_X86_ES7000 | ||
1043 | /* | ||
1044 | * Older generations of ES7000 have no legacy identity mappings | ||
1045 | */ | ||
1046 | if (es7000_plat == 1) | ||
1047 | return; | ||
1048 | #endif | ||
1049 | |||
1050 | /* | ||
1051 | * Locate the IOAPIC that manages the ISA IRQs (0-15). | ||
1052 | */ | ||
1053 | ioapic = mp_find_ioapic(0); | ||
1054 | if (ioapic < 0) | ||
1055 | return; | ||
1056 | dstapic = mp_ioapics[ioapic].mp_apicid; | ||
1057 | |||
1058 | /* | ||
1059 | * Use the default configuration for the IRQs 0-15. Unless | ||
1060 | * overridden by (MADT) interrupt source override entries. | ||
1061 | */ | ||
1062 | for (i = 0; i < 16; i++) { | ||
1063 | int idx; | ||
1064 | |||
1065 | /* Skip the 8254 timer interrupt (IRQ 0) if requested. */ | ||
1066 | if (i == 0 && disable_irq0_through_ioapic) | ||
1067 | continue; | ||
1068 | |||
1069 | for (idx = 0; idx < mp_irq_entries; idx++) { | ||
1070 | struct mp_config_intsrc *irq = mp_irqs + idx; | ||
1071 | |||
1072 | /* Do we already have a mapping for this ISA IRQ? */ | ||
1073 | if (irq->mp_srcbus == MP_ISA_BUS | ||
1074 | && irq->mp_srcbusirq == i) | ||
1075 | break; | ||
1076 | |||
1077 | /* Do we already have a mapping for this IOAPIC pin */ | ||
1078 | if (irq->mp_dstapic == dstapic && | ||
1079 | irq->mp_dstirq == i) | ||
1080 | break; | ||
1081 | } | ||
1082 | |||
1083 | if (idx != mp_irq_entries) { | ||
1084 | printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); | ||
1085 | continue; /* IRQ already used */ | ||
1086 | } | ||
1087 | |||
1088 | mp_irq.mp_type = MP_INTSRC; | ||
1089 | mp_irq.mp_irqflag = 0; /* Conforming */ | ||
1090 | mp_irq.mp_srcbus = MP_ISA_BUS; | ||
1091 | mp_irq.mp_dstapic = dstapic; | ||
1092 | mp_irq.mp_irqtype = mp_INT; | ||
1093 | mp_irq.mp_srcbusirq = i; /* Identity mapped */ | ||
1094 | mp_irq.mp_dstirq = i; | ||
1095 | |||
1096 | save_mp_irq(&mp_irq); | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | int mp_register_gsi(u32 gsi, int triggering, int polarity) | ||
1101 | { | ||
1102 | int ioapic; | ||
1103 | int ioapic_pin; | ||
1104 | #ifdef CONFIG_X86_32 | ||
1105 | #define MAX_GSI_NUM 4096 | ||
1106 | #define IRQ_COMPRESSION_START 64 | ||
1107 | |||
1108 | static int pci_irq = IRQ_COMPRESSION_START; | ||
1109 | /* | ||
1110 | * Mapping between Global System Interrupts, which | ||
1111 | * represent all possible interrupts, and IRQs | ||
1112 | * assigned to actual devices. | ||
1113 | */ | ||
1114 | static int gsi_to_irq[MAX_GSI_NUM]; | ||
1115 | #else | ||
1116 | |||
1117 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) | ||
1118 | return gsi; | ||
1119 | #endif | ||
1120 | |||
1121 | /* Don't set up the ACPI SCI because it's already set up */ | ||
1122 | if (acpi_gbl_FADT.sci_interrupt == gsi) | ||
1123 | return gsi; | ||
1124 | |||
1125 | ioapic = mp_find_ioapic(gsi); | ||
1126 | if (ioapic < 0) { | ||
1127 | printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); | ||
1128 | return gsi; | ||
1129 | } | ||
1130 | |||
1131 | ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
1132 | |||
1133 | #ifdef CONFIG_X86_32 | ||
1134 | if (ioapic_renumber_irq) | ||
1135 | gsi = ioapic_renumber_irq(ioapic, gsi); | ||
1136 | #endif | ||
1137 | |||
1138 | /* | ||
1139 | * Avoid pin reprogramming. PRTs typically include entries | ||
1140 | * with redundant pin->gsi mappings (but unique PCI devices); | ||
1141 | * we only program the IOAPIC on the first. | ||
1142 | */ | ||
1143 | if (ioapic_pin > MP_MAX_IOAPIC_PIN) { | ||
1144 | printk(KERN_ERR "Invalid reference to IOAPIC pin " | ||
1145 | "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, | ||
1146 | ioapic_pin); | ||
1147 | return gsi; | ||
1148 | } | ||
1149 | if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) { | ||
1150 | Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n", | ||
1151 | mp_ioapic_routing[ioapic].apic_id, ioapic_pin); | ||
1152 | #ifdef CONFIG_X86_32 | ||
1153 | return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]); | ||
1154 | #else | ||
1155 | return gsi; | ||
1156 | #endif | ||
1157 | } | ||
1158 | |||
1159 | set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed); | ||
1160 | #ifdef CONFIG_X86_32 | ||
1161 | /* | ||
1162 | * For GSI >= 64, use IRQ compression | ||
1163 | */ | ||
1164 | if ((gsi >= IRQ_COMPRESSION_START) | ||
1165 | && (triggering == ACPI_LEVEL_SENSITIVE)) { | ||
1166 | /* | ||
1167 | * For PCI devices assign IRQs in order, avoiding gaps | ||
1168 | * due to unused I/O APIC pins. | ||
1169 | */ | ||
1170 | int irq = gsi; | ||
1171 | if (gsi < MAX_GSI_NUM) { | ||
1172 | /* | ||
1173 | * Retain the VIA chipset work-around (gsi > 15), but | ||
1174 | * avoid a problem where the 8254 timer (IRQ0) is setup | ||
1175 | * via an override (so it's not on pin 0 of the ioapic), | ||
1176 | * and at the same time, the pin 0 interrupt is a PCI | ||
1177 | * type. The gsi > 15 test could cause these two pins | ||
1178 | * to be shared as IRQ0, and they are not shareable. | ||
1179 | * So test for this condition, and if necessary, avoid | ||
1180 | * the pin collision. | ||
1181 | */ | ||
1182 | gsi = pci_irq++; | ||
1183 | /* | ||
1184 | * Don't assign IRQ used by ACPI SCI | ||
1185 | */ | ||
1186 | if (gsi == acpi_gbl_FADT.sci_interrupt) | ||
1187 | gsi = pci_irq++; | ||
1188 | gsi_to_irq[irq] = gsi; | ||
1189 | } else { | ||
1190 | printk(KERN_ERR "GSI %u is too high\n", gsi); | ||
1191 | return gsi; | ||
1192 | } | ||
1193 | } | ||
1194 | #endif | ||
1195 | io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, | ||
1196 | triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, | ||
1197 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | ||
1198 | return gsi; | ||
1199 | } | ||
1200 | |||
1201 | int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, | ||
1202 | u32 gsi, int triggering, int polarity) | ||
1203 | { | ||
1204 | #ifdef CONFIG_X86_MPPARSE | ||
1205 | struct mp_config_intsrc mp_irq; | ||
1206 | int ioapic; | ||
1207 | |||
1208 | if (!acpi_ioapic) | ||
1209 | return 0; | ||
1210 | |||
1211 | /* print the entry should happen on mptable identically */ | ||
1212 | mp_irq.mp_type = MP_INTSRC; | ||
1213 | mp_irq.mp_irqtype = mp_INT; | ||
1214 | mp_irq.mp_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | | ||
1215 | (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); | ||
1216 | mp_irq.mp_srcbus = number; | ||
1217 | mp_irq.mp_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); | ||
1218 | ioapic = mp_find_ioapic(gsi); | ||
1219 | mp_irq.mp_dstapic = mp_ioapic_routing[ioapic].apic_id; | ||
1220 | mp_irq.mp_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
1221 | |||
1222 | save_mp_irq(&mp_irq); | ||
1223 | #endif | ||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
861 | /* | 1227 | /* |
862 | * Parse IOAPIC related entries in MADT | 1228 | * Parse IOAPIC related entries in MADT |
863 | * returns 0 on success, < 0 on error | 1229 | * returns 0 on success, < 0 on error |
@@ -1059,6 +1425,17 @@ static int __init force_acpi_ht(const struct dmi_system_id *d) | |||
1059 | } | 1425 | } |
1060 | 1426 | ||
1061 | /* | 1427 | /* |
1428 | * Don't register any I/O APIC entries for the 8254 timer IRQ. | ||
1429 | */ | ||
1430 | static int __init | ||
1431 | dmi_disable_irq0_through_ioapic(const struct dmi_system_id *d) | ||
1432 | { | ||
1433 | pr_notice("%s detected: disabling IRQ 0 through I/O APIC\n", d->ident); | ||
1434 | disable_irq0_through_ioapic = 1; | ||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1062 | * If your system is blacklisted here, but you find that acpi=force | 1439 | * If your system is blacklisted here, but you find that acpi=force |
1063 | * works for you, please contact acpi-devel@sourceforge.net | 1440 | * works for you, please contact acpi-devel@sourceforge.net |
1064 | */ | 1441 | */ |
@@ -1225,6 +1602,32 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = { | |||
1225 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), | 1602 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), |
1226 | }, | 1603 | }, |
1227 | }, | 1604 | }, |
1605 | /* | ||
1606 | * HP laptops which use a DSDT reporting as HP/SB400/10000, | ||
1607 | * which includes some code which overrides all temperature | ||
1608 | * trip points to 16C if the INTIN2 input of the I/O APIC | ||
1609 | * is enabled. This input is incorrectly designated the | ||
1610 | * ISA IRQ 0 via an interrupt source override even though | ||
1611 | * it is wired to the output of the master 8259A and INTIN0 | ||
1612 | * is not connected at all. Abandon any attempts to route | ||
1613 | * IRQ 0 through the I/O APIC therefore. | ||
1614 | */ | ||
1615 | { | ||
1616 | .callback = dmi_disable_irq0_through_ioapic, | ||
1617 | .ident = "HP NX6125 laptop", | ||
1618 | .matches = { | ||
1619 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1620 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"), | ||
1621 | }, | ||
1622 | }, | ||
1623 | { | ||
1624 | .callback = dmi_disable_irq0_through_ioapic, | ||
1625 | .ident = "HP NX6325 laptop", | ||
1626 | .matches = { | ||
1627 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1628 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), | ||
1629 | }, | ||
1630 | }, | ||
1228 | {} | 1631 | {} |
1229 | }; | 1632 | }; |
1230 | 1633 | ||