~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/hdata/paca.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2013-2014 IBM Corp.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at
 
6
 *
 
7
 *      http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
12
 * implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include <skiboot.h>
 
18
#include "spira.h"
 
19
#include <cpu.h>
 
20
#include <fsp.h>
 
21
#include <opal.h>
 
22
#include <ccan/str/str.h>
 
23
#include <device.h>
 
24
#include <types.h>
 
25
 
 
26
#include "hdata.h"
 
27
 
 
28
#define PACA_MAX_THREADS 4
 
29
 
 
30
static unsigned int paca_index(const struct HDIF_common_hdr *paca)
 
31
{
 
32
        void *start = get_hdif(&spira.ntuples.paca, PACA_HDIF_SIG);
 
33
        return ((void *)paca - start)
 
34
                / be32_to_cpu(spira.ntuples.paca.alloc_len);
 
35
}
 
36
 
 
37
static struct dt_node *add_cpu_node(struct dt_node *cpus,
 
38
                                    const struct HDIF_common_hdr *paca,
 
39
                                    const struct sppaca_cpu_id *id,
 
40
                                    bool okay)
 
41
{
 
42
        const struct sppaca_cpu_timebase *timebase;
 
43
        const struct sppaca_cpu_cache *cache;
 
44
        const struct sppaca_cpu_attr *attr;
 
45
        struct dt_node *cpu;
 
46
        u32 no, size, ve_flags, l2_phandle, chip_id;
 
47
 
 
48
        /* We use the process_interrupt_line as the res id */
 
49
        no = be32_to_cpu(id->process_interrupt_line);
 
50
 
 
51
        ve_flags = be32_to_cpu(id->verify_exists_flags);
 
52
        printf("CPU[%i]: PIR=%i RES=%i %s %s(%u threads)\n",
 
53
               paca_index(paca), be32_to_cpu(id->pir), no,
 
54
               ve_flags & CPU_ID_PACA_RESERVED
 
55
               ? "**RESERVED**" : cpu_state(ve_flags),
 
56
               ve_flags & CPU_ID_SECONDARY_THREAD
 
57
               ? "[secondary] " : 
 
58
               (be32_to_cpu(id->pir) == boot_cpu->pir ? "[boot] " : ""),
 
59
               ((ve_flags & CPU_ID_NUM_SECONDARY_THREAD_MASK)
 
60
                >> CPU_ID_NUM_SECONDARY_THREAD_SHIFT) + 1);
 
61
 
 
62
        timebase = HDIF_get_idata(paca, SPPACA_IDATA_TIMEBASE, &size);
 
63
        if (!timebase || size < sizeof(*timebase)) {
 
64
                prerror("CPU[%i]: bad timebase size %u @ %p\n",
 
65
                        paca_index(paca), size, timebase);
 
66
                return NULL;
 
67
        }
 
68
 
 
69
        cache = HDIF_get_idata(paca, SPPACA_IDATA_CACHE_SIZE, &size);
 
70
        if (!cache || size < sizeof(*cache)) {
 
71
                prerror("CPU[%i]: bad cache size %u @ %p\n",
 
72
                        paca_index(paca), size, cache);
 
73
                return NULL;
 
74
        }
 
75
 
 
76
        cpu = add_core_common(cpus, cache, timebase, no, okay);
 
77
 
 
78
        /* Core attributes */
 
79
        attr = HDIF_get_idata(paca, SPPACA_IDATA_CPU_ATTR, &size);
 
80
        if (attr)
 
81
                add_core_attr(cpu, be32_to_cpu(attr->attr));
 
82
 
 
83
        /* Add cache info */
 
84
        l2_phandle = add_core_cache_info(cpus, cache, no, okay);
 
85
        dt_add_property_cells(cpu, "l2-cache", l2_phandle);
 
86
 
 
87
        /* We append the secondary cpus in __cpu_parse */
 
88
        dt_add_property_cells(cpu, "ibm,ppc-interrupt-server#s", no);
 
89
 
 
90
        dt_add_property_cells(cpu, DT_PRIVATE "hw_proc_id",
 
91
                              be32_to_cpu(id->hardware_proc_id));
 
92
        dt_add_property_cells(cpu, "ibm,pir", be32_to_cpu(id->pir));
 
93
 
 
94
        chip_id = pcid_to_chip_id(be32_to_cpu(id->processor_chip_id));
 
95
        dt_add_property_cells(cpu, "ibm,chip-id", chip_id);
 
96
 
 
97
        return cpu;
 
98
}
 
99
 
 
100
static struct dt_node *find_cpu_by_hardware_proc_id(struct dt_node *root,
 
101
                                                    u32 hw_proc_id)
 
102
{
 
103
        struct dt_node *i;
 
104
 
 
105
        dt_for_each_node(root, i) {
 
106
                const struct dt_property *prop;
 
107
 
 
108
                if (!dt_has_node_property(i, "device_type", "cpu"))
 
109
                        continue;
 
110
 
 
111
                prop = dt_find_property(i, DT_PRIVATE "hw_proc_id");
 
112
                if (!prop)
 
113
                        return NULL;
 
114
 
 
115
                if (be32_to_cpu(*(be32 *)prop->prop) == hw_proc_id)
 
116
                        return i;
 
117
        }
 
118
        return NULL;
 
119
}
 
