diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index d278736bf774..7f26c9a70a9e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -75,6 +75,13 @@ unsigned int max_physical_apicid; | |||
75 | physid_mask_t phys_cpu_present_map; | 75 | physid_mask_t phys_cpu_present_map; |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * Processor to be disabled specified by kernel parameter | ||
79 | * disable_cpu_apicid=<int>, mostly used for the kdump 2nd kernel to | ||
80 | * avoid undefined behaviour caused by sending INIT from AP to BSP. | ||
81 | */ | ||
82 | static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID; | ||
83 | |||
84 | /* | ||
78 | * Map cpu index to physical APIC ID | 85 | * Map cpu index to physical APIC ID |
79 | */ | 86 | */ |
80 | DEFINE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid, BAD_APICID); | 87 | DEFINE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid, BAD_APICID); |
@@ -1968,7 +1975,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs) | |||
1968 | */ | 1975 | */ |
1969 | static inline void __smp_error_interrupt(struct pt_regs *regs) | 1976 | static inline void __smp_error_interrupt(struct pt_regs *regs) |
1970 | { | 1977 | { |
1971 | u32 v0, v1; | 1978 | u32 v; |
1972 | u32 i = 0; | 1979 | u32 i = 0; |
1973 | static const char * const error_interrupt_reason[] = { | 1980 | static const char * const error_interrupt_reason[] = { |
1974 | "Send CS error", /* APIC Error Bit 0 */ | 1981 | "Send CS error", /* APIC Error Bit 0 */ |
@@ -1982,21 +1989,20 @@ static inline void __smp_error_interrupt(struct pt_regs *regs) | |||
1982 | }; | 1989 | }; |
1983 | 1990 | ||
1984 | /* First tickle the hardware, only then report what went on. -- REW */ | 1991 | /* First tickle the hardware, only then report what went on. -- REW */ |
1985 | v0 = apic_read(APIC_ESR); | ||
1986 | apic_write(APIC_ESR, 0); | 1992 | apic_write(APIC_ESR, 0); |
1987 | v1 = apic_read(APIC_ESR); | 1993 | v = apic_read(APIC_ESR); |
1988 | ack_APIC_irq(); | 1994 | ack_APIC_irq(); |
1989 | atomic_inc(&irq_err_count); | 1995 | atomic_inc(&irq_err_count); |
1990 | 1996 | ||
1991 | apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)", | 1997 | apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x", |
1992 | smp_processor_id(), v0 , v1); | 1998 | smp_processor_id(), v); |
1993 | 1999 | ||
1994 | v1 = v1 & 0xff; | 2000 | v &= 0xff; |
1995 | while (v1) { | 2001 | while (v) { |
1996 | if (v1 & 0x1) | 2002 | if (v & 0x1) |
1997 | apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); | 2003 | apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); |
1998 | i++; | 2004 | i++; |
1999 | v1 >>= 1; | 2005 | v >>= 1; |
2000 | } | 2006 | } |
2001 | 2007 | ||
2002 | apic_printk(APIC_DEBUG, KERN_CONT "\n"); | 2008 | apic_printk(APIC_DEBUG, KERN_CONT "\n"); |
@@ -2115,6 +2121,39 @@ int generic_processor_info(int apicid, int version) | |||
2115 | phys_cpu_present_map); | 2121 | phys_cpu_present_map); |
2116 | 2122 | ||
2117 | /* | 2123 | /* |
2124 | * boot_cpu_physical_apicid is designed to have the apicid | ||
2125 | * returned by read_apic_id(), i.e, the apicid of the | ||
2126 | * currently booting-up processor. However, on some platforms, | ||
2127 | * it is temporarily modified by the apicid reported as BSP | ||
2128 | * through MP table. Concretely: | ||
2129 | * | ||
2130 | * - arch/x86/kernel/mpparse.c: MP_processor_info() | ||
2131 | * - arch/x86/mm/amdtopology.c: amd_numa_init() | ||
2132 | * - arch/x86/platform/visws/visws_quirks.c: MP_processor_info() | ||
2133 | * | ||
2134 | * This function is executed with the modified | ||
2135 | * boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel | ||
2136 | * parameter doesn't work to disable APs on kdump 2nd kernel. | ||
2137 | * | ||
2138 | * Since fixing handling of boot_cpu_physical_apicid requires | ||
2139 | * another discussion and tests on each platform, we leave it | ||
2140 | * for now and here we use read_apic_id() directly in this | ||
2141 | * function, generic_processor_info(). | ||
2142 | */ | ||
2143 | if (disabled_cpu_apicid != BAD_APICID && | ||
2144 | disabled_cpu_apicid != read_apic_id() && | ||
2145 | disabled_cpu_apicid == apicid) { | ||
2146 | int thiscpu = num_processors + disabled_cpus; | ||
2147 | |||
2148 | pr_warning("APIC: Disabling requested cpu." | ||
2149 | " Processor %d/0x%x ignored.\n", | ||
2150 | thiscpu, apicid); | ||
2151 | |||
2152 | disabled_cpus++; | ||
2153 | return -ENODEV; | ||
2154 | } | ||
2155 | |||
2156 | /* | ||
2118 | * If boot cpu has not been detected yet, then only allow upto | 2157 | * If boot cpu has not been detected yet, then only allow upto |
2119 | * nr_cpu_ids - 1 processors and keep one slot free for boot cpu | 2158 | * nr_cpu_ids - 1 processors and keep one slot free for boot cpu |
2120 | */ | 2159 | */ |
@@ -2592,3 +2631,12 @@ static int __init lapic_insert_resource(void) | |||
2592 | * that is using request_resource | 2631 | * that is using request_resource |
2593 | */ | 2632 | */ |
2594 | late_initcall(lapic_insert_resource); | 2633 | late_initcall(lapic_insert_resource); |
2634 | |||
2635 | static int __init apic_set_disabled_cpu_apicid(char *arg) | ||
2636 | { | ||
2637 | if (!arg || !get_option(&arg, &disabled_cpu_apicid)) | ||
2638 | return -EINVAL; | ||
2639 | |||
2640 | return 0; | ||
2641 | } | ||
2642 | early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid); | ||