qapi: Improve specificity of type/member descriptions
[qemu/armbru.git] / hw / pci-host / pnv_phb4_pec.c
blob3b2850f7a3ea5ddf75ef550d1593c72dd0c6f4db
1 /*
2 * QEMU PowerPC PowerNV (POWER9) PHB4 model
4 * Copyright (c) 2018-2020, IBM Corporation.
6 * This code is licensed under the GPL version 2 or later. See the
7 * COPYING file in the top-level directory.
8 */
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "qemu/log.h"
12 #include "target/ppc/cpu.h"
13 #include "hw/ppc/fdt.h"
14 #include "hw/pci-host/pnv_phb4_regs.h"
15 #include "hw/pci-host/pnv_phb4.h"
16 #include "hw/ppc/pnv_xscom.h"
17 #include "hw/pci/pci_bridge.h"
18 #include "hw/pci/pci_bus.h"
19 #include "hw/ppc/pnv.h"
20 #include "hw/ppc/pnv_chip.h"
21 #include "hw/qdev-properties.h"
22 #include "sysemu/sysemu.h"
24 #include <libfdt.h>
26 #define phb_pec_error(pec, fmt, ...) \
27 qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \
28 (pec)->chip_id, (pec)->index, ## __VA_ARGS__)
31 static uint64_t pnv_pec_nest_xscom_read(void *opaque, hwaddr addr,
32 unsigned size)
34 PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
35 uint32_t reg = addr >> 3;
37 /* TODO: add list of allowed registers and error out if not */
38 return pec->nest_regs[reg];
41 static void pnv_pec_nest_xscom_write(void *opaque, hwaddr addr,
42 uint64_t val, unsigned size)
44 PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
45 uint32_t reg = addr >> 3;
47 switch (reg) {
48 case PEC_NEST_PBCQ_HW_CONFIG:
49 case PEC_NEST_DROP_PRIO_CTRL:
50 case PEC_NEST_PBCQ_ERR_INJECT:
51 case PEC_NEST_PCI_NEST_CLK_TRACE_CTL:
52 case PEC_NEST_PBCQ_PMON_CTRL:
53 case PEC_NEST_PBCQ_PBUS_ADDR_EXT:
54 case PEC_NEST_PBCQ_PRED_VEC_TIMEOUT:
55 case PEC_NEST_CAPP_CTRL:
56 case PEC_NEST_PBCQ_READ_STK_OVR:
57 case PEC_NEST_PBCQ_WRITE_STK_OVR:
58 case PEC_NEST_PBCQ_STORE_STK_OVR:
59 case PEC_NEST_PBCQ_RETRY_BKOFF_CTRL:
60 pec->nest_regs[reg] = val;
61 break;
62 default:
63 phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
64 addr, val);
68 static const MemoryRegionOps pnv_pec_nest_xscom_ops = {
69 .read = pnv_pec_nest_xscom_read,
70 .write = pnv_pec_nest_xscom_write,
71 .valid.min_access_size = 8,
72 .valid.max_access_size = 8,
73 .impl.min_access_size = 8,
74 .impl.max_access_size = 8,
75 .endianness = DEVICE_BIG_ENDIAN,
78 static uint64_t pnv_pec_pci_xscom_read(void *opaque, hwaddr addr,
79 unsigned size)
81 PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
82 uint32_t reg = addr >> 3;
84 /* TODO: add list of allowed registers and error out if not */
85 return pec->pci_regs[reg];
88 static void pnv_pec_pci_xscom_write(void *opaque, hwaddr addr,
89 uint64_t val, unsigned size)
91 PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
92 uint32_t reg = addr >> 3;
94 switch (reg) {
95 case PEC_PCI_PBAIB_HW_CONFIG:
96 case PEC_PCI_PBAIB_READ_STK_OVR:
97 pec->pci_regs[reg] = val;
98 break;
99 default:
100 phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
101 addr, val);
105 static const MemoryRegionOps pnv_pec_pci_xscom_ops = {
106 .read = pnv_pec_pci_xscom_read,
107 .write = pnv_pec_pci_xscom_write,
108 .valid.min_access_size = 8,
109 .valid.max_access_size = 8,
110 .impl.min_access_size = 8,
111 .impl.max_access_size = 8,
112 .endianness = DEVICE_BIG_ENDIAN,
115 PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp)
117 PnvPhb4PecState *pecs = NULL;
118 int chip_id = phb->chip_id;
119 int index = phb->phb_id;
120 int i, j;
122 if (phb->version == 4) {
123 Pnv9Chip *chip9 = PNV9_CHIP(chip);
125 pecs = chip9->pecs;
126 } else if (phb->version == 5) {
127 Pnv10Chip *chip10 = PNV10_CHIP(chip);
129 pecs = chip10->pecs;
130 } else {
131 g_assert_not_reached();
134 for (i = 0; i < chip->num_pecs; i++) {
136 * For each PEC, check the amount of phbs it supports
137 * and see if the given phb4 index matches an index.
139 PnvPhb4PecState *pec = &pecs[i];
141 for (j = 0; j < pec->num_phbs; j++) {
142 if (index == pnv_phb4_pec_get_phb_id(pec, j)) {
143 pec->phbs[j] = phb;
144 phb->pec = pec;
145 return pec;
149 error_setg(errp,
150 "pnv-phb4 chip-id %d index %d didn't match any existing PEC",
151 chip_id, index);
153 return NULL;
156 static PnvPHB *pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
157 int stack_no,
158 Error **errp)
160 PnvPHB *phb = PNV_PHB(qdev_new(TYPE_PNV_PHB));
161 int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no);
163 object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb));
164 object_property_set_link(OBJECT(phb), "pec", OBJECT(pec),
165 &error_abort);
166 object_property_set_int(OBJECT(phb), "chip-id", pec->chip_id,
167 &error_fatal);
168 object_property_set_int(OBJECT(phb), "index", phb_id,
169 &error_fatal);
171 if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) {
172 return NULL;
174 return phb;
177 static void pnv_pec_realize(DeviceState *dev, Error **errp)
179 PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
180 PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
181 char name[64];
182 int i;
184 if (pec->index >= PNV_CHIP_GET_CLASS(pec->chip)->num_pecs) {
185 error_setg(errp, "invalid PEC index: %d", pec->index);
186 return;
189 pec->num_phbs = pecc->num_phbs[pec->index];
191 /* Create PHBs if running with defaults */
192 if (defaults_enabled()) {
193 g_assert(pec->num_phbs <= MAX_PHBS_PER_PEC);
194 for (i = 0; i < pec->num_phbs; i++) {
195 pec->phbs[i] = pnv_pec_default_phb_realize(pec, i, errp);
199 /* Initialize the XSCOM regions for the PEC registers */
200 snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest", pec->chip_id,
201 pec->index);
202 pnv_xscom_region_init(&pec->nest_regs_mr, OBJECT(dev),
203 &pnv_pec_nest_xscom_ops, pec, name,
204 PHB4_PEC_NEST_REGS_COUNT);
206 snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci", pec->chip_id,
207 pec->index);
208 pnv_xscom_region_init(&pec->pci_regs_mr, OBJECT(dev),
209 &pnv_pec_pci_xscom_ops, pec, name,
210 PHB4_PEC_PCI_REGS_COUNT);
213 static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
214 int xscom_offset)
216 PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
217 PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(dev);
218 uint32_t nbase = pecc->xscom_nest_base(pec);
219 uint32_t pbase = pecc->xscom_pci_base(pec);
220 int offset, i;
221 char *name;
222 uint32_t reg[] = {
223 cpu_to_be32(nbase),
224 cpu_to_be32(pecc->xscom_nest_size),
225 cpu_to_be32(pbase),
226 cpu_to_be32(pecc->xscom_pci_size),
229 name = g_strdup_printf("pbcq@%x", nbase);
230 offset = fdt_add_subnode(fdt, xscom_offset, name);
231 _FDT(offset);
232 g_free(name);
234 _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
236 _FDT((fdt_setprop_cell(fdt, offset, "ibm,pec-index", pec->index)));
237 _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 1)));
238 _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0)));
239 _FDT((fdt_setprop(fdt, offset, "compatible", pecc->compat,
240 pecc->compat_size)));
242 for (i = 0; i < pec->num_phbs; i++) {
243 int stk_offset;
245 if (!pec->phbs[i]) {
246 continue;
249 name = g_strdup_printf("stack@%x", i);
250 stk_offset = fdt_add_subnode(fdt, offset, name);
251 _FDT(stk_offset);
252 g_free(name);
253 _FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat,
254 pecc->stk_compat_size)));
255 _FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i)));
256 _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index",
257 pec->phbs[i]->phb_id)));
260 return 0;
263 static Property pnv_pec_properties[] = {
264 DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
265 DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
266 DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP,
267 PnvChip *),
268 DEFINE_PROP_END_OF_LIST(),
271 static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec)
273 return PNV9_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
276 static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
278 return PNV9_XSCOM_PEC_NEST_BASE + 0x400 * pec->index;
282 * PEC0 -> 1 phb
283 * PEC1 -> 2 phb
284 * PEC2 -> 3 phbs
286 static const uint32_t pnv_pec_num_phbs[] = { 1, 2, 3 };
288 static void pnv_pec_class_init(ObjectClass *klass, void *data)
290 DeviceClass *dc = DEVICE_CLASS(klass);
291 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
292 PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
293 static const char compat[] = "ibm,power9-pbcq";
294 static const char stk_compat[] = "ibm,power9-phb-stack";
296 xdc->dt_xscom = pnv_pec_dt_xscom;
298 dc->realize = pnv_pec_realize;
299 device_class_set_props(dc, pnv_pec_properties);
300 dc->user_creatable = false;
302 pecc->xscom_nest_base = pnv_pec_xscom_nest_base;
303 pecc->xscom_pci_base = pnv_pec_xscom_pci_base;
304 pecc->xscom_nest_size = PNV9_XSCOM_PEC_NEST_SIZE;
305 pecc->xscom_pci_size = PNV9_XSCOM_PEC_PCI_SIZE;
306 pecc->compat = compat;
307 pecc->compat_size = sizeof(compat);
308 pecc->stk_compat = stk_compat;
309 pecc->stk_compat_size = sizeof(stk_compat);
310 pecc->version = PNV_PHB4_VERSION;
311 pecc->phb_type = TYPE_PNV_PHB4;
312 pecc->num_phbs = pnv_pec_num_phbs;
315 static const TypeInfo pnv_pec_type_info = {
316 .name = TYPE_PNV_PHB4_PEC,
317 .parent = TYPE_DEVICE,
318 .instance_size = sizeof(PnvPhb4PecState),
319 .class_init = pnv_pec_class_init,
320 .class_size = sizeof(PnvPhb4PecClass),
321 .interfaces = (InterfaceInfo[]) {
322 { TYPE_PNV_XSCOM_INTERFACE },
328 * POWER10 definitions
331 static uint32_t pnv_phb5_pec_xscom_pci_base(PnvPhb4PecState *pec)
333 return PNV10_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
336 static uint32_t pnv_phb5_pec_xscom_nest_base(PnvPhb4PecState *pec)
338 /* index goes down ... */
339 return PNV10_XSCOM_PEC_NEST_BASE - 0x1000000 * pec->index;
343 * PEC0 -> 3 stacks
344 * PEC1 -> 3 stacks
346 static const uint32_t pnv_phb5_pec_num_stacks[] = { 3, 3 };
348 static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
350 PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
351 static const char compat[] = "ibm,power10-pbcq";
352 static const char stk_compat[] = "ibm,power10-phb-stack";
354 pecc->xscom_nest_base = pnv_phb5_pec_xscom_nest_base;
355 pecc->xscom_pci_base = pnv_phb5_pec_xscom_pci_base;
356 pecc->xscom_nest_size = PNV10_XSCOM_PEC_NEST_SIZE;
357 pecc->xscom_pci_size = PNV10_XSCOM_PEC_PCI_SIZE;
358 pecc->compat = compat;
359 pecc->compat_size = sizeof(compat);
360 pecc->stk_compat = stk_compat;
361 pecc->stk_compat_size = sizeof(stk_compat);
362 pecc->version = PNV_PHB5_VERSION;
363 pecc->phb_type = TYPE_PNV_PHB5;
364 pecc->num_phbs = pnv_phb5_pec_num_stacks;
367 static const TypeInfo pnv_phb5_pec_type_info = {
368 .name = TYPE_PNV_PHB5_PEC,
369 .parent = TYPE_PNV_PHB4_PEC,
370 .instance_size = sizeof(PnvPhb4PecState),
371 .class_init = pnv_phb5_pec_class_init,
372 .class_size = sizeof(PnvPhb4PecClass),
373 .interfaces = (InterfaceInfo[]) {
374 { TYPE_PNV_XSCOM_INTERFACE },
379 static void pnv_pec_register_types(void)
381 type_register_static(&pnv_pec_type_info);
382 type_register_static(&pnv_phb5_pec_type_info);
385 type_init(pnv_pec_register_types);