1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <include/assert.h>
5 #include <console/console.h>
8 * A structure to hold a cache pointer
9 * and its corresponding reference within
12 struct cache_reference
{
13 struct pptt_cache
*cache
; // cache pointer
14 u32 ref
; // and its reference within PPTT
18 * A list of 'struct cache_reference', used
19 * to keep track of generated caches per topology level.
22 u32 n_caches
; // number of caches in list
23 struct cache_reference cache_refs
[CONFIG_ACPI_PPTT_MAX_CACHES
]; // cache reference list
27 * Start of the PPTT table. Constant
28 * value as soon as we enter acpi_create_pptt_body.
30 static uintptr_t pptt_start
;
32 /* --- Helper Functions (non exposed) --- */
34 static inline u32
node_to_reference(const void *node
)
37 * References are the offset from the start
41 * +---------+ <- pptt_start (acpi_pptt_t) <---+
42 * | | | node - pptt_start
44 * +---------+ <- node (cpu or cache) <--------+
50 return ((uintptr_t)node
- pptt_start
);
53 static u32
count_resources(struct pptt_cpu_resources
*res
)
65 static u32
cache_list_ref_of(struct cache_list
*cache_list
, const struct pptt_cache
*cache
)
68 * Lookup the PPTT reference of 'cache'.
69 * Return 0, if no PPTT structure exists for 'cache'.
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
;
77 /* no cache reference found */
81 static inline void cache_list_append(struct cache_list
*cache_list
, struct pptt_cache
*cache
, const u32 ref
)
83 printk(BIOS_DEBUG
, "acpi: pptt: cache=%p ref=%u\n", cache
, ref
);
85 cache_list
->cache_refs
[cache_list
->n_caches
].cache
= cache
;
86 cache_list
->cache_refs
[cache_list
->n_caches
].ref
= ref
;
88 cache_list
->n_caches
+= 1;
91 static u32
new_pptt_cache(unsigned long *current
, struct pptt_cache
*cache
, struct cache_list
*cache_list
)
93 static u32 unique_cache_id
= 1;
94 u32 current_reference
= 0;
96 if ((current_reference
= cache_list_ref_of(cache_list
, cache
)) != 0)
97 return current_reference
;
99 if (cache_list
->n_caches
>= CONFIG_ACPI_PPTT_MAX_CACHES
) {
100 printk(BIOS_WARNING
, "acpi: pptt: Too many distinct caches! PPTT incomplete.\n");
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
));
107 cache_node
->type
= PPTT_NODE_TYPE_CACHE
;
108 cache_node
->length
= sizeof(acpi_pptt_cache_node_t
);
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
;
115 cache_node
->attributes
= cache
->attributes
;
116 cache_node
->line_size
= cache
->line_size
;
117 cache_node
->cache_id
= unique_cache_id
++;
119 *current
+= cache_node
->length
;
121 current_reference
= node_to_reference(cache_node
);
122 cache_list_append(cache_list
, cache
, current_reference
);
124 if (cache
->next_level
!= NULL
)
125 cache_node
->next_level
= new_pptt_cache(current
, cache
->next_level
, cache_list
);
127 return current_reference
;
130 static u32
new_pptt_cpu(unsigned long *current
, const struct pptt_topology
*cpu
, const u32 parent_ref
, struct cache_list
*cache_list
)
132 acpi_pptt_cpu_node_t
*cpu_node
= (acpi_pptt_cpu_node_t
*)*current
;
134 const u32 n_resources
= count_resources(cpu
->resources
);
135 const u32 structure_length
= sizeof(acpi_pptt_cpu_node_t
) + (n_resources
* sizeof(u32
));
137 memset(cpu_node
, 0x0, structure_length
);
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
;
145 *current
+= cpu_node
->length
;
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
);
150 return node_to_reference(cpu_node
);
153 static void setup_topology(const struct pptt_topology
*node
, const u32 parent_ref
, unsigned long *current
)
155 struct cache_list cache_list
= {
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
);
164 node
= node
->sibling
;
168 /* --- PPTT generation helper functions (exposed) --- */
170 void acpi_create_pptt_body(acpi_pptt_t
*pptt
)
172 /* set start of pptt table */
173 pptt_start
= (uintptr_t)pptt
;
175 /* locate start of pptt body */
176 unsigned long current
= (unsigned long)(pptt
->body
);
178 /* retrieve processor topology */
179 const struct pptt_topology
*topology_tree
= acpi_get_pptt_topology();
181 /* write processor properties topology table to memory */
182 setup_topology(topology_tree
, 0, ¤t
);
184 /* update length field in pptt header */
185 pptt
->header
.length
= current
- (unsigned long)pptt
;