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