120
 
 
121
/* Note that numbers are small. */
 
122
static void add_be32_sorted(__be32 arr[], __be32 new, unsigned num)
 
123
{
 
124
        unsigned int i;
 
125
 
 
126
        /* Walk until we find where we belong (insertion sort). */
 
127
        for (i = 0; i < num; i++) {
 
128
                if (be32_to_cpu(new) < be32_to_cpu(arr[i])) {
 
129
                        __be32 tmp = arr[i];
 
130
                        arr[i] = new;
 
131
                        new = tmp;
 
132
                }
 
133
        }
 
134
        arr[i] = new;
 
135
}
 
136
 
 
137
static void add_icps(void)
 
138
{
 
139
        struct dt_node *cpu;
 
140
        unsigned int i;
 
141
        u64 reg[PACA_MAX_THREADS * 2];
 
142
        struct dt_node *icp;
 
143
 
 
144
        dt_for_each_node(dt_root, cpu) {
 
145
                u32 irange[2], size, pir;
 
146
                const struct dt_property *intsrv;
 
147
                const struct HDIF_common_hdr *paca;
 
148
                u64 ibase;
 
149
                unsigned int num_threads;
 
150
                bool found = false;
 
151
 
 
152
                if (!dt_has_node_property(cpu, "device_type", "cpu"))
 
153
                        continue;
 
154
 
 
155
                intsrv = dt_find_property(cpu, "ibm,ppc-interrupt-server#s");
 
156
                pir = dt_prop_get_u32(cpu, "ibm,pir");
 
157
 
 
158
                /* Get ibase address */
 
159
                paca = get_hdif(&spira.ntuples.paca, PACA_HDIF_SIG);
 
160
                for_each_paca(paca) {
 
161
                        const struct sppaca_cpu_id *id;
 
162
                        id = HDIF_get_idata(paca, SPPACA_IDATA_CPU_ID, &size);
 
163
 
 
164
                        if (!CHECK_SPPTR(id))
 
165
                                continue;
 
166
 
 
167
                        if (pir != be32_to_cpu(id->pir))
 
168
                                continue;
 
169
                        ibase = cleanup_addr(be64_to_cpu(id->ibase));
 
170
                        found = true;
 
171
                        break;
 
172
                }
 
173
                if (!found)
 
174
                        return;
 
175
 
 
176
                num_threads = intsrv->len / sizeof(u32);
 
177
                assert(num_threads <= PACA_MAX_THREADS);
 
178
 
 
179
                icp = dt_new_addr(dt_root, "interrupt-controller", ibase);
 
180
                if (!icp)
 
181
                        continue;
 
182
 
 
183
                dt_add_property_strings(icp, "compatible",
 
184
                                        "IBM,ppc-xicp",
 
185
                                        "IBM,power7-xicp");
 
186
 
 
187
                irange[0] = dt_property_get_cell(intsrv, 0); /* Index */
 
188
                irange[1] = num_threads;                     /* num servers */
 
189
                dt_add_property(icp, "ibm,interrupt-server-ranges",
 
190
                                irange, sizeof(irange));
 
191
                dt_add_property(icp, "interrupt-controller", NULL, 0);
 
192
                dt_add_property_cells(icp, "#address-cells", 0);
 
193
                dt_add_property_string(icp, "device_type",
 
194
                                   "PowerPC-External-Interrupt-Presentation");
 
195
                for (i = 0; i < num_threads*2; i += 2) {
 
196
                        reg[i] = ibase;
 
197
                        /* One page is enough for a handful of regs. */
 
198
                        reg[i+1] = 4096;
 
199
                        ibase += reg[i+1];
 
200
                }
 
201
                dt_add_property(icp, "reg", reg, sizeof(reg));  
 
202
        }
 
203
}
 
204
 
 
205
static bool __paca_parse(void)
 
