o Rename ia64_count_aps to ia64_count_cpus and reimplement the
function to return the total number of CPUs and not the highest CPU id. o Define mp_maxid based on the minimum of the actual number of CPUs in the system and MAXCPU. o In cpu_mp_add, when the CPU id of the CPU we're trying to add is larger than mp_maxid, don't add the CPU. Formerly this was based on MAXCPU. Don't count CPUs when we add them. We already know how many CPUs exist. o Replace MAXCPU with mp_maxid when used in loops that iterate over the id space. This avoids a couple of useless iterations. o In cpu_mp_unleash, use the number of CPUs to determine if we need to launch the CPUs. o Remove mp_hardware as it's not used anymore. o Move the IPI vector array from mp_machdep.c to sal.c. We use the array as a centralized place to collect vector assignments. Note that we still assign vectors to SMP specific IPIs in non-SMP configurations. Rename the array from mp_ipi_vector to ipi_vector. o Add IPI_MCA_RENDEZ and IPI_MCA_CMCV. These are used by MCA. Note that IPI_MCA_CMCV is not SMP specific. o Initialize the ipi_vector array so that we place the IPIs in sensible priority classes. The classes are relative to where the AP wake-up vector is located to guarantee that it's the highest priority (external) interrupt. Class assignment is as follows: class IPI notes x AP wake-up (normally x=15) x-1 MCA rendezvous x-2 AST, Rendezvous, stop x-3 CMCV, test
This commit is contained in:
parent
47c3ccc467
commit
f5b454cf25
@ -134,30 +134,39 @@ parse_platform_interrupt(PLATFORM_INTERRUPT_SOURCE *source)
|
||||
static int
|
||||
parse_madt(APIC_TABLE *madt, int countcpus)
|
||||
{
|
||||
char *p, *end;
|
||||
int maxid = 0;
|
||||
char *end, *p;
|
||||
int cpus;
|
||||
|
||||
end = (char *)madt + madt->Header.Length;
|
||||
|
||||
/*
|
||||
* MADT header is followed by a number of variable length
|
||||
* structures.
|
||||
*/
|
||||
end = (char *) madt + madt->Header.Length;
|
||||
for (p = (char *) (madt + 1); p < end; ) {
|
||||
APIC_HEADER *head = (APIC_HEADER *) p;
|
||||
|
||||
if (countcpus) {
|
||||
if (countcpus) {
|
||||
cpus = 0;
|
||||
|
||||
for (p = (char *)(madt + 1); p < end; ) {
|
||||
APIC_HEADER *head = (APIC_HEADER *)p;
|
||||
|
||||
if (head->Type == APIC_LOCAL_SAPIC) {
|
||||
LOCAL_SAPIC *sapic = (LOCAL_SAPIC *) head;
|
||||
if (sapic->ProcessorEnabled)
|
||||
if (sapic->ProcessorId > maxid)
|
||||
maxid = sapic->ProcessorId;
|
||||
cpus++;
|
||||
}
|
||||
p = p + head->Length;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (cpus);
|
||||
}
|
||||
|
||||
for (p = (char *)(madt + 1); p < end; ) {
|
||||
APIC_HEADER *head = (APIC_HEADER *)p;
|
||||
|
||||
if (bootverbose)
|
||||
printf("\t");
|
||||
|
||||
switch (head->Type) {
|
||||
case APIC_PROC:
|
||||
if (bootverbose)
|
||||
@ -220,7 +229,7 @@ parse_madt(APIC_TABLE *madt, int countcpus)
|
||||
p = p + head->Length;
|
||||
}
|
||||
|
||||
return (maxid);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -262,11 +271,11 @@ ia64_probe_sapics(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the maximum cpuid used by any cpu in the system. This will
|
||||
* return zero for systems with only one cpu.
|
||||
* Count the number of local SAPIC entries in the APIC table. Every enabled
|
||||
* entry corresponds to a processor.
|
||||
*/
|
||||
int
|
||||
ia64_count_aps(void)
|
||||
ia64_count_cpus(void)
|
||||
{
|
||||
return (parse_table(1));
|
||||
}
|
||||
|
@ -122,12 +122,12 @@ interrupt(u_int64_t vector, struct trapframe *framep)
|
||||
statclock((struct clockframe *)framep);
|
||||
critical_exit();
|
||||
#ifdef SMP
|
||||
} else if (vector == mp_ipi_vector[IPI_AST]) {
|
||||
} else if (vector == ipi_vector[IPI_AST]) {
|
||||
CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
|
||||
} else if (vector == mp_ipi_vector[IPI_RENDEZVOUS]) {
|
||||
} else if (vector == ipi_vector[IPI_RENDEZVOUS]) {
|
||||
CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
|
||||
smp_rendezvous_action();
|
||||
} else if (vector == mp_ipi_vector[IPI_STOP]) {
|
||||
} else if (vector == ipi_vector[IPI_STOP]) {
|
||||
u_int32_t mybit = PCPU_GET(cpumask);
|
||||
|
||||
CTR1(KTR_SMP, "IPI_STOP, cpuid=%d", PCPU_GET(cpuid));
|
||||
@ -142,7 +142,7 @@ interrupt(u_int64_t vector, struct trapframe *framep)
|
||||
cpustop_restartfunc = NULL;
|
||||
(*f)();
|
||||
}
|
||||
} else if (vector == mp_ipi_vector[IPI_TEST]) {
|
||||
} else if (vector == ipi_vector[IPI_TEST]) {
|
||||
CTR1(KTR_SMP, "IPI_TEST, cpuid=%d", PCPU_GET(cpuid));
|
||||
mp_ipi_test++;
|
||||
#endif
|
||||
|
@ -63,8 +63,6 @@ extern vm_offset_t vhpt_base, vhpt_size;
|
||||
#define LID_SAPIC_SET(id,eid) (((id & 0xff) << 8 | (eid & 0xff)) << 16);
|
||||
#define LID_SAPIC_MASK 0xffff0000UL
|
||||
|
||||
int mp_hardware = 0;
|
||||
int mp_ipi_vector[IPI_COUNT];
|
||||
int mp_ipi_test = 0;
|
||||
|
||||
/* Variables used by os_boot_rendez */
|
||||
@ -124,15 +122,26 @@ int
|
||||
cpu_mp_probe()
|
||||
{
|
||||
/*
|
||||
* We've already discovered any APs when they're present.
|
||||
* Just return the result here.
|
||||
* Count the number of processors in the system by walking the ACPI
|
||||
* tables. Note that we record the actual number of processors, even
|
||||
* if this is larger than MAXCPU. We only activate MAXCPU processors.
|
||||
*/
|
||||
if (mp_hardware) {
|
||||
mp_maxid = ia64_count_aps();
|
||||
return (mp_maxid > 0);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
mp_ncpus = ia64_count_cpus();
|
||||
|
||||
/*
|
||||
* Set the largest cpuid we're going to use. This is necessary for
|
||||
* VM initialization.
|
||||
*/
|
||||
mp_maxid = min(mp_ncpus, MAXCPU) - 1;
|
||||
|
||||
/*
|
||||
* If there's only 1 processor, or we don't have a wake-up vector,
|
||||
* we're not going to enable SMP. Note that no wake-up vector can
|
||||
* also mean that the wake-up mechanism is not supported. In this
|
||||
* case we can have multiple processors, but we simply can't wake
|
||||
* them up...
|
||||
*/
|
||||
return (mp_ncpus > 1 && ipi_vector[IPI_AP_WAKEUP] != 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -141,14 +150,9 @@ cpu_mp_add(uint acpiid, uint apicid, uint apiceid)
|
||||
struct pcpu *pc;
|
||||
u_int64_t lid;
|
||||
|
||||
/* Count all CPUs, even the ones we cannot use */
|
||||
mp_ncpus++;
|
||||
|
||||
/* Ignore any processor numbers outside our range */
|
||||
if (acpiid >= MAXCPU) {
|
||||
printf("SMP: cpu%d skipped; increase MAXCPU\n", acpiid);
|
||||
if (acpiid > mp_maxid)
|
||||
return;
|
||||
}
|
||||
|
||||
KASSERT((all_cpus & (1UL << acpiid)) == 0,
|
||||
("%s: cpu%d already in CPU map", __func__, acpiid));
|
||||
@ -176,7 +180,7 @@ cpu_mp_announce()
|
||||
struct pcpu *pc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXCPU; i++) {
|
||||
for (i = 0; i <= mp_maxid; i++) {
|
||||
pc = pcpu_find(i);
|
||||
if (pc != NULL) {
|
||||
printf("cpu%d: SAPIC Id=%x, SAPIC Eid=%x", i,
|
||||
@ -247,7 +251,7 @@ cpu_mp_unleash(void *dummy)
|
||||
struct pcpu *pc;
|
||||
int cpus;
|
||||
|
||||
if (!mp_hardware)
|
||||
if (mp_ncpus <= 1)
|
||||
return;
|
||||
|
||||
if (mp_ipi_test != 1)
|
||||
@ -340,8 +344,9 @@ ipi_send(u_int64_t lid, int ipi)
|
||||
|
||||
pipi = ia64_memory_address(PAL_PIB_DEFAULT_ADDR |
|
||||
((lid & LID_SAPIC_MASK) >> 12));
|
||||
vector = (u_int64_t)(mp_ipi_vector[ipi] & 0xff);
|
||||
CTR3(KTR_SMP, "ipi_send(%p, %ld), cpuid=%d", pipi, vector, PCPU_GET(cpuid));
|
||||
vector = (u_int64_t)(ipi_vector[ipi] & 0xff);
|
||||
CTR3(KTR_SMP, "ipi_send(%p, %ld), cpuid=%d", pipi, vector,
|
||||
PCPU_GET(cpuid));
|
||||
*pipi = vector;
|
||||
ia64_mf_a();
|
||||
}
|
||||
|
@ -36,6 +36,13 @@
|
||||
#include <machine/sal.h>
|
||||
#include <machine/smp.h>
|
||||
|
||||
/*
|
||||
* IPIs are used more genericly than only
|
||||
* for inter-processor interrupts. Don't
|
||||
* make it a SMP specific thing...
|
||||
*/
|
||||
int ipi_vector[IPI_COUNT];
|
||||
|
||||
static struct ia64_fdesc sal_fdesc;
|
||||
static sal_entry_t fake_sal;
|
||||
|
||||
@ -54,6 +61,21 @@ fake_sal(u_int64_t a1, u_int64_t a2, u_int64_t a3, u_int64_t a4,
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_ipi_vectors(int ceil)
|
||||
{
|
||||
int ipi;
|
||||
|
||||
ipi_vector[IPI_MCA_RENDEZ] = ceil - 0x10;
|
||||
ipi_vector[IPI_MCA_CMCV] = ceil - 0x30;
|
||||
ipi_vector[IPI_TEST] = ceil - 0x30 + 1;
|
||||
|
||||
ipi = IPI_AST; /* First generic IPI. */
|
||||
ceil -= 0x20; /* First vector in group. */
|
||||
while (ipi < IPI_COUNT)
|
||||
ipi_vector[ipi++] = ceil++;
|
||||
}
|
||||
|
||||
void
|
||||
ia64_sal_init(struct sal_system_table *saltab)
|
||||
{
|
||||
@ -90,30 +112,60 @@ ia64_sal_init(struct sal_system_table *saltab)
|
||||
struct sal_ap_wakeup_descriptor *dp;
|
||||
#ifdef SMP
|
||||
struct ia64_sal_result result;
|
||||
int ipi;
|
||||
#endif
|
||||
|
||||
dp = (struct sal_ap_wakeup_descriptor*)p;
|
||||
KASSERT(dp->sale_mechanism == 0,
|
||||
("Unsupported AP wake-up mechanism"));
|
||||
if (bootverbose)
|
||||
printf("SMP: AP wake-up vector: 0x%lx\n",
|
||||
dp->sale_vector);
|
||||
#ifdef SMP
|
||||
for (ipi = 0; ipi < IPI_COUNT; ipi++)
|
||||
mp_ipi_vector[ipi] = dp->sale_vector + ipi;
|
||||
if (dp->sale_mechanism != 0) {
|
||||
printf("SAL: unsupported AP wake-up mechanism "
|
||||
"(%d)\n", dp->sale_mechanism);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dp->sale_vector < 0x10 || dp->sale_vector > 0xff) {
|
||||
printf("SAL: invalid AP wake-up vector "
|
||||
"(0x%lx)\n", dp->sale_vector);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* SAL documents that the wake-up vector should be
|
||||
* high (close to 255). The MCA rendezvous vector
|
||||
* should be less than the wake-up vector, but still
|
||||
* "high". We use the following priority assignment:
|
||||
* Wake-up: priority of the sale_vector
|
||||
* Rendezvous: priority-1
|
||||
* Generic IPIs: priority-2
|
||||
* Special IPIs: priority-3
|
||||
* Consequently, the wake-up priority should be at
|
||||
* least 4 (ie vector >= 0x40).
|
||||
*/
|
||||
if (dp->sale_vector < 0x40) {
|
||||
printf("SAL: AP wake-up vector too low "
|
||||
"(0x%lx)\n", dp->sale_vector);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("SAL: AP wake-up vector: 0x%x\n",
|
||||
dp->sale_vector);
|
||||
|
||||
ipi_vector[IPI_AP_WAKEUP] = dp->sale_vector;
|
||||
setup_ipi_vectors(dp->sale_vector & 0xf0);
|
||||
|
||||
#ifdef SMP
|
||||
result = ia64_sal_entry(SAL_SET_VECTORS,
|
||||
SAL_OS_BOOT_RENDEZ,
|
||||
ia64_tpa(FDESC_FUNC(os_boot_rendez)),
|
||||
ia64_tpa(FDESC_GP(os_boot_rendez)),
|
||||
0, 0, 0, 0);
|
||||
|
||||
mp_hardware = 1;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
p += sizes[*p];
|
||||
}
|
||||
|
||||
if (ipi_vector[IPI_AP_WAKEUP] == 0)
|
||||
setup_ipi_vectors(0xf0);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ void fork_trampoline(void); /* MAGIC */
|
||||
void syscall(int, u_int64_t *, struct trapframe *);
|
||||
void trap(int vector, int imm, struct trapframe *framep);
|
||||
void ia64_probe_sapics(void);
|
||||
int ia64_count_aps(void);
|
||||
int ia64_count_cpus(void);
|
||||
void map_pal_code(void);
|
||||
void cpu_mp_add(uint, uint, uint);
|
||||
|
||||
|
@ -10,20 +10,23 @@
|
||||
* Interprocessor interrupts for SMP. The following values are indices
|
||||
* into the IPI vector table. The SAL gives us the vector used for AP
|
||||
* wake-up. We base the other vectors on that. Keep IPI_AP_WAKEUP at
|
||||
* index 0.
|
||||
* index 0 and IPI_MCA_RENDEZ at index 1. See sal.c for details.
|
||||
*/
|
||||
#define IPI_AP_WAKEUP 0 /* ia64 specific */
|
||||
#define IPI_AST 1
|
||||
#define IPI_RENDEZVOUS 2
|
||||
#define IPI_STOP 3
|
||||
#define IPI_TEST 4 /* ia64 specific */
|
||||
/* Architecture specific IPIs. */
|
||||
#define IPI_AP_WAKEUP 0
|
||||
#define IPI_MCA_RENDEZ 1
|
||||
#define IPI_MCA_CMCV 2
|
||||
#define IPI_TEST 3
|
||||
/* Machine independent IPIs. */
|
||||
#define IPI_AST 4
|
||||
#define IPI_RENDEZVOUS 5
|
||||
#define IPI_STOP 6
|
||||
|
||||
#define IPI_COUNT 5
|
||||
#define IPI_COUNT 7
|
||||
|
||||
#ifndef LOCORE
|
||||
|
||||
extern int mp_hardware;
|
||||
extern int mp_ipi_vector[];
|
||||
extern int ipi_vector[];
|
||||
|
||||
void ipi_all(int ipi);
|
||||
void ipi_all_but_self(int ipi);
|
||||
|
Loading…
x
Reference in New Issue
Block a user