svn commit: r322348 - in head/sys/x86: acpica include x86

Roger Pau Monné royger at FreeBSD.org
Thu Aug 10 09:16:05 UTC 2017


Author: royger
Date: Thu Aug 10 09:16:03 2017
New Revision: 322348
URL: https://svnweb.freebsd.org/changeset/base/322348

Log:
  x86: make the arrays that depend on MAX_APIC_ID dynamic
  
  So that MAX_APIC_ID can be bumped without wasting memory.
  
  Note that the usage of MAX_APIC_ID in the SRAT parsing forces the
  parser to allocate memory directly from the phys_avail physical memory
  array, which is not the best approach probably, but I haven't found
  any other way to allocate memory so early in boot. This memory is not
  returned to the system afterwards, but at least it's sized according
  to the maximum APIC ID found in the MADT table.
  
  Sponsored by:		Citrix Systems R&D
  MFC after:		1 month
  Reviewed by:		kib
  Differential revision:	https://reviews.freebsd.org/D11912

Modified:
  head/sys/x86/acpica/madt.c
  head/sys/x86/acpica/srat.c
  head/sys/x86/include/apicvar.h
  head/sys/x86/include/x86_smp.h
  head/sys/x86/x86/local_apic.c
  head/sys/x86/x86/mp_x86.c

Modified: head/sys/x86/acpica/madt.c
==============================================================================
--- head/sys/x86/acpica/madt.c	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/acpica/madt.c	Thu Aug 10 09:16:03 2017	(r322348)
@@ -59,7 +59,7 @@ static struct {
 static struct lapic_info {
 	u_int la_enabled;
 	u_int la_acpi_id;
-} lapics[MAX_APIC_ID + 1];
+} *lapics;
 
 int madt_found_sci_override;
 static ACPI_TABLE_MADT *madt;
@@ -141,8 +141,6 @@ madt_setup_local(void)
 	int user_x2apic;
 	bool bios_x2apic;
 
-	madt = pmap_mapbios(madt_physaddr, madt_length);
-	madt_walk_table(madt_setup_cpus_handler, NULL);
 	if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
 		reason = NULL;
 
@@ -214,6 +212,11 @@ madt_setup_local(void)
 		}
 	}
 
