mp_machdep.c revision 86204
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 86204 2001-11-09 05:18:45Z marcel $
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/globaldata.h>
46#include <machine/pal.h>
47#include <machine/pmap.h>
48#include <machine/clock.h>
49#include <machine/sal.h>
50
51#define	LID_SAPIC_ID(x)		((int)((x) >> 24) & 0xff)
52#define	LID_SAPIC_EID(x)	((int)((x) >> 16) & 0xff)
53
54void ia64_probe_sapics(void);
55
56static MALLOC_DEFINE(M_SMP, "smp", "SMP structures");
57
58static void ipi_send(u_int64_t, int);
59static void cpu_mp_unleash(void *);
60
61struct mp_cpu {
62	TAILQ_ENTRY(mp_cpu) cpu_next;
63	u_int64_t	cpu_lid;	/* Local processor ID */
64	int32_t		cpu_no;		/* Sequential CPU number */
65	u_int32_t	cpu_bsp:1;	/* 1=BSP; 0=AP */
66	u_int32_t	cpu_awake:1;	/* 1=Awake; 0=sleeping */
67	void		*cpu_stack;
68};
69
70int	mp_hardware = 0;
71int	mp_ipi_vector[IPI_COUNT];
72int	mp_ipi_test = 0;
73
74TAILQ_HEAD(, mp_cpu) ia64_cpus = TAILQ_HEAD_INITIALIZER(ia64_cpus);
75
76void *
77ia64_ap_get_stack(void)
78{
79	struct mp_cpu *cpu;
80	u_int64_t lid = ia64_get_lid() & 0xffff0000L;
81
82	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
83		if (cpu->cpu_lid == lid)
84			return (cpu->cpu_stack);
85	}
86
87	panic(__func__": bad LID or RR5 misconfigured");
88}
89
90void
91ia64_ap_startup(void)
92{
93	struct mp_cpu *cpu;
94	u_int64_t lid = ia64_get_lid() & 0xffff0000L;
95
96	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
97		if (cpu->cpu_lid == lid)
98			break;
99	}
100
101	KASSERT(cpu != NULL, ("foo!"));
102
103	cpu->cpu_lid = ia64_get_lid();
104	cpu->cpu_awake = 1;
105
106	while(1)
107		ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
108}
109
110int
111cpu_mp_probe()
112{
113	ia64_probe_sapics();
114	return (mp_hardware);
115}
116
117void
118cpu_mp_add(uint acpiid, uint apicid, uint apiceid)
119{
120	struct mp_cpu *cpu;
121	u_int64_t bsp = ia64_get_lid() & 0xffff0000L;
122
123	cpu = malloc(sizeof(*cpu), M_SMP, M_WAITOK|M_ZERO);
124	if (cpu == NULL)
125		return;
126
127	TAILQ_INSERT_TAIL(&ia64_cpus, cpu, cpu_next);
128	cpu->cpu_no = acpiid;
129	cpu->cpu_lid = ((apicid & 0xff) << 8 | (apiceid & 0xff)) << 16;
130	if (cpu->cpu_lid == bsp)
131		cpu->cpu_bsp = 1;
132	all_cpus |= (1 << acpiid);
133	mp_ncpus++;
134}
135
136void
137cpu_mp_announce()
138{
139	struct mp_cpu *cpu;
140
141	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
142		printf("cpu%d: SAPIC Id=%x, SAPIC Eid=%x", cpu->cpu_no,
143		    LID_SAPIC_ID(cpu->cpu_lid), LID_SAPIC_EID(cpu->cpu_lid));
144		if (cpu->cpu_bsp)
145			printf(" (BSP)\n");
146		else
147			printf("\n");
148	}
149}
150
151void
152cpu_mp_start()
153{
154	struct mp_cpu *cpu;
155
156	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
157		if (!cpu->cpu_bsp) {
158			cpu->cpu_stack = malloc(KSTACK_PAGES * PAGE_SIZE,
159			    M_SMP, M_WAITOK);
160			if (bootverbose)
161				printf("SMP: waking up cpu%d\n", cpu->cpu_no);
162			ipi_send(cpu->cpu_lid, IPI_AP_WAKEUP);
163		} else {
164			cpu->cpu_lid = ia64_get_lid();
165			cpu->cpu_awake = 1;
166			ipi_self(IPI_TEST);
167		}
168	}
169}
170
171static void
172cpu_mp_unleash(void *dummy)
173{
174	struct mp_cpu *cpu;
175	int awake = 0;
176
177	if (!mp_hardware)
178		return;
179
180	if (mp_ipi_test != 1)
181		printf("SMP: sending of a test IPI to BSP failed\n");
182
183	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
184		awake += cpu->cpu_awake;
185	}
186
187	if (awake != mp_ncpus)
188		printf("SMP: %d CPU(s) didn't get woken\n", mp_ncpus - awake);
189}
190
191/*
192 * send an IPI to a set of cpus.
193 */
194void
195ipi_selected(u_int64_t cpus, int ipi)
196{
197	struct mp_cpu *cpu;
198
199	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
200		if (cpus & (1 << cpu->cpu_no))
201			ipi_send(cpu->cpu_lid, ipi);
202	}
203}
204
205/*
206 * send an IPI to all CPUs, including myself.
207 */
208void
209ipi_all(int ipi)
210{
211	struct mp_cpu *cpu;
212
213	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
214		ipi_send(cpu->cpu_lid, ipi);
215	}
216}
217
218/*
219 * send an IPI to all CPUs EXCEPT myself.
220 */
221void
222ipi_all_but_self(int ipi)
223{
224	struct mp_cpu *cpu;
225	u_int64_t lid = ia64_get_lid();
226
227	TAILQ_FOREACH(cpu, &ia64_cpus, cpu_next) {
228		if (cpu->cpu_lid != lid)
229			ipi_send(cpu->cpu_lid, ipi);
230	}
231}
232
233/*
234 * send an IPI to myself.
235 */
236void
237ipi_self(int ipi)
238{
239
240	ipi_send(ia64_get_lid(), ipi);
241}
242
243/*
244 * Send an IPI to the specified processor. The lid parameter holds the
245 * cr.lid (CR64) contents of the target processor. Only the id and eid
246 * fields are used here.
247 */
248static void
249ipi_send(u_int64_t lid, int ipi)
250{
251	volatile u_int64_t *pipi;
252	u_int64_t vector;
253
254	pipi = ia64_memory_address(PAL_PIB_DEFAULT_ADDR |
255	    ((lid >> 12) & 0xFFFF0L));
256	vector = (u_int64_t)(mp_ipi_vector[ipi] & 0xff);
257	*pipi = vector;
258	ia64_mf_a();
259}
260
261SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
262