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:
		
							parent
							
								
									bc030d6cb9
								
							
						
					
					
						commit
						cb2ded37fd
					
				| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include <asm/mpspec_def.h> | ||||
| #include <asm/x86_init.h> | ||||
| #include <asm/apicdef.h> | ||||
| 
 | ||||
| extern int apic_version[]; | ||||
| 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); | ||||
| #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 { | ||||
| 	unsigned long mask[PHYSID_ARRAY_SIZE]; | ||||
| @ -122,31 +123,31 @@ typedef struct physid_mask physid_mask_t; | ||||
| 	test_and_set_bit(physid, (map).mask) | ||||
| 
 | ||||
| #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)					\ | ||||
| 	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)					\ | ||||
| 	bitmap_zero((map).mask, MAX_APICS) | ||||
| 	bitmap_zero((map).mask, MAX_LOCAL_APIC) | ||||
| 
 | ||||
| #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)					\ | ||||
| 	bitmap_empty((map).mask, MAX_APICS) | ||||
| 	bitmap_empty((map).mask, MAX_LOCAL_APIC) | ||||
| 
 | ||||
| #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)					\ | ||||
| 	bitmap_weight((map).mask, MAX_APICS) | ||||
| 	bitmap_weight((map).mask, MAX_LOCAL_APIC) | ||||
| 
 | ||||
| #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)				\ | ||||
| 	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) | ||||
| { | ||||
| @ -159,14 +160,6 @@ static inline void physids_promote(unsigned long physids, physid_mask_t *map) | ||||
| 	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) | ||||
| { | ||||
| 	physids_clear(*map); | ||||
|  | ||||
| @ -15,13 +15,6 @@ | ||||
| 
 | ||||
| #ifdef CONFIG_X86_32 | ||||
| # 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 | ||||
| 
 | ||||
| /* Intel MP Floating Pointer Structure */ | ||||
|  | ||||
| @ -915,13 +915,13 @@ static int __init acpi_parse_madt_lapic_entries(void) | ||||
| 	acpi_register_lapic_address(acpi_lapic_addr); | ||||
| 
 | ||||
| 	count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, | ||||
| 				      acpi_parse_sapic, MAX_APICS); | ||||
| 				      acpi_parse_sapic, MAX_LOCAL_APIC); | ||||
| 
 | ||||
| 	if (!count) { | ||||
| 		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, | ||||
| 					      acpi_parse_lapic, MAX_APICS); | ||||
| 					acpi_parse_lapic, MAX_LOCAL_APIC); | ||||
| 	} | ||||
| 	if (!count && !x2count) { | ||||
| 		printk(KERN_ERR PREFIX "No LAPIC entries present\n"); | ||||
|  | ||||
| @ -4109,7 +4109,8 @@ void __init pre_init_apic_IRQ0(void) | ||||
| 
 | ||||
| 	printk(KERN_INFO "Early APIC setup for system timer0\n"); | ||||
| #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 | ||||
| 	/* Make sure the irq descriptor is set up */ | ||||
| 	cfg = alloc_irq_and_cfg_at(0, 0); | ||||
|  | ||||
| @ -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 */ | ||||
| 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", | ||||
| 			id, MAX_APICS); | ||||
| 			id, MAX_LOCAL_APIC); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -171,7 +171,7 @@ static void __init MP_processor_info(struct mpc_cpu *m) | ||||
| 	ver = m->apicver; | ||||
| 	if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) { | ||||
| 		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", | ||||
| 			m->apicid, MAX_APICS); | ||||
| 			m->apicid, MAX_LOCAL_APIC); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user