mp_machdep.c revision 86204
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 86204 2001-11-09 05:18:45Z marcel $ 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/globaldata.h> 46#include <machine/pal.h> 47#include <machine/pmap.h> 48#include <machine/clock.h> 49#include <machine/sal.h> 50 51#define LID_SAPIC_ID(x) ((int)((x) >> 24) & 0xff) 52#define LID_SAPIC_EID(x) ((int)((x) >> 16) & 0xff) 53 54void ia64_probe_sapics(void); 55 56static MALLOC_DEFINE(M_SMP, "smp", "SMP structures"); 57 58static void ipi_send(u_int64_t, int); 59static void cpu_mp_unleash(void *); 60 61struct mp_cpu { 62 TAILQ_ENTRY(mp_cpu) cpu_next; 63 u_int64_t cpu_lid; /* Local processor ID */ 64 int32_t cpu_no; /* Sequential CPU number */ 65 u_int32_t cpu_bsp:1; /* 1=BSP; 0=AP */ 66 u_int32_t cpu_awake:1; /* 1=Awake; 0=sleeping */ 67 void *cpu_stack; 68}; 69 70int mp_hardware = 0; 71int mp_ipi_vector[IPI_COUNT]; 72int mp_ipi_test = 0; 73 74TAILQ_HEAD(, mp_cpu) ia64_cpus = TAILQ_HEAD_INITIALIZER(ia64_cpus); 75 76void * 77ia64_ap_get_stack(void) 78{ 79 struct mp_cpu *cpu; 80 u_int64_t lid = ia64_get_lid() & 0xffff0000L; 81 82 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 83 if (cpu->cpu_lid == lid) 84 return (cpu->cpu_stack); 85 } 86 87 panic(__func__": bad LID or RR5 misconfigured"); 88} 89 90void 91ia64_ap_startup(void) 92{ 93 struct mp_cpu *cpu; 94 u_int64_t lid = ia64_get_lid() & 0xffff0000L; 95 96 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 97 if (cpu->cpu_lid == lid) 98 break; 99 } 100 101 KASSERT(cpu != NULL, ("foo!")); 102 103 cpu->cpu_lid = ia64_get_lid(); 104 cpu->cpu_awake = 1; 105 106 while(1) 107 ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0); 108} 109 110int 111cpu_mp_probe() 112{ 113 ia64_probe_sapics(); 114 return (mp_hardware); 115} 116 117void 118cpu_mp_add(uint acpiid, uint apicid, uint apiceid) 119{ 120 struct mp_cpu *cpu; 121 u_int64_t bsp = ia64_get_lid() & 0xffff0000L; 122 123 cpu = malloc(sizeof(*cpu), M_SMP, M_WAITOK|M_ZERO); 124 if (cpu == NULL) 125 return; 126 127 TAILQ_INSERT_TAIL(&ia64_cpus, cpu, cpu_next); 128 cpu->cpu_no = acpiid; 129 cpu->cpu_lid = ((apicid & 0xff) << 8 | (apiceid & 0xff)) << 16; 130 if (cpu->cpu_lid == bsp) 131 cpu->cpu_bsp = 1; 132 all_cpus |= (1 << acpiid); 133 mp_ncpus++; 134} 135 136void 137cpu_mp_announce() 138{ 139 struct mp_cpu *cpu; 140 141 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 142 printf("cpu%d: SAPIC Id=%x, SAPIC Eid=%x", cpu->cpu_no, 143 LID_SAPIC_ID(cpu->cpu_lid), LID_SAPIC_EID(cpu->cpu_lid)); 144 if (cpu->cpu_bsp) 145 printf(" (BSP)\n"); 146 else 147 printf("\n"); 148 } 149} 150 151void 152cpu_mp_start() 153{ 154 struct mp_cpu *cpu; 155 156 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 157 if (!cpu->cpu_bsp) { 158 cpu->cpu_stack = malloc(KSTACK_PAGES * PAGE_SIZE, 159 M_SMP, M_WAITOK); 160 if (bootverbose) 161 printf("SMP: waking up cpu%d\n", cpu->cpu_no); 162 ipi_send(cpu->cpu_lid, IPI_AP_WAKEUP); 163 } else { 164 cpu->cpu_lid = ia64_get_lid(); 165 cpu->cpu_awake = 1; 166 ipi_self(IPI_TEST); 167 } 168 } 169} 170 171static void 172cpu_mp_unleash(void *dummy) 173{ 174 struct mp_cpu *cpu; 175 int awake = 0; 176 177 if (!mp_hardware) 178 return; 179 180 if (mp_ipi_test != 1) 181 printf("SMP: sending of a test IPI to BSP failed\n"); 182 183 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 184 awake += cpu->cpu_awake; 185 } 186 187 if (awake != mp_ncpus) 188 printf("SMP: %d CPU(s) didn't get woken\n", mp_ncpus - awake); 189} 190 191/* 192 * send an IPI to a set of cpus. 193 */ 194void 195ipi_selected(u_int64_t cpus, int ipi) 196{ 197 struct mp_cpu *cpu; 198 199 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 200 if (cpus & (1 << cpu->cpu_no)) 201 ipi_send(cpu->cpu_lid, ipi); 202 } 203} 204 205/* 206 * send an IPI to all CPUs, including myself. 207 */ 208void 209ipi_all(int ipi) 210{ 211 struct mp_cpu *cpu; 212 213 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 214 ipi_send(cpu->cpu_lid, ipi); 215 } 216} 217 218/* 219 * send an IPI to all CPUs EXCEPT myself. 220 */ 221void 222ipi_all_but_self(int ipi) 223{ 224 struct mp_cpu *cpu; 225 u_int64_t lid = ia64_get_lid(); 226 227 TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) { 228 if (cpu->cpu_lid != lid) 229 ipi_send(cpu->cpu_lid, ipi); 230 } 231} 232 233/* 234 * send an IPI to myself. 235 */ 236void 237ipi_self(int ipi) 238{ 239 240 ipi_send(ia64_get_lid(), ipi); 241} 242 243/* 244 * Send an IPI to the specified processor. The lid parameter holds the 245 * cr.lid (CR64) contents of the target processor. Only the id and eid 246 * fields are used here. 247 */ 248static void 249ipi_send(u_int64_t lid, int ipi) 250{ 251 volatile u_int64_t *pipi; 252 u_int64_t vector; 253 254 pipi = ia64_memory_address(PAL_PIB_DEFAULT_ADDR | 255 ((lid >> 12) & 0xFFFF0L)); 256 vector = (u_int64_t)(mp_ipi_vector[ipi] & 0xff); 257 *pipi = vector; 258 ia64_mf_a(); 259} 260 261SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL); 262