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