xref: /openbmc/qemu/hw/ppc/pnv_core.c (revision aa5ac64b2394712b6269d0b15ba06c9c564dee92)
1 /*
2  * QEMU PowerPC PowerNV CPU Core model
3  *
4  * Copyright (c) 2016, IBM Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "sysemu/reset.h"
22 #include "qapi/error.h"
23 #include "qemu/log.h"
24 #include "qemu/module.h"
25 #include "target/ppc/cpu.h"
26 #include "hw/ppc/ppc.h"
27 #include "hw/ppc/pnv.h"
28 #include "hw/ppc/pnv_core.h"
29 #include "hw/ppc/pnv_xscom.h"
30 #include "hw/ppc/xics.h"
31 #include "hw/qdev-properties.h"
32 
33 static const char *pnv_core_cpu_typename(PnvCore *pc)
34 {
35     const char *core_type = object_class_get_name(object_get_class(OBJECT(pc)));
36     int len = strlen(core_type) - strlen(PNV_CORE_TYPE_SUFFIX);
37     char *s = g_strdup_printf(POWERPC_CPU_TYPE_NAME("%.*s"), len, core_type);
38     const char *cpu_type = object_class_get_name(object_class_by_name(s));
39     g_free(s);
40     return cpu_type;
41 }
42 
43 static void pnv_core_cpu_reset(PowerPCCPU *cpu)
44 {
45     CPUState *cs = CPU(cpu);
46     CPUPPCState *env = &cpu->env;
47 
48     cpu_reset(cs);
49 
50     /*
51      * the skiboot firmware elects a primary thread to initialize the
52      * system and it can be any.
53      */
54     env->gpr[3] = PNV_FDT_ADDR;
55     env->nip = 0x10;
56     env->msr |= MSR_HVB; /* Hypervisor mode */
57 }
58 
59 /*
60  * These values are read by the PowerNV HW monitors under Linux
61  */
62 #define PNV_XSCOM_EX_DTS_RESULT0     0x50000
63 #define PNV_XSCOM_EX_DTS_RESULT1     0x50001
64 
65 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
66                                            unsigned int width)
67 {
68     uint32_t offset = addr >> 3;
69     uint64_t val = 0;
70 
71     /* The result should be 38 C */
72     switch (offset) {
73     case PNV_XSCOM_EX_DTS_RESULT0:
74         val = 0x26f024f023f0000ull;
75         break;
76     case PNV_XSCOM_EX_DTS_RESULT1:
77         val = 0x24f000000000000ull;
78         break;
79     default:
80         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
81                   addr);
82     }
83 
84     return val;
85 }
86 
87 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
88                                         unsigned int width)
89 {
90     qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
91                   addr);
92 }
93 
94 static const MemoryRegionOps pnv_core_power8_xscom_ops = {
95     .read = pnv_core_power8_xscom_read,
96     .write = pnv_core_power8_xscom_write,
97     .valid.min_access_size = 8,
98     .valid.max_access_size = 8,
99     .impl.min_access_size = 8,
100     .impl.max_access_size = 8,
101     .endianness = DEVICE_BIG_ENDIAN,
102 };
103 
104 
105 /*
106  * POWER9 core controls
107  */
108 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
109 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
110 
111 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
112                                            unsigned int width)
113 {
114     uint32_t offset = addr >> 3;
115     uint64_t val = 0;
116 
117     /* The result should be 38 C */
118     switch (offset) {
119     case PNV_XSCOM_EX_DTS_RESULT0:
120         val = 0x26f024f023f0000ull;
121         break;
122     case PNV_XSCOM_EX_DTS_RESULT1:
123         val = 0x24f000000000000ull;
124         break;
125     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
126     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
127         val = 0x0;
128         break;
129     default:
130         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
131                   addr);
132     }
133 
134     return val;
135 }
136 
137 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
138                                         unsigned int width)
139 {
140     uint32_t offset = addr >> 3;
141 
142     switch (offset) {
143     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
144     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
145         break;
146     default:
147         qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
148                       addr);
149     }
150 }
151 
152 static const MemoryRegionOps pnv_core_power9_xscom_ops = {
153     .read = pnv_core_power9_xscom_read,
154     .write = pnv_core_power9_xscom_write,
155     .valid.min_access_size = 8,
156     .valid.max_access_size = 8,
157     .impl.min_access_size = 8,
158     .impl.max_access_size = 8,
159     .endianness = DEVICE_BIG_ENDIAN,
160 };
161 
162 static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp)
163 {
164     CPUPPCState *env = &cpu->env;
165     int core_pir;
166     int thread_index = 0; /* TODO: TCG supports only one thread */
167     ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
168     Error *local_err = NULL;
169     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
170 
171     object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
172     if (local_err) {
173         error_propagate(errp, local_err);
174         return;
175     }
176 
177     pcc->intc_create(chip, cpu, &local_err);
178     if (local_err) {
179         error_propagate(errp, local_err);
180         return;
181     }
182 
183     core_pir = object_property_get_uint(OBJECT(cpu), "core-pir", &error_abort);
184 
185     /*
186      * The PIR of a thread is the core PIR + the thread index. We will
187      * need to find a way to get the thread index when TCG supports
188      * more than 1. We could use the object name ?
189      */
190     pir->default_value = core_pir + thread_index;
191 
192     /* Set time-base frequency to 512 MHz */
193     cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
194 }
195 
196 static void pnv_core_reset(void *dev)
197 {
198     CPUCore *cc = CPU_CORE(dev);
199     PnvCore *pc = PNV_CORE(dev);
200     int i;
201 
202     for (i = 0; i < cc->nr_threads; i++) {
203         pnv_core_cpu_reset(pc->threads[i]);
204     }
205 }
206 
207 static void pnv_core_realize(DeviceState *dev, Error **errp)
208 {
209     PnvCore *pc = PNV_CORE(OBJECT(dev));
210     PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
211     CPUCore *cc = CPU_CORE(OBJECT(dev));
212     const char *typename = pnv_core_cpu_typename(pc);
213     Error *local_err = NULL;
214     void *obj;
215     int i, j;
216     char name[32];
217     Object *chip;
218 
219     chip = object_property_get_link(OBJECT(dev), "chip", &local_err);
220     if (!chip) {
221         error_propagate_prepend(errp, local_err,
222                                 "required link 'chip' not found: ");
223         return;
224     }
225     pc->chip = PNV_CHIP(chip);
226 
227     pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
228     for (i = 0; i < cc->nr_threads; i++) {
229         PowerPCCPU *cpu;
230 
231         obj = object_new(typename);
232         cpu = POWERPC_CPU(obj);
233 
234         pc->threads[i] = POWERPC_CPU(obj);
235 
236         snprintf(name, sizeof(name), "thread[%d]", i);
237         object_property_add_child(OBJECT(pc), name, obj, &error_abort);
238         object_property_add_alias(obj, "core-pir", OBJECT(pc),
239                                   "pir", &error_abort);
240 
241         cpu->machine_data = g_new0(PnvCPUState, 1);
242 
243         object_unref(obj);
244     }
245 
246     for (j = 0; j < cc->nr_threads; j++) {
247         pnv_realize_vcpu(pc->threads[j], pc->chip, &local_err);
248         if (local_err) {
249             goto err;
250         }
251     }
252 
253     snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
254     pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
255                           pc, name, PNV_XSCOM_EX_SIZE);
256 
257     qemu_register_reset(pnv_core_reset, pc);
258     return;
259 
260 err:
261     while (--i >= 0) {
262         obj = OBJECT(pc->threads[i]);
263         object_unparent(obj);
264     }
265     g_free(pc->threads);
266     error_propagate(errp, local_err);
267 }
268 
269 static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
270 {
271     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
272 
273     object_unparent(OBJECT(pnv_cpu_state(cpu)->intc));
274     cpu_remove_sync(CPU(cpu));
275     cpu->machine_data = NULL;
276     g_free(pnv_cpu);
277     object_unparent(OBJECT(cpu));
278 }
279 
280 static void pnv_core_unrealize(DeviceState *dev, Error **errp)
281 {
282     PnvCore *pc = PNV_CORE(dev);
283     CPUCore *cc = CPU_CORE(dev);
284     int i;
285 
286     qemu_unregister_reset(pnv_core_reset, pc);
287 
288     for (i = 0; i < cc->nr_threads; i++) {
289         pnv_unrealize_vcpu(pc->threads[i]);
290     }
291     g_free(pc->threads);
292 }
293 
294 static Property pnv_core_properties[] = {
295     DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
296     DEFINE_PROP_END_OF_LIST(),
297 };
298 
299 static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
300 {
301     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
302 
303     pcc->xscom_ops = &pnv_core_power8_xscom_ops;
304 }
305 
306 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
307 {
308     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
309 
310     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
311 }
312 
313 static void pnv_core_class_init(ObjectClass *oc, void *data)
314 {
315     DeviceClass *dc = DEVICE_CLASS(oc);
316 
317     dc->realize = pnv_core_realize;
318     dc->unrealize = pnv_core_unrealize;
319     dc->props = pnv_core_properties;
320 }
321 
322 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
323     {                                           \
324         .parent = TYPE_PNV_CORE,                \
325         .name = PNV_CORE_TYPE_NAME(cpu_model),  \
326         .class_init = pnv_core_##family##_class_init, \
327     }
328 
329 static const TypeInfo pnv_core_infos[] = {
330     {
331         .name           = TYPE_PNV_CORE,
332         .parent         = TYPE_CPU_CORE,
333         .instance_size  = sizeof(PnvCore),
334         .class_size     = sizeof(PnvCoreClass),
335         .class_init = pnv_core_class_init,
336         .abstract       = true,
337     },
338     DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
339     DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
340     DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
341     DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"),
342 };
343 
344 DEFINE_TYPES(pnv_core_infos)
345 
346 /*
347  * POWER9 Quads
348  */
349 
350 #define P9X_EX_NCU_SPEC_BAR                     0x11010
351 
352 static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
353                                     unsigned int width)
354 {
355     uint32_t offset = addr >> 3;
356     uint64_t val = -1;
357 
358     switch (offset) {
359     case P9X_EX_NCU_SPEC_BAR:
360     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
361         val = 0;
362         break;
363     default:
364         qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
365                       offset);
366     }
367 
368     return val;
369 }
370 
371 static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
372                                  unsigned int width)
373 {
374     uint32_t offset = addr >> 3;
375 
376     switch (offset) {
377     case P9X_EX_NCU_SPEC_BAR:
378     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
379         break;
380     default:
381         qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
382                   offset);
383     }
384 }
385 
386 static const MemoryRegionOps pnv_quad_xscom_ops = {
387     .read = pnv_quad_xscom_read,
388     .write = pnv_quad_xscom_write,
389     .valid.min_access_size = 8,
390     .valid.max_access_size = 8,
391     .impl.min_access_size = 8,
392     .impl.max_access_size = 8,
393     .endianness = DEVICE_BIG_ENDIAN,
394 };
395 
396 static void pnv_quad_realize(DeviceState *dev, Error **errp)
397 {
398     PnvQuad *eq = PNV_QUAD(dev);
399     char name[32];
400 
401     snprintf(name, sizeof(name), "xscom-quad.%d", eq->id);
402     pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops,
403                           eq, name, PNV9_XSCOM_EQ_SIZE);
404 }
405 
406 static Property pnv_quad_properties[] = {
407     DEFINE_PROP_UINT32("id", PnvQuad, id, 0),
408     DEFINE_PROP_END_OF_LIST(),
409 };
410 
411 static void pnv_quad_class_init(ObjectClass *oc, void *data)
412 {
413     DeviceClass *dc = DEVICE_CLASS(oc);
414 
415     dc->realize = pnv_quad_realize;
416     dc->props = pnv_quad_properties;
417 }
418 
419 static const TypeInfo pnv_quad_info = {
420     .name          = TYPE_PNV_QUAD,
421     .parent        = TYPE_DEVICE,
422     .instance_size = sizeof(PnvQuad),
423     .class_init    = pnv_quad_class_init,
424 };
425 
426 static void pnv_core_register_types(void)
427 {
428     type_register_static(&pnv_quad_info);
429 }
430 
431 type_init(pnv_core_register_types)
432