diff options
author | Yinghai Lu <yinghai@kernel.org> | 2008-11-16 06:12:49 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-17 11:57:34 -0500 |
commit | 569712b2b0970fa5b19673544d62ae661d04a220 (patch) | |
tree | 2bfd507fe1ab746115586d556ec9624d36d16337 /arch/x86/kernel/smpboot.c | |
parent | e14c8bf86350f6c39186a139c5c584a6111b2f01 (diff) |
x86: fix wakeup_cpu with numaq/es7000, v2
Impact: fix secondary-CPU wakeup/init path with numaq and es7000
While looking at wakeup_secondary_cpu for WAKE_SECONDARY_VIA_NMI:
|#ifdef WAKE_SECONDARY_VIA_NMI
|/*
| * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
| * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
| * won't ... remember to clear down the APIC, etc later.
| */
|static int __devinit
|wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
|{
| unsigned long send_status, accept_status = 0;
| int maxlvt;
|...
| if (APIC_INTEGRATED(apic_version[phys_apicid])) {
| maxlvt = lapic_get_maxlvt();
I noticed that there is no warning about undefined phys_apicid...
because WAKE_SECONDARY_VIA_NMI and WAKE_SECONDARY_VIA_INIT can not be
defined at the same time. So NUMAQ is using wrong wakeup_secondary_cpu.
WAKE_SECONDARY_VIA_NMI, WAKE_SECONDARY_VIA_INIT and
WAKE_SECONDARY_VIA_MIP are variants of a weird and fragile
preprocessor-driven "HAL" mechanisms to specify the kind of secondary-CPU
wakeup strategy a given x86 kernel will use.
The vast majority of systems want to use INIT for secondary wakeup - NUMAQ
uses an NMI, (old-style-) ES7000 uses 'MIP' (a firmware driven in-memory
flag to let secondaries continue).
So convert these mechanisms to x86_quirks and add a
->wakeup_secondary_cpu() method to specify the rare exception
to the sane default.
Extend genapic accordingly as well, for 32-bit.
While looking further, I noticed that functions in wakecup.h for numaq
and es7000 are different to the default in mach_wakecpu.h - but smpboot.c
will only use default mach_wakecpu.h with smphook.h.
So we need to add mach_wakecpu.h for mach_generic, to properly support
numaq and es7000, and vectorize the following SMP init methods:
int trampoline_phys_low;
int trampoline_phys_high;
void (*wait_for_init_deassert)(atomic_t *deassert);
void (*smp_callin_clear_local_apic)(void);
void (*store_NMI_vector)(unsigned short *high, unsigned short *low);
void (*restore_NMI_vector)(unsigned short *high, unsigned short *low);
void (*inquire_remote_apic)(int apicid);
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r-- | arch/x86/kernel/smpboot.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 7b1093397319..498c1ef37fe0 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/mtrr.h> | 62 | #include <asm/mtrr.h> |
63 | #include <asm/vmi.h> | 63 | #include <asm/vmi.h> |
64 | #include <asm/genapic.h> | 64 | #include <asm/genapic.h> |
65 | #include <asm/setup.h> | ||
65 | #include <linux/mc146818rtc.h> | 66 | #include <linux/mc146818rtc.h> |
66 | 67 | ||
67 | #include <mach_apic.h> | 68 | #include <mach_apic.h> |
@@ -536,7 +537,7 @@ static void impress_friends(void) | |||
536 | pr_debug("Before bogocount - setting activated=1.\n"); | 537 | pr_debug("Before bogocount - setting activated=1.\n"); |
537 | } | 538 | } |
538 | 539 | ||
539 | static inline void __inquire_remote_apic(int apicid) | 540 | void __inquire_remote_apic(int apicid) |
540 | { | 541 | { |
541 | unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; | 542 | unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; |
542 | char *names[] = { "ID", "VERSION", "SPIV" }; | 543 | char *names[] = { "ID", "VERSION", "SPIV" }; |
@@ -575,14 +576,13 @@ static inline void __inquire_remote_apic(int apicid) | |||
575 | } | 576 | } |
576 | } | 577 | } |
577 | 578 | ||
578 | #ifdef WAKE_SECONDARY_VIA_NMI | ||
579 | /* | 579 | /* |
580 | * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal | 580 | * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal |
581 | * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this | 581 | * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this |
582 | * won't ... remember to clear down the APIC, etc later. | 582 | * won't ... remember to clear down the APIC, etc later. |
583 | */ | 583 | */ |
584 | static int __devinit | 584 | int __devinit |
585 | wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) | 585 | wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip) |
586 | { | 586 | { |
587 | unsigned long send_status, accept_status = 0; | 587 | unsigned long send_status, accept_status = 0; |
588 | int maxlvt; | 588 | int maxlvt; |
@@ -599,7 +599,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) | |||
599 | * Give the other CPU some time to accept the IPI. | 599 | * Give the other CPU some time to accept the IPI. |
600 | */ | 600 | */ |
601 | udelay(200); | 601 | udelay(200); |
602 | if (APIC_INTEGRATED(apic_version[phys_apicid])) { | 602 | if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { |
603 | maxlvt = lapic_get_maxlvt(); | 603 | maxlvt = lapic_get_maxlvt(); |
604 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ | 604 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ |
605 | apic_write(APIC_ESR, 0); | 605 | apic_write(APIC_ESR, 0); |
@@ -614,11 +614,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) | |||
614 | 614 | ||
615 | return (send_status | accept_status); | 615 | return (send_status | accept_status); |
616 | } | 616 | } |
617 | #endif /* WAKE_SECONDARY_VIA_NMI */ | ||
618 | 617 | ||
619 | #ifdef WAKE_SECONDARY_VIA_INIT | ||
620 | static int __devinit | 618 | static int __devinit |
621 | wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) | 619 | wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip) |
622 | { | 620 | { |
623 | unsigned long send_status, accept_status = 0; | 621 | unsigned long send_status, accept_status = 0; |
624 | int maxlvt, num_starts, j; | 622 | int maxlvt, num_starts, j; |
@@ -737,7 +735,15 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) | |||
737 | 735 | ||
738 | return (send_status | accept_status); | 736 | return (send_status | accept_status); |
739 | } | 737 | } |
740 | #endif /* WAKE_SECONDARY_VIA_INIT */ | 738 | |
739 | static int __devinit | ||
740 | wakeup_secondary_cpu(int apicid, unsigned long start_eip) | ||
741 | { | ||
742 | if (x86_quirks->wakeup_secondary_cpu) | ||
743 | return x86_quirks->wakeup_secondary_cpu(apicid, start_eip); | ||
744 | |||
745 | return wakeup_secondary_cpu_via_init(apicid, start_eip); | ||
746 | } | ||
741 | 747 | ||
742 | struct create_idle { | 748 | struct create_idle { |
743 | struct work_struct work; | 749 | struct work_struct work; |