xref: /haiku/src/system/kernel/arch/x86/arch_smp.cpp (revision e6ea745e8114d5fa05ab0ccab92c070e2dcdcfb7)
1bd185b41SIngo Weinhold /*
2bd185b41SIngo Weinhold  * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3bd185b41SIngo Weinhold  * Distributed under the terms of the MIT License.
4bd185b41SIngo Weinhold  *
5bd185b41SIngo Weinhold  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6bd185b41SIngo Weinhold  * Distributed under the terms of the NewOS License.
7bd185b41SIngo Weinhold  */
8bd185b41SIngo Weinhold 
9bd185b41SIngo Weinhold 
10bd185b41SIngo Weinhold #include <boot/kernel_args.h>
11e50cf876SIngo Weinhold #include <vm/vm.h>
12bd185b41SIngo Weinhold #include <int.h>
13bd185b41SIngo Weinhold #include <smp.h>
14bd185b41SIngo Weinhold #include <smp_priv.h>
15bd185b41SIngo Weinhold 
16bd185b41SIngo Weinhold #include <arch/cpu.h>
17bd185b41SIngo Weinhold #include <arch/vm.h>
18bd185b41SIngo Weinhold #include <arch/smp.h>
19bd185b41SIngo Weinhold 
20655f3b41SMichael Lotz #include <arch/x86/apic.h>
21655f3b41SMichael Lotz #include <arch/x86/arch_smp.h>
22bd185b41SIngo Weinhold #include <arch/x86/smp_priv.h>
23bd185b41SIngo Weinhold #include <arch/x86/timer.h>
24bd185b41SIngo Weinhold 
25bd185b41SIngo Weinhold #include <string.h>
26bd185b41SIngo Weinhold #include <stdio.h>
27bd185b41SIngo Weinhold 
28bd185b41SIngo Weinhold 
29bd185b41SIngo Weinhold //#define TRACE_ARCH_SMP
30bd185b41SIngo Weinhold #ifdef TRACE_ARCH_SMP
31bd185b41SIngo Weinhold #	define TRACE(x) dprintf x
32bd185b41SIngo Weinhold #else
33bd185b41SIngo Weinhold #	define TRACE(x) ;
34bd185b41SIngo Weinhold #endif
35bd185b41SIngo Weinhold 
363f1eed70SAlexander von Gluck IV 
37*e6ea745eSPawel Dziepak static uint32 sCPUAPICIds[SMP_MAX_CPUS];
38*e6ea745eSPawel Dziepak static uint32 sAPICVersions[SMP_MAX_CPUS];
39bd185b41SIngo Weinhold 
40bd185b41SIngo Weinhold 
41bd185b41SIngo Weinhold static int32
425e9bb17dSAlex Smith x86_ici_interrupt(void *data)
43bd185b41SIngo Weinhold {
44bd185b41SIngo Weinhold 	// genuine inter-cpu interrupt
45bd185b41SIngo Weinhold 	int cpu = smp_get_current_cpu();
46bd185b41SIngo Weinhold 	TRACE(("inter-cpu interrupt on cpu %d\n", cpu));
47bd185b41SIngo Weinhold 	return smp_intercpu_int_handler(cpu);
48bd185b41SIngo Weinhold }
49bd185b41SIngo Weinhold 
50bd185b41SIngo Weinhold 
51bd185b41SIngo Weinhold static int32
525e9bb17dSAlex Smith x86_spurious_interrupt(void *data)
53bd185b41SIngo Weinhold {
54bd185b41SIngo Weinhold 	// spurious interrupt
5576a1175dSAlex Smith 	TRACE(("spurious interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
56bd185b41SIngo Weinhold 
57bd185b41SIngo Weinhold 	// spurious interrupts must not be acknowledged as it does not expect
58bd185b41SIngo Weinhold 	// a end of interrupt - if we still do it we would loose the next best
59bd185b41SIngo Weinhold 	// interrupt
60bd185b41SIngo Weinhold 	return B_HANDLED_INTERRUPT;
61bd185b41SIngo Weinhold }
62bd185b41SIngo Weinhold 
63bd185b41SIngo Weinhold 
64bd185b41SIngo Weinhold static int32
655e9bb17dSAlex Smith x86_smp_error_interrupt(void *data)
66bd185b41SIngo Weinhold {
67bd185b41SIngo Weinhold 	// smp error interrupt
6876a1175dSAlex Smith 	TRACE(("smp error interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
69bd185b41SIngo Weinhold 	return B_HANDLED_INTERRUPT;
70bd185b41SIngo Weinhold }
71bd185b41SIngo Weinhold 
72bd185b41SIngo Weinhold 
73d897a478SPawel Dziepak uint32
74d897a478SPawel Dziepak x86_get_cpu_apic_id(int32 cpu)
75d897a478SPawel Dziepak {
76d897a478SPawel Dziepak 	ASSERT(cpu >= 0 && cpu < B_MAX_CPU_COUNT);
77d897a478SPawel Dziepak 	return sCPUAPICIds[cpu];
78d897a478SPawel Dziepak }
79d897a478SPawel Dziepak 
80d897a478SPawel Dziepak 
81bd185b41SIngo Weinhold status_t
82bd185b41SIngo Weinhold arch_smp_init(kernel_args *args)
83bd185b41SIngo Weinhold {
84c1cd48b7SAlexander von Gluck IV 	TRACE(("%s: entry\n", __func__));
85bd185b41SIngo Weinhold 
86655f3b41SMichael Lotz 	if (!apic_available()) {
87655f3b41SMichael Lotz 		// if we don't have an apic we can't do smp
88c1cd48b7SAlexander von Gluck IV 		TRACE(("%s: apic not available for smp\n", __func__));
89bd185b41SIngo Weinhold 		return B_OK;
90655f3b41SMichael Lotz 	}
91bd185b41SIngo Weinhold 
92bd185b41SIngo Weinhold 	// setup some globals
93bd185b41SIngo Weinhold 	memcpy(sCPUAPICIds, args->arch_args.cpu_apic_id, sizeof(args->arch_args.cpu_apic_id));
94bd185b41SIngo Weinhold 	memcpy(sAPICVersions, args->arch_args.cpu_apic_version, sizeof(args->arch_args.cpu_apic_version));
95bd185b41SIngo Weinhold 
96bd185b41SIngo Weinhold 	// set up the local apic on the boot cpu
97bd185b41SIngo Weinhold 	arch_smp_per_cpu_init(args, 0);
98bd185b41SIngo Weinhold 
99bd185b41SIngo Weinhold 	if (args->num_cpus > 1) {
100bd185b41SIngo Weinhold 		// I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted
1016a164daaSPawel Dziepak 		reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE,
1026a164daaSPawel Dziepak 			INTERRUPT_TYPE_ICI);
1035e9bb17dSAlex Smith 		install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
1045e9bb17dSAlex Smith 		install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
1055e9bb17dSAlex Smith 		install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);
106bd185b41SIngo Weinhold 	}
107bd185b41SIngo Weinhold 
108bd185b41SIngo Weinhold 	return B_OK;
109bd185b41SIngo Weinhold }
110bd185b41SIngo Weinhold 
111bd185b41SIngo Weinhold 
112bd185b41SIngo Weinhold status_t
113bd185b41SIngo Weinhold arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
114bd185b41SIngo Weinhold {
115bd185b41SIngo Weinhold 	// set up the local apic on the current cpu
11676a1175dSAlex Smith 	TRACE(("arch_smp_init_percpu: setting up the apic on cpu %" B_PRId32 "\n",
11776a1175dSAlex Smith 		cpu));
118655f3b41SMichael Lotz 	apic_per_cpu_init(args, cpu);
119bd185b41SIngo Weinhold 
1208dd1e875SAlexander von Gluck IV 	// setup FPU and SSE if supported
1213f1eed70SAlexander von Gluck IV 	x86_init_fpu();
122bd185b41SIngo Weinhold 
123bd185b41SIngo Weinhold 	return B_OK;
124bd185b41SIngo Weinhold }
125bd185b41SIngo Weinhold 
126bd185b41SIngo Weinhold 
127bd185b41SIngo Weinhold void
128bd185b41SIngo Weinhold arch_smp_send_broadcast_ici(void)
129bd185b41SIngo Weinhold {
130bd185b41SIngo Weinhold 	uint32 config;
131bd185b41SIngo Weinhold 	cpu_status state = disable_interrupts();
132bd185b41SIngo Weinhold 
13378777340SJérôme Duval 	config = apic_intr_command_1() & APIC_INTR_COMMAND_1_MASK;
13478777340SJérôme Duval 	apic_set_intr_command_1(config | 0xfd | APIC_DELIVERY_MODE_FIXED
135bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_ASSERT
136bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
137bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF);
138bd185b41SIngo Weinhold 
139bd185b41SIngo Weinhold 	restore_interrupts(state);
140bd185b41SIngo Weinhold }
141bd185b41SIngo Weinhold 
142bd185b41SIngo Weinhold 
143bd185b41SIngo Weinhold void
144bd185b41SIngo Weinhold arch_smp_send_ici(int32 target_cpu)
145bd185b41SIngo Weinhold {
146bd185b41SIngo Weinhold 	uint32 config;
147bd185b41SIngo Weinhold 	uint32 timeout;
148bd185b41SIngo Weinhold 	cpu_status state;
149bd185b41SIngo Weinhold 
150bd185b41SIngo Weinhold 	state = disable_interrupts();
151bd185b41SIngo Weinhold 
15278777340SJérôme Duval 	config = apic_intr_command_2() & APIC_INTR_COMMAND_2_MASK;
15378777340SJérôme Duval 	apic_set_intr_command_2(config | sCPUAPICIds[target_cpu] << 24);
154bd185b41SIngo Weinhold 
15578777340SJérôme Duval 	config = apic_intr_command_1() & APIC_INTR_COMMAND_1_MASK;
15678777340SJérôme Duval 	apic_set_intr_command_1(config | 0xfd | APIC_DELIVERY_MODE_FIXED
157bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_ASSERT
158bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
159bd185b41SIngo Weinhold 		| APIC_INTR_COMMAND_1_DEST_FIELD);
160bd185b41SIngo Weinhold 
161bd185b41SIngo Weinhold 	timeout = 100000000;
162bd185b41SIngo Weinhold 	// wait for message to be sent
16378777340SJérôme Duval 	while ((apic_intr_command_1() & APIC_DELIVERY_STATUS) != 0 && --timeout != 0)
164bd185b41SIngo Weinhold 		asm volatile ("pause;");
165bd185b41SIngo Weinhold 
166bd185b41SIngo Weinhold 	if (timeout == 0)
16776a1175dSAlex Smith 		panic("arch_smp_send_ici: timeout, target_cpu %" B_PRId32, target_cpu);
168bd185b41SIngo Weinhold 
169bd185b41SIngo Weinhold 	restore_interrupts(state);
170bd185b41SIngo Weinhold }
171