mp_machdep.c revision 261986
1132718Skan/*- 2169689Skan * Copyright (c) 2001-2005 Marcel Moolenaar 3169689Skan * Copyright (c) 2000 Doug Rabson 418334Speter * All rights reserved. 590075Sobrien * 618334Speter * Redistribution and use in source and binary forms, with or without 790075Sobrien * modification, are permitted provided that the following conditions 890075Sobrien * are met: 990075Sobrien * 1. Redistributions of source code must retain the above copyright 1090075Sobrien * notice, this list of conditions and the following disclaimer. 1118334Speter * 2. Redistributions in binary form must reproduce the above copyright 1290075Sobrien * notice, this list of conditions and the following disclaimer in the 1390075Sobrien * documentation and/or other materials provided with the distribution. 1490075Sobrien * 1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1618334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1718334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1890075Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2118334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2290075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2390075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2418334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25223262Sbenl * SUCH DAMAGE. 26223262Sbenl */ 27223262Sbenl 28223262Sbenl#include <sys/cdefs.h> 29223262Sbenl__FBSDID("$FreeBSD: stable/10/sys/ia64/ia64/mp_machdep.c 261986 2014-02-16 19:20:13Z marcel $"); 30169689Skan 3118334Speter#include "opt_kstack_pages.h" 32132718Skan 33169689Skan#include <sys/param.h> 34169689Skan#include <sys/systm.h> 3518334Speter#include <sys/ktr.h> 3618334Speter#include <sys/proc.h> 3718334Speter#include <sys/bus.h> 3818334Speter#include <sys/kthread.h> 3918334Speter#include <sys/lock.h> 4018334Speter#include <sys/malloc.h> 4190075Sobrien#include <sys/mutex.h> 4290075Sobrien#include <sys/kernel.h> 4390075Sobrien#include <sys/pcpu.h> 4418334Speter#include <sys/sched.h> 4518334Speter#include <sys/smp.h> 4618334Speter#include <sys/sysctl.h> 4718334Speter#include <sys/uuid.h> 4818334Speter 4918334Speter#include <machine/atomic.h> 5018334Speter#include <machine/bootinfo.h> 5118334Speter#include <machine/cpu.h> 5218334Speter#include <machine/fpu.h> 5318334Speter#include <machine/intr.h> 5418334Speter#include <machine/mca.h> 5518334Speter#include <machine/md_var.h> 5618334Speter#include <machine/pal.h> 5718334Speter#include <machine/pcb.h> 5890075Sobrien#include <machine/sal.h> 5918334Speter#include <machine/smp.h> 6018334Speter 61169689Skan#include <vm/vm.h> 62169689Skan#include <vm/pmap.h> 63169689Skan#include <vm/vm_extern.h> 64169689Skan#include <vm/vm_kern.h> 65169689Skan 66169689Skanextern uint64_t bdata[]; 67169689Skan 68169689SkanMALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations"); 69169689Skan 70169689Skanvoid ia64_ap_startup(void); 71169689Skan 72169689Skan#define SAPIC_ID_GET_ID(x) ((u_int)((x) >> 8) & 0xff) 73169689Skan#define SAPIC_ID_GET_EID(x) ((u_int)(x) & 0xff) 74169689Skan#define SAPIC_ID_SET(id, eid) ((u_int)(((id) & 0xff) << 8) | ((eid) & 0xff)) 75169689Skan 76169689Skan/* State used to wake and bootstrap APs. */ 77169689Skanstruct ia64_ap_state ia64_ap_state; 78169689Skan 79169689Skanint ia64_ipi_ast; 80169689Skanint ia64_ipi_hardclock; 81169689Skanint ia64_ipi_highfp; 82169689Skanint ia64_ipi_nmi; 83169689Skanint ia64_ipi_preempt; 84169689Skanint ia64_ipi_rndzvs; 85169689Skanint ia64_ipi_stop; 86169689Skan 87169689Skanstatic u_int 88169689Skansz2shft(uint64_t sz) 89169689Skan{ 90169689Skan uint64_t s; 91169689Skan u_int shft; 92169689Skan 93169689Skan shft = 12; /* Start with 4K */ 94169689Skan s = 1 << shft; 95169689Skan while (s < sz) { 96169689Skan shft++; 97169689Skan s <<= 1; 98169689Skan } 99169689Skan return (shft); 100169689Skan} 10190075Sobrien 10250397Sobrienstatic u_int 10318334Speteria64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf) 10490075Sobrien{ 10550397Sobrien 10618334Speter PCPU_INC(md.stats.pcs_nasts); 10790075Sobrien CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid)); 10850397Sobrien return (0); 10918334Speter} 110169689Skan 11150397Sobrienstatic u_int 112117395Skania64_ih_hardclock(struct thread *td, u_int xiv, struct trapframe *tf) 113169689Skan{ 114117395Skan 11518334Speter PCPU_INC(md.stats.pcs_nhardclocks); 11650397Sobrien CTR1(KTR_SMP, "IPI_HARDCLOCK, cpuid=%d", PCPU_GET(cpuid)); 11750397Sobrien hardclockintr(); 11850397Sobrien return (0); 11950397Sobrien} 12050397Sobrien 12150397Sobrienstatic u_int 12250397Sobrienia64_ih_highfp(struct thread *td, u_int xiv, struct trapframe *tf) 12350397Sobrien{ 12490075Sobrien 12590075Sobrien PCPU_INC(md.stats.pcs_nhighfps); 12690075Sobrien ia64_highfp_save_ipi(); 12790075Sobrien return (0); 12890075Sobrien} 12990075Sobrien 13090075Sobrienstatic u_int 13190075Sobrienia64_ih_preempt(struct thread *td, u_int xiv, struct trapframe *tf) 13250397Sobrien{ 13350397Sobrien 13450397Sobrien PCPU_INC(md.stats.pcs_npreempts); 13550397Sobrien CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid)); 13650397Sobrien sched_preempt(curthread); 13750397Sobrien return (0); 13890075Sobrien} 13990075Sobrien 14090075Sobrienstatic u_int 14190075Sobrienia64_ih_rndzvs(struct thread *td, u_int xiv, struct trapframe *tf) 142117395Skan{ 143117395Skan 144117395Skan PCPU_INC(md.stats.pcs_nrdvs); 145117395Skan CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid)); 14690075Sobrien smp_rendezvous_action(); 14790075Sobrien return (0); 14890075Sobrien} 14990075Sobrien 15090075Sobrienstatic u_int 15190075Sobrienia64_ih_stop(struct thread *td, u_int xiv, struct trapframe *tf) 15290075Sobrien{ 15390075Sobrien u_int cpuid; 154132718Skan 155132718Skan PCPU_INC(md.stats.pcs_nstops); 156132718Skan cpuid = PCPU_GET(cpuid); 157132718Skan 158132718Skan savectx(PCPU_PTR(md.pcb)); 159132718Skan 160132718Skan CPU_SET_ATOMIC(cpuid, &stopped_cpus); 161132718Skan while (!CPU_ISSET(cpuid, &started_cpus)) 162132718Skan cpu_spinwait(); 16318334Speter CPU_CLR_ATOMIC(cpuid, &started_cpus); 16418334Speter CPU_CLR_ATOMIC(cpuid, &stopped_cpus); 165117395Skan return (0); 16618334Speter} 167169689Skan 168169689Skanstruct cpu_group * 169169689Skancpu_topo(void) 170169689Skan{ 171169689Skan 172169689Skan return smp_topo_none(); 17350397Sobrien} 17490075Sobrien 175169689Skanstatic void 176169689Skania64_store_mca_state(void* arg) 177169689Skan{ 178169689Skan struct pcpu *pc = arg; 179169689Skan struct thread *td = curthread; 180169689Skan 181117395Skan /* 182117395Skan * ia64_mca_save_state() is CPU-sensitive, so bind ourself to our 18318334Speter * target CPU. 184169689Skan */ 185169689Skan thread_lock(td); 186169689Skan sched_bind(td, pc->pc_cpuid); 187169689Skan thread_unlock(td); 188169689Skan 189169689Skan ia64_mca_init_ap(); 190169689Skan 191169689Skan /* 192169689Skan * Get and save the CPU specific MCA records. Should we get the 193169689Skan * MCA state for each processor, or just the CMC state? 194169689Skan */ 195169689Skan ia64_mca_save_state(SAL_INFO_MCA); 196169689Skan ia64_mca_save_state(SAL_INFO_CMC); 197169689Skan 198169689Skan kproc_exit(0); 199169689Skan} 200169689Skan 201169689Skanvoid 202169689Skania64_ap_startup(void) 203169689Skan{ 204169689Skan uint64_t vhpt; 205169689Skan 206169689Skan ia64_ap_state.as_trace = 0x100; 207169689Skan 208169689Skan ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1); 209169689Skan ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (LOG2_ID_PAGE_SIZE << 2)); 210169689Skan ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (LOG2_ID_PAGE_SIZE << 2)); 211169689Skan ia64_srlz_d(); 212169689Skan 213169689Skan pcpup = ia64_ap_state.as_pcpu; 214169689Skan ia64_set_k4((intptr_t)pcpup); 215169689Skan 216169689Skan ia64_ap_state.as_trace = 0x108; 217169689Skan 218169689Skan vhpt = PCPU_GET(md.vhpt); 219169689Skan map_vhpt(vhpt); 220169689Skan ia64_set_pta(vhpt + (1 << 8) + (pmap_vhpt_log2size << 2) + 1); 221169689Skan ia64_srlz_i(); 222169689Skan 223169689Skan ia64_ap_state.as_trace = 0x110; 224169689Skan 225169689Skan ia64_ap_state.as_awake = 1; 226169689Skan ia64_ap_state.as_delay = 0; 227169689Skan 228169689Skan map_pal_code(); 229169689Skan map_gateway_page(); 230169689Skan 231169689Skan ia64_set_fpsr(IA64_FPSR_DEFAULT); 232169689Skan 233169689Skan /* Wait until it's time for us to be unleashed */ 234169689Skan while (ia64_ap_state.as_spin) 235169689Skan cpu_spinwait(); 236169689Skan 23718334Speter /* Initialize curthread. */ 23818334Speter KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread")); 239132718Skan PCPU_SET(curthread, PCPU_GET(idlethread)); 240117395Skan 24118334Speter atomic_add_int(&ia64_ap_state.as_awake, 1); 24218334Speter while (!smp_started) 24390075Sobrien cpu_spinwait(); 24490075Sobrien 24518334Speter CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid)); 24690075Sobrien 24790075Sobrien cpu_initclocks(); 248117395Skan 249117395Skan ia64_set_tpr(0); 250117395Skan ia64_srlz_d(); 251117395Skan 252117395Skan sched_throw(NULL); 25318334Speter /* NOTREACHED */ 254117395Skan} 255117395Skan 25618334Spetervoid 257117395Skancpu_mp_setmaxid(void) 258117395Skan{ 259117395Skan 26018334Speter /* 26118334Speter * Count the number of processors in the system by walking the ACPI 262117395Skan * tables. Note that we record the actual number of processors, even 263117395Skan * if this is larger than MAXCPU. We only activate MAXCPU processors. 26418334Speter */ 265117395Skan mp_ncpus = ia64_count_cpus(); 266117395Skan 267117395Skan /* 268117395Skan * Set the largest cpuid we're going to use. This is necessary for 26918334Speter * VM initialization. 270117395Skan */ 271117395Skan mp_maxid = min(mp_ncpus, MAXCPU) - 1; 272117395Skan} 27318334Speter 27450397Sobrienint 27518334Spetercpu_mp_probe(void) 27618334Speter{ 27718334Speter 27890075Sobrien /* 27918334Speter * If there's only 1 processor, or we don't have a wake-up vector, 28018334Speter * we're not going to enable SMP. Note that no wake-up vector can 28118334Speter * also mean that the wake-up mechanism is not supported. In this 282117395Skan * case we can have multiple processors, but we simply can't wake 28318334Speter * them up... 28418334Speter */ 28518334Speter return (mp_ncpus > 1 && ia64_ipi_wakeup != 0); 286169689Skan} 28718334Speter 288117395Skanvoid 289117395Skancpu_mp_add(u_int acpi_id, u_int id, u_int eid) 29090075Sobrien{ 29118334Speter struct pcpu *pc; 292117395Skan void *dpcpu; 29318334Speter u_int cpuid, sapic_id; 29418334Speter 29552284Sobrien sapic_id = SAPIC_ID_SET(id, eid); 29652284Sobrien cpuid = (IA64_LID_GET_SAPIC_ID(ia64_get_lid()) == sapic_id) 29790075Sobrien ? 0 : smp_cpus++; 298169689Skan 29990075Sobrien KASSERT(!CPU_ISSET(cpuid, &all_cpus), 30090075Sobrien ("%s: cpu%d already in CPU map", __func__, acpi_id)); 30150397Sobrien 302169689Skan if (cpuid != 0) { 303169689Skan pc = (struct pcpu *)malloc(sizeof(*pc), M_SMP, M_WAITOK); 304169689Skan pcpu_init(pc, cpuid, sizeof(*pc)); 305169689Skan dpcpu = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, 30690075Sobrien M_WAITOK | M_ZERO); 30718334Speter dpcpu_init(dpcpu, cpuid); 30818334Speter } else 30918334Speter pc = pcpup; 310132718Skan 311132718Skan cpu_pcpu_setup(pc, acpi_id, sapic_id); 312132718Skan 313169689Skan CPU_SET(pc->pc_cpuid, &all_cpus); 314169689Skan} 315132718Skan 31690075Sobrienvoid 31718334Spetercpu_mp_announce() 318132718Skan{ 319132718Skan struct pcpu *pc; 320132718Skan uint32_t sapic_id; 321132718Skan int i; 322169689Skan 323132718Skan for (i = 0; i <= mp_maxid; i++) { 32418334Speter pc = pcpu_find(i); 32518334Speter if (pc != NULL) { 326117395Skan sapic_id = IA64_LID_GET_SAPIC_ID(pc->pc_md.lid); 327117395Skan printf("cpu%d: ACPI Id=%x, SAPIC Id=%x, SAPIC Eid=%x", 328117395Skan i, pc->pc_acpi_id, SAPIC_ID_GET_ID(sapic_id), 329117395Skan SAPIC_ID_GET_EID(sapic_id)); 330117395Skan if (i == 0) 331117395Skan printf(" (BSP)\n"); 332117395Skan else 333169689Skan printf("\n"); 334169689Skan } 335169689Skan } 336169689Skan} 337117395Skan 338117395Skanvoid 339117395Skancpu_mp_start() 340117395Skan{ 34118334Speter struct ia64_sal_result result; 34218334Speter struct ia64_fdesc *fd; 34390075Sobrien struct pcpu *pc; 344132718Skan uintptr_t state; 34518334Speter u_char *stp; 34690075Sobrien 347132718Skan state = ia64_tpa((uintptr_t)&ia64_ap_state); 34818334Speter fd = (struct ia64_fdesc *) os_boot_rendez; 34918334Speter result = ia64_sal_entry(SAL_SET_VECTORS, SAL_OS_BOOT_RENDEZ, 35018334Speter ia64_tpa(fd->func), state, 0, 0, 0, 0); 35118334Speter 35218334Speter ia64_ap_state.as_pgtbl_pte = PTE_PRESENT | PTE_MA_WB | 353117395Skan PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW | 35450397Sobrien (bootinfo->bi_pbvm_pgtbl & PTE_PPN_MASK); 355117395Skan ia64_ap_state.as_pgtbl_itir = sz2shft(bootinfo->bi_pbvm_pgtblsz) << 2; 35690075Sobrien ia64_ap_state.as_text_va = IA64_PBVM_BASE; 35718334Speter ia64_ap_state.as_text_pte = PTE_PRESENT | PTE_MA_WB | 35818334Speter PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RX | 35918334Speter (ia64_tpa(IA64_PBVM_BASE) & PTE_PPN_MASK); 36018334Speter ia64_ap_state.as_text_itir = bootinfo->bi_text_mapped << 2; 36150397Sobrien ia64_ap_state.as_data_va = (uintptr_t)bdata; 36218334Speter ia64_ap_state.as_data_pte = PTE_PRESENT | PTE_MA_WB | 363169689Skan PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW | 36490075Sobrien (ia64_tpa((uintptr_t)bdata) & PTE_PPN_MASK); 36518334Speter ia64_ap_state.as_data_itir = bootinfo->bi_data_mapped << 2; 366169689Skan 367169689Skan /* Keep 'em spinning until we unleash them... */ 368169689Skan ia64_ap_state.as_spin = 1; 369169689Skan 370169689Skan STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 371169689Skan pc->pc_md.current_pmap = kernel_pmap; 37290075Sobrien /* The BSP is obviously running already. */ 37390075Sobrien if (pc->pc_cpuid == 0) { 37418334Speter pc->pc_md.awake = 1; 37590075Sobrien continue; 37690075Sobrien } 37718334Speter 378169689Skan ia64_ap_state.as_pcpu = pc; 379169689Skan pc->pc_md.vhpt = pmap_alloc_vhpt(); 380169689Skan if (pc->pc_md.vhpt == 0) { 381169689Skan printf("SMP: WARNING: unable to allocate VHPT" 382169689Skan " for cpu%d", pc->pc_cpuid); 383169689Skan continue; 384169689Skan } 385169689Skan 386169689Skan stp = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, M_WAITOK); 387169689Skan ia64_ap_state.as_kstack = stp; 38890075Sobrien ia64_ap_state.as_kstack_top = stp + KSTACK_PAGES * PAGE_SIZE; 38990075Sobrien 39090075Sobrien ia64_ap_state.as_trace = 0; 39190075Sobrien ia64_ap_state.as_delay = 2000; 39290075Sobrien ia64_ap_state.as_awake = 0; 39390075Sobrien 39490075Sobrien if (bootverbose) 39590075Sobrien printf("SMP: waking up cpu%d\n", pc->pc_cpuid); 39690075Sobrien 39790075Sobrien /* Here she goes... */ 39890075Sobrien ipi_send(pc, ia64_ipi_wakeup); 399169689Skan do { 400169689Skan DELAY(1000); 401169689Skan } while (--ia64_ap_state.as_delay > 0); 402169689Skan 403169689Skan pc->pc_md.awake = ia64_ap_state.as_awake; 404169689Skan 405169689Skan if (!ia64_ap_state.as_awake) { 406169689Skan printf("SMP: WARNING: cpu%d did not wake up (code " 407169689Skan "%#lx)\n", pc->pc_cpuid, 408169689Skan ia64_ap_state.as_trace - state); 409169689Skan } 410169689Skan } 411169689Skan} 412169689Skan 413169689Skanstatic void 414169689Skancpu_mp_unleash(void *dummy) 415169689Skan{ 416169689Skan struct pcpu *pc; 417169689Skan int cpus; 418169689Skan 419169689Skan if (mp_ncpus <= 1) 420169689Skan return; 421169689Skan 422169689Skan /* Allocate XIVs for IPIs */ 423169689Skan ia64_ipi_ast = ia64_xiv_alloc(PI_DULL, IA64_XIV_IPI, ia64_ih_ast); 424169689Skan ia64_ipi_hardclock = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, 425169689Skan ia64_ih_hardclock); 426169689Skan ia64_ipi_highfp = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_highfp); 427169689Skan ia64_ipi_preempt = ia64_xiv_alloc(PI_SOFT, IA64_XIV_IPI, 428169689Skan ia64_ih_preempt); 429169689Skan ia64_ipi_rndzvs = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_rndzvs); 430169689Skan ia64_ipi_stop = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, ia64_ih_stop); 431169689Skan 432169689Skan /* Reserve the NMI vector for IPI_STOP_HARD if possible */ 433169689Skan ia64_ipi_nmi = (ia64_xiv_reserve(2, IA64_XIV_IPI, ia64_ih_stop) != 0) 434169689Skan ? ia64_ipi_stop : 0x400; /* DM=NMI, Vector=n/a */ 435169689Skan 436169689Skan cpus = 0; 437169689Skan smp_cpus = 0; 438169689Skan STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 439169689Skan cpus++; 440169689Skan if (pc->pc_md.awake) { 441169689Skan kproc_create(ia64_store_mca_state, pc, NULL, 0, 0, 442169689Skan "mca %u", pc->pc_cpuid); 443169689Skan smp_cpus++; 444169689Skan } 445169689Skan } 44618334Speter 44718334Speter ia64_ap_state.as_awake = 1; 44818334Speter ia64_ap_state.as_spin = 0; 449169689Skan 45018334Speter while (ia64_ap_state.as_awake != smp_cpus) 451169689Skan cpu_spinwait(); 452169689Skan 453169689Skan if (smp_cpus != cpus || cpus != mp_ncpus) { 454169689Skan printf("SMP: %d CPUs found; %d CPUs usable; %d CPUs woken\n", 45518334Speter mp_ncpus, cpus, smp_cpus); 45618334Speter } 45790075Sobrien 45890075Sobrien smp_active = 1; 45990075Sobrien smp_started = 1; 46090075Sobrien 461117395Skan /* 462117395Skan * Now that all CPUs are up and running, bind interrupts to each of 46390075Sobrien * them. 46490075Sobrien */ 46590075Sobrien ia64_bind_intr(); 46690075Sobrien} 46790075SobrienSYSINIT(start_aps, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, cpu_mp_unleash, NULL); 46890075Sobrien 469132718Skan/* 47050397Sobrien * send an IPI to a set of cpus. 47190075Sobrien */ 472117395Skanvoid 473117395Skanipi_selected(cpuset_t cpus, int ipi) 47490075Sobrien{ 47590075Sobrien struct pcpu *pc; 47690075Sobrien 47790075Sobrien STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 47890075Sobrien if (CPU_ISSET(pc->pc_cpuid, &cpus)) 47990075Sobrien ipi_send(pc, ipi); 48090075Sobrien } 481132718Skan} 48290075Sobrien 48390075Sobrien/* 484117395Skan * send an IPI to a specific CPU. 48590075Sobrien */ 48690075Sobrienvoid 48790075Sobrienipi_cpu(int cpu, u_int ipi) 488132718Skan{ 48990075Sobrien 49090075Sobrien ipi_send(cpuid_to_pcpu[cpu], ipi); 491117395Skan} 492117395Skan 49390075Sobrien/* 49490075Sobrien * send an IPI to all CPUs EXCEPT myself. 49590075Sobrien */ 496132718Skanvoid 49790075Sobrienipi_all_but_self(int ipi) 49890075Sobrien{ 499117395Skan struct pcpu *pc; 50090075Sobrien 50190075Sobrien STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 50290075Sobrien if (pc != pcpup) 50390075Sobrien ipi_send(pc, ipi); 50490075Sobrien } 505132718Skan} 506132718Skan 507132718Skan/* 508132718Skan * Send an IPI to the specified processor. 509132718Skan */ 510132718Skanvoid 511132718Skanipi_send(struct pcpu *cpu, int xiv) 512132718Skan{ 513132718Skan u_int sapic_id; 514132718Skan 515132718Skan KASSERT(xiv != 0, ("ipi_send")); 516132718Skan 517132718Skan sapic_id = IA64_LID_GET_SAPIC_ID(cpu->pc_md.lid); 518132718Skan 519132718Skan ia64_mf(); 520132718Skan ia64_st8(&(ia64_pib->ib_ipi[sapic_id][0]), xiv); 521132718Skan ia64_mf_a(); 522132718Skan CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid)); 523169689Skan} 524169689Skan