mp_machdep.c revision 87702
1/*-
2 * Copyright (c) 2000 Doug Rabson
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 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$FreeBSD: head/sys/ia64/ia64/mp_machdep.c 87702 2001-12-11 23:33:44Z jhb $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/ktr.h>
32#include <sys/proc.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/mutex.h>
36#include <sys/kernel.h>
37#include <sys/pcpu.h>
38#include <sys/smp.h>
39#include <sys/sysctl.h>
40
41#include <vm/vm.h>
42#include <vm/pmap.h>
43
44#include <machine/atomic.h>
45#include <machine/pal.h>
46#include <machine/pmap.h>
47#include <machine/clock.h>
48#include <machine/sal.h>
49
50#define	LID_SAPIC_ID(x)		((int)((x) >> 24) & 0xff)
51#define	LID_SAPIC_EID(x)	((int)((x) >> 16) & 0xff)
52
53static MALLOC_DEFINE(M_SMP, "smp", "SMP structures");
54
55static void ipi_send(u_int64_t, int);
56static void cpu_mp_unleash(void *);
57
58struct mp_cpu {
59	TAILQ_ENTRY(mp_cpu) cpu_next;
60	u_int64_t	cpu_lid;	/* Local processor ID */
61	int32_t		cpu_no;		/* Sequential CPU number */
62	u_int32_t	cpu_bsp:1;	/* 1=BSP; 0=AP */
63	u_int32_t	cpu_awake:1;	/* 1=Awake; 0=sleeping */
64	void		*cpu_stack;
65};
66
67int	mp_hardware = 0;
68int	mp_ipi_vector[IPI_COUNT];
69int	mp_ipi_test = 0;
70
71/* Variables used by os_boot_rendez */
72volatile void *ap_stack;
73volatile int ap_delay;
74volatile int ap_awake;
75
76TAILQ_HEAD(, mp_cpu) ia64_cpus = TAILQ_HEAD_INITIALIZER(ia64_cpus);
77
78void
79ia64_ap_startup(void)
80{
81#if 0
82	struct mp_cpu *cpu;
83	u_int64_t lid = ia64_get_lid() & 0xffff0000L;
84#endif
85
86	ap_awake = 1;
87	ap_delay = 0;
88	while (1);
89
90#if 0
91	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
92		if (cpu->cpu_lid == lid)
93			break;
94	}
95
96	KASSERT(cpu != NULL, ("foo!"));
97
98	cpu->cpu_lid = ia64_get_lid();
99	cpu->cpu_awake = 1;
100#endif
101}
102
103int
104cpu_mp_probe()
105{
106	/*
107	 * We've already discovered any APs when they're present.
108	 * Just return the result here.
109	 */
110	return (mp_hardware && mp_ncpus > 1);
111}
112
113void
114cpu_mp_add(uint acpiid, uint apicid, uint apiceid)
115{
116	struct mp_cpu *cpu;
117	u_int64_t bsp = ia64_get_lid() & 0xffff0000L;
118
119	cpu = malloc(sizeof(*cpu), M_SMP, M_WAITOK|M_ZERO);
120	if (cpu == NULL)
121		return;
122
123	TAILQ_INSERT_TAIL(&ia64_cpus, cpu, cpu_next);
124	cpu->cpu_no = acpiid;
125	cpu->cpu_lid = ((apicid & 0xff) << 8 | (apiceid & 0xff)) << 16;
126	if (cpu->cpu_lid == bsp)
127		cpu->cpu_bsp = 1;
128	all_cpus |= (1 << acpiid);
129	mp_ncpus++;
130}
131
132void
133cpu_mp_announce()
134{
135	struct mp_cpu *cpu;
136
137	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
138		printf("cpu%d: SAPIC Id=%x, SAPIC Eid=%x", cpu->cpu_no,
139		    LID_SAPIC_ID(cpu->cpu_lid), LID_SAPIC_EID(cpu->cpu_lid));
140		if (cpu->cpu_bsp)
141			printf(" (BSP)\n");
142		else
143			printf("\n");
144	}
145}
146
147void
148cpu_mp_start()
149{
150	struct mp_cpu *cpu;
151
152	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
153		if (!cpu->cpu_bsp) {
154			cpu->cpu_stack = malloc(KSTACK_PAGES * PAGE_SIZE,
155			    M_SMP, M_WAITOK);
156
157			if (bootverbose)
158				printf("SMP: waking up cpu%d\n", cpu->cpu_no);
159
160			ap_stack = cpu->cpu_stack;
161			ap_delay = 2000;
162			ap_awake = 0;
163			ipi_send(cpu->cpu_lid, IPI_AP_WAKEUP);
164
165			do {
166				DELAY(1000);
167			} while (--ap_delay > 0);
168			cpu->cpu_awake = (ap_awake) ? 1 : 0;
169
170			if (bootverbose && !ap_awake)
171				printf("SMP: WARNING: cpu%d did not wake up\n",
172				    cpu->cpu_no);
173		} else {
174			cpu->cpu_lid = ia64_get_lid();
175			cpu->cpu_awake = 1;
176			ipi_self(IPI_TEST);
177		}
178	}
179}
180
181static void
182cpu_mp_unleash(void *dummy)
183{
184	struct mp_cpu *cpu;
185	int awake = 0;
186
187	if (!mp_hardware)
188		return;
189
190	if (mp_ipi_test != 1)
191		printf("SMP: sending of a test IPI to BSP failed\n");
192
193	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
194		awake += cpu->cpu_awake;
195	}
196
197	if (awake != mp_ncpus)
198		printf("SMP: %d CPU(s) didn't get woken\n", mp_ncpus - awake);
199}
200
201/*
202 * send an IPI to a set of cpus.
203 */
204void
205ipi_selected(u_int64_t cpus, int ipi)
206{
207	struct mp_cpu *cpu;
208
209	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
210		if (cpus & (1 << cpu->cpu_no))
211			ipi_send(cpu->cpu_lid, ipi);
212	}
213}
214
215/*
216 * send an IPI to all CPUs, including myself.
217 */
218void
219ipi_all(int ipi)
220{
221	struct mp_cpu *cpu;
222
223	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
224		ipi_send(cpu->cpu_lid, ipi);
225	}
226}
227
228/*
229 * send an IPI to all CPUs EXCEPT myself.
230 */
231void
232ipi_all_but_self(int ipi)
233{
234	struct mp_cpu *cpu;
235	u_int64_t lid = ia64_get_lid();
236
237	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
238		if (cpu->cpu_lid != lid)
239			ipi_send(cpu->cpu_lid, ipi);
240	}
241}
242
243/*
244 * send an IPI to myself.
245 */
246void
247ipi_self(int ipi)
248{
249
250	ipi_send(ia64_get_lid(), ipi);
251}
252
253/*
254 * Send an IPI to the specified processor. The lid parameter holds the
255 * cr.lid (CR64) contents of the target processor. Only the id and eid
256 * fields are used here.
257 */
258static void
259ipi_send(u_int64_t lid, int ipi)
260{
261	volatile u_int64_t *pipi;
262	u_int64_t vector;
263
264	pipi = ia64_memory_address(PAL_PIB_DEFAULT_ADDR |
265	    ((lid >> 12) & 0xFFFF0L));
266	vector = (u_int64_t)(mp_ipi_vector[ipi] & 0xff);
267	*pipi = vector;
268	ia64_mf_a();
269}
270
271SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
272