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
This commit is contained in:
royger 2017-08-10 09:16:03 +00:00
parent 345fb32684
commit e45f85c53f
6 changed files with 75 additions and 21 deletions

View File

@ -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));

View File

@ -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 *arg)
"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 *arg)
"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))
@ -424,6 +426,25 @@ parse_srat(void)
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
* mem_info[] tables.

View File

@ -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);

View File

@ -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];

View File

@ -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);
@ -1862,6 +1865,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();
if (retval != 0)

View File

@ -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;
}