From 9f40a72a7e819789f66910c8cd60aab005cdb413 Mon Sep 17 00:00:00 2001 From: Natalie Protasevich Date: Sun, 30 Oct 2005 14:59:32 -0800 Subject: [PATCH] x86: hot plug CPU to support physical add of new processors The patch allows physical bring-up of new processors (not initially present in the configuration) from facilities such as driver/utility implemented on a platform. The actual method of making processors available is up to the platform implementation. Signed-off-by: Natalie Protasevich Cc: Shaohua Li Cc: Ashok Raj Cc: Zwane Mwaikambo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/smpboot.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/i386/kernel/smpboot.c') diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 1fb26d0e30b..01b618e73ec 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -87,7 +87,11 @@ EXPORT_SYMBOL(cpu_online_map); cpumask_t cpu_callin_map; cpumask_t cpu_callout_map; EXPORT_SYMBOL(cpu_callout_map); +#ifdef CONFIG_HOTPLUG_CPU +cpumask_t cpu_possible_map = CPU_MASK_ALL; +#else cpumask_t cpu_possible_map; +#endif EXPORT_SYMBOL(cpu_possible_map); static cpumask_t smp_commenced_mask; -- cgit v1.2.3-70-g09d2 From f2b36db692b7ff6972320ad9839ae656a3b0ee3e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 30 Oct 2005 14:59:41 -0800 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/apic.c | 81 +++++++++++++++++++++------ arch/i386/kernel/i8259.c | 4 ++ arch/i386/kernel/io_apic.c | 6 +- arch/i386/kernel/smpboot.c | 68 ++++++---------------- arch/i386/kernel/time.c | 12 +++- include/asm-i386/apic.h | 3 +- include/asm-i386/hw_irq.h | 1 + include/asm-i386/mach-default/smpboot_hooks.h | 15 ----- include/asm-i386/mach-visws/smpboot_hooks.h | 7 --- init/main.c | 11 ---- 10 files changed, 103 insertions(+), 105 deletions(-) (limited to 'arch/i386/kernel/smpboot.c') diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 5546ddebec3..8d81b7bf7ad 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -803,6 +803,7 @@ no_apic: void __init init_apic_mappings(void) { + unsigned int orig_apicid; unsigned long apic_phys; /* @@ -824,8 +825,11 @@ void __init init_apic_mappings(void) * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ - if (boot_cpu_physical_apicid == -1U) - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + orig_apicid = boot_cpu_physical_apicid; + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid)) + printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)", + orig_apicid, boot_cpu_physical_apicid); #ifdef CONFIG_X86_IO_APIC { @@ -1046,9 +1050,11 @@ static unsigned int calibration_result; void __init setup_boot_APIC_clock(void) { + unsigned long flags; apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); using_apic_timer = 1; + local_irq_save(flags); local_irq_disable(); calibration_result = calibrate_APIC_clock(); @@ -1057,7 +1063,7 @@ void __init setup_boot_APIC_clock(void) */ setup_APIC_timer(calibration_result); - local_irq_enable(); + local_irq_restore(flags); } void __devinit setup_secondary_APIC_clock(void) @@ -1254,40 +1260,81 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) } /* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. + * This initializes the IO-APIC and APIC hardware. */ -int __init APIC_init_uniprocessor (void) +int __init APIC_init(void) { - if (enable_local_apic < 0) - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); + if (enable_local_apic < 0) { + printk(KERN_INFO "APIC disabled\n"); + return -1; + } - if (!smp_found_config && !cpu_has_apic) + /* See if we have a SMP configuration or have forced enabled + * the local apic. + */ + if (!smp_found_config && !acpi_lapic && !cpu_has_apic) { + enable_local_apic = -1; return -1; + } /* - * Complain if the BIOS pretends there is one. + * Complain if the BIOS pretends there is an apic. + * Then get out because we don't have an a local apic. */ if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); + printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); + enable_local_apic = -1; return -1; } verify_local_APIC(); + /* + * Should not be necessary because the MP table should list the boot + * CPU too, but we do it for the sake of robustness anyway. + * Makes no sense to do this check in clustered apic mode, so skip it + */ + if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { + printk("weird, boot CPU (#%d) not listed by the BIOS.\n", + boot_cpu_physical_apicid); + physid_set(hard_smp_processor_id(), phys_cpu_present_map); + } + + /* + * Switch from PIC to APIC mode. + */ connect_bsp_APIC(); + setup_local_APIC(); - phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); +#ifdef CONFIG_X86_IO_APIC + /* + * Now start the IO-APICs + */ + if (smp_found_config && !skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +#endif + return 0; +} - setup_local_APIC(); +void __init APIC_late_time_init(void) +{ + /* Improve our loops per jiffy estimate */ + loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz; + boot_cpu_data.loops_per_jiffy = loops_per_jiffy; + cpu_data[0].loops_per_jiffy = loops_per_jiffy; + + /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is + * initialized. So redo it here to ensure the boot cpu is setup + * properly. + */ + if (nmi_watchdog == NMI_LOCAL_APIC) + setup_apic_nmi_watchdog(); #ifdef CONFIG_X86_IO_APIC - if (smp_found_config) - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); + if (smp_found_config && !skip_ioapic_setup && nr_ioapics) + IO_APIC_late_time_init(); #endif setup_boot_APIC_clock(); - - return 0; } diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index 323ef8ab324..d86f2490928 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -435,4 +435,8 @@ void __init init_IRQ(void) setup_irq(FPU_IRQ, &fpu_irq); irq_ctx_init(smp_processor_id()); + +#ifdef CONFIG_X86_LOCAL_APIC + APIC_init(); +#endif } diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index cc5d7ac5b2e..5a77c52b20a 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) sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); - check_timer(); if (!acpi_ioapic) print_IO_APIC(); } +void __init IO_APIC_late_time_init(void) +{ + check_timer(); +} + /* * Called after all the initialization is done. If we didnt find any * 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 01b618e73ec..5a2bbe0c4ff 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1078,6 +1078,16 @@ void *xquad_portio; EXPORT_SYMBOL(xquad_portio); #endif +/* + * Fall back to non SMP mode after errors. + * + */ +static __init void disable_smp(void) +{ + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); +} + static void __init smp_boot_cpus(unsigned int max_cpus) { int apicid, cpu, bit, kicked; @@ -1090,7 +1100,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) printk("CPU%d: ", 0); print_cpu_info(&cpu_data[0]); - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); boot_cpu_logical_apicid = logical_smp_processor_id(); x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; @@ -1102,68 +1111,27 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpus_clear(cpu_core_map[0]); cpu_set(0, cpu_core_map[0]); + map_cpu_to_logical_apicid(); + /* * If we couldn't find an SMP configuration at boot time, * get out of here now! */ if (!smp_found_config && !acpi_lapic) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); - smpboot_clear_io_apic_irqs(); - phys_cpu_present_map = physid_mask_of_physid(0); - if (APIC_init_uniprocessor()) - printk(KERN_NOTICE "Local APIC not detected." - " Using dummy APIC emulation.\n"); - map_cpu_to_logical_apicid(); - cpu_set(0, cpu_sibling_map[0]); - cpu_set(0, cpu_core_map[0]); - return; - } - - /* - * Should not be necessary because the MP table should list the boot - * CPU too, but we do it for the sake of robustness anyway. - * Makes no sense to do this check in clustered apic mode, so skip it - */ - if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { - printk("weird, boot CPU (#%d) not listed by the BIOS.\n", - boot_cpu_physical_apicid); - physid_set(hard_smp_processor_id(), phys_cpu_present_map); - } - - /* - * If we couldn't find a local APIC, then get out of here now! - */ - if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { - printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", - boot_cpu_physical_apicid); - printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); - smpboot_clear_io_apic_irqs(); - phys_cpu_present_map = physid_mask_of_physid(0); - cpu_set(0, cpu_sibling_map[0]); - cpu_set(0, cpu_core_map[0]); + disable_smp(); return; } - verify_local_APIC(); - /* * If SMP should be disabled, then really disable it! */ - if (!max_cpus) { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); - smpboot_clear_io_apic_irqs(); - phys_cpu_present_map = physid_mask_of_physid(0); - cpu_set(0, cpu_sibling_map[0]); - cpu_set(0, cpu_core_map[0]); + if (!max_cpus || (enable_local_apic < 0)) { + printk(KERN_INFO "SMP mode deactivated.\n"); + disable_smp(); return; } - connect_bsp_APIC(); - setup_local_APIC(); - map_cpu_to_logical_apicid(); - - setup_portio_remap(); /* @@ -1244,10 +1212,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpu_set(0, cpu_sibling_map[0]); cpu_set(0, cpu_core_map[0]); - smpboot_setup_io_apic(); - - setup_boot_APIC_clock(); - /* * Synchronize the TSC with the AP */ diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 2883a4d4f01..46c35ec9137 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -444,8 +444,8 @@ static int time_init_device(void) device_initcall(time_init_device); -#ifdef CONFIG_HPET_TIMER extern void (*late_time_init)(void); +#ifdef CONFIG_HPET_TIMER /* Duplicate of time_init() below, with hpet_enable part added */ static void __init hpet_time_init(void) { @@ -462,6 +462,11 @@ static void __init hpet_time_init(void) printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); time_init_hook(); + +#ifdef CONFIG_X86_LOCAL_APIC + if (enable_local_apic >= 0) + APIC_late_time_init(); +#endif } #endif @@ -486,4 +491,9 @@ void __init time_init(void) printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); time_init_hook(); + +#ifdef CONFIG_X86_LOCAL_APIC + if (enable_local_apic >= 0) + late_time_init = APIC_late_time_init; +#endif } diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 8c454aa58ac..a515e2aed82 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -118,7 +118,8 @@ extern void release_lapic_nmi(void); extern void disable_timer_nmi_watchdog(void); extern void enable_timer_nmi_watchdog(void); extern void nmi_watchdog_tick (struct pt_regs * regs); -extern int APIC_init_uniprocessor (void); +extern int APIC_init(void); +extern void APIC_late_time_init(void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 622815bf324..9139b89497a 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -55,6 +55,7 @@ void init_8259A(int aeoi); void FASTCALL(send_IPI_self(int vector)); void init_VISWS_APIC_irqs(void); void setup_IO_APIC(void); +void IO_APIC_late_time_init(void); void disable_IO_APIC(void); void print_IO_APIC(void); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); diff --git a/include/asm-i386/mach-default/smpboot_hooks.h b/include/asm-i386/mach-default/smpboot_hooks.h index 7f45f631105..d7c70c144f9 100644 --- a/include/asm-i386/mach-default/smpboot_hooks.h +++ b/include/asm-i386/mach-default/smpboot_hooks.h @@ -1,11 +1,6 @@ /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws * which needs to alter them. */ -static inline void smpboot_clear_io_apic_irqs(void) -{ - io_apic_irqs = 0; -} - static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { CMOS_WRITE(0xa, 0xf); @@ -32,13 +27,3 @@ static inline void smpboot_restore_warm_reset_vector(void) *((volatile long *) phys_to_virt(0x467)) = 0; } - -static inline void smpboot_setup_io_apic(void) -{ - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); -} diff --git a/include/asm-i386/mach-visws/smpboot_hooks.h b/include/asm-i386/mach-visws/smpboot_hooks.h index d926471fa35..14d8e0375f7 100644 --- a/include/asm-i386/mach-visws/smpboot_hooks.h +++ b/include/asm-i386/mach-visws/smpboot_hooks.h @@ -11,14 +11,7 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) /* for visws do nothing for any of these */ -static inline void smpboot_clear_io_apic_irqs(void) -{ -} - static inline void smpboot_restore_warm_reset_vector(void) { } -static inline void smpboot_setup_io_apic(void) -{ -} diff --git a/init/main.c b/init/main.c index f142d403534..4075d97e94b 100644 --- a/init/main.c +++ b/init/main.c @@ -64,10 +64,6 @@ #endif #endif -#ifdef CONFIG_X86_LOCAL_APIC -#include -#endif - /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -314,14 +310,7 @@ extern void setup_arch(char **); #ifndef CONFIG_SMP -#ifdef CONFIG_X86_LOCAL_APIC -static void __init smp_init(void) -{ - APIC_init_uniprocessor(); -} -#else #define smp_init() do { } while (0) -#endif static inline void setup_per_cpu_areas(void) { } static inline void smp_prepare_cpus(unsigned int maxcpus) { } -- cgit v1.2.3-70-g09d2 From 1e4c85f97fe26fbd70da12148b3992c0e00361fd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 31 Oct 2005 19:16:17 -0800 Subject: Revert "i386: move apic init in init_IRQs" Commit f2b36db692b7ff6972320ad9839ae656a3b0ee3e causes a bootup hang on at least one machine. Revert for now until we understand why. The old code may be ugly, but it works. Signed-off-by: Linus Torvalds --- arch/i386/kernel/apic.c | 77 ++++++--------------------- arch/i386/kernel/i8259.c | 4 -- arch/i386/kernel/io_apic.c | 6 +-- arch/i386/kernel/smpboot.c | 68 +++++++++++++++++------ arch/i386/kernel/time.c | 12 +---- include/asm-i386/apic.h | 3 +- include/asm-i386/hw_irq.h | 1 - include/asm-i386/mach-default/smpboot_hooks.h | 15 ++++++ include/asm-i386/mach-visws/smpboot_hooks.h | 7 +++ init/main.c | 11 ++++ 10 files changed, 104 insertions(+), 100 deletions(-) (limited to 'arch/i386/kernel/smpboot.c') diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 9204be6eedb..7c724ffa08b 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -803,7 +803,6 @@ no_apic: void __init init_apic_mappings(void) { - unsigned int orig_apicid; unsigned long apic_phys; /* @@ -825,11 +824,8 @@ void __init init_apic_mappings(void) * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ - orig_apicid = boot_cpu_physical_apicid; - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); - if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid)) - printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)", - orig_apicid, boot_cpu_physical_apicid); + if (boot_cpu_physical_apicid == -1U) + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); #ifdef CONFIG_X86_IO_APIC { @@ -1259,81 +1255,40 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) } /* - * This initializes the IO-APIC and APIC hardware. + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. */ -int __init APIC_init(void) +int __init APIC_init_uniprocessor (void) { - if (enable_local_apic < 0) { - printk(KERN_INFO "APIC disabled\n"); - return -1; - } + if (enable_local_apic < 0) + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); - /* See if we have a SMP configuration or have forced enabled - * the local apic. - */ - if (!smp_found_config && !acpi_lapic && !cpu_has_apic) { - enable_local_apic = -1; + if (!smp_found_config && !cpu_has_apic) return -1; - } /* - * Complain if the BIOS pretends there is an apic. - * Then get out because we don't have an a local apic. + * Complain if the BIOS pretends there is one. */ if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); - printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); - enable_local_apic = -1; return -1; } verify_local_APIC(); - /* - * Should not be necessary because the MP table should list the boot - * CPU too, but we do it for the sake of robustness anyway. - * Makes no sense to do this check in clustered apic mode, so skip it - */ - if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { - printk("weird, boot CPU (#%d) not listed by the BIOS.\n", - boot_cpu_physical_apicid); - physid_set(boot_cpu_physical_apicid, phys_cpu_present_map); - } - - /* - * Switch from PIC to APIC mode. - */ connect_bsp_APIC(); - setup_local_APIC(); -#ifdef CONFIG_X86_IO_APIC - /* - * Now start the IO-APICs - */ - if (smp_found_config && !skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); -#endif - return 0; -} + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); -void __init APIC_late_time_init(void) -{ - /* Improve our loops per jiffy estimate */ - loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz; - boot_cpu_data.loops_per_jiffy = loops_per_jiffy; - cpu_data[0].loops_per_jiffy = loops_per_jiffy; - - /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is - * initialized. So redo it here to ensure the boot cpu is setup - * properly. - */ - if (nmi_watchdog == NMI_LOCAL_APIC) - setup_apic_nmi_watchdog(); + setup_local_APIC(); #ifdef CONFIG_X86_IO_APIC - if (smp_found_config && !skip_ioapic_setup && nr_ioapics) - IO_APIC_late_time_init(); + if (smp_found_config) + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); #endif setup_boot_APIC_clock(); + + return 0; } diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d86f2490928..323ef8ab324 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -435,8 +435,4 @@ void __init init_IRQ(void) setup_irq(FPU_IRQ, &fpu_irq); irq_ctx_init(smp_processor_id()); - -#ifdef CONFIG_X86_LOCAL_APIC - APIC_init(); -#endif } diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5a77c52b20a..cc5d7ac5b2e 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2387,15 +2387,11 @@ void __init setup_IO_APIC(void) sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); + check_timer(); if (!acpi_ioapic) print_IO_APIC(); } -void __init IO_APIC_late_time_init(void) -{ - check_timer(); -} - /* * Called after all the initialization is done. If we didnt find any * 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 5a2bbe0c4ff..01b618e73ec 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1078,16 +1078,6 @@ void *xquad_portio; EXPORT_SYMBOL(xquad_portio); #endif -/* - * Fall back to non SMP mode after errors. - * - */ -static __init void disable_smp(void) -{ - cpu_set(0, cpu_sibling_map[0]); - cpu_set(0, cpu_core_map[0]); -} - static void __init smp_boot_cpus(unsigned int max_cpus) { int apicid, cpu, bit, kicked; @@ -1100,6 +1090,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) printk("CPU%d: ", 0); print_cpu_info(&cpu_data[0]); + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); boot_cpu_logical_apicid = logical_smp_processor_id(); x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; @@ -1111,27 +1102,68 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpus_clear(cpu_core_map[0]); cpu_set(0, cpu_core_map[0]); - map_cpu_to_logical_apicid(); - /* * If we couldn't find an SMP configuration at boot time, * get out of here now! */ if (!smp_found_config && !acpi_lapic) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); - disable_smp(); + smpboot_clear_io_apic_irqs(); + phys_cpu_present_map = physid_mask_of_physid(0); + if (APIC_init_uniprocessor()) + printk(KERN_NOTICE "Local APIC not detected." + " Using dummy APIC emulation.\n"); + map_cpu_to_logical_apicid(); + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); + return; + } + + /* + * Should not be necessary because the MP table should list the boot + * CPU too, but we do it for the sake of robustness anyway. + * Makes no sense to do this check in clustered apic mode, so skip it + */ + if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { + printk("weird, boot CPU (#%d) not listed by the BIOS.\n", + boot_cpu_physical_apicid); + physid_set(hard_smp_processor_id(), phys_cpu_present_map); + } + + /* + * If we couldn't find a local APIC, then get out of here now! + */ + if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_physical_apicid); + printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); + smpboot_clear_io_apic_irqs(); + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); return; } + verify_local_APIC(); + /* * If SMP should be disabled, then really disable it! */ - if (!max_cpus || (enable_local_apic < 0)) { - printk(KERN_INFO "SMP mode deactivated.\n"); - disable_smp(); + if (!max_cpus) { + smp_found_config = 0; + printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); + smpboot_clear_io_apic_irqs(); + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); return; } + connect_bsp_APIC(); + setup_local_APIC(); + map_cpu_to_logical_apicid(); + + setup_portio_remap(); /* @@ -1212,6 +1244,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpu_set(0, cpu_sibling_map[0]); cpu_set(0, cpu_core_map[0]); + smpboot_setup_io_apic(); + + setup_boot_APIC_clock(); + /* * Synchronize the TSC with the AP */ diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 07471bba2dc..41c5b2dc620 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -440,8 +440,8 @@ static int time_init_device(void) device_initcall(time_init_device); -extern void (*late_time_init)(void); #ifdef CONFIG_HPET_TIMER +extern void (*late_time_init)(void); /* Duplicate of time_init() below, with hpet_enable part added */ static void __init hpet_time_init(void) { @@ -458,11 +458,6 @@ static void __init hpet_time_init(void) printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); time_init_hook(); - -#ifdef CONFIG_X86_LOCAL_APIC - if (enable_local_apic >= 0) - APIC_late_time_init(); -#endif } #endif @@ -487,9 +482,4 @@ void __init time_init(void) printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); time_init_hook(); - -#ifdef CONFIG_X86_LOCAL_APIC - if (enable_local_apic >= 0) - late_time_init = APIC_late_time_init; -#endif } diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index a515e2aed82..8c454aa58ac 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -118,8 +118,7 @@ extern void release_lapic_nmi(void); extern void disable_timer_nmi_watchdog(void); extern void enable_timer_nmi_watchdog(void); extern void nmi_watchdog_tick (struct pt_regs * regs); -extern int APIC_init(void); -extern void APIC_late_time_init(void); +extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 9139b89497a..622815bf324 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -55,7 +55,6 @@ void init_8259A(int aeoi); void FASTCALL(send_IPI_self(int vector)); void init_VISWS_APIC_irqs(void); void setup_IO_APIC(void); -void IO_APIC_late_time_init(void); void disable_IO_APIC(void); void print_IO_APIC(void); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); diff --git a/include/asm-i386/mach-default/smpboot_hooks.h b/include/asm-i386/mach-default/smpboot_hooks.h index d7c70c144f9..7f45f631105 100644 --- a/include/asm-i386/mach-default/smpboot_hooks.h +++ b/include/asm-i386/mach-default/smpboot_hooks.h @@ -1,6 +1,11 @@ /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws * which needs to alter them. */ +static inline void smpboot_clear_io_apic_irqs(void) +{ + io_apic_irqs = 0; +} + static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { CMOS_WRITE(0xa, 0xf); @@ -27,3 +32,13 @@ static inline void smpboot_restore_warm_reset_vector(void) *((volatile long *) phys_to_virt(0x467)) = 0; } + +static inline void smpboot_setup_io_apic(void) +{ + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +} diff --git a/include/asm-i386/mach-visws/smpboot_hooks.h b/include/asm-i386/mach-visws/smpboot_hooks.h index 14d8e0375f7..d926471fa35 100644 --- a/include/asm-i386/mach-visws/smpboot_hooks.h +++ b/include/asm-i386/mach-visws/smpboot_hooks.h @@ -11,7 +11,14 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) /* for visws do nothing for any of these */ +static inline void smpboot_clear_io_apic_irqs(void) +{ +} + static inline void smpboot_restore_warm_reset_vector(void) { } +static inline void smpboot_setup_io_apic(void) +{ +} diff --git a/init/main.c b/init/main.c index 4075d97e94b..f142d403534 100644 --- a/init/main.c +++ b/init/main.c @@ -64,6 +64,10 @@ #endif #endif +#ifdef CONFIG_X86_LOCAL_APIC +#include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -310,7 +314,14 @@ extern void setup_arch(char **); #ifndef CONFIG_SMP +#ifdef CONFIG_X86_LOCAL_APIC +static void __init smp_init(void) +{ + APIC_init_uniprocessor(); +} +#else #define smp_init() do { } while (0) +#endif static inline void setup_per_cpu_areas(void) { } static inline void smp_prepare_cpus(unsigned int maxcpus) { } -- cgit v1.2.3-70-g09d2