1 /*
2  * Copyright (c) 2014 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <arch/mp.h>
9 
10 #include <assert.h>
11 #include <lk/trace.h>
12 #include <lk/err.h>
13 #include <platform/interrupts.h>
14 #include <arch/ops.h>
15 
16 #if WITH_DEV_INTERRUPT_ARM_GIC
17 #include <dev/interrupt/arm_gic.h>
18 #elif PLATFORM_BCM28XX
19 /* bcm28xx has a weird custom interrupt controller for MP */
20 extern void bcm28xx_send_ipi(uint irq, uint cpu_mask);
21 #else
22 #error need other implementation of interrupt controller that can ipi
23 #endif
24 
25 #define LOCAL_TRACE 0
26 
27 #define GIC_IPI_BASE (14)
28 
arch_mp_send_ipi(mp_cpu_mask_t target,mp_ipi_t ipi)29 status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) {
30     LTRACEF("target 0x%x, ipi %u\n", target, ipi);
31 
32 #if WITH_DEV_INTERRUPT_ARM_GIC
33     uint gic_ipi_num = ipi + GIC_IPI_BASE;
34 
35     /* filter out targets outside of the range of cpus we care about */
36     target &= ((1UL << SMP_MAX_CPUS) - 1);
37     if (target != 0) {
38         LTRACEF("target 0x%x, gic_ipi %u\n", target, gic_ipi_num);
39         u_int flags = 0;
40 #if WITH_LIB_SM
41         flags |= ARM_GIC_SGI_FLAG_NS;
42 #endif
43         arm_gic_sgi(gic_ipi_num, flags, target);
44     }
45 #elif PLATFORM_BCM28XX
46     /* filter out targets outside of the range of cpus we care about */
47     target &= ((1UL << SMP_MAX_CPUS) - 1);
48     if (target != 0) {
49         bcm28xx_send_ipi(ipi, target);
50     }
51 #endif
52 
53     return NO_ERROR;
54 }
55 
56 enum handler_return arm_ipi_generic_handler(void *arg);
arm_ipi_generic_handler(void * arg)57 enum handler_return arm_ipi_generic_handler(void *arg) {
58     LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg);
59 
60     return INT_NO_RESCHEDULE;
61 }
62 
63 enum handler_return arm_ipi_reschedule_handler(void *arg);
arm_ipi_reschedule_handler(void * arg)64 enum handler_return arm_ipi_reschedule_handler(void *arg) {
65     LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg);
66 
67     return mp_mbx_reschedule_irq();
68 }
69 
arch_mp_init_percpu(void)70 void arch_mp_init_percpu(void) {
71 #if WITH_DEV_INTERRUPT_ARM_GIC
72     register_int_handler(MP_IPI_GENERIC + GIC_IPI_BASE, &arm_ipi_generic_handler, 0);
73     register_int_handler(MP_IPI_RESCHEDULE + GIC_IPI_BASE, &arm_ipi_reschedule_handler, 0);
74 #endif
75 }
76 
77