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 #pragma once
9 
10 #include <kernel/thread.h>
11 #include <limits.h>
12 #include <lk/compiler.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 
16 __BEGIN_CDECLS
17 
18 typedef uint32_t mp_cpu_mask_t;
19 
20 #define MP_CPU_ALL_BUT_LOCAL (UINT32_MAX)
21 
22 /* by default, mp_mbx_reschedule does not signal to cpus that are running realtime
23  * threads. Override this behavior.
24  */
25 #define MP_RESCHEDULE_FLAG_REALTIME (0x1)
26 
27 typedef enum {
28     MP_IPI_GENERIC,
29     MP_IPI_RESCHEDULE,
30 } mp_ipi_t;
31 
32 #ifdef WITH_SMP
33 void mp_init(void);
34 
35 void mp_reschedule(mp_cpu_mask_t target, uint flags);
36 void mp_set_curr_cpu_active(bool active);
37 
38 /* called from arch code during reschedule irq */
39 enum handler_return mp_mbx_reschedule_irq(void);
40 
41 /* global mp state to track what the cpus are up to */
42 struct mp_state {
43     volatile mp_cpu_mask_t active_cpus;
44 
45     /* only safely accessible with thread lock held */
46     mp_cpu_mask_t idle_cpus;
47     mp_cpu_mask_t realtime_cpus;
48 };
49 
50 extern struct mp_state mp;
51 
mp_is_cpu_active(uint cpu)52 static inline int mp_is_cpu_active(uint cpu) {
53     return mp.active_cpus & (1 << cpu);
54 }
55 
mp_is_cpu_idle(uint cpu)56 static inline int mp_is_cpu_idle(uint cpu) {
57     return mp.idle_cpus & (1 << cpu);
58 }
59 
60 /* must be called with the thread lock held */
mp_set_cpu_idle(uint cpu)61 static inline void mp_set_cpu_idle(uint cpu) {
62     mp.idle_cpus |= 1UL << cpu;
63 }
64 
mp_set_cpu_busy(uint cpu)65 static inline void mp_set_cpu_busy(uint cpu) {
66     mp.idle_cpus &= ~(1UL << cpu);
67 }
68 
mp_get_idle_mask(void)69 static inline mp_cpu_mask_t mp_get_idle_mask(void) {
70     return mp.idle_cpus;
71 }
72 
mp_set_cpu_realtime(uint cpu)73 static inline void mp_set_cpu_realtime(uint cpu) {
74     mp.realtime_cpus |= 1UL << cpu;
75 }
76 
mp_set_cpu_non_realtime(uint cpu)77 static inline void mp_set_cpu_non_realtime(uint cpu) {
78     mp.realtime_cpus &= ~(1UL << cpu);
79 }
80 
mp_get_realtime_mask(void)81 static inline mp_cpu_mask_t mp_get_realtime_mask(void) {
82     return mp.realtime_cpus;
83 }
84 #else
mp_init(void)85 static inline void mp_init(void) {}
mp_reschedule(mp_cpu_mask_t target,uint flags)86 static inline void mp_reschedule(mp_cpu_mask_t target, uint flags) {}
mp_set_curr_cpu_active(bool active)87 static inline void mp_set_curr_cpu_active(bool active) {}
88 
mp_mbx_reschedule_irq(void)89 static inline enum handler_return mp_mbx_reschedule_irq(void) { return INT_NO_RESCHEDULE; }
90 
91 // only one cpu exists in UP and if you're calling these functions, it's active...
mp_is_cpu_active(uint cpu)92 static inline int mp_is_cpu_active(uint cpu) { return 1; }
mp_is_cpu_idle(uint cpu)93 static inline int mp_is_cpu_idle(uint cpu) { return (get_current_thread()->flags & THREAD_FLAG_IDLE) != 0; }
94 
mp_set_cpu_idle(uint cpu)95 static inline void mp_set_cpu_idle(uint cpu) {}
mp_set_cpu_busy(uint cpu)96 static inline void mp_set_cpu_busy(uint cpu) {}
97 
mp_get_idle_mask(void)98 static inline mp_cpu_mask_t mp_get_idle_mask(void) { return 0; }
99 
mp_set_cpu_realtime(uint cpu)100 static inline void mp_set_cpu_realtime(uint cpu) {}
mp_set_cpu_non_realtime(uint cpu)101 static inline void mp_set_cpu_non_realtime(uint cpu) {}
102 
mp_get_realtime_mask(void)103 static inline mp_cpu_mask_t mp_get_realtime_mask(void) { return 0; }
104 #endif
105 
106 __END_CDECLS
107