mp_cpudep.c revision 183060
1/*-
2 * Copyright (c) 2008 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/powerpc/aim/mp_cpudep.c 183060 2008-09-16 01:05:54Z marcel $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/bus.h>
34#include <sys/pcpu.h>
35#include <sys/proc.h>
36#include <sys/smp.h>
37
38#include <machine/bat.h>
39#include <machine/bus.h>
40#include <machine/cpu.h>
41#include <machine/hid.h>
42#include <machine/intr_machdep.h>
43#include <machine/pcb.h>
44#include <machine/psl.h>
45#include <machine/smp.h>
46#include <machine/spr.h>
47#include <machine/trap_aim.h>
48
49#include <dev/ofw/openfirm.h>
50#include <machine/ofw_machdep.h>
51
52extern void *rstcode;
53
54void *ap_pcpu;
55
56static int
57powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
58{
59	int cpuid, res;
60
61	cpuref->cr_hwref = cpu;
62	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
63	if (res < 0)
64		return (ENOENT);
65
66	cpuref->cr_cpuid = cpuid & 0xff;
67	return (0);
68}
69
70int
71powerpc_smp_first_cpu(struct cpuref *cpuref)
72{
73	char buf[8];
74	phandle_t cpu, dev, root;
75	int res;
76
77	root = OF_peer(0);
78
79	dev = OF_child(root);
80	while (dev != 0) {
81		res = OF_getprop(dev, "name", buf, sizeof(buf));
82		if (res > 0 && strcmp(buf, "cpus") == 0)
83			break;
84		dev = OF_peer(dev);
85	}
86	if (dev == 0)
87		return (ENOENT);
88
89	cpu = OF_child(dev);
90	while (cpu != 0) {
91		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
92		if (res > 0 && strcmp(buf, "cpu") == 0)
93			break;
94		cpu = OF_peer(cpu);
95	}
96	if (cpu == 0)
97		return (ENOENT);
98
99	return (powerpc_smp_fill_cpuref(cpuref, cpu));
100}
101
102int
103powerpc_smp_next_cpu(struct cpuref *cpuref)
104{
105	char buf[8];
106	phandle_t cpu;
107	int res;
108
109	cpu = OF_peer(cpuref->cr_hwref);
110	while (cpu != 0) {
111		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
112		if (res > 0 && strcmp(buf, "cpu") == 0)
113			break;
114		cpu = OF_peer(cpu);
115	}
116	if (cpu == 0)
117		return (ENOENT);
118
119	return (powerpc_smp_fill_cpuref(cpuref, cpu));
120}
121
122int
123powerpc_smp_get_bsp(struct cpuref *cpuref)
124{
125	ihandle_t inst;
126	phandle_t bsp, chosen;
127	int res;
128
129	chosen = OF_finddevice("/chosen");
130	if (chosen == 0)
131		return (ENXIO);
132
133	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
134	if (res < 0)
135		return (ENXIO);
136
137	bsp = OF_instance_to_package(inst);
138	return (powerpc_smp_fill_cpuref(cpuref, bsp));
139}
140
141uint32_t
142cpudep_ap_bootstrap(void)
143{
144	uint32_t hid, msr, sp;
145
146	__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
147	__asm __volatile("sync");
148
149	hid = mfspr(SPR_HID0);
150	hid &= ~(HID0_ICE | HID0_DCE);
151	hid &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
152	mtspr(SPR_HID0, hid);
153	isync();
154
155	hid |= HID0_ICFI | HID0_DCFI;
156	hid |= HID0_ICE | HID0_DCE;
157	mtspr(SPR_HID0, hid);
158	isync();
159
160	msr = PSL_IR | PSL_DR | PSL_ME | PSL_RI;
161	mtmsr(msr);
162	isync();
163
164	hid |= HID0_NAP | HID0_DPM;
165	mtspr(SPR_HID0, hid);
166	isync();
167
168	pcpup->pc_curthread = pcpup->pc_idlethread;
169	pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
170	sp = pcpup->pc_curpcb->pcb_sp;
171
172	return (sp);
173}
174
175int
176powerpc_smp_start_cpu(struct pcpu *pc)
177{
178	phandle_t cpu;
179	volatile uint8_t *rstvec;
180	int res, reset, timeout;
181
182	cpu = pc->pc_hwref;
183	res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
184	if (res < 0)
185		return (ENXIO);
186
187	ap_pcpu = pc;
188
189	rstvec = (uint8_t *)(0x80000000 + reset);
190
191	*rstvec = 4;
192	__asm __volatile("sync");
193	DELAY(1);
194	*rstvec = 0;
195	__asm __volatile("sync");
196
197	timeout = 1000;
198	while (!pc->pc_awake && timeout--)
199		DELAY(100);
200
201	return ((pc->pc_awake) ? 0 : EBUSY);
202}
203