206
{
 
207
        const struct HDIF_common_hdr *paca;
 
208
        struct dt_node *cpus;
 
209
 
 
210
        paca = get_hdif(&spira.ntuples.paca, PACA_HDIF_SIG);
 
211
        if (!paca) {
 
212
                prerror("Invalid PACA (PCIA = %p)\n",
 
213
                        ntuple_addr(&spira.ntuples.pcia));
 
214
                return false;
 
215
        }
 
216
 
 
217
        if (be32_to_cpu(spira.ntuples.paca.act_len) < sizeof(*paca)) {
 
218
                prerror("PACA: invalid size %u\n",
 
219
                        be32_to_cpu(spira.ntuples.paca.act_len));
 
220
                return false;
 
221
        }
 
222
 
 
223
        cpus = dt_new(dt_root, "cpus");
 
224
        dt_add_property_cells(cpus, "#address-cells", 1);
 
225
        dt_add_property_cells(cpus, "#size-cells", 0);
 
226
 
 
227
        for_each_paca(paca) {
 
228
                const struct sppaca_cpu_id *id;
 
229
                u32 size, ve_flags;
 
230
                bool okay;
 
231
 
 
232
                id = HDIF_get_idata(paca, SPPACA_IDATA_CPU_ID, &size);
 
233
 
 
234
                /* The ID structure on Blade314 is only 0x54 long. We can
 
235
                 * cope with it as we don't use all the additional fields.
 
236
                 * The minimum size we support is  0x40
 
237
                 */
 
238
                if (!id || size < SPIRA_CPU_ID_MIN_SIZE) {
 
239
                        prerror("CPU[%i]: bad id size %u @ %p\n",
 
240
                                paca_index(paca), size, id);
 
241
                        return false;
 
242
                }
 
243
 
 
244
                ve_flags = be32_to_cpu(id->verify_exists_flags);
 
245
                switch ((ve_flags&CPU_ID_VERIFY_MASK) >> CPU_ID_VERIFY_SHIFT) {
 
246
                case CPU_ID_VERIFY_USABLE_NO_FAILURES:
 
247
                case CPU_ID_VERIFY_USABLE_FAILURES:
 
248
                        okay = true;
 
249
                        break;
 
250
                default:
 
251
                        okay = false;
 
252
                }
 
253
 
 
254
                printf("CPU[%i]: PIR=%i RES=%i %s\n",
 
255
                       paca_index(paca), be32_to_cpu(id->pir),
 
256
                       be32_to_cpu(id->process_interrupt_line),
 
257
                       okay ? "OK" : "UNAVAILABLE");
 
258
 
 
259
                /* Secondary threads don't get their own node. */
 
260
                if (ve_flags & CPU_ID_SECONDARY_THREAD)
 
261
                        continue;
 
262
 
 
263
                if (!add_cpu_node(cpus, paca, id, okay))
 
264
                        return false;
 
265
        }
 
266
 
 
267
        /* Now account for secondaries. */
 
268
        for_each_paca(paca) {
 
269
                const struct dt_property *prop;
 
270
                const struct sppaca_cpu_id *id;
 
271
                u32 size, state, num, ve_flags;
 
272
                struct dt_node *cpu;
 
273
                __be32 *new_prop;
 
274
 
 
275
                id = HDIF_get_idata(paca, 2, &size);
 
276
                if (!CHECK_SPPTR(id))
 
277
                        continue;
 
278
 
 
279
                ve_flags = be32_to_cpu(id->verify_exists_flags);
 
280
                state = (ve_flags & CPU_ID_VERIFY_MASK) >> CPU_ID_VERIFY_SHIFT;
 
281
                switch (state) {
 
282
                case CPU_ID_VERIFY_USABLE_NO_FAILURES:
 
283
                case CPU_ID_VERIFY_USABLE_FAILURES:
 
284
                        break;
 
285
                default:
 
286
                        continue;
 
287
                }
 
288
 
 
289
                /* Only interested in secondary threads. */
 
290
                if (!(ve_flags & CPU_ID_SECONDARY_THREAD))
 
291
                        continue;
 
292
 
 
293
                cpu = find_cpu_by_hardware_proc_id(cpus,
 
294
                                   be32_to_cpu(id->hardware_proc_id));
 
295
                if (!cpu) {
 
296
                        prerror("CPU[%i]: could not find primary hwid %i\n",
 
297
                                paca_index(paca),
 
298
                                be32_to_cpu(id->hardware_proc_id));
 
299
                        return false;
 
300
                }
 
301
 
 
302
                /* Add the cpu #. */
 
303
                prop = dt_find_property(cpu, "ibm,ppc-interrupt-server#s");
 
304
                if (!prop) {
 
305
                        prerror("CPU[%i]: could not find mapping information\n",
 
306
                                paca_index(paca));
 
307
                        return false;
 
308
                }
 
309
                num = prop->len / sizeof(u32);
 
310
                new_prop = malloc((num + 1) * sizeof(u32));
 
311
                if (!new_prop) {
 
312
                        prerror("Property allocation length %zu failed\n",
 
313
                                (num + 1) * sizeof(u32));
 
314
                        return false;
 
315
                }
 
316
                memcpy(new_prop, prop->prop, prop->len);
 
317
                add_be32_sorted(new_prop, id->process_interrupt_line, num);
 
318
                dt_del_property(cpu, (struct dt_property *)prop);
 
319
                dt_add_property(cpu, "ibm,ppc-interrupt-server#s",
 
320
                                new_prop, (num + 1) * sizeof(__be32));
 
321
                free(new_prop);
 
322
        }
 
323
 
 
324
        add_icps();
 
325
 
 
326
        return true;
 
327
}
 
328
 
 
329
int paca_parse(void)
 
330
{
 
331
        if (!__paca_parse()) {
 
332
                prerror("CPU: Initial CPU parsing failed\n");
 
333
                return -1;
 
334
        }
 
335
        return 0;
 
336
}