| 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 | |
| 9 | enum 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 | */ |
| 36 | enum 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 */ |
| 53 | struct topology_contract { |
| 54 | enum topology_level scope; |
| 55 | enum topology_caller caller; |
| 56 | }; |
| 57 | |
| 58 | /* TODO: enum this stuff */ |
| 59 | struct 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 | |
| 67 | struct topology_package_info { |
| 68 | uint32_t package_id; |
| 69 | struct cpu_mask cores; |
| 70 | }; |
| 71 | |
| 72 | struct 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 | |
| 97 | struct topology { |
| 98 | struct topology_node *level[TOPOLOGY_LEVEL_MAX]; |
| 99 | uint16_t count[TOPOLOGY_LEVEL_MAX]; |
| 100 | }; |
| 101 | |
| 102 | void topology_mark_core_idle(cpu_id_t cpu_id, bool idle); |
| 103 | struct core *topology_find_idle_core(struct core *local_core, |
| 104 | enum topology_level max_search); |
| 105 | struct core **topology_get_smts_under_numa(struct topology_node *numa, |
| 106 | size_t *count); |
| 107 | const char *topology_level_name(enum topology_level l); |
| 108 | bool topology_contract_verify(struct topology_contract c); |
| 109 | |