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