1 // Copyright (c) 2014 Travis Geiselbrecht
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 #pragma once
7
8 #include <kernel/thread.h>
9 #include <lk/compiler.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12
13 __BEGIN_CDECLS
14
15 // This file defines apis that deal with high level multiprocessor (MP)
16 // support for the kernel.
17 // May be used in both SMP and UP configurations, but in UP
18 // configurations, the APIs are no-ops and the mp_state structure
19 // is not used.
20 // WITH_SMP is defined in the build system to indicate that
21 // the kernel is built with SMP support.
22 //
23 // Most of thesse APIs are used to manage the state of CPUs in a multiprocessor system,
24 // including their active status, idle status, and whether they are running realtime threads.
25
26 // A bitmap representing active CPUs.
27 typedef uint32_t mp_cpu_mask_t;
28
29 #define MP_CPU_ALL_BUT_LOCAL (UINT32_MAX)
30
31 // By default, mp_mbx_reschedule does not signal to cpus that are running realtime
32 // threads. Override this behavior.
33 #define MP_RESCHEDULE_FLAG_REALTIME (0x1)
34
35 // Interprocessor Interrupt (IPI) types
36 typedef enum {
37 MP_IPI_GENERIC,
38 MP_IPI_RESCHEDULE,
39 } mp_ipi_t;
40
41 #ifdef WITH_SMP
42 void mp_init(void);
43
44 // Trigger a reschedule on the specified target CPUs.
45 void mp_reschedule(mp_cpu_mask_t target, uint flags);
46 void mp_set_curr_cpu_active(bool active);
47
48 // Called from arch code during reschedule irq
49 enum handler_return mp_mbx_reschedule_irq(void);
50
51 // Global mp state to track what the cpus are up to.
52 struct mp_state {
53 volatile mp_cpu_mask_t active_cpus;
54
55 // only safely accessible with thread lock held
56 mp_cpu_mask_t idle_cpus;
57 mp_cpu_mask_t realtime_cpus;
58 };
59
60 extern struct mp_state mp;
61
62 // Active cpus are currently running any sort of thread, including idle threads.
mp_is_cpu_active(uint cpu)63 static inline bool mp_is_cpu_active(uint cpu) {
64 return mp.active_cpus & (1UL << cpu);
65 }
66
67 // Idle cpus are currently running the idle thread.
mp_is_cpu_idle(uint cpu)68 static inline bool mp_is_cpu_idle(uint cpu) {
69 return mp.idle_cpus & (1UL << cpu);
70 }
71
72 // Must be called with the thread lock held.
mp_set_cpu_idle(uint cpu)73 static inline void mp_set_cpu_idle(uint cpu) {
74 mp.idle_cpus |= 1UL << cpu;
75 }
76
mp_set_cpu_busy(uint cpu)77 static inline void mp_set_cpu_busy(uint cpu) {
78 mp.idle_cpus &= ~(1UL << cpu);
79 }
80
mp_get_idle_mask(void)81 static inline mp_cpu_mask_t mp_get_idle_mask(void) {
82 return mp.idle_cpus;
83 }
84
85 // Realtime cpus are currently running realtime threads.
mp_set_cpu_realtime(uint cpu)86 static inline void mp_set_cpu_realtime(uint cpu) {
87 mp.realtime_cpus |= 1UL << cpu;
88 }
89
mp_set_cpu_non_realtime(uint cpu)90 static inline void mp_set_cpu_non_realtime(uint cpu) {
91 mp.realtime_cpus &= ~(1UL << cpu);
92 }
93
mp_get_realtime_mask(void)94 static inline mp_cpu_mask_t mp_get_realtime_mask(void) {
95 return mp.realtime_cpus;
96 }
97 #else
mp_init(void)98 static inline void mp_init(void) {}
mp_reschedule(mp_cpu_mask_t target,uint flags)99 static inline void mp_reschedule(mp_cpu_mask_t target, uint flags) {}
mp_set_curr_cpu_active(bool active)100 static inline void mp_set_curr_cpu_active(bool active) {}
101
mp_mbx_reschedule_irq(void)102 static inline enum handler_return mp_mbx_reschedule_irq(void) { return INT_NO_RESCHEDULE; }
103
104 // only one cpu exists in UP and if you're calling these functions, it's active...
mp_is_cpu_active(uint cpu)105 static inline int mp_is_cpu_active(uint cpu) { return 1; }
mp_is_cpu_idle(uint cpu)106 static inline int mp_is_cpu_idle(uint cpu) { return (get_current_thread()->flags & THREAD_FLAG_IDLE) != 0; }
107
mp_set_cpu_idle(uint cpu)108 static inline void mp_set_cpu_idle(uint cpu) {}
mp_set_cpu_busy(uint cpu)109 static inline void mp_set_cpu_busy(uint cpu) {}
110
mp_get_idle_mask(void)111 static inline mp_cpu_mask_t mp_get_idle_mask(void) { return 0; }
112
mp_set_cpu_realtime(uint cpu)113 static inline void mp_set_cpu_realtime(uint cpu) {}
mp_set_cpu_non_realtime(uint cpu)114 static inline void mp_set_cpu_non_realtime(uint cpu) {}
115
mp_get_realtime_mask(void)116 static inline mp_cpu_mask_t mp_get_realtime_mask(void) { return 0; }
117 #endif
118
119 __END_CDECLS
120