x86: Fix APIC ID sizing bug on larger systems, clean up MAX_APICS confusion

Found one x2apic pre-enabled system, x2apic_mode suddenly get
corrupted after register some cpus, when compiled
CONFIG_NR_CPUS=255 instead of 512.

It turns out that generic_processor_info() ==> phyid_set(apicid,
phys_cpu_present_map) causes the problem.

phys_cpu_present_map is sized by MAX_APICS bits, and pre-enabled
system some cpus have an apic id > 255.

The variable after phys_cpu_present_map may get corrupted
silently:

 ffffffff828e8420 B phys_cpu_present_map
 ffffffff828e8440 B apic_verbosity
 ffffffff828e8444 B local_apic_timer_c2_ok
 ffffffff828e8448 B disable_apic
 ffffffff828e844c B x2apic_mode
 ffffffff828e8450 B x2apic_disabled
 ffffffff828e8454 B num_processors
 ...

Actually phys_cpu_present_map is referenced via apic id, instead
index. We should use MAX_LOCAL_APIC instead MAX_APICS.

For 64-bit it will be 32768 in all cases. BSS will increase by 4k bytes
on 64-bit:

	text		data		bss		dec		filename
	21696943	4193748		12787712	38678403	vmlinux.before
	21696943	4193748		12791808	38682499	vmlinux.after

No change on 32bit.

Finally we can remove MAX_APCIS that was rather confusing.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: H. Peter Anvin <hpa@linux.intel.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
LKML-Reference: <4D23BD9C.3070102@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Yinghai Lu 2011-01-04 16:38:52 -08:00 committed by Ingo Molnar
parent bc030d6cb9
commit cb2ded37fd
6 changed files with 19 additions and 32 deletions

View File

