2 * Copyright (c) 2001-2005 Marcel Moolenaar
3 * Copyright (c) 2000 Doug Rabson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include "opt_kstack_pages.h"
32 #include "opt_xtrace.h"
34 #include <sys/param.h>
35 #include <sys/systm.h>
39 #include <sys/kthread.h>
41 #include <sys/malloc.h>
42 #include <sys/mutex.h>
43 #include <sys/kernel.h>
45 #include <sys/sched.h>
47 #include <sys/sysctl.h>
50 #include <machine/atomic.h>
51 #include <machine/bootinfo.h>
52 #include <machine/cpu.h>
53 #include <machine/fpu.h>
54 #include <machine/intr.h>
55 #include <machine/mca.h>
56 #include <machine/md_var.h>
57 #include <machine/pal.h>
58 #include <machine/pcb.h>
59 #include <machine/sal.h>
60 #include <machine/smp.h>
64 #include <vm/vm_extern.h>
65 #include <vm/vm_kern.h>
67 extern uint64_t bdata[];
69 extern int smp_disabled;
71 MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations");
73 void ia64_ap_startup(void);
75 #define SAPIC_ID_GET_ID(x) ((u_int)((x) >> 8) & 0xff)
76 #define SAPIC_ID_GET_EID(x) ((u_int)(x) & 0xff)
77 #define SAPIC_ID_SET(id, eid) ((u_int)(((id) & 0xff) << 8) | ((eid) & 0xff))
79 /* State used to wake and bootstrap APs. */
80 struct ia64_ap_state ia64_ap_state;
83 int ia64_ipi_hardclock;
96 shft = 12; /* Start with 4K */
106 ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf)
109 PCPU_INC(md.stats.pcs_nasts);
110 CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
115 ia64_ih_hardclock(struct thread *td, u_int xiv, struct trapframe *tf)
117 struct trapframe *stf;
119 PCPU_INC(md.stats.pcs_nhardclocks);
120 CTR1(KTR_SMP, "IPI_HARDCLOCK, cpuid=%d", PCPU_GET(cpuid));
121 stf = td->td_intr_frame;
122 td->td_intr_frame = tf;
124 td->td_intr_frame = stf;
129 ia64_ih_highfp(struct thread *td, u_int xiv, struct trapframe *tf)
132 PCPU_INC(md.stats.pcs_nhighfps);
133 ia64_highfp_save_ipi();
138 ia64_ih_preempt(struct thread *td, u_int xiv, struct trapframe *tf)
141 PCPU_INC(md.stats.pcs_npreempts);
142 CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
143 sched_preempt(curthread);
148 ia64_ih_rndzvs(struct thread *td, u_int xiv, struct trapframe *tf)
151 PCPU_INC(md.stats.pcs_nrdvs);
152 CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
153 smp_rendezvous_action();
158 ia64_ih_stop(struct thread *td, u_int xiv, struct trapframe *tf)
162 PCPU_INC(md.stats.pcs_nstops);
163 cpuid = PCPU_GET(cpuid);
165 savectx(PCPU_PTR(md.pcb));
167 CPU_SET_ATOMIC(cpuid, &stopped_cpus);
168 while (!CPU_ISSET(cpuid, &started_cpus))
170 CPU_CLR_ATOMIC(cpuid, &started_cpus);
171 CPU_CLR_ATOMIC(cpuid, &stopped_cpus);
179 return smp_topo_none();
183 ia64_store_mca_state(void* arg)
185 struct pcpu *pc = arg;
186 struct thread *td = curthread;
189 * ia64_mca_save_state() is CPU-sensitive, so bind ourself to our
193 sched_bind(td, pc->pc_cpuid);
199 * Get and save the CPU specific MCA records. Should we get the
200 * MCA state for each processor, or just the CMC state?
202 ia64_mca_save_state(SAL_INFO_MCA);
203 ia64_mca_save_state(SAL_INFO_CMC);
209 ia64_ap_startup(void)
213 ia64_ap_state.as_trace = 0x100;
215 ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1);
216 ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (LOG2_ID_PAGE_SIZE << 2));
217 ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (LOG2_ID_PAGE_SIZE << 2));
220 pcpup = ia64_ap_state.as_pcpu;
221 ia64_set_k4((intptr_t)pcpup);
223 ia64_ap_state.as_trace = 0x108;
225 vhpt = pcpup->pc_md.vhpt;
227 ia64_set_pta(vhpt + (1 << 8) + (pmap_vhpt_log2size << 2) + 1);
230 ia64_ap_state.as_trace = 0x110;
232 ia64_ap_state.as_awake = 1;
233 ia64_ap_state.as_delay = 0;
238 ia64_set_fpsr(IA64_FPSR_DEFAULT);
241 ia64_xtrace_init_ap(ia64_ap_state.as_xtrace_buffer);
244 /* Wait until it's time for us to be unleashed */
245 while (ia64_ap_state.as_spin)
248 /* Initialize curthread. */
249 KASSERT(pcpup->pc_idlethread != NULL, ("no idle thread"));
250 pcpup->pc_curthread = pcpup->pc_idlethread;
252 pmap_invalidate_all();
254 atomic_add_int(&ia64_ap_state.as_awake, 1);
258 CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid));
270 cpu_mp_setmaxid(void)
274 * Count the number of processors in the system by walking the ACPI
275 * tables. Note that we record the actual number of processors, even
276 * if this is larger than MAXCPU. We only activate MAXCPU processors.
278 mp_ncpus = ia64_count_cpus();
281 * Set the largest cpuid we're going to use. This is necessary for
284 mp_maxid = min(mp_ncpus, MAXCPU) - 1;
292 * If there's only 1 processor, or we don't have a wake-up vector,
293 * we're not going to enable SMP. Note that no wake-up vector can
294 * also mean that the wake-up mechanism is not supported. In this
295 * case we can have multiple processors, but we simply can't wake
298 return (mp_ncpus > 1 && ia64_ipi_wakeup != 0);
302 cpu_mp_add(u_int acpi_id, u_int id, u_int eid)
306 u_int cpuid, sapic_id;
311 sapic_id = SAPIC_ID_SET(id, eid);
312 cpuid = (IA64_LID_GET_SAPIC_ID(ia64_get_lid()) == sapic_id)
315 KASSERT(!CPU_ISSET(cpuid, &all_cpus),
316 ("%s: cpu%d already in CPU map", __func__, acpi_id));
319 pc = (struct pcpu *)malloc(sizeof(*pc), M_SMP, M_WAITOK);
320 pcpu_init(pc, cpuid, sizeof(*pc));
321 dpcpu = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
323 dpcpu_init(dpcpu, cpuid);
327 cpu_pcpu_setup(pc, acpi_id, sapic_id);
329 CPU_SET(pc->pc_cpuid, &all_cpus);
339 for (i = 0; i <= mp_maxid; i++) {
342 sapic_id = IA64_LID_GET_SAPIC_ID(pc->pc_md.lid);
343 printf("cpu%d: ACPI Id=%x, SAPIC Id=%x, SAPIC Eid=%x",
344 i, pc->pc_acpi_id, SAPIC_ID_GET_ID(sapic_id),
345 SAPIC_ID_GET_EID(sapic_id));
357 struct ia64_sal_result result;
358 struct ia64_fdesc *fd;
363 state = ia64_tpa((uintptr_t)&ia64_ap_state);
364 fd = (struct ia64_fdesc *) os_boot_rendez;
365 result = ia64_sal_entry(SAL_SET_VECTORS, SAL_OS_BOOT_RENDEZ,
366 ia64_tpa(fd->func), state, 0, 0, 0, 0);
368 ia64_ap_state.as_pgtbl_pte = PTE_PRESENT | PTE_MA_WB |
369 PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW |
370 (bootinfo->bi_pbvm_pgtbl & PTE_PPN_MASK);
371 ia64_ap_state.as_pgtbl_itir = sz2shft(bootinfo->bi_pbvm_pgtblsz) << 2;
372 ia64_ap_state.as_text_va = IA64_PBVM_BASE;
373 ia64_ap_state.as_text_pte = PTE_PRESENT | PTE_MA_WB |
374 PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RX |
375 (ia64_tpa(IA64_PBVM_BASE) & PTE_PPN_MASK);
376 ia64_ap_state.as_text_itir = bootinfo->bi_text_mapped << 2;
377 ia64_ap_state.as_data_va = (uintptr_t)bdata;
378 ia64_ap_state.as_data_pte = PTE_PRESENT | PTE_MA_WB |
379 PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW |
380 (ia64_tpa((uintptr_t)bdata) & PTE_PPN_MASK);
381 ia64_ap_state.as_data_itir = bootinfo->bi_data_mapped << 2;
383 /* Keep 'em spinning until we unleash them... */
384 ia64_ap_state.as_spin = 1;
386 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
387 pc->pc_md.current_pmap = kernel_pmap;
388 /* The BSP is obviously running already. */
389 if (pc->pc_cpuid == 0) {
394 ia64_ap_state.as_pcpu = pc;
395 pc->pc_md.vhpt = pmap_alloc_vhpt();
396 if (pc->pc_md.vhpt == 0) {
397 printf("SMP: WARNING: unable to allocate VHPT"
398 " for cpu%d", pc->pc_cpuid);
402 stp = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, M_WAITOK);
403 ia64_ap_state.as_kstack = stp;
404 ia64_ap_state.as_kstack_top = stp + KSTACK_PAGES * PAGE_SIZE;
407 ia64_ap_state.as_xtrace_buffer = ia64_xtrace_alloc();
410 ia64_ap_state.as_trace = 0;
411 ia64_ap_state.as_delay = 2000;
412 ia64_ap_state.as_awake = 0;
415 printf("SMP: waking up cpu%d\n", pc->pc_cpuid);
417 /* Here she goes... */
418 ipi_send(pc, ia64_ipi_wakeup);
421 } while (--ia64_ap_state.as_delay > 0);
423 pc->pc_md.awake = ia64_ap_state.as_awake;
425 if (!ia64_ap_state.as_awake) {
426 printf("SMP: WARNING: cpu%d did not wake up (code "
427 "%#lx)\n", pc->pc_cpuid,
428 ia64_ap_state.as_trace - state);
434 cpu_mp_unleash(void *dummy)
442 /* Allocate XIVs for IPIs */
443 ia64_ipi_ast = ia64_xiv_alloc(PI_DULL, IA64_XIV_IPI, ia64_ih_ast);
444 ia64_ipi_hardclock = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
446 ia64_ipi_highfp = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_highfp);
447 ia64_ipi_preempt = ia64_xiv_alloc(PI_SOFT, IA64_XIV_IPI,
449 ia64_ipi_rndzvs = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_rndzvs);
450 ia64_ipi_stop = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, ia64_ih_stop);
452 /* Reserve the NMI vector for IPI_STOP_HARD if possible */
453 ia64_ipi_nmi = (ia64_xiv_reserve(2, IA64_XIV_IPI, ia64_ih_stop) != 0)
454 ? ia64_ipi_stop : 0x400; /* DM=NMI, Vector=n/a */
458 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
460 if (pc->pc_md.awake) {
461 kproc_create(ia64_store_mca_state, pc, NULL, 0, 0,
462 "mca %u", pc->pc_cpuid);
467 ia64_ap_state.as_awake = 1;
468 ia64_ap_state.as_spin = 0;
470 while (ia64_ap_state.as_awake != smp_cpus)
473 if (smp_cpus != cpus || cpus != mp_ncpus) {
474 printf("SMP: %d CPUs found; %d CPUs usable; %d CPUs woken\n",
475 mp_ncpus, cpus, smp_cpus);
478 /* XXX Atomic set operation? */
482 * Now that all CPUs are up and running, bind interrupts to each of
487 SYSINIT(start_aps, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, cpu_mp_unleash, NULL);
490 * send an IPI to a set of cpus.
493 ipi_selected(cpuset_t cpus, int ipi)
497 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
498 if (CPU_ISSET(pc->pc_cpuid, &cpus))
504 * send an IPI to a specific CPU.
507 ipi_cpu(int cpu, u_int ipi)
510 ipi_send(cpuid_to_pcpu[cpu], ipi);
514 * send an IPI to all CPUs EXCEPT myself.
517 ipi_all_but_self(int ipi)
521 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
528 * Send an IPI to the specified processor.
531 ipi_send(struct pcpu *cpu, int xiv)
535 KASSERT(xiv != 0, ("ipi_send"));
537 sapic_id = IA64_LID_GET_SAPIC_ID(cpu->pc_md.lid);
540 ia64_st8(&(ia64_pib->ib_ipi[sapic_id][0]), xiv);
542 CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid));