forked from mirrors/linux
		
	x86/topology: Create logical package id
For per package oriented services we must be able to rely on the number of CPU packages to be within bounds. Create a tracking facility, which - calculates the number of possible packages depending on nr_cpu_ids after boot - makes sure that the package id is within the number of possible packages. If the apic id is outside we map it to a logical package id if there is enough space available. Provide interfaces for drivers to query the mapping and do translations from physcial to logical ids. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andi Kleen <andi.kleen@intel.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Harish Chegondi <harish.chegondi@intel.com> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Luis R. Rodriguez <mcgrof@suse.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Toshi Kani <toshi.kani@hp.com> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20160222221011.541071755@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									1f2569fac6
								
							
						
					
					
						commit
						1f12e32f4c
					
				
					 6 changed files with 142 additions and 0 deletions
				
			
		|  | @ -129,6 +129,8 @@ struct cpuinfo_x86 { | |||
| 	u16			booted_cores; | ||||
| 	/* Physical processor id: */ | ||||
| 	u16			phys_proc_id; | ||||
| 	/* Logical processor id: */ | ||||
| 	u16			logical_proc_id; | ||||
| 	/* Core id: */ | ||||
| 	u16			cpu_core_id; | ||||
| 	/* Compute unit id */ | ||||
|  |  | |||
|  | @ -119,12 +119,23 @@ static inline void setup_node_to_cpumask_map(void) { } | |||
| 
 | ||||
| extern const struct cpumask *cpu_coregroup_mask(int cpu); | ||||
| 
 | ||||
| #define topology_logical_package_id(cpu)	(cpu_data(cpu).logical_proc_id) | ||||
| #define topology_physical_package_id(cpu)	(cpu_data(cpu).phys_proc_id) | ||||
| #define topology_core_id(cpu)			(cpu_data(cpu).cpu_core_id) | ||||
| 
 | ||||
| #ifdef ENABLE_TOPO_DEFINES | ||||
| #define topology_core_cpumask(cpu)		(per_cpu(cpu_core_map, cpu)) | ||||
| #define topology_sibling_cpumask(cpu)		(per_cpu(cpu_sibling_map, cpu)) | ||||
| 
 | ||||
| extern unsigned int __max_logical_packages; | ||||
| #define topology_max_packages()			(__max_logical_packages) | ||||
| int topology_update_package_map(unsigned int apicid, unsigned int cpu); | ||||
| extern int topology_phys_to_logical_pkg(unsigned int pkg); | ||||
| #else | ||||
| #define topology_max_packages()			(1) | ||||
| static inline int | ||||
| topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; } | ||||
| static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; } | ||||
| #endif | ||||
| 
 | ||||
| static inline void arch_fix_phys_package_id(int num, u32 slot) | ||||
|  |  | |||
|  | @ -2077,6 +2077,20 @@ int generic_processor_info(int apicid, int version) | |||
| 	} else | ||||
| 		cpu = cpumask_next_zero(-1, cpu_present_mask); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This can happen on physical hotplug. The sanity check at boot time | ||||
| 	 * is done from native_smp_prepare_cpus() after num_possible_cpus() is | ||||
| 	 * established. | ||||
| 	 */ | ||||
| 	if (topology_update_package_map(apicid, cpu) < 0) { | ||||
| 		int thiscpu = max + disabled_cpus; | ||||
| 
 | ||||
| 		pr_warning("ACPI: Package limit reached. Processor %d/0x%x ignored.\n", | ||||
| 			   thiscpu, apicid); | ||||
| 		disabled_cpus++; | ||||
| 		return -ENOSPC; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Validate version | ||||
| 	 */ | ||||
|  |  | |||
|  | @ -975,6 +975,8 @@ static void identify_cpu(struct cpuinfo_x86 *c) | |||
| #ifdef CONFIG_NUMA | ||||
| 	numa_add_cpu(smp_processor_id()); | ||||
| #endif | ||||
| 	/* The boot/hotplug time assigment got cleared, restore it */ | ||||
| 	c->logical_proc_id = topology_phys_to_logical_pkg(c->phys_proc_id); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -160,6 +160,19 @@ static void early_init_intel(struct cpuinfo_x86 *c) | |||
| 		pr_info("Disabling PGE capability bit\n"); | ||||
| 		setup_clear_cpu_cap(X86_FEATURE_PGE); | ||||
| 	} | ||||
| 
 | ||||
| 	if (c->cpuid_level >= 0x00000001) { | ||||
| 		u32 eax, ebx, ecx, edx; | ||||
| 
 | ||||
| 		cpuid(0x00000001, &eax, &ebx, &ecx, &edx); | ||||
| 		/*
 | ||||
| 		 * If HTT (EDX[28]) is set EBX[16:23] contain the number of | ||||
| 		 * apicids which are reserved per package. Store the resulting | ||||
| 		 * shift value for the package management code. | ||||
| 		 */ | ||||
| 		if (edx & (1U << 28)) | ||||
| 			c->x86_coreid_bits = get_count_order((ebx >> 16) & 0xff); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_X86_32 | ||||
|  |  | |||
|  | @ -97,6 +97,14 @@ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map); | |||
| DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info); | ||||
| EXPORT_PER_CPU_SYMBOL(cpu_info); | ||||
| 
 | ||||