@ -5,6 +5,7 @@
#include <asm/mpspec_def.h> #include <asm/mpspec_def.h>
#include <asm/x86_init.h> #include <asm/x86_init.h>
#include <asm/apicdef.h>
extern int apic_version[]; extern int apic_version[];
extern int pic_mode; extern int pic_mode;
@ -107,7 +108,7 @@ extern int mp_register_gsi(struct device *dev, u32 gsi, int edge_level,
int active_high_low); int active_high_low);
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS) #define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_LOCAL_APIC)
struct physid_mask { struct physid_mask {
unsigned long mask[PHYSID_ARRAY_SIZE]; unsigned long mask[PHYSID_ARRAY_SIZE];
@ -122,31 +123,31 @@ typedef struct physid_mask physid_mask_t;
test_and_set_bit(physid, (map).mask) test_and_set_bit(physid, (map).mask)
#define physids_and(dst, src1, src2) \ #define physids_and(dst, src1, src2) \
bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS) bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_LOCAL_APIC)
#define physids_or(dst, src1, src2) \ #define physids_or(dst, src1, src2) \
bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS) bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_LOCAL_APIC)
#define physids_clear(map) \ #define physids_clear(map) \
bitmap_zero((map).mask, MAX_APICS) bitmap_zero((map).mask, MAX_LOCAL_APIC)
#define physids_complement(dst, src) \ #define physids_complement(dst, src) \
bitmap_complement((dst).mask, (src).mask, MAX_APICS) bitmap_complement((dst).mask, (src).mask, MAX_LOCAL_APIC)
#define physids_empty(map) \ #define physids_empty(map) \
bitmap_empty((map).mask, MAX_APICS) bitmap_empty((map).mask, MAX_LOCAL_APIC)
#define physids_equal(map1, map2) \ #define physids_equal(map1, map2) \
bitmap_equal((map1).mask, (map2).mask, MAX_APICS) bitmap_equal((map1).mask, (map2).mask, MAX_LOCAL_APIC)
#define physids_weight(map) \ #define physids_weight(map) \
bitmap_weight((map).mask, MAX_APICS) bitmap_weight((map).mask, MAX_LOCAL_APIC)
#define physids_shift_right(d, s, n) \ #define physids_shift_right(d, s, n) \
bitmap_shift_right((d).mask, (s).mask, n, MAX_APICS) bitmap_shift_right((d).mask, (s).mask, n, MAX_LOCAL_APIC)
#define physids_shift_left(d, s, n) \ #define physids_shift_left(d, s, n) \
bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS) bitmap_shift_left((d).mask, (s).mask, n, MAX_LOCAL_APIC)
static inline unsigned long physids_coerce(physid_mask_t *map) static inline unsigned long physids_coerce(physid_mask_t *map)
{ {
@ -159,14 +160,6 @@ static inline void physids_promote(unsigned long physids, physid_mask_t *map)
map->mask[0] = physids; map->mask[0] = physids;
} }
/* Note: will create very large stack frames if physid_mask_t is big */
#define physid_mask_of_physid(physid) \
({ \
physid_mask_t __physid_mask = PHYSID_MASK_NONE; \
physid_set(physid, __physid_mask); \
__physid_mask; \
})
static inline void physid_set_mask_of_physid(int physid, physid_mask_t *map) static inline void physid_set_mask_of_physid(int physid, physid_mask_t *map)
{ {
physids_clear(*map); physids_clear(*map);

View File

@ -15,13 +15,6 @@
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
# define MAX_MPC_ENTRY 1024 # define MAX_MPC_ENTRY 1024
# define MAX_APICS 256
#else
# if NR_CPUS <= 255
# define MAX_APICS 255
# else
# define MAX_APICS 32768
# endif
#endif #endif
/* Intel MP Floating Pointer Structure */ /* Intel MP Floating Pointer Structure */

View File

@ -915,13 +915,13 @@ static int __init acpi_parse_madt_lapic_entries(void)
acpi_register_lapic_address(acpi_lapic_addr); acpi_register_lapic_address(acpi_lapic_addr);
count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
acpi_parse_sapic, MAX_APICS); acpi_parse_sapic, MAX_LOCAL_APIC);
if (!count) { if (!count) {
x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC, x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC,
acpi_parse_x2apic, MAX_APICS); acpi_parse_x2apic, MAX_LOCAL_APIC);
count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
acpi_parse_lapic, MAX_APICS); acpi_parse_lapic, MAX_LOCAL_APIC);
} }
if (!count && !x2count) { if (!count && !x2count) {
printk(KERN_ERR PREFIX "No LAPIC entries present\n"); printk(KERN_ERR PREFIX "No LAPIC entries present\n");

View File

@ -4109,7 +4109,8 @@ void __init pre_init_apic_IRQ0(void)
printk(KERN_INFO "Early APIC setup for system timer0\n"); printk(KERN_INFO "Early APIC setup for system timer0\n");
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); physid_set_mask_of_physid(boot_cpu_physical_apicid,
&phys_cpu_present_map);
#endif #endif
/* Make sure the irq descriptor is set up */ /* Make sure the irq descriptor is set up */
cfg = alloc_irq_and_cfg_at(0, 0); cfg = alloc_irq_and_cfg_at(0, 0);

View File

@ -48,9 +48,9 @@ static void __init mp_sfi_register_lapic_address(unsigned long address)
/* All CPUs enumerated by SFI must be present and enabled */ /* All CPUs enumerated by SFI must be present and enabled */
static void __cpuinit mp_sfi_register_lapic(u8 id) static void __cpuinit mp_sfi_register_lapic(u8 id)
{ {
if (MAX_APICS - id <= 0) { if (MAX_LOCAL_APIC - id <= 0) {
pr_warning("Processor #%d invalid (max %d)\n", pr_warning("Processor #%d invalid (max %d)\n",
id, MAX_APICS); id, MAX_LOCAL_APIC);
return; return;
} }

View File

@ -171,7 +171,7 @@ static void __init MP_processor_info(struct mpc_cpu *m)
ver = m->apicver; ver = m->apicver;
if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) { if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->apicid, MAX_APICS); m->apicid, MAX_LOCAL_APIC);
return; return;
} }