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 <fsp.h>
8 : : #include <opal.h>
9 : : #include <ccan/str/str.h>
10 : : #include <device.h>
11 : :
12 : : #include "hdata.h"
13 : :
14 : : #define PCIA_MAX_THREADS 8
15 : :
16 : 12 : static unsigned int pcia_index(const void *pcia)
17 : : {
18 : 12 : return (pcia - (void *)get_hdif(&spiras->ntuples.pcia, "SPPCIA"))
19 : 12 : / be32_to_cpu(spiras->ntuples.pcia.alloc_len);
20 : : }
21 : :
22 : 102 : static const struct sppcia_cpu_thread *find_tada(const void *pcia,
23 : : unsigned int thread)
24 : : {
25 : 102 : int count = HDIF_get_iarray_size(pcia, SPPCIA_IDATA_THREAD_ARRAY);
26 : : int i;
27 : :
28 : 102 : if (count < 0)
29 : 0 : return NULL;
30 : :
31 : 438 : for (i = 0; i < count; i++) {
32 : : const struct sppcia_cpu_thread *t;
33 : : unsigned int size;
34 : :
35 : 438 : t = HDIF_get_iarray_item(pcia, SPPCIA_IDATA_THREAD_ARRAY,
36 : : i, &size);
37 : 438 : if (!t || size < sizeof(*t))
38 : 0 : continue;
39 : 438 : if (be32_to_cpu(t->phys_thread_id) == thread)
40 : 102 : return t;
41 : : }
42 : 0 : return NULL;
43 : : }
44 : :
45 : 6 : static void add_xics_icp(const void *pcia, u32 tcount, const char *compat)
46 : : {
47 : : const struct sppcia_cpu_thread *t;
48 : : struct dt_node *icp;
49 : : __be64 *reg;
50 : : u32 i, irange[2], rsize;
51 : :
52 : 6 : rsize = tcount * 2 * sizeof(__be64);
53 : 6 : reg = malloc(rsize);
54 : 6 : assert(reg);
55 : :
56 : : /* Suppresses uninitialized warning from gcc */
57 : 6 : irange[0] = 0;
58 : 54 : for (i = 0; i < tcount; i++) {
59 : 48 : t = find_tada(pcia, i);
60 : 48 : assert(t);
61 : 48 : if (i == 0)
62 : 6 : irange[0] = be32_to_cpu(t->pir);
63 : 48 : reg[i * 2] = cpu_to_be64(cleanup_addr(be64_to_cpu(t->ibase)));
64 : 48 : reg[i * 2 + 1] = cpu_to_be64(0x1000);
65 : : }
66 : 6 : irange[1] = tcount;
67 : :
68 : 6 : icp = dt_new_addr(dt_root, "interrupt-controller", be64_to_cpu(reg[0]));
69 : 6 : if (!icp) {
70 : 0 : free(reg);
71 : 0 : return;
72 : : }
73 : :
74 : 6 : if (compat)
75 : 6 : dt_add_property_strings(icp, "compatible", "ibm,ppc-xicp", compat);
76 : : else
77 : 0 : dt_add_property_strings(icp, "compatible", "ibm,ppc-xicp");
78 : 6 : dt_add_property_cells(icp, "ibm,interrupt-server-ranges",
79 : : irange[0], irange[1]);
80 : 6 : dt_add_property(icp, "interrupt-controller", NULL, 0);
81 : 6 : dt_add_property_cells(icp, "#interrupt-cells", 1);
82 : 6 : dt_add_property(icp, "reg", reg, rsize);
83 : 6 : dt_add_property_cells(icp, "#address-cells", 0);
84 : 6 : dt_add_property_string(icp, "device_type",
85 : : "PowerPC-External-Interrupt-Presentation");
86 : 6 : free(reg);
87 : : }
88 : :
89 : 6 : static struct dt_node *add_core_node(struct dt_node *cpus,
90 : : const void *pcia,
91 : : const struct sppcia_core_unique *id,
92 : : bool okay)
93 : : {
94 : : const struct sppcia_cpu_thread *t;
95 : : const struct sppcia_cpu_timebase *timebase;
96 : : const struct sppcia_cpu_cache *cache;
97 : : const struct sppcia_cpu_attr *attr;
98 : : struct dt_node *cpu;
99 : : const char *icp_compat;
100 : : u32 i, size, threads, ve_flags, l2_phandle, chip_id;
101 : : __be32 iserv[PCIA_MAX_THREADS];
102 : :
103 : : /* Look for thread 0 */
104 : 6 : t = find_tada(pcia, 0);
105 : 6 : if (!t) {
106 : 0 : prerror("CORE[%i]: Failed to find thread 0 !\n",
107 : : pcia_index(pcia));
108 : 0 : return NULL;
109 : : }
110 : :
111 : 6 : ve_flags = be32_to_cpu(id->verif_exist_flags);
112 : 6 : threads = ((ve_flags & CPU_ID_NUM_SECONDARY_THREAD_MASK)
113 : 6 : >> CPU_ID_NUM_SECONDARY_THREAD_SHIFT) + 1;
114 : 6 : assert(threads <= PCIA_MAX_THREADS);
115 : :
116 : 6 : prlog(PR_INFO, "CORE[%i]: PIR=%.8x %s %s(%u threads)\n",
117 : : pcia_index(pcia), be32_to_cpu(t->pir),
118 : : ve_flags & CPU_ID_PCIA_RESERVED
119 : : ? "**RESERVED**" : cpu_state(ve_flags),
120 : : be32_to_cpu(t->pir) == boot_cpu->pir ? "[boot] " : "", threads);
121 : :
122 : 6 : timebase = HDIF_get_idata(pcia, SPPCIA_IDATA_TIMEBASE, &size);
123 : 6 : if (!timebase || size < sizeof(*timebase)) {
124 : 0 : prerror("CORE[%i]: bad timebase size %u @ %p\n",
125 : : pcia_index(pcia), size, timebase);
126 : 0 : return NULL;
127 : : }
128 : :
129 : 6 : cache = HDIF_get_idata(pcia, SPPCIA_IDATA_CPU_CACHE, &size);
130 : 6 : if (!cache || size < sizeof(*cache)) {
131 : 0 : prerror("CORE[%i]: bad cache size %u @ %p\n",
132 : : pcia_index(pcia), size, cache);
133 : 0 : return NULL;
134 : : }
135 : :
136 : 6 : cpu = add_core_common(cpus, cache, timebase,
137 : 6 : be32_to_cpu(t->pir), okay);
138 : :
139 : : /* Core attributes */
140 : 6 : attr = HDIF_get_idata(pcia, SPPCIA_IDATA_CPU_ATTR, &size);
141 : 6 : if (attr)
142 : 6 : add_core_attr(cpu, be32_to_cpu(attr->attr));
143 : :
144 : : /* Add cache info */
145 : 6 : l2_phandle = add_core_cache_info(cpus, cache,
146 : 6 : be32_to_cpu(t->pir), okay);
147 : 6 : dt_add_property_cells(cpu, "l2-cache", l2_phandle);
148 : :
149 : 6 : if (proc_gen == proc_gen_p8)
150 : 6 : icp_compat = "IBM,power8-icp";
151 : :
152 : : /* Get HW Chip ID */
153 : 6 : chip_id = pcid_to_chip_id(be32_to_cpu(id->proc_chip_id));
154 : :
155 : 6 : dt_add_property_cells(cpu, "ibm,pir", be32_to_cpu(t->pir));
156 : 6 : dt_add_property_cells(cpu, "ibm,chip-id", chip_id);
157 : :
158 : : /* Build ibm,ppc-interrupt-server#s with all threads */
159 : 54 : for (i = 0; i < threads; i++) {
160 : 48 : t = find_tada(pcia, i);
161 : 48 : if (!t) {
162 : 0 : threads = i;
163 : 0 : break;
164 : : }
165 : :
166 : 48 : iserv[i] = t->pir;
167 : : }
168 : :
169 : 6 : dt_add_property(cpu, "ibm,ppc-interrupt-server#s", iserv, 4 * threads);
170 : :
171 : : /* Add the ICP node for this CPU for P8 */
172 : 6 : if (proc_gen == proc_gen_p8)
173 : 6 : add_xics_icp(pcia, threads, icp_compat);
174 : :
175 : 6 : return cpu;
176 : : }
177 : :
178 : 1 : bool pcia_parse(void)
179 : : {
180 : : const void *pcia;
181 : : struct dt_node *cpus;
182 : :
183 : 1 : pcia = get_hdif(&spiras->ntuples.pcia, SPPCIA_HDIF_SIG);
184 : 1 : if (!pcia)
185 : 0 : return false;
186 : :
187 : 1 : prlog(PR_INFO, "Got PCIA !\n");
188 : :
189 : 1 : cpus = dt_new(dt_root, "cpus");
190 : 1 : dt_add_property_cells(cpus, "#address-cells", 1);
191 : 1 : dt_add_property_cells(cpus, "#size-cells", 0);
192 : :
193 : 7 : for_each_pcia(spiras, pcia) {
194 : : const struct sppcia_core_unique *id;
195 : : u32 size, ve_flags;
196 : : bool okay;
197 : :
198 : 6 : id = HDIF_get_idata(pcia, SPPCIA_IDATA_CORE_UNIQUE, &size);
199 : 6 : if (!id || size < sizeof(*id)) {
200 : 0 : prerror("CORE[%i]: bad id size %u @ %p\n",
201 : : pcia_index(pcia), size, id);
202 : 0 : return false;
203 : : }
204 : 6 : ve_flags = be32_to_cpu(id->verif_exist_flags);
205 : :
206 : 6 : switch ((ve_flags & CPU_ID_VERIFY_MASK)
207 : 6 : >> CPU_ID_VERIFY_SHIFT) {
208 : 6 : case CPU_ID_VERIFY_USABLE_NO_FAILURES:
209 : : case CPU_ID_VERIFY_USABLE_FAILURES:
210 : 6 : okay = true;
211 : 6 : break;
212 : 0 : default:
213 : 0 : okay = false;
214 : : }
215 : :
216 : 6 : prlog(okay ? PR_INFO : PR_WARNING,
217 : : "CORE[%i]: HW_PROC_ID=%i PROC_CHIP_ID=%i EC=0x%x %s\n",
218 : : pcia_index(pcia), be32_to_cpu(id->hw_proc_id),
219 : : be32_to_cpu(id->proc_chip_id),
220 : : be32_to_cpu(id->chip_ec_level),
221 : : okay ? "OK" : "UNAVAILABLE");
222 : :
223 : 6 : if (!add_core_node(cpus, pcia, id, okay))
224 : 0 : break;
225 : : }
226 : 1 : return true;
227 : : }
|