diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2005-10-30 17:59:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 20:37:13 -0500 |
commit | f2b36db692b7ff6972320ad9839ae656a3b0ee3e (patch) | |
tree | 110387d2557a156d6b9453ea0c45d392b47796c2 /arch/i386 | |
parent | 29b70081f7cb094513d5189e82d3478b50777a28 (diff) |
[PATCH] i386: move apic init in init_IRQs
All kinds of ugliness exists because we don't initialize
the apics during init_IRQs.
- We calibrate jiffies in non apic mode even when we are using apics.
- We have to have special code to initialize the apics when non-smp.
- The legacy i8259 must exist and be setup correctly, even
when we won't use it past initialization.
- The kexec on panic code must restore the state of the io_apics.
- init/main.c needs a special case for !smp smp_init on x86
In addition to pure code movement I needed a couple
of non-obvious changes:
- Move setup_boot_APIC_clock into APIC_late_time_init for
simplicity.
- Use cpu_khz to generate a better approximation of loops_per_jiffies
so I can verify the timer interrupt is working.
- Call setup_apic_nmi_watchdog again after cpu_khz is initialized on
the boot cpu.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/apic.c | 81 | ||||
-rw-r--r-- | arch/i386/kernel/i8259.c | 4 | ||||
-rw-r--r-- | arch/i386/kernel/io_apic.c | 6 | ||||
-rw-r--r-- | arch/i386/kernel/smpboot.c | 68 | ||||
-rw-r--r-- | arch/i386/kernel/time.c | 12 |
5 files changed, 100 insertions, 71 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 5546ddebec33..8d81b7bf7ad2 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -803,6 +803,7 @@ no_apic: | |||
803 | 803 | ||
804 | void __init init_apic_mappings(void) | 804 | void __init init_apic_mappings(void) |
805 | { | 805 | { |
806 | unsigned int orig_apicid; | ||
806 | unsigned long apic_phys; | 807 | unsigned long apic_phys; |
807 | 808 | ||
808 | /* | 809 | /* |
@@ -824,8 +825,11 @@ void __init init_apic_mappings(void) | |||
824 | * Fetch the APIC ID of the BSP in case we have a | 825 | * Fetch the APIC ID of the BSP in case we have a |
825 | * default configuration (or the MP table is broken). | 826 | * default configuration (or the MP table is broken). |
826 | */ | 827 | */ |
827 | if (boot_cpu_physical_apicid == -1U) | 828 | orig_apicid = boot_cpu_physical_apicid; |
828 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | 829 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); |
830 | if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid)) | ||
831 | printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)", | ||
832 | orig_apicid, boot_cpu_physical_apicid); | ||
829 | 833 | ||
830 | #ifdef CONFIG_X86_IO_APIC | 834 | #ifdef CONFIG_X86_IO_APIC |
831 | { | 835 | { |
@@ -1046,9 +1050,11 @@ static unsigned int calibration_result; | |||
1046 | 1050 | ||
1047 | void __init setup_boot_APIC_clock(void) | 1051 | void __init setup_boot_APIC_clock(void) |
1048 | { | 1052 | { |
1053 | unsigned long flags; | ||
1049 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); | 1054 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); |
1050 | using_apic_timer = 1; | 1055 | using_apic_timer = 1; |
1051 | 1056 | ||
1057 | local_irq_save(flags); | ||
1052 | local_irq_disable(); | 1058 | local_irq_disable(); |
1053 | 1059 | ||
1054 | calibration_result = calibrate_APIC_clock(); | 1060 | calibration_result = calibrate_APIC_clock(); |
@@ -1057,7 +1063,7 @@ void __init setup_boot_APIC_clock(void) | |||
1057 | */ | 1063 | */ |
1058 | setup_APIC_timer(calibration_result); | 1064 | setup_APIC_timer(calibration_result); |
1059 | 1065 | ||
1060 | local_irq_enable(); | 1066 | local_irq_restore(flags); |
1061 | } | 1067 | } |
1062 | 1068 | ||
1063 | void __devinit setup_secondary_APIC_clock(void) | 1069 | void __devinit setup_secondary_APIC_clock(void) |
@@ -1254,40 +1260,81 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) | |||
1254 | } | 1260 | } |
1255 | 1261 | ||
1256 | /* | 1262 | /* |
1257 | * This initializes the IO-APIC and APIC hardware if this is | 1263 | * This initializes the IO-APIC and APIC hardware. |
1258 | * a UP kernel. | ||
1259 | */ | 1264 | */ |
1260 | int __init APIC_init_uniprocessor (void) | 1265 | int __init APIC_init(void) |
1261 | { | 1266 | { |
1262 | if (enable_local_apic < 0) | 1267 | if (enable_local_apic < 0) { |
1263 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); | 1268 | printk(KERN_INFO "APIC disabled\n"); |
1269 | return -1; | ||
1270 | } | ||
1264 | 1271 | ||
1265 | if (!smp_found_config && !cpu_has_apic) | 1272 | /* See if we have a SMP configuration or have forced enabled |
1273 | * the local apic. | ||
1274 | */ | ||
1275 | if (!smp_found_config && !acpi_lapic && !cpu_has_apic) { | ||
1276 | enable_local_apic = -1; | ||
1266 | return -1; | 1277 | return -1; |
1278 | } | ||
1267 | 1279 | ||
1268 | /* | 1280 | /* |
1269 | * Complain if the BIOS pretends there is one. | 1281 | * Complain if the BIOS pretends there is an apic. |
1282 | * Then get out because we don't have an a local apic. | ||
1270 | */ | 1283 | */ |
1271 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { | 1284 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { |
1272 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | 1285 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", |
1273 | boot_cpu_physical_apicid); | 1286 | boot_cpu_physical_apicid); |
1287 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
1288 | enable_local_apic = -1; | ||
1274 | return -1; | 1289 | return -1; |
1275 | } | 1290 | } |
1276 | 1291 | ||
1277 | verify_local_APIC(); | 1292 | verify_local_APIC(); |
1278 | 1293 | ||
1294 | /* | ||
1295 | * Should not be necessary because the MP table should list the boot | ||
1296 | * CPU too, but we do it for the sake of robustness anyway. | ||
1297 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
1298 | */ | ||
1299 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
1300 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
1301 | boot_cpu_physical_apicid); | ||
1302 | physid_set(hard_smp_processor_id(), phys_cpu_present_map); | ||
1303 | } | ||
1304 | |||
1305 | /* | ||
1306 | * Switch from PIC to APIC mode. | ||
1307 | */ | ||
1279 | connect_bsp_APIC(); | 1308 | connect_bsp_APIC(); |
1309 | setup_local_APIC(); | ||
1280 | 1310 | ||
1281 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); | 1311 | #ifdef CONFIG_X86_IO_APIC |
1312 | /* | ||
1313 | * Now start the IO-APICs | ||
1314 | */ | ||
1315 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | ||
1316 | setup_IO_APIC(); | ||
1317 | #endif | ||
1318 | return 0; | ||
1319 | } | ||
1282 | 1320 | ||
1283 | setup_local_APIC(); | 1321 | void __init APIC_late_time_init(void) |
1322 | { | ||
1323 | /* Improve our loops per jiffy estimate */ | ||
1324 | loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz; | ||
1325 | boot_cpu_data.loops_per_jiffy = loops_per_jiffy; | ||
1326 | cpu_data[0].loops_per_jiffy = loops_per_jiffy; | ||
1327 | |||
1328 | /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is | ||
1329 | * initialized. So redo it here to ensure the boot cpu is setup | ||
1330 | * properly. | ||
1331 | */ | ||
1332 | if (nmi_watchdog == NMI_LOCAL_APIC) | ||
1333 | setup_apic_nmi_watchdog(); | ||
1284 | 1334 | ||
1285 | #ifdef CONFIG_X86_IO_APIC | 1335 | #ifdef CONFIG_X86_IO_APIC |
1286 | if (smp_found_config) | 1336 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) |
1287 | if (!skip_ioapic_setup && nr_ioapics) | 1337 | IO_APIC_late_time_init(); |
1288 | setup_IO_APIC(); | ||
1289 | #endif | 1338 | #endif |
1290 | setup_boot_APIC_clock(); | 1339 | setup_boot_APIC_clock(); |
1291 | |||
1292 | return 0; | ||
1293 | } | 1340 | } |
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index 323ef8ab3244..d86f24909284 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c | |||
@@ -435,4 +435,8 @@ void __init init_IRQ(void) | |||
435 | setup_irq(FPU_IRQ, &fpu_irq); | 435 | setup_irq(FPU_IRQ, &fpu_irq); |
436 | 436 | ||
437 | irq_ctx_init(smp_processor_id()); | 437 | irq_ctx_init(smp_processor_id()); |
438 | |||
439 | #ifdef CONFIG_X86_LOCAL_APIC | ||
440 | APIC_init(); | ||
441 | #endif | ||
438 | } | 442 | } |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index cc5d7ac5b2e7..5a77c52b20a9 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -2387,11 +2387,15 @@ void __init setup_IO_APIC(void) | |||
2387 | sync_Arb_IDs(); | 2387 | sync_Arb_IDs(); |
2388 | setup_IO_APIC_irqs(); | 2388 | setup_IO_APIC_irqs(); |
2389 | init_IO_APIC_traps(); | 2389 | init_IO_APIC_traps(); |
2390 | check_timer(); | ||
2391 | if (!acpi_ioapic) | 2390 | if (!acpi_ioapic) |
2392 | print_IO_APIC(); | 2391 | print_IO_APIC(); |
2393 | } | 2392 | } |
2394 | 2393 | ||
2394 | void __init IO_APIC_late_time_init(void) | ||
2395 | { | ||
2396 | check_timer(); | ||
2397 | } | ||
2398 | |||
2395 | /* | 2399 | /* |
2396 | * Called after all the initialization is done. If we didnt find any | 2400 | * Called after all the initialization is done. If we didnt find any |
2397 | * APIC bugs then we can allow the modify fast path | 2401 | * APIC bugs then we can allow the modify fast path |
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 01b618e73ecd..5a2bbe0c4fff 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
@@ -1078,6 +1078,16 @@ void *xquad_portio; | |||
1078 | EXPORT_SYMBOL(xquad_portio); | 1078 | EXPORT_SYMBOL(xquad_portio); |
1079 | #endif | 1079 | #endif |
1080 | 1080 | ||
1081 | /* | ||
1082 | * Fall back to non SMP mode after errors. | ||
1083 | * | ||
1084 | */ | ||
1085 | static __init void disable_smp(void) | ||
1086 | { | ||
1087 | cpu_set(0, cpu_sibling_map[0]); | ||
1088 | cpu_set(0, cpu_core_map[0]); | ||
1089 | } | ||
1090 | |||
1081 | static void __init smp_boot_cpus(unsigned int max_cpus) | 1091 | static void __init smp_boot_cpus(unsigned int max_cpus) |
1082 | { | 1092 | { |
1083 | int apicid, cpu, bit, kicked; | 1093 | int apicid, cpu, bit, kicked; |
@@ -1090,7 +1100,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1090 | printk("CPU%d: ", 0); | 1100 | printk("CPU%d: ", 0); |
1091 | print_cpu_info(&cpu_data[0]); | 1101 | print_cpu_info(&cpu_data[0]); |
1092 | 1102 | ||
1093 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | ||
1094 | boot_cpu_logical_apicid = logical_smp_processor_id(); | 1103 | boot_cpu_logical_apicid = logical_smp_processor_id(); |
1095 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; | 1104 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; |
1096 | 1105 | ||
@@ -1102,68 +1111,27 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1102 | cpus_clear(cpu_core_map[0]); | 1111 | cpus_clear(cpu_core_map[0]); |
1103 | cpu_set(0, cpu_core_map[0]); | 1112 | cpu_set(0, cpu_core_map[0]); |
1104 | 1113 | ||
1114 | map_cpu_to_logical_apicid(); | ||
1115 | |||
1105 | /* | 1116 | /* |
1106 | * If we couldn't find an SMP configuration at boot time, | 1117 | * If we couldn't find an SMP configuration at boot time, |
1107 | * get out of here now! | 1118 | * get out of here now! |
1108 | */ | 1119 | */ |
1109 | if (!smp_found_config && !acpi_lapic) { | 1120 | if (!smp_found_config && !acpi_lapic) { |
1110 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); | 1121 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); |
1111 | smpboot_clear_io_apic_irqs(); | 1122 | disable_smp(); |
1112 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1113 | if (APIC_init_uniprocessor()) | ||
1114 | printk(KERN_NOTICE "Local APIC not detected." | ||
1115 | " Using dummy APIC emulation.\n"); | ||
1116 | map_cpu_to_logical_apicid(); | ||
1117 | cpu_set(0, cpu_sibling_map[0]); | ||
1118 | cpu_set(0, cpu_core_map[0]); | ||
1119 | return; | ||
1120 | } | ||
1121 | |||
1122 | /* | ||
1123 | * Should not be necessary because the MP table should list the boot | ||
1124 | * CPU too, but we do it for the sake of robustness anyway. | ||
1125 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
1126 | */ | ||
1127 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
1128 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
1129 | boot_cpu_physical_apicid); | ||
1130 | physid_set(hard_smp_processor_id(), phys_cpu_present_map); | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * If we couldn't find a local APIC, then get out of here now! | ||
1135 | */ | ||
1136 | if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { | ||
1137 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | ||
1138 | boot_cpu_physical_apicid); | ||
1139 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
1140 | smpboot_clear_io_apic_irqs(); | ||
1141 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1142 | cpu_set(0, cpu_sibling_map[0]); | ||
1143 | cpu_set(0, cpu_core_map[0]); | ||
1144 | return; | 1123 | return; |
1145 | } | 1124 | } |
1146 | 1125 | ||
1147 | verify_local_APIC(); | ||
1148 | |||
1149 | /* | 1126 | /* |
1150 | * If SMP should be disabled, then really disable it! | 1127 | * If SMP should be disabled, then really disable it! |
1151 | */ | 1128 | */ |
1152 | if (!max_cpus) { | 1129 | if (!max_cpus || (enable_local_apic < 0)) { |
1153 | smp_found_config = 0; | 1130 | printk(KERN_INFO "SMP mode deactivated.\n"); |
1154 | printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); | 1131 | disable_smp(); |
1155 | smpboot_clear_io_apic_irqs(); | ||
1156 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1157 | cpu_set(0, cpu_sibling_map[0]); | ||
1158 | cpu_set(0, cpu_core_map[0]); | ||
1159 | return; | 1132 | return; |
1160 | } | 1133 | } |
1161 | 1134 | ||
1162 | connect_bsp_APIC(); | ||
1163 | setup_local_APIC(); | ||
1164 | map_cpu_to_logical_apicid(); | ||
1165 | |||
1166 | |||
1167 | setup_portio_remap(); | 1135 | setup_portio_remap(); |
1168 | 1136 | ||
1169 | /* | 1137 | /* |
@@ -1244,10 +1212,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1244 | cpu_set(0, cpu_sibling_map[0]); | 1212 | cpu_set(0, cpu_sibling_map[0]); |
1245 | cpu_set(0, cpu_core_map[0]); | 1213 | cpu_set(0, cpu_core_map[0]); |
1246 | 1214 | ||
1247 | smpboot_setup_io_apic(); | ||
1248 | |||
1249 | setup_boot_APIC_clock(); | ||
1250 | |||
1251 | /* | 1215 | /* |
1252 | * Synchronize the TSC with the AP | 1216 | * Synchronize the TSC with the AP |
1253 | */ | 1217 | */ |
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 2883a4d4f01f..46c35ec9137d 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -444,8 +444,8 @@ static int time_init_device(void) | |||
444 | 444 | ||
445 | device_initcall(time_init_device); | 445 | device_initcall(time_init_device); |
446 | 446 | ||
447 | #ifdef CONFIG_HPET_TIMER | ||
448 | extern void (*late_time_init)(void); | 447 | extern void (*late_time_init)(void); |
448 | #ifdef CONFIG_HPET_TIMER | ||
449 | /* Duplicate of time_init() below, with hpet_enable part added */ | 449 | /* Duplicate of time_init() below, with hpet_enable part added */ |
450 | static void __init hpet_time_init(void) | 450 | static void __init hpet_time_init(void) |
451 | { | 451 | { |
@@ -462,6 +462,11 @@ static void __init hpet_time_init(void) | |||
462 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 462 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
463 | 463 | ||
464 | time_init_hook(); | 464 | time_init_hook(); |
465 | |||
466 | #ifdef CONFIG_X86_LOCAL_APIC | ||
467 | if (enable_local_apic >= 0) | ||
468 | APIC_late_time_init(); | ||
469 | #endif | ||
465 | } | 470 | } |
466 | #endif | 471 | #endif |
467 | 472 | ||
@@ -486,4 +491,9 @@ void __init time_init(void) | |||
486 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 491 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
487 | 492 | ||
488 | time_init_hook(); | 493 | time_init_hook(); |
494 | |||
495 | #ifdef CONFIG_X86_LOCAL_APIC | ||
496 | if (enable_local_apic >= 0) | ||
497 | late_time_init = APIC_late_time_init; | ||
498 | #endif | ||
489 | } | 499 | } |