mp_machdep.c revision 91617
150397Sobrien/*- 250397Sobrien * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. 350397Sobrien * 450397Sobrien * Redistribution and use in source and binary forms, with or without 550397Sobrien * modification, are permitted provided that the following conditions 650397Sobrien * are met: 750397Sobrien * 1. Redistributions of source code must retain the above copyright 850397Sobrien * notice, this list of conditions and the following disclaimer. 950397Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1050397Sobrien * notice, this list of conditions and the following disclaimer in the 1150397Sobrien * documentation and/or other materials provided with the distribution. 1250397Sobrien * 3. Berkeley Software Design Inc's name may not be used to endorse or 1390075Sobrien * promote products derived from this software without specific prior 1450397Sobrien * written permission. 1550397Sobrien * 1650397Sobrien * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 1750397Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1850397Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1950397Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 2050397Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2150397Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2250397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2350397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2450397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2550397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2650397Sobrien * SUCH DAMAGE. 2750397Sobrien * 2850397Sobrien * from BSDI: locore.s,v 1.36.2.15 1999/08/23 22:34:41 cp Exp 2950397Sobrien */ 3050397Sobrien/*- 31117395Skan * Copyright (c) 2002 Jake Burkholder. 3250397Sobrien * All rights reserved. 3350397Sobrien * 3450397Sobrien * Redistribution and use in source and binary forms, with or without 35132718Skan * modification, are permitted provided that the following conditions 36132718Skan * are met: 37132718Skan * 1. Redistributions of source code must retain the above copyright 38132718Skan * notice, this list of conditions and the following disclaimer. 39132718Skan * 2. Redistributions in binary form must reproduce the above copyright 4050397Sobrien * notice, this list of conditions and the following disclaimer in the 4150397Sobrien * documentation and/or other materials provided with the distribution. 4250397Sobrien * 4350397Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4450397Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4550397Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4650397Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4750397Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4850397Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4950397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5050397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5150397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5250397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5350397Sobrien * SUCH DAMAGE. 5450397Sobrien * 5550397Sobrien * $FreeBSD: head/sys/sparc64/sparc64/mp_machdep.c 91617 2002-03-04 07:12:36Z jake $ 5650397Sobrien */ 5750397Sobrien 5850397Sobrien#include <sys/param.h> 5950397Sobrien#include <sys/systm.h> 6050397Sobrien#include <sys/lock.h> 6150397Sobrien#include <sys/kernel.h> 6250397Sobrien#include <sys/ktr.h> 6350397Sobrien#include <sys/mutex.h> 6450397Sobrien#include <sys/pcpu.h> 6550397Sobrien#include <sys/proc.h> 6650397Sobrien#include <sys/smp.h> 6750397Sobrien 6850397Sobrien#include <vm/vm.h> 6950397Sobrien#include <vm/vm_param.h> 7050397Sobrien#include <vm/pmap.h> 7150397Sobrien#include <vm/vm_kern.h> 7250397Sobrien#include <vm/vm_extern.h> 7350397Sobrien#include <vm/vm_map.h> 7450397Sobrien 7550397Sobrien#include <dev/ofw/openfirm.h> 7650397Sobrien 7750397Sobrien#include <machine/asi.h> 7850397Sobrien#include <machine/md_var.h> 7950397Sobrien#include <machine/smp.h> 8050397Sobrien#include <machine/tlb.h> 8150397Sobrien#include <machine/tte.h> 8250397Sobrien 8350397Sobrienstatic ih_func_t cpu_ipi_ast; 8450397Sobrienstatic ih_func_t cpu_ipi_stop; 8550397Sobrien 8650397Sobrien/* 8750397Sobrien * Argument area used to pass data to non-boot processors as they start up. 8850397Sobrien * This must be statically initialized with a known invalid upa module id, 8950397Sobrien * since the other processors will use it before the boot cpu enters the 9050397Sobrien * kernel. 91132718Skan */ 92132718Skanstruct cpu_start_args cpu_start_args = { -1, -1, 0, 0 }; 93132718Skan 9450397Sobrienvm_offset_t mp_tramp; 95132718Skan 9650397Sobrienstatic struct mtx ap_boot_mtx; 9750397Sobrien 9850397Sobrienu_int mp_boot_mid; 9950397Sobrien 10050397Sobrienvoid cpu_mp_unleash(void *); 10150397SobrienSYSINIT(cpu_mp_unleash, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL); 10250397Sobrien 10350397Sobrienvm_offset_t 10450397Sobrienmp_tramp_alloc(void) 10550397Sobrien{ 10690075Sobrien struct tte *tp; 10750397Sobrien char *v; 10850397Sobrien int i; 10990075Sobrien 11050397Sobrien v = OF_claim(NULL, PAGE_SIZE, PAGE_SIZE); 11150397Sobrien if (v == NULL) 11250397Sobrien panic("mp_tramp_alloc"); 11350397Sobrien bcopy(mp_tramp_code, v, mp_tramp_code_len); 11450397Sobrien *(u_long *)(v + mp_tramp_tlb_slots) = kernel_tlb_slots; 11550397Sobrien *(u_long *)(v + mp_tramp_func) = (u_long)mp_startup; 11650397Sobrien tp = (struct tte *)(v + mp_tramp_code_len); 11750397Sobrien for (i = 0; i < kernel_tlb_slots; i++) 11850397Sobrien tp[i] = kernel_ttes[i]; 11950397Sobrien for (i = 0; i < PAGE_SIZE; i += sizeof(long)) 12050397Sobrien flush(v + i); 12150397Sobrien return (vm_offset_t)v; 12250397Sobrien} 12350397Sobrien 12450397Sobrien/* 12550397Sobrien * Probe for other cpus. 12650397Sobrien */ 12750397Sobrienint 12850397Sobriencpu_mp_probe(void) 12950397Sobrien{ 13050397Sobrien phandle_t child; 13150397Sobrien phandle_t root; 13250397Sobrien char buf[128]; 13350397Sobrien int cpus; 13450397Sobrien 13550397Sobrien all_cpus = 1 << PCPU_GET(cpuid); 13650397Sobrien mp_boot_mid = PCPU_GET(mid); 13750397Sobrien mp_ncpus = 1; 13850397Sobrien 13950397Sobrien cpus = 0; 14050397Sobrien root = OF_peer(0); 14150397Sobrien for (child = OF_child(root); child != 0; child = OF_peer(child)) { 14250397Sobrien if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 14350397Sobrien strcmp(buf, "cpu") == 0) 14450397Sobrien cpus++; 14550397Sobrien } 14650397Sobrien return (cpus > 1); 14750397Sobrien} 14850397Sobrien 14950397Sobrienstatic void 15050397Sobriensun4u_startcpu(phandle_t cpu, void *func, u_long arg) 15150397Sobrien{ 15250397Sobrien static struct { 15350397Sobrien cell_t name; 15450397Sobrien cell_t nargs; 15550397Sobrien cell_t nreturns; 15650397Sobrien cell_t cpu; 15750397Sobrien cell_t func; 15850397Sobrien cell_t arg; 15950397Sobrien } args = { 16050397Sobrien (cell_t)"SUNW,start-cpu", 16150397Sobrien 3, 16250397Sobrien 0, 16350397Sobrien 0, 16450397Sobrien 0, 16550397Sobrien 0 16650397Sobrien }; 16750397Sobrien 16850397Sobrien args.cpu = cpu; 16950397Sobrien args.func = (cell_t)func; 17050397Sobrien args.arg = (cell_t)arg; 171132718Skan openfirmware(&args); 17250397Sobrien} 17350397Sobrien 17450397Sobrien/* 17550397Sobrien * Fire up any non-boot processors. 17650397Sobrien */ 17750397Sobrienvoid 17850397Sobriencpu_mp_start(void) 17950397Sobrien{ 18052284Sobrien volatile struct cpu_start_args *csa; 18150397Sobrien struct pcpu *pc; 18250397Sobrien phandle_t child; 18350397Sobrien phandle_t root; 18450397Sobrien vm_offset_t va; 18550397Sobrien char buf[128]; 18650397Sobrien u_int clock; 18750397Sobrien int cpuid; 18850397Sobrien u_int mid; 18950397Sobrien u_long s; 19050397Sobrien 19150397Sobrien mtx_init(&ap_boot_mtx, "ap boot", MTX_SPIN); 19250397Sobrien 19350397Sobrien intr_setup(PIL_AST, cpu_ipi_ast, -1, NULL, NULL); 19450397Sobrien intr_setup(PIL_RENDEZVOUS, (ih_func_t *)smp_rendezvous_action, 19550397Sobrien -1, NULL, NULL); 19650397Sobrien intr_setup(PIL_STOP, cpu_ipi_stop, -1, NULL, NULL); 19750397Sobrien 19850397Sobrien root = OF_peer(0); 19990075Sobrien csa = &cpu_start_args; 20050397Sobrien for (child = OF_child(root); child != 0; child = OF_peer(child)) { 20150397Sobrien if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0 || 20250397Sobrien strcmp(buf, "cpu") != 0) 20350397Sobrien continue; 20450397Sobrien if (OF_getprop(child, "upa-portid", &mid, sizeof(mid)) <= 0) 20550397Sobrien panic("cpu_mp_start: can't get module id"); 20650397Sobrien if (mid == mp_boot_mid) 20750397Sobrien continue; 20850397Sobrien if (OF_getprop(child, "clock-frequency", &clock, 20950397Sobrien sizeof(clock)) <= 0) 21050397Sobrien panic("cpu_mp_start: can't get clock"); 21150397Sobrien 21290075Sobrien csa->csa_state = 0; 21350397Sobrien sun4u_startcpu(child, (void *)mp_tramp, 0); 21450397Sobrien s = intr_disable(); 21550397Sobrien while (csa->csa_state != CPU_CLKSYNC) 21650397Sobrien ; 21750397Sobrien membar(StoreLoad); 21850397Sobrien csa->csa_tick = rd(tick); 21950397Sobrien while (csa->csa_state != CPU_INIT) 22050397Sobrien ; 22150397Sobrien csa->csa_tick = 0; 22250397Sobrien intr_restore(s); 22350397Sobrien 22450397Sobrien cpuid = mp_ncpus++; 22590075Sobrien cpu_identify(csa->csa_ver, clock, cpuid); 22650397Sobrien 22750397Sobrien va = kmem_alloc(kernel_map, PCPU_PAGES * PAGE_SIZE); 22850397Sobrien pc = (struct pcpu *)(va + (PCPU_PAGES * PAGE_SIZE)) - 1; 22950397Sobrien pcpu_init(pc, cpuid, sizeof(*pc)); 23050397Sobrien pc->pc_addr = va; 23150397Sobrien pc->pc_mid = mid; 23250397Sobrien 23350397Sobrien all_cpus |= 1 << cpuid; 23450397Sobrien } 23550397Sobrien PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid))); 236117395Skan} 23750397Sobrien 23850397Sobrienvoid 23950397Sobriencpu_mp_announce(void) 24050397Sobrien{ 24150397Sobrien} 24250397Sobrien 24350397Sobrienvoid 24450397Sobriencpu_mp_unleash(void *v) 24550397Sobrien{ 24650397Sobrien volatile struct cpu_start_args *csa; 24750397Sobrien struct pcpu *pc; 24850397Sobrien vm_offset_t pa; 24950397Sobrien vm_offset_t va; 25050397Sobrien u_int ctx_min; 25150397Sobrien u_int ctx_inc; 25250397Sobrien u_long s; 25350397Sobrien int i; 25450397Sobrien 25550397Sobrien ctx_min = 1; 25650397Sobrien ctx_inc = (8192 - 1) / mp_ncpus; 25750397Sobrien csa = &cpu_start_args; 25850397Sobrien SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { 25950397Sobrien pc->pc_tlb_ctx = ctx_min; 26050397Sobrien pc->pc_tlb_ctx_min = ctx_min; 26150397Sobrien pc->pc_tlb_ctx_max = ctx_min + ctx_inc; 26250397Sobrien ctx_min += ctx_inc; 26350397Sobrien 26450397Sobrien if (pc->pc_cpuid == PCPU_GET(cpuid)) 26550397Sobrien continue; 26650397Sobrien KASSERT(pc->pc_idlethread != NULL, 26750397Sobrien ("cpu_mp_unleash: idlethread")); 26850397Sobrien KASSERT(pc->pc_curthread == pc->pc_idlethread, 26950397Sobrien ("cpu_mp_unleash: curthread")); 270132718Skan 271132718Skan pc->pc_curpcb = pc->pc_curthread->td_pcb; 27252284Sobrien for (i = 0; i < PCPU_PAGES; i++) { 27350397Sobrien va = pc->pc_addr + i * PAGE_SIZE; 27450397Sobrien pa = pmap_kextract(va); 27550397Sobrien if (pa == 0) 27650397Sobrien panic("cpu_mp_unleash: pmap_kextract\n"); 27750397Sobrien csa->csa_ttes[i].tte_vpn = TV_VPN(va); 27850397Sobrien csa->csa_ttes[i].tte_data = TD_V | TD_8K | TD_PA(pa) | 27950397Sobrien TD_L | TD_CP | TD_CV | TD_P | TD_W; 280132718Skan } 28150397Sobrien csa->csa_state = 0; 28250397Sobrien csa->csa_mid = pc->pc_mid; 28350397Sobrien s = intr_disable(); 28450397Sobrien while (csa->csa_state != CPU_BOOTSTRAP) 28550397Sobrien ; 28650397Sobrien intr_restore(s); 28750397Sobrien } 28850397Sobrien} 28950397Sobrien 29050397Sobrienvoid 29150397Sobriencpu_mp_bootstrap(struct pcpu *pc) 29250397Sobrien{ 29352284Sobrien volatile struct cpu_start_args *csa; 29496263Sobrien 29596263Sobrien csa = &cpu_start_args; 29650397Sobrien pmap_map_tsb(); 29796263Sobrien cpu_setregs(pc); 29850397Sobrien 29950397Sobrien smp_cpus++; 30050397Sobrien PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid))); 30150397Sobrien printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid)); 30250397Sobrien 30350397Sobrien csa->csa_state = CPU_BOOTSTRAP; 30450397Sobrien for (;;) 30550397Sobrien ; 30650397Sobrien 30750397Sobrien binuptime(PCPU_PTR(switchtime)); 30850397Sobrien PCPU_SET(switchticks, ticks); 30950397Sobrien 31050397Sobrien /* ok, now grab sched_lock and enter the scheduler */ 31150397Sobrien mtx_lock_spin(&sched_lock); 31250397Sobrien cpu_throw(); /* doesn't return */ 31350397Sobrien} 31450397Sobrien 31550397Sobrienstatic void 31650397Sobriencpu_ipi_ast(struct trapframe *tf) 31750397Sobrien{ 31850397Sobrien} 31950397Sobrien 32050397Sobrienstatic void 32150397Sobriencpu_ipi_stop(struct trapframe *tf) 32250397Sobrien{ 32350397Sobrien TODO; 32450397Sobrien} 32550397Sobrien 32650397Sobrienvoid 32750397Sobriencpu_ipi_selected(u_int cpus, u_long d0, u_long d1, u_long d2) 32850397Sobrien{ 32950397Sobrien struct pcpu *pc; 33050397Sobrien u_int cpu; 33150397Sobrien 33250397Sobrien while (cpus) { 33350397Sobrien cpu = ffs(cpus) - 1; 33450397Sobrien cpus &= ~(1 << cpu); 33550397Sobrien pc = pcpu_find(cpu); 33650397Sobrien cpu_ipi_send(pc->pc_mid, d0, d1, d2); 33750397Sobrien } 33850397Sobrien} 33950397Sobrien 34050397Sobrienvoid 34150397Sobriencpu_ipi_send(u_int mid, u_long d0, u_long d1, u_long d2) 34250397Sobrien{ 34350397Sobrien u_long pstate; 34450397Sobrien int i; 34550397Sobrien 34650397Sobrien KASSERT((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY) == 0, 34750397Sobrien ("ipi_send: outstanding dispatch")); 34850397Sobrien pstate = rdpr(pstate); 34950397Sobrien for (i = 0; i < IPI_RETRIES; i++) { 35050397Sobrien if (pstate & PSTATE_IE) 35150397Sobrien wrpr(pstate, pstate, PSTATE_IE); 35250397Sobrien stxa(AA_SDB_INTR_D0, ASI_SDB_INTR_W, d0); 35350397Sobrien stxa(AA_SDB_INTR_D1, ASI_SDB_INTR_W, d1); 35450397Sobrien stxa(AA_SDB_INTR_D2, ASI_SDB_INTR_W, d2); 35550397Sobrien stxa(AA_INTR_SEND | (mid << 14), ASI_SDB_INTR_W, 0); 35650397Sobrien membar(Sync); 35750397Sobrien while (ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY) 35850397Sobrien ; 35950397Sobrien wrpr(pstate, pstate, 0); 36050397Sobrien if ((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_NACK) == 0) 36150397Sobrien return; 36250397Sobrien } 36350397Sobrien panic("ipi_send: couldn't send ipi"); 36450397Sobrien} 36550397Sobrien 36650397Sobrienvoid 36750397Sobrienipi_selected(u_int cpus, u_int ipi) 36850397Sobrien{ 36950397Sobrien cpu_ipi_selected(cpus, 0, (u_long)tl_ipi_level, ipi); 37050397Sobrien} 37150397Sobrien 37250397Sobrienvoid 37350397Sobrienipi_all(u_int ipi) 37450397Sobrien{ 37550397Sobrien TODO; 37650397Sobrien} 37750397Sobrien 37850397Sobrienvoid 37950397Sobrienipi_all_but_self(u_int ipi) 38050397Sobrien{ 38150397Sobrien cpu_ipi_selected(PCPU_GET(other_cpus), 0, (u_long)tl_ipi_level, ipi); 38250397Sobrien} 38350397Sobrien