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