Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2013-2019 IBM Corp. */
3 : :
4 : : #include <skiboot.h>
5 : : #include "spira.h"
6 : : #include <cpu.h>
7 : : #include <ccan/str/str.h>
8 : : #include <device.h>
9 : :
10 : : #include "hdata.h"
11 : :
12 : 6 : struct dt_node * add_core_common(struct dt_node *cpus,
13 : : const struct sppcia_cpu_cache *cache,
14 : : const struct sppcia_cpu_timebase *tb,
15 : : uint32_t int_server, bool okay)
16 : : {
17 : : const char *name;
18 : : struct dt_node *cpu;
19 : : uint32_t version;
20 : : uint64_t freq;
21 : 6 : const uint8_t pa_features_p8[] = {
22 : : 24, 0,
23 : : 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00,
24 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
26 : : };
27 : 6 : const uint8_t pa_features_p9n_dd20[] = {
28 : : 64, 0,
29 : : 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, /* 0 .. 7 */
30 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 .. 15 */
31 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 16 .. 23 */
32 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 24 .. 31 */
33 : : 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, /* 32 .. 39 */
34 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 40 .. 47 */
35 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 .. 55 */
36 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 56 .. 63 */
37 : : };
38 : 6 : const uint8_t pa_features_p9[] = {
39 : : 64, 0,
40 : : 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, /* 0 .. 7 */
41 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 .. 15 */
42 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 16 .. 23 */
43 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 24 .. 31 */
44 : : 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, /* 32 .. 39 */
45 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 40 .. 47 */
46 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 .. 55 */
47 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 56 .. 63 */
48 : : };
49 : 6 : const uint8_t pa_features_p10[] = {
50 : : 66, 0,
51 : : 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, /* 0 .. 7 */
52 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 .. 15 */
53 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 16 .. 23 */
54 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 24 .. 31 */
55 : : 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, /* 32 .. 39 */
56 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 40 .. 47 */
57 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 .. 55 */
58 : : 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 56 .. 63 */
59 : : 0x80, 0x00, /* 64 .. 65 */
60 : : };
61 : :
62 : : const uint8_t *pa_features;
63 : : size_t pa_features_size;
64 : :
65 : 6 : prlog(PR_INFO, " Cache: I=%u D=%u/%u/%u/%u\n",
66 : : be32_to_cpu(cache->icache_size_kb),
67 : : be32_to_cpu(cache->l1_dcache_size_kb),
68 : : be32_to_cpu(cache->l2_dcache_size_kb),
69 : : be32_to_cpu(cache->l3_dcache_size_kb),
70 : : be32_to_cpu(cache->l35_dcache_size_kb));
71 : :
72 : : /* Use the boot CPU PVR to make up a CPU name in the device-tree
73 : : * since the HDAT doesn't seem to tell....
74 : : */
75 : 6 : version = mfspr(SPR_PVR);
76 : 6 : switch(PVR_TYPE(version)) {
77 : 6 : case PVR_TYPE_P8E:
78 : : case PVR_TYPE_P8:
79 : : case PVR_TYPE_P8NVL:
80 : 6 : name = "PowerPC,POWER8";
81 : 6 : pa_features = pa_features_p8;
82 : 6 : pa_features_size = sizeof(pa_features_p8);
83 : 6 : break;
84 : 0 : case PVR_TYPE_P9:
85 : : case PVR_TYPE_P9P:
86 : 0 : name = "PowerPC,POWER9";
87 : 0 : if (is_power9n(version) &&
88 : 0 : (PVR_VERS_MAJ(version) == 2) &&
89 : 0 : (PVR_VERS_MIN(version) == 0)) {
90 : : /* P9N DD2.0 */
91 : 0 : pa_features = pa_features_p9n_dd20;
92 : 0 : pa_features_size = sizeof(pa_features_p9n_dd20);
93 : : } else {
94 : 0 : pa_features = pa_features_p9;
95 : 0 : pa_features_size = sizeof(pa_features_p9);
96 : : }
97 : 0 : break;
98 : 0 : case PVR_TYPE_P10:
99 : 0 : name = "PowerPC,POWER10";
100 : 0 : pa_features = pa_features_p10;
101 : 0 : pa_features_size = sizeof(pa_features_p10);
102 : 0 : break;
103 : 0 : default:
104 : 0 : name = "PowerPC,Unknown";
105 : 0 : pa_features = NULL;
106 : : }
107 : :
108 : 6 : cpu = dt_new_addr(cpus, name, int_server);
109 : 6 : assert(cpu);
110 : 6 : dt_add_property_string(cpu, "device_type", "cpu");
111 : 6 : dt_add_property_string(cpu, "status", okay ? "okay" : "bad");
112 : 6 : dt_add_property_cells(cpu, "reg", int_server);
113 : 6 : dt_add_property_cells(cpu, "cpu-version", version);
114 : 6 : dt_add_property(cpu, "64-bit", NULL, 0);
115 : 6 : dt_add_property(cpu, "32-64-bridge", NULL, 0);
116 : 6 : dt_add_property(cpu, "graphics", NULL, 0);
117 : 6 : dt_add_property(cpu, "general-purpose", NULL, 0);
118 : 6 : dt_add_property_cells(cpu, "ibm,processor-segment-sizes",
119 : : 0x1c, 0x28, 0xffffffff, 0xffffffff);
120 : 6 : dt_add_property_cells(cpu, "ibm,processor-page-sizes",
121 : : 0xc, 0x10, 0x18, 0x22);
122 : :
123 : 6 : if (proc_gen >= proc_gen_p9)
124 : 0 : dt_add_property_cells(cpu, "ibm,processor-radix-AP-encodings",
125 : : 0x0000000c, 0xa0000010, 0x20000015, 0x4000001e);
126 : 6 : if (proc_gen >= proc_gen_p10) {
127 : 0 : dt_add_property_cells(cpu, "ibm,mmu-pid-bits", 20);
128 : 0 : dt_add_property_cells(cpu, "ibm,mmu-lpid-bits", 12);
129 : : }
130 : 6 : if (lpar_per_core)
131 : 0 : dt_add_property(cpu, "ibm,mmu-lpar-per-core", NULL, 0);
132 : :
133 : : /* HPT segment page size encodings, common to all supported CPUs */
134 : 6 : dt_add_property_cells(cpu, "ibm,segment-page-sizes",
135 : : 0x0c, 0x000, 3, 0x0c, 0x0000, /* 4K seg 4k pages */
136 : : 0x10, 0x0007, /* 4K seg 64k pages */
137 : : 0x18, 0x0038, /* 4K seg 16M pages */
138 : : 0x10, 0x110, 2, 0x10, 0x0001, /* 64K seg 64k pages */
139 : : 0x18, 0x0008, /* 64K seg 16M pages */
140 : : 0x18, 0x100, 1, 0x18, 0x0000, /* 16M seg 16M pages */
141 : : 0x22, 0x120, 1, 0x22, 0x0003); /* 16G seg 16G pages */
142 : :
143 : :
144 : 6 : if (pa_features) {
145 : 6 : dt_add_property(cpu, "ibm,pa-features",
146 : : pa_features, pa_features_size);
147 : : }
148 : 6 : dt_add_property_cells(cpu, "ibm,slb-size", 0x20);
149 : :
150 : 6 : dt_add_property_cells(cpu, "ibm,vmx", 0x2);
151 : 6 : dt_add_property_cells(cpu, "ibm,dfp", 0x2);
152 : 6 : dt_add_property_cells(cpu, "ibm,purr", 0x1);
153 : 6 : dt_add_property_cells(cpu, "ibm,spurr", 0x1);
154 : :
155 : : /*
156 : : * Do not create "clock-frequency" if the frequency doesn't
157 : : * fit in a single cell
158 : : */
159 : 6 : freq = ((uint64_t)be32_to_cpu(tb->actual_clock_speed)) * 1000000ul;
160 : 6 : if (freq <= 0xfffffffful)
161 : 6 : dt_add_property_cells(cpu, "clock-frequency", freq);
162 : 6 : dt_add_property_u64(cpu, "ibm,extended-clock-frequency", freq);
163 : :
164 : : /* FIXME: Hardcoding is bad. */
165 : 6 : dt_add_property_cells(cpu, "timebase-frequency", 512000000);
166 : 6 : dt_add_property_cells(cpu, "ibm,extended-timebase-frequency",
167 : : 0, 512000000);
168 : :
169 : 6 : dt_add_property_cells(cpu, "reservation-granule-size",
170 : : be32_to_cpu(cache->reservation_size));
171 : :
172 : 6 : dt_add_property_cells(cpu, "d-tlb-size",
173 : : be32_to_cpu(cache->dtlb_entries));
174 : 6 : dt_add_property_cells(cpu, "i-tlb-size",
175 : : be32_to_cpu(cache->itlb_entries));
176 : : /* Assume unified TLB */
177 : 6 : dt_add_property_cells(cpu, "tlb-size",
178 : : be32_to_cpu(cache->dtlb_entries));
179 : 6 : dt_add_property_cells(cpu, "d-tlb-sets",
180 : : be32_to_cpu(cache->dtlb_assoc_sets));
181 : 6 : dt_add_property_cells(cpu, "i-tlb-sets",
182 : : be32_to_cpu(cache->itlb_assoc_sets));
183 : 6 : dt_add_property_cells(cpu, "tlb-sets",
184 : : be32_to_cpu(cache->dtlb_assoc_sets));
185 : :
186 : 6 : dt_add_property_cells(cpu, "d-cache-block-size",
187 : : be32_to_cpu(cache->dcache_block_size));
188 : 6 : dt_add_property_cells(cpu, "i-cache-block-size",
189 : : be32_to_cpu(cache->icache_block_size));
190 : 6 : dt_add_property_cells(cpu, "d-cache-size",
191 : : be32_to_cpu(cache->l1_dcache_size_kb)*1024);
192 : 6 : dt_add_property_cells(cpu, "i-cache-size",
193 : : be32_to_cpu(cache->icache_size_kb)*1024);
194 : 6 : dt_add_property_cells(cpu, "i-cache-sets",
195 : : be32_to_cpu(cache->icache_assoc_sets));
196 : 6 : dt_add_property_cells(cpu, "d-cache-sets",
197 : : be32_to_cpu(cache->dcache_assoc_sets));
198 : :
199 : 6 : if (cache->icache_line_size != cache->icache_block_size)
200 : 0 : dt_add_property_cells(cpu, "i-cache-line-size",
201 : : be32_to_cpu(cache->icache_line_size));
202 : 6 : if (cache->l1_dcache_line_size != cache->dcache_block_size)
203 : 0 : dt_add_property_cells(cpu, "d-cache-line-size",
204 : : be32_to_cpu(cache->l1_dcache_line_size));
205 : 6 : return cpu;
206 : : }
207 : :
208 : 6 : void add_core_attr(struct dt_node *cpu, uint32_t attr)
209 : : {
210 : 6 : if (attr & CPU_ATTR_UNIFIED_PL1)
211 : 0 : dt_add_property(cpu, "cache-unified", NULL, 0);
212 : 6 : if (attr & CPU_ATTR_SPLIT_TLB)
213 : 0 : dt_add_property(cpu, "tlb-split", NULL, 0);
214 : 6 : if (attr & CPU_ATTR_TLBIA)
215 : 0 : dt_add_property(cpu, "tlbia", NULL, 0);
216 : 6 : if (attr & CPU_ATTR_PERF_MONITOR)
217 : 6 : dt_add_property_cells(cpu, "performance-monitor", 0, 1);
218 : 6 : if (attr & CPU_ATTR_EXTERN_CONT)
219 : 0 : dt_add_property(cpu, "external-control", NULL, 0);
220 : 6 : }
221 : :
222 : 12 : static struct dt_node *create_cache_node(struct dt_node *cpus,
223 : : const struct sppcia_cpu_cache *cache,
224 : : const char *name, uint32_t unit_addr,
225 : : int okay)
226 : : {
227 : : struct dt_node *node;
228 : :
229 : 12 : node = dt_new_addr(cpus, name, unit_addr);
230 : 12 : assert(node);
231 : :
232 : 12 : dt_add_property_string(node, "device_type", "cache");
233 : 12 : dt_add_property_cells(node, "reg", unit_addr);
234 : 12 : dt_add_property_string(node, "status", okay ? "okay" : "bad");
235 : 12 : dt_add_property(node, "cache-unified", NULL, 0);
236 : :
237 : : /* Assume cache associavitity sets is same for L2, L3 and L3.5 */
238 : 12 : dt_add_property_cells(node, "d-cache-sets",
239 : : be32_to_cpu(cache->l2_cache_assoc_sets));
240 : 12 : dt_add_property_cells(node, "i-cache-sets",
241 : : be32_to_cpu(cache->l2_cache_assoc_sets));
242 : :
243 : 12 : return node;
244 : : }
245 : :
246 : 0 : static struct dt_node *l35_cache_node(struct dt_node *cpus,
247 : : const struct sppcia_cpu_cache *cache,
248 : : uint32_t unit_addr, int okay)
249 : : {
250 : : struct dt_node *node;
251 : :
252 : 0 : node = create_cache_node(cpus, cache, "l35-cache", unit_addr, okay);
253 : :
254 : 0 : dt_add_property_cells(node, "d-cache-size",
255 : : be32_to_cpu(cache->l35_dcache_size_kb) * 1024);
256 : 0 : dt_add_property_cells(node, "i-cache-size",
257 : : be32_to_cpu(cache->l35_dcache_size_kb) * 1024);
258 : :
259 : 0 : if (cache->icache_line_size != cache->icache_block_size)
260 : 0 : dt_add_property_cells(node, "i-cache-line-size",
261 : : be32_to_cpu(cache->icache_line_size));
262 : 0 : if (cache->l35_cache_line_size != cache->dcache_block_size)
263 : 0 : dt_add_property_cells(node, "d-cache-line-size",
264 : : be32_to_cpu(cache->l35_cache_line_size));
265 : :
266 : 0 : return node;
267 : : }
268 : :
269 : 6 : static struct dt_node *l3_cache_node(struct dt_node *cpus,
270 : : const struct sppcia_cpu_cache *cache,
271 : : uint32_t unit_addr, int okay)
272 : : {
273 : : struct dt_node *node;
274 : :
275 : 6 : node = create_cache_node(cpus, cache, "l3-cache", unit_addr, okay);
276 : :
277 : 6 : dt_add_property_cells(node, "d-cache-size",
278 : : be32_to_cpu(cache->l3_dcache_size_kb) * 1024);
279 : 6 : dt_add_property_cells(node, "i-cache-size",
280 : : be32_to_cpu(cache->l3_dcache_size_kb) * 1024);
281 : :
282 : 6 : if (cache->icache_line_size != cache->icache_block_size)
283 : 0 : dt_add_property_cells(node, "i-cache-line-size",
284 : : be32_to_cpu(cache->icache_line_size));
285 : 6 : if (cache->l3_line_size != cache->dcache_block_size)
286 : 0 : dt_add_property_cells(node, "d-cache-line-size",
287 : : be32_to_cpu(cache->l3_line_size));
288 : :
289 : 6 : return node;
290 : : }
291 : :
292 : 6 : static struct dt_node *l2_cache_node(struct dt_node *cpus,
293 : : const struct sppcia_cpu_cache *cache,
294 : : uint32_t unit_addr, int okay)
295 : : {
296 : : struct dt_node *node;
297 : :
298 : 6 : node = create_cache_node(cpus, cache, "l2-cache", unit_addr, okay);
299 : :
300 : 6 : dt_add_property_cells(node, "d-cache-size",
301 : : be32_to_cpu(cache->l2_dcache_size_kb) * 1024);
302 : 6 : dt_add_property_cells(node, "i-cache-size",
303 : : be32_to_cpu(cache->l2_dcache_size_kb) * 1024);
304 : :
305 : 6 : if (cache->icache_line_size != cache->icache_block_size)
306 : 0 : dt_add_property_cells(node, "i-cache-line-size",
307 : : be32_to_cpu(cache->icache_line_size));
308 : 6 : if (cache->l2_line_size != cache->dcache_block_size)
309 : 0 : dt_add_property_cells(node, "d-cache-line-size",
310 : : be32_to_cpu(cache->l2_line_size));
311 : :
312 : 6 : return node;
313 : : }
314 : :
315 : 0 : static struct dt_node *find_l2_node(struct dt_node *cpus, u32 unit_addr)
316 : : {
317 : : char name[32];
318 : :
319 : 0 : snprintf(name, sizeof(name), "l2-cache@%.08x", unit_addr);
320 : 0 : return dt_find_by_name(cpus, name);
321 : : }
322 : :
323 : 6 : uint32_t add_core_cache_info(struct dt_node *cpus,
324 : : const struct sppcia_cpu_cache *cache,
325 : : uint32_t core_pir, int okay)
326 : : {
327 : : struct dt_node *l2_node, *l3_node, *l35_node;
328 : : uint32_t unit_addr;
329 : :
330 : : /*
331 : : * On P9 the L2 is shared by pairs of SMT=4 cores. We only want
332 : : * to create a cache node for the first of these so we mask off
333 : : * the low PIR bits to get the unit address of the shared cache.
334 : : */
335 : 6 : if (proc_gen == proc_gen_p9) {
336 : 0 : core_pir &= ~0x7;
337 : :
338 : 0 : l2_node = find_l2_node(cpus, 0x20 << 24 | core_pir);
339 : 0 : if (l2_node)
340 : 0 : return l2_node->phandle;
341 : : }
342 : :
343 : 6 : unit_addr = 0x20 << 24 | core_pir;
344 : 6 : l2_node = l2_cache_node(cpus, cache, unit_addr, okay);
345 : :
346 : 6 : unit_addr = 0x30 << 24 | core_pir;
347 : 6 : l3_node = l3_cache_node(cpus, cache, unit_addr, okay);
348 : :
349 : : /* Represents the next level of cache in the memory hierarchy */
350 : 6 : dt_add_property_cells(l2_node, "l2-cache", l3_node->phandle);
351 : :
352 : 6 : if (be32_to_cpu(cache->l35_dcache_size_kb)) {
353 : 0 : unit_addr = 0x35 << 24 | core_pir;
354 : 0 : l35_node = l35_cache_node(cpus, cache, unit_addr, okay);
355 : 0 : dt_add_property_cells(l3_node, "l2-cache", l35_node->phandle);
356 : : }
357 : :
358 : 6 : return l2_node->phandle;
359 : : }
|