17d36db35SAvi Kivity 27d36db35SAvi Kivity #include <libcflat.h> 3b73c7c6eSAndrew Jones #include "processor.h" 4b73c7c6eSAndrew Jones #include "atomic.h" 57d36db35SAvi Kivity #include "smp.h" 67d36db35SAvi Kivity #include "apic.h" 77d36db35SAvi Kivity #include "fwcfg.h" 8a4f9d79dSJan Kiszka #include "desc.h" 97d36db35SAvi Kivity 107d36db35SAvi Kivity #define IPI_VECTOR 0x20 117d36db35SAvi Kivity 12fa816346SAvi Kivity typedef void (*ipi_function_type)(void *data); 13fa816346SAvi Kivity 147d36db35SAvi Kivity static struct spinlock ipi_lock; 15fa816346SAvi Kivity static volatile ipi_function_type ipi_function; 16a4f9d79dSJan Kiszka static void *volatile ipi_data; 177d36db35SAvi Kivity static volatile int ipi_done; 18e7bc5602SAvi Kivity static volatile bool ipi_wait; 19e7bc5602SAvi Kivity static int _cpu_count; 20b73c7c6eSAndrew Jones static atomic_t active_cpus; 217d36db35SAvi Kivity 227db17e21SThomas Huth static __attribute__((used)) void ipi(void) 237d36db35SAvi Kivity { 24e7bc5602SAvi Kivity void (*function)(void *data) = ipi_function; 25e7bc5602SAvi Kivity void *data = ipi_data; 26e7bc5602SAvi Kivity bool wait = ipi_wait; 27e7bc5602SAvi Kivity 28e7bc5602SAvi Kivity if (!wait) { 297d36db35SAvi Kivity ipi_done = 1; 30e7bc5602SAvi Kivity apic_write(APIC_EOI, 0); 31e7bc5602SAvi Kivity } 32e7bc5602SAvi Kivity function(data); 33b73c7c6eSAndrew Jones atomic_dec(&active_cpus); 34e7bc5602SAvi Kivity if (wait) { 35e7bc5602SAvi Kivity ipi_done = 1; 36e7bc5602SAvi Kivity apic_write(APIC_EOI, 0); 37e7bc5602SAvi Kivity } 387d36db35SAvi Kivity } 397d36db35SAvi Kivity 407d36db35SAvi Kivity asm ( 417d36db35SAvi Kivity "ipi_entry: \n" 427d36db35SAvi Kivity " call ipi \n" 437d36db35SAvi Kivity #ifndef __x86_64__ 447d36db35SAvi Kivity " iret" 457d36db35SAvi Kivity #else 467d36db35SAvi Kivity " iretq" 477d36db35SAvi Kivity #endif 487d36db35SAvi Kivity ); 497d36db35SAvi Kivity 507d36db35SAvi Kivity int cpu_count(void) 517d36db35SAvi Kivity { 52a9f949c7SAvi Kivity return _cpu_count; 537d36db35SAvi Kivity } 547d36db35SAvi Kivity 557d36db35SAvi Kivity int smp_id(void) 567d36db35SAvi Kivity { 577d36db35SAvi Kivity unsigned id; 587d36db35SAvi Kivity 597d36db35SAvi Kivity asm ("mov %%gs:0, %0" : "=r"(id)); 607d36db35SAvi Kivity return id; 617d36db35SAvi Kivity } 627d36db35SAvi Kivity 637d36db35SAvi Kivity static void setup_smp_id(void *data) 647d36db35SAvi Kivity { 657d36db35SAvi Kivity asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory"); 667d36db35SAvi Kivity } 677d36db35SAvi Kivity 68*0a2f06f7SSean Christopherson static void __on_cpu(int cpu, void (*function)(void *data), void *data, int wait) 697d36db35SAvi Kivity { 70*0a2f06f7SSean Christopherson const u32 ipi_icr = APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED | IPI_VECTOR; 7118a34cceSNadav Amit unsigned int target = id_map[cpu]; 7218a34cceSNadav Amit 737d36db35SAvi Kivity spin_lock(&ipi_lock); 74*0a2f06f7SSean Christopherson if (target == smp_id()) { 757d36db35SAvi Kivity function(data); 76*0a2f06f7SSean Christopherson } else { 77b73c7c6eSAndrew Jones atomic_inc(&active_cpus); 787d36db35SAvi Kivity ipi_done = 0; 797d36db35SAvi Kivity ipi_function = function; 807d36db35SAvi Kivity ipi_data = data; 81e7bc5602SAvi Kivity ipi_wait = wait; 82*0a2f06f7SSean Christopherson apic_icr_write(ipi_icr, target); 837d36db35SAvi Kivity while (!ipi_done) 847d36db35SAvi Kivity ; 857d36db35SAvi Kivity } 867d36db35SAvi Kivity spin_unlock(&ipi_lock); 877d36db35SAvi Kivity } 887d36db35SAvi Kivity 897d36db35SAvi Kivity void on_cpu(int cpu, void (*function)(void *data), void *data) 907d36db35SAvi Kivity { 917d36db35SAvi Kivity __on_cpu(cpu, function, data, 1); 927d36db35SAvi Kivity } 937d36db35SAvi Kivity 947d36db35SAvi Kivity void on_cpu_async(int cpu, void (*function)(void *data), void *data) 957d36db35SAvi Kivity { 967d36db35SAvi Kivity __on_cpu(cpu, function, data, 0); 977d36db35SAvi Kivity } 987d36db35SAvi Kivity 99b73c7c6eSAndrew Jones void on_cpus(void (*function)(void *data), void *data) 100b73c7c6eSAndrew Jones { 101b73c7c6eSAndrew Jones int cpu; 102b73c7c6eSAndrew Jones 103b73c7c6eSAndrew Jones for (cpu = cpu_count() - 1; cpu >= 0; --cpu) 104b73c7c6eSAndrew Jones on_cpu_async(cpu, function, data); 105b73c7c6eSAndrew Jones 106b73c7c6eSAndrew Jones while (cpus_active() > 1) 107b73c7c6eSAndrew Jones pause(); 108b73c7c6eSAndrew Jones } 109b73c7c6eSAndrew Jones 110b73c7c6eSAndrew Jones int cpus_active(void) 111b73c7c6eSAndrew Jones { 112b73c7c6eSAndrew Jones return atomic_read(&active_cpus); 113b73c7c6eSAndrew Jones } 1147d36db35SAvi Kivity 1157d36db35SAvi Kivity void smp_init(void) 1167d36db35SAvi Kivity { 1177d36db35SAvi Kivity int i; 1187d36db35SAvi Kivity void ipi_entry(void); 1197d36db35SAvi Kivity 120a9f949c7SAvi Kivity _cpu_count = fwcfg_get_nb_cpus(); 121a9f949c7SAvi Kivity 1222bb987f3SAvi Kivity setup_idt(); 12318a34cceSNadav Amit init_apic_map(); 1242bb987f3SAvi Kivity set_idt_entry(IPI_VECTOR, ipi_entry, 0); 1257d36db35SAvi Kivity 1267d36db35SAvi Kivity setup_smp_id(0); 1277d36db35SAvi Kivity for (i = 1; i < cpu_count(); ++i) 1287d36db35SAvi Kivity on_cpu(i, setup_smp_id, 0); 1297d36db35SAvi Kivity 130b73c7c6eSAndrew Jones atomic_inc(&active_cpus); 1317d36db35SAvi Kivity } 13274e79380SPaolo Bonzini 13374e79380SPaolo Bonzini static void do_reset_apic(void *data) 13474e79380SPaolo Bonzini { 13574e79380SPaolo Bonzini reset_apic(); 13674e79380SPaolo Bonzini } 13774e79380SPaolo Bonzini 13874e79380SPaolo Bonzini void smp_reset_apic(void) 13974e79380SPaolo Bonzini { 14074e79380SPaolo Bonzini int i; 14174e79380SPaolo Bonzini 14274e79380SPaolo Bonzini reset_apic(); 14374e79380SPaolo Bonzini for (i = 1; i < cpu_count(); ++i) 14474e79380SPaolo Bonzini on_cpu(i, do_reset_apic, 0); 14574e79380SPaolo Bonzini 14674e79380SPaolo Bonzini atomic_inc(&active_cpus); 14774e79380SPaolo Bonzini } 148