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:
Marcel Moolenaar 2002-05-12 05:54:21 +00:00
parent 47c3ccc467
commit f5b454cf25
6 changed files with 127 additions and 58 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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