From c35a41320dfb01cb83eb30926ea52a16c765f042 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Mon, 12 Nov 2001 07:18:16 +0000 Subject: [PATCH] o os_boot_rendez is responsible for clearing the IRR bit by reading cr.ivr, as well as writing to cr.eoi. o use global variables to pass information to os_boot_rendez so that it doesn't have to jump through hoops to find it out. This avoids traps on the AP without it even being initialized. This fixes SMP configurations. o Move the probing of the MADT to the end of cpu_startup, instead of at the start of cpu_mp_probe. We need to probe the MADT for non-SMP configurations as well. This fixes uniprocessor configurations. o Serialize AP wake-up by waiting for the AP. We need to do this since we use global variables to for the AP to use. As a side-effect, we can use printf() more easily to see what's going on. --- sys/ia64/ia64/locore.S | 20 +++++++++----- sys/ia64/ia64/locore.s | 20 +++++++++----- sys/ia64/ia64/machdep.c | 13 +++++++--- sys/ia64/ia64/mp_machdep.c | 53 +++++++++++++++++++++++--------------- 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/sys/ia64/ia64/locore.S b/sys/ia64/ia64/locore.S index 24ac142692f..544d192946c 100644 --- a/sys/ia64/ia64/locore.S +++ b/sys/ia64/ia64/locore.S @@ -151,9 +151,18 @@ END(mi_startup_trampoline) * as described on page 3-9 of the IPF SAL Specification. The difference * lies in the contents of register b0. For APs this register holds the * return address into the SAL rendezvous routine. + * + * Note that we're responsible for clearing the IRR bit by reading cr.ivr + * and issuing the EOI to the local SAPIC. */ .align 32 ENTRY(os_boot_rendez,0) + mov r16=cr.ivr // clear IRR bit + ;; + srlz.d + mov cr.eoi=r0 // ACK the wake-up + ;; + srlz.d rsm IA64_PSR_IC|IA64_PSR_I ;; srlz.d @@ -214,18 +223,17 @@ ENTRY(os_boot_rendez,0) mov cr.pta = r17 ;; srlz.i - ssm psr.i ;; srlz.d + movl r16 = ap_stack mov ar.rsc = 0 movl gp = __gp ;; - br.call.sptk.few rp = ia64_ap_get_stack + ld8 r16 = [r16] + mov r17 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16 ;; - mov r9 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16 - ;; - add sp = r9, r8 - mov ar.bspstore = r8 + add sp = r17, r16 + mov ar.bspstore = r16 ;; loadrs ;; diff --git a/sys/ia64/ia64/locore.s b/sys/ia64/ia64/locore.s index 24ac142692f..544d192946c 100644 --- a/sys/ia64/ia64/locore.s +++ b/sys/ia64/ia64/locore.s @@ -151,9 +151,18 @@ END(mi_startup_trampoline) * as described on page 3-9 of the IPF SAL Specification. The difference * lies in the contents of register b0. For APs this register holds the * return address into the SAL rendezvous routine. + * + * Note that we're responsible for clearing the IRR bit by reading cr.ivr + * and issuing the EOI to the local SAPIC. */ .align 32 ENTRY(os_boot_rendez,0) + mov r16=cr.ivr // clear IRR bit + ;; + srlz.d + mov cr.eoi=r0 // ACK the wake-up + ;; + srlz.d rsm IA64_PSR_IC|IA64_PSR_I ;; srlz.d @@ -214,18 +223,17 @@ ENTRY(os_boot_rendez,0) mov cr.pta = r17 ;; srlz.i - ssm psr.i ;; srlz.d + movl r16 = ap_stack mov ar.rsc = 0 movl gp = __gp ;; - br.call.sptk.few rp = ia64_ap_get_stack + ld8 r16 = [r16] + mov r17 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16 ;; - mov r9 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16 - ;; - add sp = r9, r8 - mov ar.bspstore = r8 + add sp = r17, r16 + mov ar.bspstore = r16 ;; loadrs ;; diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index c59fd6f32eb..a67f7a99976 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -81,6 +81,8 @@ #include #include +void ia64_probe_sapics(void); + #ifdef SKI extern void ia64_ski_init(void); #endif @@ -228,6 +230,12 @@ cpu_startup(dummy) */ bufinit(); vm_pager_bufferinit(); + + /* + * Traverse the MADT to discover IOSAPIC and Local SAPIC + * information. + */ + ia64_probe_sapics(); } static void @@ -744,15 +752,12 @@ DELAY(int n) { u_int64_t start, end, now; - /* - * XXX This can't cope with rollovers. - */ start = ia64_get_itc(); end = start + (itc_frequency * n) / 1000000; /* printf("DELAY from 0x%lx to 0x%lx\n", start, end); */ do { now = ia64_get_itc(); - } while (now < end); + } while (now < end || (now > start && end < start)); } /* diff --git a/sys/ia64/ia64/mp_machdep.c b/sys/ia64/ia64/mp_machdep.c index eb8c0f05400..aadbd7d7542 100644 --- a/sys/ia64/ia64/mp_machdep.c +++ b/sys/ia64/ia64/mp_machdep.c @@ -51,8 +51,6 @@ #define LID_SAPIC_ID(x) ((int)((x) >> 24) & 0xff) #define LID_SAPIC_EID(x) ((int)((x) >> 16) & 0xff) -void ia64_probe_sapics(void); - static MALLOC_DEFINE(M_SMP, "smp", "SMP structures"); static void ipi_send(u_int64_t, int); @@ -71,28 +69,26 @@ int mp_hardware = 0; int mp_ipi_vector[IPI_COUNT]; int mp_ipi_test = 0; +/* Variables used by os_boot_rendez */ +volatile void *ap_stack; +volatile int ap_delay; +volatile int ap_awake; + TAILQ_HEAD(, mp_cpu) ia64_cpus = TAILQ_HEAD_INITIALIZER(ia64_cpus); -void * -ia64_ap_get_stack(void) -{ - struct mp_cpu *cpu; - u_int64_t lid = ia64_get_lid() & 0xffff0000L; - - TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { - if (cpu->cpu_lid == lid) - return (cpu->cpu_stack); - } - - panic(__func__": bad LID or RR5 misconfigured"); -} - void ia64_ap_startup(void) { +#if 0 struct mp_cpu *cpu; u_int64_t lid = ia64_get_lid() & 0xffff0000L; +#endif + ap_awake = 1; + ap_delay = 0; + while (1); + +#if 0 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { if (cpu->cpu_lid == lid) break; @@ -102,16 +98,17 @@ ia64_ap_startup(void) cpu->cpu_lid = ia64_get_lid(); cpu->cpu_awake = 1; - - while(1) - ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0); +#endif } int cpu_mp_probe() { - ia64_probe_sapics(); - return (mp_hardware); + /* + * We've already discovered any APs when they're present. + * Just return the result here. + */ + return (mp_hardware && mp_ncpus > 1); } void @@ -157,9 +154,23 @@ cpu_mp_start() if (!cpu->cpu_bsp) { cpu->cpu_stack = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, M_WAITOK); + if (bootverbose) printf("SMP: waking up cpu%d\n", cpu->cpu_no); + + ap_stack = cpu->cpu_stack; + ap_delay = 2000; + ap_awake = 0; ipi_send(cpu->cpu_lid, IPI_AP_WAKEUP); + + do { + DELAY(1000); + } while (--ap_delay > 0); + cpu->cpu_awake = (ap_awake) ? 1 : 0; + + if (bootverbose && !ap_awake) + printf("SMP: WARNING: cpu%d did not wake up\n", + cpu->cpu_no); } else { cpu->cpu_lid = ia64_get_lid(); cpu->cpu_awake = 1;