| /* Logical package management. We might want to allocate that dynamically */ | ||||
| static int *physical_to_logical_pkg __read_mostly; | ||||
| static unsigned long *physical_package_map __read_mostly;; | ||||
| static unsigned long *logical_package_map  __read_mostly; | ||||
| static unsigned int max_physical_pkg_id __read_mostly; | ||||
| unsigned int __max_logical_packages __read_mostly; | ||||
| EXPORT_SYMBOL(__max_logical_packages); | ||||
| 
 | ||||
| static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) | ||||
| { | ||||
| 	unsigned long flags; | ||||
|  | @ -251,6 +259,97 @@ static void notrace start_secondary(void *unused) | |||
| 	cpu_startup_entry(CPUHP_ONLINE); | ||||
| } | ||||
| 
 | ||||
| int topology_update_package_map(unsigned int apicid, unsigned int cpu) | ||||
| { | ||||
| 	unsigned int new, pkg = apicid >> boot_cpu_data.x86_coreid_bits; | ||||
| 
 | ||||
| 	/* Called from early boot ? */ | ||||
| 	if (!physical_package_map) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (pkg >= max_physical_pkg_id) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Set the logical package id */ | ||||
| 	if (test_and_set_bit(pkg, physical_package_map)) | ||||
| 		goto found; | ||||
| 
 | ||||
| 	if (pkg < __max_logical_packages) { | ||||
| 		set_bit(pkg, logical_package_map); | ||||
| 		physical_to_logical_pkg[pkg] = pkg; | ||||
| 		goto found; | ||||
| 	} | ||||
| 	new = find_first_zero_bit(logical_package_map, __max_logical_packages); | ||||
| 	if (new >= __max_logical_packages) { | ||||
| 		physical_to_logical_pkg[pkg] = -1; | ||||
| 		pr_warn("APIC(%x) Package %u exceeds logical package map\n", | ||||
| 			apicid, pkg); | ||||
| 		return -ENOSPC; | ||||
| 	} | ||||
| 	set_bit(new, logical_package_map); | ||||
| 	pr_info("APIC(%x) Converting physical %u to logical package %u\n", | ||||
| 		apicid, pkg, new); | ||||
| 	physical_to_logical_pkg[pkg] = new; | ||||
| 
 | ||||
| found: | ||||
| 	cpu_data(cpu).logical_proc_id = physical_to_logical_pkg[pkg]; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * topology_phys_to_logical_pkg - Map a physical package id to a logical | ||||
|  * | ||||
|  * Returns logical package id or -1 if not found | ||||
|  */ | ||||
| int topology_phys_to_logical_pkg(unsigned int phys_pkg) | ||||
| { | ||||
| 	if (phys_pkg >= max_physical_pkg_id) | ||||
| 		return -1; | ||||
| 	return physical_to_logical_pkg[phys_pkg]; | ||||
| } | ||||
| EXPORT_SYMBOL(topology_phys_to_logical_pkg); | ||||
| 
 | ||||
| static void __init smp_init_package_map(void) | ||||
| { | ||||
| 	unsigned int ncpus, cpu; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Today neither Intel nor AMD support heterogenous systems. That | ||||
| 	 * might change in the future.... | ||||
| 	 */ | ||||
| 	ncpus = boot_cpu_data.x86_max_cores * smp_num_siblings; | ||||
| 	__max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Possibly larger than what we need as the number of apic ids per | ||||
| 	 * package can be smaller than the actual used apic ids. | ||||
| 	 */ | ||||
| 	max_physical_pkg_id = DIV_ROUND_UP(MAX_LOCAL_APIC, ncpus); | ||||
| 	size = max_physical_pkg_id * sizeof(unsigned int); | ||||
| 	physical_to_logical_pkg = kmalloc(size, GFP_KERNEL); | ||||
| 	memset(physical_to_logical_pkg, 0xff, size); | ||||
| 	size = BITS_TO_LONGS(max_physical_pkg_id) * sizeof(unsigned long); | ||||
| 	physical_package_map = kzalloc(size, GFP_KERNEL); | ||||
| 	size = BITS_TO_LONGS(__max_logical_packages) * sizeof(unsigned long); | ||||
| 	logical_package_map = kzalloc(size, GFP_KERNEL); | ||||
| 
 | ||||
| 	pr_info("Max logical packages: %u\n", __max_logical_packages); | ||||
| 
 | ||||
| 	for_each_present_cpu(cpu) { | ||||
| 		unsigned int apicid = apic->cpu_present_to_apicid(cpu); | ||||
| 
 | ||||
| 		if (apicid == BAD_APICID || !apic->apic_id_valid(apicid)) | ||||
| 			continue; | ||||
| 		if (!topology_update_package_map(apicid, cpu)) | ||||
| 			continue; | ||||
| 		pr_warn("CPU %u APICId %x disabled\n", cpu, apicid); | ||||
| 		per_cpu(x86_bios_cpu_apicid, cpu) = BAD_APICID; | ||||
| 		set_cpu_possible(cpu, false); | ||||
| 		set_cpu_present(cpu, false); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void __init smp_store_boot_cpu_info(void) | ||||
| { | ||||
| 	int id = 0; /* CPU 0 */ | ||||
|  | @ -258,6 +357,7 @@ void __init smp_store_boot_cpu_info(void) | |||
| 
 | ||||
| 	*c = boot_cpu_data; | ||||
| 	c->cpu_index = id; | ||||
| 	smp_init_package_map(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Thomas Gleixner
						Thomas Gleixner