+	madt = pmap_mapbios(madt_physaddr, madt_length);
+	lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_MADT,
+	    M_WAITOK | M_ZERO);
+	madt_walk_table(madt_setup_cpus_handler, NULL);
+
 	lapic_init(madt->Address);
 	printf("ACPI APIC Table: <%.*s %.*s>\n",
 	    (int)sizeof(madt->Header.OemId), madt->Header.OemId,
@@ -236,6 +239,8 @@ madt_setup_io(void)
 	u_int pin;
 	int i;
 
+	KASSERT(lapics != NULL, ("local APICs not initialized"));
+
 	/* Try to initialize ACPI so that we can access the FADT. */
 	i = acpi_Startup();
 	if (ACPI_FAILURE(i)) {
@@ -282,6 +287,10 @@ madt_setup_io(void)
 	free(ioapics, M_MADT);
 	ioapics = NULL;
 
+	/* NB: this is the last use of the lapics array. */
+	free(lapics, M_MADT);
+	lapics = NULL;
+
 	return (0);
 }
 
@@ -332,7 +341,7 @@ madt_add_cpu(u_int acpi_id, u_int apic_id, u_int flags
 		    "enabled" : "disabled");
 	if (!(flags & ACPI_MADT_ENABLED))
 		return;
-	if (apic_id > MAX_APIC_ID) {
+	if (apic_id > max_apic_id) {
 		printf("MADT: Ignoring local APIC ID %u (too high)\n",
 		    apic_id);
 		return;
@@ -471,7 +480,7 @@ madt_find_cpu(u_int acpi_id, u_int *apic_id)
 {
 	int i;
 
-	for (i = 0; i <= MAX_APIC_ID; i++) {
+	for (i = 0; i <= max_apic_id; i++) {
 		if (!lapics[i].la_enabled)
 			continue;
 		if (lapics[i].la_acpi_id != acpi_id)
@@ -723,6 +732,9 @@ madt_set_ids(void *dummy)
 
 	if (madt == NULL)
 		return;
+
+	KASSERT(lapics != NULL, ("local APICs not initialized"));
+
 	CPU_FOREACH(i) {
 		pc = pcpu_find(i);
 		KASSERT(pc != NULL, ("no pcpu data for CPU %u", i));

Modified: head/sys/x86/acpica/srat.c
==============================================================================
--- head/sys/x86/acpica/srat.c	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/acpica/srat.c	Thu Aug 10 09:16:03 2017	(r322348)
@@ -55,11 +55,11 @@ __FBSDID("$FreeBSD$");
 #include <dev/acpica/acpivar.h>
 
 #if MAXMEMDOM > 1
-struct cpu_info {
+static struct cpu_info {
 	int enabled:1;
 	int has_memory:1;
 	int domain;
-} cpus[MAX_APIC_ID + 1];
+} *cpus;
 
 struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1];
 int num_mem;
@@ -204,7 +204,7 @@ srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *ar
 			    "enabled" : "disabled");
 		if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
 			break;
-		if (cpu->ApicId > MAX_APIC_ID) {
+		if (cpu->ApicId > max_apic_id) {
 			printf("SRAT: Ignoring local APIC ID %u (too high)\n",
 			    cpu->ApicId);
 			break;
@@ -228,7 +228,7 @@ srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *ar
 			    "enabled" : "disabled");
 		if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED))
 			break;
-		if (x2apic->ApicId > MAX_APIC_ID) {
+		if (x2apic->ApicId > max_apic_id) {
 			printf("SRAT: Ignoring local APIC ID %u (too high)\n",
 			    x2apic->ApicId);
 			break;
@@ -294,7 +294,7 @@ check_domains(void)
 
 	for (i = 0; i < num_mem; i++) {
 		found = 0;
-		for (j = 0; j <= MAX_APIC_ID; j++)
+		for (j = 0; j <= max_apic_id; j++)
 			if (cpus[j].enabled &&
 			    cpus[j].domain == mem_info[i].domain) {
 				cpus[j].has_memory = 1;
@@ -306,7 +306,7 @@ check_domains(void)
 			return (ENXIO);
 		}
 	}
-	for (i = 0; i <= MAX_APIC_ID; i++)
+	for (i = 0; i <= max_apic_id; i++)
 		if (cpus[i].enabled && !cpus[i].has_memory) {
 			printf("SRAT: No memory found for CPU %d\n", i);
 			return (ENXIO);
@@ -401,7 +401,7 @@ renumber_domains(void)
 		for (j = 0; j < num_mem; j++)
 			if (mem_info[j].domain == domain_pxm[i])
 				mem_info[j].domain = i;
-		for (j = 0; j <= MAX_APIC_ID; j++)
+		for (j = 0; j <= max_apic_id; j++)
 			if (cpus[j].enabled && cpus[j].domain == domain_pxm[i])
 				cpus[j].domain = i;
 	}
@@ -415,6 +415,8 @@ renumber_domains(void)
 static int
 parse_srat(void)
 {
+	unsigned int idx, size;
+	vm_paddr_t addr;
 	int error;
 
 	if (resource_disabled("srat", 0))
@@ -423,6 +425,25 @@ parse_srat(void)
 	srat_physaddr = acpi_find_table(ACPI_SIG_SRAT);
 	if (srat_physaddr == 0)
 		return (-1);
+
+	/*
+	 * Allocate data structure:
+	 *
+	 * Find the last physical memory region and steal some memory from
+	 * it. This is done because at this point in the boot process
+	 * malloc is still not usable.
+	 */
+	for (idx = 0; phys_avail[idx + 1] != 0; idx += 2);
+	KASSERT(idx != 0, ("phys_avail is empty!"));
+	idx -= 2;
+
+	size =  sizeof(*cpus) * (max_apic_id + 1);
+	addr = trunc_page(phys_avail[idx + 1] - size);
+	KASSERT(addr >= phys_avail[idx],
+	    ("Not enough memory for SRAT table items"));
+	phys_avail[idx + 1] = addr - 1;
+
+	cpus = (struct cpu_info *)PHYS_TO_DMAP(addr);
 
 	/*
 	 * Make a pass over the table to populate the cpus[] and

Modified: head/sys/x86/include/apicvar.h
==============================================================================
--- head/sys/x86/include/apicvar.h	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/include/apicvar.h	Thu Aug 10 09:16:03 2017	(r322348)
@@ -182,7 +182,7 @@ inthand_t
 	IDTVEC(spuriousint), IDTVEC(timerint);
 
 extern vm_paddr_t lapic_paddr;
-extern int apic_cpuids[];
+extern int *apic_cpuids;
 
 void	apic_register_enumerator(struct apic_enumerator *enumerator);
 void	*ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase);

Modified: head/sys/x86/include/x86_smp.h
==============================================================================
--- head/sys/x86/include/x86_smp.h	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/include/x86_smp.h	Thu Aug 10 09:16:03 2017	(r322348)
@@ -54,7 +54,7 @@ struct cpu_info {
 	int	cpu_disabled:1;
 	int	cpu_hyperthread:1;
 };
-extern struct cpu_info cpu_info[];
+extern struct cpu_info *cpu_info;
 
 #ifdef COUNT_IPIS
 extern u_long *ipi_invltlb_counts[MAXCPU];

Modified: head/sys/x86/x86/local_apic.c
==============================================================================
--- head/sys/x86/x86/local_apic.c	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/x86/local_apic.c	Thu Aug 10 09:16:03 2017	(r322348)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
+#include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/pcpu.h>
 #include <sys/proc.h>
@@ -83,6 +84,8 @@ __FBSDID("$FreeBSD$");
 #define	GSEL_APIC	GSEL(GCODE_SEL, SEL_KPL)
 #endif
 
+static MALLOC_DEFINE(M_LAPIC, "local_apic", "Local APIC items");
+
 /* Sanity checks on IDT vectors. */
 CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT);
 CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS);
@@ -134,7 +137,7 @@ struct lapic {
 	uint32_t lvt_timer_last;
 	/* Include IDT_SYSCALL to make indexing easier. */
 	int la_ioint_irqs[APIC_NUM_IOINTS + 1];
-} static lapics[MAX_APIC_ID + 1];
+} static *lapics;
 
 /* Global defaults for local APIC LVT entries. */
 static struct lvt lvts[APIC_LVT_MAX + 1] = {
@@ -601,7 +604,7 @@ native_lapic_create(u_int apic_id, int boot_cpu)
 {
 	int i;
 
-	if (apic_id > MAX_APIC_ID) {
+	if (apic_id > max_apic_id) {
 		printf("APIC: Ignoring local APIC with ID %d\n", apic_id);
 		if (boot_cpu)
 			panic("Can't ignore BSP");
@@ -1661,7 +1664,7 @@ DB_SHOW_COMMAND(apic, db_show_apic)
 		verbose = 1;
 	else
 		verbose = 0;
-	for (apic_id = 0; apic_id <= MAX_APIC_ID; apic_id++) {
+	for (apic_id = 0; apic_id <= max_apic_id; apic_id++) {
 		if (lapics[apic_id].la_present == 0)
 			continue;
 		db_printf("Interrupts bound to lapic %u\n", apic_id);
@@ -1861,6 +1864,9 @@ apic_setup_local(void *dummy __unused)
 
 	if (best_enum == NULL)
 		return;
+
+	lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_LAPIC,
+	    M_WAITOK | M_ZERO);
 
 	/* Initialize the local APIC. */
 	retval = best_enum->apic_setup_local();

Modified: head/sys/x86/x86/mp_x86.c
==============================================================================
--- head/sys/x86/x86/mp_x86.c	Thu Aug 10 09:15:18 2017	(r322347)
+++ head/sys/x86/x86/mp_x86.c	Thu Aug 10 09:16:03 2017	(r322348)
@@ -84,6 +84,8 @@ __FBSDID("$FreeBSD$");
 #define BIOS_RESET		(0x0f)
 #define BIOS_WARM		(0x0a)
 
+static MALLOC_DEFINE(M_CPUS, "cpus", "CPU items");
+
 /* lock region used by kernel profiling */
 int	mcount_lock;
 
@@ -132,8 +134,8 @@ volatile int aps_ready = 0;
  * Store data from cpu_add() until later in the boot when we actually setup
  * the APs.
  */
-struct cpu_info cpu_info[MAX_APIC_ID + 1];
-int apic_cpuids[MAX_APIC_ID + 1];
+struct cpu_info *cpu_info;
+int *apic_cpuids;
 int cpu_apic_ids[MAXCPU];
 
 /* Holds pending bitmap based IPIs per CPU */
@@ -546,7 +548,7 @@ topo_probe(void)
 	nlayers++;
 
 	topo_init_root(&topo_root);
-	for (i = 0; i <= MAX_APIC_ID; ++i) {
+	for (i = 0; i <= max_apic_id; ++i) {
 		if (!cpu_info[i].cpu_present)
 			continue;
 
@@ -803,6 +805,19 @@ cpu_topo(void)
 	return (cg_root);
 }
 
+static void
+cpu_alloc(void *dummy __unused)
+{
+	/*
+	 * Dynamically allocate the arrays that depend on the
+	 * maximum APIC ID.
+	 */
+	cpu_info = malloc(sizeof(*cpu_info) * (max_apic_id + 1), M_CPUS,
+	    M_WAITOK | M_ZERO);
+	apic_cpuids = malloc(sizeof(*apic_cpuids) * (max_apic_id + 1), M_CPUS,
+	    M_WAITOK | M_ZERO);
+}
+SYSINIT(cpu_alloc, SI_SUB_CPU, SI_ORDER_FIRST, cpu_alloc, NULL);
 
 /*
  * Add a logical CPU to the topology.
@@ -811,7 +826,7 @@ void
 cpu_add(u_int apic_id, char boot_cpu)
 {
 
-	if (apic_id > MAX_APIC_ID) {
+	if (apic_id > max_apic_id) {
 		panic("SMP: APIC ID %d too high", apic_id);
 		return;
 	}


More information about the svn-src-head mailing list