mp_machdep.c revision 87702
1/*- 2 * Copyright (c) 2000 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/ia64/ia64/mp_machdep.c 87702 2001-12-11 23:33:44Z jhb $ 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/ktr.h> 32#include <sys/proc.h> 33#include <sys/lock.h> 34#include <sys/malloc.h> 35#include <sys/mutex.h> 36#include <sys/kernel.h> 37#include <sys/pcpu.h> 38#include <sys/smp.h> 39#include <sys/sysctl.h> 40 41#include <vm/vm.h> 42#include <vm/pmap.h> 43 44#include <machine/atomic.h> 45#include <machine/pal.h> 46#include <machine/pmap.h> 47#include <machine/clock.h> 48#include <machine/sal.h> 49 50#define LID_SAPIC_ID(x) ((int)((x) >> 24) & 0xff) 51#define LID_SAPIC_EID(x) ((int)((x) >> 16) & 0xff) 52 53static MALLOC_DEFINE(M_SMP, "smp", "SMP structures"); 54 55static void ipi_send(u_int64_t, int); 56static void cpu_mp_unleash(void *); 57 58struct mp_cpu { 59 TAILQ_ENTRY(mp_cpu) cpu_next; 60 u_int64_t cpu_lid; /* Local processor ID */ 61 int32_t cpu_no; /* Sequential CPU number */ 62 u_int32_t cpu_bsp:1; /* 1=BSP; 0=AP */ 63 u_int32_t cpu_awake:1; /* 1=Awake; 0=sleeping */ 64 void *cpu_stack; 65}; 66 67int mp_hardware = 0; 68int mp_ipi_vector[IPI_COUNT]; 69int mp_ipi_test = 0; 70 71/* Variables used by os_boot_rendez */ 72volatile void *ap_stack; 73volatile int ap_delay; 74volatile int ap_awake; 75 76TAILQ_HEAD(, mp_cpu) ia64_cpus = TAILQ_HEAD_INITIALIZER(ia64_cpus); 77 78void 79ia64_ap_startup(void) 80{ 81#if 0 82 struct mp_cpu *cpu; 83 u_int64_t lid = ia64_get_lid() & 0xffff0000L; 84#endif 85 86 ap_awake = 1; 87 ap_delay = 0; 88 while (1); 89 90#if 0 91 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 92 if (cpu->cpu_lid == lid) 93 break; 94 } 95 96 KASSERT(cpu != NULL, ("foo!")); 97 98 cpu->cpu_lid = ia64_get_lid(); 99 cpu->cpu_awake = 1; 100#endif 101} 102 103int 104cpu_mp_probe() 105{ 106 /* 107 * We've already discovered any APs when they're present. 108 * Just return the result here. 109 */ 110 return (mp_hardware && mp_ncpus > 1); 111} 112 113void 114cpu_mp_add(uint acpiid, uint apicid, uint apiceid) 115{ 116 struct mp_cpu *cpu; 117 u_int64_t bsp = ia64_get_lid() & 0xffff0000L; 118 119 cpu = malloc(sizeof(*cpu), M_SMP, M_WAITOK|M_ZERO); 120 if (cpu == NULL) 121 return; 122 123 TAILQ_INSERT_TAIL(&ia64_cpus, cpu, cpu_next); 124 cpu->cpu_no = acpiid; 125 cpu->cpu_lid = ((apicid & 0xff) << 8 | (apiceid & 0xff)) << 16; 126 if (cpu->cpu_lid == bsp) 127 cpu->cpu_bsp = 1; 128 all_cpus |= (1 << acpiid); 129 mp_ncpus++; 130} 131 132void 133cpu_mp_announce() 134{ 135 struct mp_cpu *cpu; 136 137 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 138 printf("cpu%d: SAPIC Id=%x, SAPIC Eid=%x", cpu->cpu_no, 139 LID_SAPIC_ID(cpu->cpu_lid), LID_SAPIC_EID(cpu->cpu_lid)); 140 if (cpu->cpu_bsp) 141 printf(" (BSP)\n"); 142 else 143 printf("\n"); 144 } 145} 146 147void 148cpu_mp_start() 149{ 150 struct mp_cpu *cpu; 151 152 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 153 if (!cpu->cpu_bsp) { 154 cpu->cpu_stack = malloc(KSTACK_PAGES * PAGE_SIZE, 155 M_SMP, M_WAITOK); 156 157 if (bootverbose) 158 printf("SMP: waking up cpu%d\n", cpu->cpu_no); 159 160 ap_stack = cpu->cpu_stack; 161 ap_delay = 2000; 162 ap_awake = 0; 163 ipi_send(cpu->cpu_lid, IPI_AP_WAKEUP); 164 165 do { 166 DELAY(1000); 167 } while (--ap_delay > 0); 168 cpu->cpu_awake = (ap_awake) ? 1 : 0; 169 170 if (bootverbose && !ap_awake) 171 printf("SMP: WARNING: cpu%d did not wake up\n", 172 cpu->cpu_no); 173 } else { 174 cpu->cpu_lid = ia64_get_lid(); 175 cpu->cpu_awake = 1; 176 ipi_self(IPI_TEST); 177 } 178 } 179} 180 181static void 182cpu_mp_unleash(void *dummy) 183{ 184 struct mp_cpu *cpu; 185 int awake = 0; 186 187 if (!mp_hardware) 188 return; 189 190 if (mp_ipi_test != 1) 191 printf("SMP: sending of a test IPI to BSP failed\n"); 192 193 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 194 awake += cpu->cpu_awake; 195 } 196 197 if (awake != mp_ncpus) 198 printf("SMP: %d CPU(s) didn't get woken\n", mp_ncpus - awake); 199} 200 201/* 202 * send an IPI to a set of cpus. 203 */ 204void 205ipi_selected(u_int64_t cpus, int ipi) 206{ 207 struct mp_cpu *cpu; 208 209 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 210 if (cpus & (1 << cpu->cpu_no)) 211 ipi_send(cpu->cpu_lid, ipi); 212 } 213} 214 215/* 216 * send an IPI to all CPUs, including myself. 217 */ 218void 219ipi_all(int ipi) 220{ 221 struct mp_cpu *cpu; 222 223 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 224 ipi_send(cpu->cpu_lid, ipi); 225 } 226} 227 228/* 229 * send an IPI to all CPUs EXCEPT myself. 230 */ 231void 232ipi_all_but_self(int ipi) 233{ 234 struct mp_cpu *cpu; 235 u_int64_t lid = ia64_get_lid(); 236 237 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 238 if (cpu->cpu_lid != lid) 239 ipi_send(cpu->cpu_lid, ipi); 240 } 241} 242 243/* 244 * send an IPI to myself. 245 */ 246void 247ipi_self(int ipi) 248{ 249 250 ipi_send(ia64_get_lid(), ipi); 251} 252 253/* 254 * Send an IPI to the specified processor. The lid parameter holds the 255 * cr.lid (CR64) contents of the target processor. Only the id and eid 256 * fields are used here. 257 */ 258static void 259ipi_send(u_int64_t lid, int ipi) 260{ 261 volatile u_int64_t *pipi; 262 u_int64_t vector; 263 264 pipi = ia64_memory_address(PAL_PIB_DEFAULT_ADDR | 265 ((lid >> 12) & 0xFFFF0L)); 266 vector = (u_int64_t)(mp_ipi_vector[ipi] & 0xff); 267 *pipi = vector; 268 ia64_mf_a(); 269} 270 271SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL); 272