1/* @title: Topology */
2#pragma once
3#include <stdbool.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <structures/cpu_mask.h>
7#include <types/types.h>
8
9enum topology_level {
10 TOPOLOGY_LEVEL_SMT, /* Symmetric multiprocessing threads */
11 TOPOLOGY_LEVEL_CORE, /* SMTs under a core */
12 TOPOLOGY_LEVEL_NUMA, /* NUMA node */
13 TOPOLOGY_LEVEL_LLC, /* Last level cache (some processors
14 * have multiple L3 caches for a given
15 * physical processor) */
16 TOPOLOGY_LEVEL_PACKAGE, /* Physical processor in a socket */
17 TOPOLOGY_LEVEL_MACHINE, /* All processors in a machine */
18 TOPOLOGY_LEVEL_MAX, /* count */
19
20 TOPOLOGY_LEVEL_DOMAIN, /* This exists solely because the topology_contract
21 * has a domain granularity that does not
22 * necessarily correspond to one of the others,
23 * thus, it is outside of MAX and is its
24 * own layer just for that API */
25};
26
27/* This enum is used to verify topology contracts to guarantee a caller
28 * cannot be migrated out of a given scope of logical processors.
29 *
30 * wrt. naming, we'll suffix all instances of caller contracts with a C.
31 * e.g. SMPC, NODEC, PACKAGEC(specific bits go here)
32 *
33 * TODO: we might need to come up with a naming document in docs/ because
34 * I've been doing this ad-hoc naming scheme stuff a few times
35 */
36enum topology_caller {
37 TOPC_NONE = 0,
38 TOPC_IRQL = 1 << 0,
39
40 /* NOTE: PINNED and IRQ are mutually exclusive */
41 TOPC_PINNED = 1 << 1,
42 TOPC_IRQ = 1 << 2,
43 TOPC_IFLAG = 1 << 3,
44
45 /* IRQ, IRQL and IFLAG: IRQ checks in_interrupt, IRQL that >= DISPATCH */
46 TOPC_ANY = TOPC_IRQL | TOPC_PINNED | TOPC_IRQ | TOPC_IFLAG,
47};
48
49/* Contracts essentially state "I will not migrate outside of this scope",
50 * with a set of named, verifiable reasons, so that "self topology" related
51 * functions can prove that they are in a safe state (specified), or
52 * in the edge case, have TOPOC_NONE contracts to uphold */
53struct topology_contract {
54 enum topology_level scope;
55 enum topology_caller caller;
56};
57
58/* TODO: enum this stuff */
59struct topology_cache_info {
60 uint8_t level; /* 1, 2, 3 */
61 uint8_t type; /* Data, unified, instruction */
62 uint32_t size_kb;
63 uint32_t line_size;
64 uint32_t cores_sharing; /* Who shares this */
65};
66
67struct topology_package_info {
68 uint32_t package_id;
69 struct cpu_mask cores;
70};
71
72struct topology_node {
73 enum topology_level level;
74 uint64_t id; /* Index in this node */
75 uint64_t parent; /* Parent node index, -1 for root */
76 struct topology_node *parent_node;
77 int32_t first_child; /* For cores this is in the cores array.
78 * For NUMA this is also in the cores array.
79 * For LLC this is in the numa array.
80 * For package this is LLC.
81 * For machine this is package. */
82 int32_t nr_children;
83
84 struct cpu_mask cpus;
85 struct cpu_mask idle;
86 struct cpu_mask rt_sched_rq_active; /* For RT scheduler */
87
88 struct core *core; /* Pointer to this node's `core` struct */
89
90 union {
91 struct numa_node *numa;
92 struct topology_cache_info *cache;
93 struct topology_package_info *package;
94 } data;
95};
96
97struct topology {
98 struct topology_node *level[TOPOLOGY_LEVEL_MAX];
99 uint16_t count[TOPOLOGY_LEVEL_MAX];
100};
101
102void topology_mark_core_idle(cpu_id_t cpu_id, bool idle);
103struct core *topology_find_idle_core(struct core *local_core,
104 enum topology_level max_search);
105struct core **topology_get_smts_under_numa(struct topology_node *numa,
106 size_t *count);
107const char *topology_level_name(enum topology_level l);
108bool topology_contract_verify(struct topology_contract c);
109