aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/acpi/boot.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2008-05-14 11:02:57 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-25 04:55:12 -0400
commit11113f84c72bd832dc4e76122e613b0e623e2346 (patch)
treea2c8f05d35cb41f6b14eae3908278af08902a31b /arch/x86/kernel/acpi/boot.c
parent32c5061265caf201d6a2c0d02181e2b68769c22c (diff)
x86: complete move ACPI from mpparse.c
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/acpi/boot.c')
-rw-r--r--arch/x86/kernel/acpi/boot.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 6f20fa92bbaf..b2ad09c4c6ae 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -846,6 +846,310 @@ static int __init acpi_parse_madt_lapic_entries(void)
846#endif /* CONFIG_X86_LOCAL_APIC */ 846#endif /* CONFIG_X86_LOCAL_APIC */
847 847
848#ifdef CONFIG_X86_IO_APIC 848#ifdef CONFIG_X86_IO_APIC
849#define MP_ISA_BUS 0
850
851#if defined(CONFIG_X86_ES7000) || defined(CONFIG_X86_GENERICARCH)
852extern int es7000_plat;
853#endif
854
855static struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
856
857static int mp_find_ioapic(int gsi)
858{
859 int i = 0;
860
861 /* Find the IOAPIC that manages this GSI. */
862 for (i = 0; i < nr_ioapics; i++) {
863 if ((gsi >= mp_ioapic_routing[i].gsi_base)
864 && (gsi <= mp_ioapic_routing[i].gsi_end))
865 return i;
866 }
867
868 printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
869 return -1;
870}
871
872static u8 __init uniq_ioapic_id(u8 id)
873{
874#ifdef CONFIG_X86_32
875 if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
876 !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
877 return io_apic_get_unique_id(nr_ioapics, id);
878 else
879 return id;
880#else
881 int i;
882 DECLARE_BITMAP(used, 256);
883 bitmap_zero(used, 256);
884 for (i = 0; i < nr_ioapics; i++) {
885 struct mpc_config_ioapic *ia = &mp_ioapics[i];
886 __set_bit(ia->mpc_apicid, used);
887 }
888 if (!test_bit(id, used))
889 return id;
890 return find_first_zero_bit(used, 256);
891#endif
892}
893
894static int bad_ioapic(unsigned long address)
895{
896 if (nr_ioapics >= MAX_IO_APICS) {
897 printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
898 "(found %d)\n", MAX_IO_APICS, nr_ioapics);
899 panic("Recompile kernel with bigger MAX_IO_APICS!\n");
900 }
901 if (!address) {
902 printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
903 " found in table, skipping!\n");
904 return 1;
905 }
906 return 0;
907}
908
909void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
910{
911 int idx = 0;
912
913 if (bad_ioapic(address))
914 return;
915
916 idx = nr_ioapics;
917
918 mp_ioapics[idx].mpc_type = MP_IOAPIC;
919 mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
920 mp_ioapics[idx].mpc_apicaddr = address;
921
922 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
923 mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
924#ifdef CONFIG_X86_32
925 mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
926#else
927 mp_ioapics[idx].mpc_apicver = 0;
928#endif
929 /*
930 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
931 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
932 */
933 mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
934 mp_ioapic_routing[idx].gsi_base = gsi_base;
935 mp_ioapic_routing[idx].gsi_end = gsi_base +
936 io_apic_get_redir_entries(idx);
937
938 printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
939 "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
940 mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
941 mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
942
943 nr_ioapics++;
944}
945
946void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
947{
948 int ioapic = -1;
949 int pin = -1;
950
951 /*
952 * Convert 'gsi' to 'ioapic.pin'.
953 */
954 ioapic = mp_find_ioapic(gsi);
955 if (ioapic < 0)
956 return;
957 pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
958
959 /*
960 * TBD: This check is for faulty timer entries, where the override
961 * erroneously sets the trigger to level, resulting in a HUGE
962 * increase of timer interrupts!
963 */
964 if ((bus_irq == 0) && (trigger == 3))
965 trigger = 1;
966
967 mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC;
968 mp_irqs[mp_irq_entries].mpc_irqtype = mp_INT;
969 mp_irqs[mp_irq_entries].mpc_irqflag = (trigger << 2) | polarity;
970 mp_irqs[mp_irq_entries].mpc_srcbus = MP_ISA_BUS;
971 mp_irqs[mp_irq_entries].mpc_srcbusirq = bus_irq; /* IRQ */
972 mp_irqs[mp_irq_entries].mpc_dstapic =
973 mp_ioapics[ioapic].mpc_apicid; /* APIC ID */
974 mp_irqs[mp_irq_entries].mpc_dstirq = pin; /* INTIN# */
975
976 if (++mp_irq_entries == MAX_IRQ_SOURCES)
977 panic("Max # of irq sources exceeded!!\n");
978
979}
980
981void __init mp_config_acpi_legacy_irqs(void)
982{
983 int i = 0;
984 int ioapic = -1;
985
986#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
987 /*
988 * Fabricate the legacy ISA bus (bus #31).
989 */
990 mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
991#endif
992 set_bit(MP_ISA_BUS, mp_bus_not_pci);
993 Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
994
995#if defined(CONFIG_X86_ES7000) || defined(CONFIG_X86_GENERICARCH)
996 /*
997 * Older generations of ES7000 have no legacy identity mappings
998 */
999 if (es7000_plat == 1)
1000 return;
1001#endif
1002
1003 /*
1004 * Locate the IOAPIC that manages the ISA IRQs (0-15).
1005 */
1006 ioapic = mp_find_ioapic(0);
1007 if (ioapic < 0)
1008 return;
1009
1010 mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC;
1011 mp_irqs[mp_irq_entries].mpc_irqflag = 0; /* Conforming */
1012 mp_irqs[mp_irq_entries].mpc_srcbus = MP_ISA_BUS;
1013#ifdef CONFIG_X86_IO_APIC
1014 mp_irqs[mp_irq_entries].mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
1015#endif
1016 /*
1017 * Use the default configuration for the IRQs 0-15. Unless
1018 * overridden by (MADT) interrupt source override entries.
1019 */
1020 for (i = 0; i < 16; i++) {
1021 int idx;
1022
1023 for (idx = 0; idx < mp_irq_entries; idx++) {
1024 struct mpc_config_intsrc *irq = mp_irqs + idx;
1025
1026 /* Do we already have a mapping for this ISA IRQ? */
1027 if (irq->mpc_srcbus == MP_ISA_BUS
1028 && irq->mpc_srcbusirq == i)
1029 break;
1030
1031 /* Do we already have a mapping for this IOAPIC pin */
1032 if ((irq->mpc_dstapic ==
1033 mp_irqs[mp_irq_entries].mpc_dstapic) &&
1034 (irq->mpc_dstirq == i))
1035 break;
1036 }
1037
1038 if (idx != mp_irq_entries) {
1039 printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
1040 continue; /* IRQ already used */
1041 }
1042
1043 mp_irqs[mp_irq_entries].mpc_irqtype = mp_INT;
1044 mp_irqs[mp_irq_entries].mpc_srcbusirq = i; /* Identity mapped */
1045 mp_irqs[mp_irq_entries].mpc_dstirq = i;
1046
1047 if (++mp_irq_entries == MAX_IRQ_SOURCES)
1048 panic("Max # of irq sources exceeded!!\n");
1049 }
1050}
1051
1052int mp_register_gsi(u32 gsi, int triggering, int polarity)
1053{
1054 int ioapic;
1055 int ioapic_pin;
1056#ifdef CONFIG_X86_32
1057#define MAX_GSI_NUM 4096
1058#define IRQ_COMPRESSION_START 64
1059
1060 static int pci_irq = IRQ_COMPRESSION_START;
1061 /*
1062 * Mapping between Global System Interrupts, which
1063 * represent all possible interrupts, and IRQs
1064 * assigned to actual devices.
1065 */
1066 static int gsi_to_irq[MAX_GSI_NUM];
1067#else
1068
1069 if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
1070 return gsi;
1071#endif
1072
1073 /* Don't set up the ACPI SCI because it's already set up */
1074 if (acpi_gbl_FADT.sci_interrupt == gsi)
1075 return gsi;
1076
1077 ioapic = mp_find_ioapic(gsi);
1078 if (ioapic < 0) {
1079 printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
1080 return gsi;
1081 }
1082
1083 ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
1084
1085#ifdef CONFIG_X86_32
1086 if (ioapic_renumber_irq)
1087 gsi = ioapic_renumber_irq(ioapic, gsi);
1088#endif
1089
1090 /*
1091 * Avoid pin reprogramming. PRTs typically include entries
1092 * with redundant pin->gsi mappings (but unique PCI devices);
1093 * we only program the IOAPIC on the first.
1094 */
1095 if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
1096 printk(KERN_ERR "Invalid reference to IOAPIC pin "
1097 "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
1098 ioapic_pin);
1099 return gsi;
1100 }
1101 if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
1102 Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
1103 mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
1104#ifdef CONFIG_X86_32
1105 return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]);
1106#else
1107 return gsi;
1108#endif
1109 }
1110
1111 set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed);
1112#ifdef CONFIG_X86_32
1113 /*
1114 * For GSI >= 64, use IRQ compression
1115 */
1116 if ((gsi >= IRQ_COMPRESSION_START)
1117 && (triggering == ACPI_LEVEL_SENSITIVE)) {
1118 /*
1119 * For PCI devices assign IRQs in order, avoiding gaps
1120 * due to unused I/O APIC pins.
1121 */
1122 int irq = gsi;
1123 if (gsi < MAX_GSI_NUM) {
1124 /*
1125 * Retain the VIA chipset work-around (gsi > 15), but
1126 * avoid a problem where the 8254 timer (IRQ0) is setup
1127 * via an override (so it's not on pin 0 of the ioapic),
1128 * and at the same time, the pin 0 interrupt is a PCI
1129 * type. The gsi > 15 test could cause these two pins
1130 * to be shared as IRQ0, and they are not shareable.
1131 * So test for this condition, and if necessary, avoid
1132 * the pin collision.
1133 */
1134 gsi = pci_irq++;
1135 /*
1136 * Don't assign IRQ used by ACPI SCI
1137 */
1138 if (gsi == acpi_gbl_FADT.sci_interrupt)
1139 gsi = pci_irq++;
1140 gsi_to_irq[irq] = gsi;
1141 } else {
1142 printk(KERN_ERR "GSI %u is too high\n", gsi);
1143 return gsi;
1144 }
1145 }
1146#endif
1147 io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
1148 triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
1149 polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
1150 return gsi;
1151}
1152
849/* 1153/*
850 * Parse IOAPIC related entries in MADT 1154 * Parse IOAPIC related entries in MADT
851 * returns 0 on success, < 0 on error 1155 * returns 0 on success, < 0 on error