xref: /aosp_15_r20/external/coreboot/src/acpi/acpi_pptt.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpi.h>
4 #include <include/assert.h>
5 #include <console/console.h>
6 
7 /*
8  * A structure to hold a cache pointer
9  * and its corresponding reference within
10  * the PPTT table.
11  */
12 struct cache_reference {
13 	struct pptt_cache *cache; // cache pointer
14 	u32                ref;   // and its reference within PPTT
15 };
16 
17 /*
18  * A list of 'struct cache_reference', used
19  * to keep track of generated caches per topology level.
20  */
21 struct cache_list {
22 	u32                    n_caches;                                // number of caches in list
23 	struct cache_reference cache_refs[CONFIG_ACPI_PPTT_MAX_CACHES]; // cache reference list
24 };
25 
26 /*
27  * Start of the PPTT table. Constant
28  * value as soon as we enter acpi_create_pptt_body.
29  */
30 static uintptr_t pptt_start;
31 
32 /* --- Helper Functions (non exposed) --- */
33 
node_to_reference(const void * node)34 static inline u32 node_to_reference(const void *node)
35 {
36 	/*
37 	 * References are the offset from the start
38 	 * of the PPTT table.
39 	 *
40 	 *    PPTT
41 	 * +---------+ <- pptt_start (acpi_pptt_t) <---+
42 	 * |         |                                 | node - pptt_start
43 	 * |         |                                 |
44 	 * +---------+ <- node (cpu or cache) <--------+
45 	 * |         |
46 	 * |         |
47 	 * |         |
48 	 * +---------+
49 	 */
50 	return ((uintptr_t)node - pptt_start);
51 }
52 
count_resources(struct pptt_cpu_resources * res)53 static u32 count_resources(struct pptt_cpu_resources *res)
54 {
55 	u32 n_resources = 0;
56 
57 	while (res != NULL) {
58 		n_resources += 1;
59 		res = res->next;
60 	}
61 
62 	return n_resources;
63 }
64 
cache_list_ref_of(struct cache_list * cache_list,const struct pptt_cache * cache)65 static u32 cache_list_ref_of(struct cache_list *cache_list, const struct pptt_cache *cache)
66 {
67 	/*
68 	 * Lookup the PPTT reference of 'cache'.
69 	 * Return 0, if no PPTT structure exists for 'cache'.
70 	 */
71 
72 	for (int i = 0; i < cache_list->n_caches; i++) {
73 		if (cache_list->cache_refs[i].cache == cache)
74 			return cache_list->cache_refs[i].ref;
75 	}
76 
77 	/* no cache reference found */
78 	return 0;
79 }
80 
cache_list_append(struct cache_list * cache_list,struct pptt_cache * cache,const u32 ref)81 static inline void cache_list_append(struct cache_list *cache_list, struct pptt_cache *cache, const u32 ref)
82 {
83 	printk(BIOS_DEBUG, "acpi: pptt: cache=%p ref=%u\n", cache, ref);
84 
85 	cache_list->cache_refs[cache_list->n_caches].cache = cache;
86 	cache_list->cache_refs[cache_list->n_caches].ref   = ref;
87 
88 	cache_list->n_caches += 1;
89 }
90 
new_pptt_cache(unsigned long * current,struct pptt_cache * cache,struct cache_list * cache_list)91 static u32 new_pptt_cache(unsigned long *current, struct pptt_cache *cache, struct cache_list *cache_list)
92 {
93 	static u32 unique_cache_id = 1;
94 	u32 current_reference      = 0;
95 
96 	if ((current_reference = cache_list_ref_of(cache_list, cache)) != 0)
97 		return current_reference;
98 
99 	if (cache_list->n_caches >= CONFIG_ACPI_PPTT_MAX_CACHES) {
100 		printk(BIOS_WARNING, "acpi: pptt: Too many distinct caches! PPTT incomplete.\n");
101 		return 0;
102 	}
103 
104 	acpi_pptt_cache_node_t *cache_node = (acpi_pptt_cache_node_t *)*current;
105 	memset(cache_node, 0x0, sizeof(acpi_pptt_cache_node_t));
106 
107 	cache_node->type   = PPTT_NODE_TYPE_CACHE;
108 	cache_node->length = sizeof(acpi_pptt_cache_node_t);
109 
110 	cache_node->flags         = cache->flags.raw;
111 	cache_node->size          = cache->size;
112 	cache_node->n_sets        = cache->numsets;
113 	cache_node->associativity = cache->associativity;
114 
115 	cache_node->attributes = cache->attributes;
116 	cache_node->line_size  = cache->line_size;
117 	cache_node->cache_id   = unique_cache_id++;
118 
119 	*current += cache_node->length;
120 
121 	current_reference = node_to_reference(cache_node);
122 	cache_list_append(cache_list, cache, current_reference);
123 
124 	if (cache->next_level != NULL)
125 		cache_node->next_level = new_pptt_cache(current, cache->next_level, cache_list);
126 
127 	return current_reference;
128 }
129 
new_pptt_cpu(unsigned long * current,const struct pptt_topology * cpu,const u32 parent_ref,struct cache_list * cache_list)130 static u32 new_pptt_cpu(unsigned long *current, const struct pptt_topology *cpu, const u32 parent_ref, struct cache_list *cache_list)
131 {
132 	acpi_pptt_cpu_node_t *cpu_node = (acpi_pptt_cpu_node_t *)*current;
133 
134 	const u32 n_resources      = count_resources(cpu->resources);
135 	const u32 structure_length = sizeof(acpi_pptt_cpu_node_t) + (n_resources * sizeof(u32));
136 
137 	memset(cpu_node, 0x0, structure_length);
138 
139 	cpu_node->type         = PPTT_NODE_TYPE_CPU;
140 	cpu_node->length       = structure_length;
141 	cpu_node->flags        = cpu->flags.raw;
142 	cpu_node->processor_id = cpu->processor_id;
143 	cpu_node->parent       = parent_ref;
144 
145 	*current += cpu_node->length;
146 
147 	for (struct pptt_cpu_resources *it = cpu->resources; it != NULL; it = it->next)
148 		cpu_node->resources[cpu_node->n_resources++] = new_pptt_cache(current, it->cache, cache_list);
149 
150 	return node_to_reference(cpu_node);
151 }
152 
setup_topology(const struct pptt_topology * node,const u32 parent_ref,unsigned long * current)153 static void setup_topology(const struct pptt_topology *node, const u32 parent_ref, unsigned long *current)
154 {
155 	struct cache_list cache_list = {
156 		.cache_refs = { },
157 		.n_caches   = 0
158 	};
159 
160 	while (node != NULL) {
161 		const u32 cpu_ref = new_pptt_cpu(current, node, parent_ref, &cache_list);
162 		setup_topology(node->child, cpu_ref, current);
163 
164 		node = node->sibling;
165 	}
166 }
167 
168 /* --- PPTT generation helper functions (exposed) --- */
169 
acpi_create_pptt_body(acpi_pptt_t * pptt)170 void acpi_create_pptt_body(acpi_pptt_t *pptt)
171 {
172 	/* set start of pptt table */
173 	pptt_start = (uintptr_t)pptt;
174 
175 	/* locate start of pptt body */
176 	unsigned long current = (unsigned long)(pptt->body);
177 
178 	/* retrieve processor topology */
179 	const struct pptt_topology *topology_tree = acpi_get_pptt_topology();
180 
181 	/* write processor properties topology table to memory */
182 	setup_topology(topology_tree, 0, &current);
183 
184 	/* update length field in pptt header */
185 	pptt->header.length = current - (unsigned long)pptt;
186 }
187