]> git.proxmox.com Git - mirror_qemu.git/blame - hw/pci-host/pnv_phb3_pbcq.c
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
[mirror_qemu.git] / hw / pci-host / pnv_phb3_pbcq.c
CommitLineData
9ae1329e
CLG
1/*
2 * QEMU PowerPC PowerNV (POWER8) PHB3 model
3 *
4 * Copyright (c) 2014-2020, IBM Corporation.
5 *
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-common.h"
12#include "qemu/log.h"
13#include "target/ppc/cpu.h"
14#include "hw/ppc/fdt.h"
15#include "hw/pci-host/pnv_phb3_regs.h"
16#include "hw/pci-host/pnv_phb3.h"
17#include "hw/ppc/pnv.h"
18#include "hw/ppc/pnv_xscom.h"
19#include "hw/pci/pci_bridge.h"
20#include "hw/pci/pci_bus.h"
21
22#include <libfdt.h>
23
24#define phb3_pbcq_error(pbcq, fmt, ...) \
25 qemu_log_mask(LOG_GUEST_ERROR, "phb3_pbcq[%d:%d]: " fmt "\n", \
26 (pbcq)->phb->chip_id, (pbcq)->phb->phb_id, ## __VA_ARGS__)
27
28static uint64_t pnv_pbcq_nest_xscom_read(void *opaque, hwaddr addr,
29 unsigned size)
30{
31 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
32 uint32_t offset = addr >> 3;
33
34 return pbcq->nest_regs[offset];
35}
36
37static uint64_t pnv_pbcq_pci_xscom_read(void *opaque, hwaddr addr,
38 unsigned size)
39{
40 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
41 uint32_t offset = addr >> 3;
42
43 return pbcq->pci_regs[offset];
44}
45
46static uint64_t pnv_pbcq_spci_xscom_read(void *opaque, hwaddr addr,
47 unsigned size)
48{
49 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
50 uint32_t offset = addr >> 3;
51
52 if (offset == PBCQ_SPCI_ASB_DATA) {
53 return pnv_phb3_reg_read(pbcq->phb,
54 pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR], 8);
55 }
56 return pbcq->spci_regs[offset];
57}
58
59static void pnv_pbcq_update_map(PnvPBCQState *pbcq)
60{
61 uint64_t bar_en = pbcq->nest_regs[PBCQ_NEST_BAR_EN];
62 uint64_t bar, mask, size;
63
64 /*
65 * NOTE: This will really not work well if those are remapped
66 * after the PHB has created its sub regions. We could do better
67 * if we had a way to resize regions but we don't really care
68 * that much in practice as the stuff below really only happens
69 * once early during boot
70 */
71
72 /* Handle unmaps */
73 if (memory_region_is_mapped(&pbcq->mmbar0) &&
74 !(bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
75 memory_region_del_subregion(get_system_memory(), &pbcq->mmbar0);
76 }
77 if (memory_region_is_mapped(&pbcq->mmbar1) &&
78 !(bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
79 memory_region_del_subregion(get_system_memory(), &pbcq->mmbar1);
80 }
81 if (memory_region_is_mapped(&pbcq->phbbar) &&
82 !(bar_en & PBCQ_NEST_BAR_EN_PHB)) {
83 memory_region_del_subregion(get_system_memory(), &pbcq->phbbar);
84 }
85
86 /* Update PHB */
87 pnv_phb3_update_regions(pbcq->phb);
88
89 /* Handle maps */
90 if (!memory_region_is_mapped(&pbcq->mmbar0) &&
91 (bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
92 bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] >> 14;
93 mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0];
94 size = ((~mask) >> 14) + 1;
95 memory_region_init(&pbcq->mmbar0, OBJECT(pbcq), "pbcq-mmio0", size);
96 memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar0);
97 pbcq->mmio0_base = bar;
98 pbcq->mmio0_size = size;
99 }
100 if (!memory_region_is_mapped(&pbcq->mmbar1) &&
101 (bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
102 bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] >> 14;
103 mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1];
104 size = ((~mask) >> 14) + 1;
105 memory_region_init(&pbcq->mmbar1, OBJECT(pbcq), "pbcq-mmio1", size);
106 memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar1);
107 pbcq->mmio1_base = bar;
108 pbcq->mmio1_size = size;
109 }
110 if (!memory_region_is_mapped(&pbcq->phbbar)
111 && (bar_en & PBCQ_NEST_BAR_EN_PHB)) {
112 bar = pbcq->nest_regs[PBCQ_NEST_PHB_BAR] >> 14;
113 size = 0x1000;
114 memory_region_init(&pbcq->phbbar, OBJECT(pbcq), "pbcq-phb", size);
115 memory_region_add_subregion(get_system_memory(), bar, &pbcq->phbbar);
116 }
117
118 /* Update PHB */
119 pnv_phb3_update_regions(pbcq->phb);
120}
121
122static void pnv_pbcq_nest_xscom_write(void *opaque, hwaddr addr,
123 uint64_t val, unsigned size)
124{
125 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
126 uint32_t reg = addr >> 3;
127
128 switch (reg) {
129 case PBCQ_NEST_MMIO_BAR0:
130 case PBCQ_NEST_MMIO_BAR1:
131 case PBCQ_NEST_MMIO_MASK0:
132 case PBCQ_NEST_MMIO_MASK1:
133 if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] &
134 (PBCQ_NEST_BAR_EN_MMIO0 |
135 PBCQ_NEST_BAR_EN_MMIO1)) {
136 phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
137 }
138 pbcq->nest_regs[reg] = val & 0xffffffffc0000000ull;
139 break;
140 case PBCQ_NEST_PHB_BAR:
141 if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] & PBCQ_NEST_BAR_EN_PHB) {
142 phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
143 }
144 pbcq->nest_regs[reg] = val & 0xfffffffffc000000ull;
145 break;
146 case PBCQ_NEST_BAR_EN:
147 pbcq->nest_regs[reg] = val & 0xf800000000000000ull;
148 pnv_pbcq_update_map(pbcq);
149 pnv_phb3_remap_irqs(pbcq->phb);
150 break;
151 case PBCQ_NEST_IRSN_COMPARE:
152 case PBCQ_NEST_IRSN_MASK:
153 pbcq->nest_regs[reg] = val & PBCQ_NEST_IRSN_COMP;
154 pnv_phb3_remap_irqs(pbcq->phb);
155 break;
156 case PBCQ_NEST_LSI_SRC_ID:
157 pbcq->nest_regs[reg] = val & PBCQ_NEST_LSI_SRC;
158 pnv_phb3_remap_irqs(pbcq->phb);
159 break;
160 default:
161 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
162 addr, val);
163 }
164}
165
166static void pnv_pbcq_pci_xscom_write(void *opaque, hwaddr addr,
167 uint64_t val, unsigned size)
168{
169 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
170 uint32_t reg = addr >> 3;
171
172 switch (reg) {
173 case PBCQ_PCI_BAR2:
174 pbcq->pci_regs[reg] = val & 0xfffffffffc000000ull;
175 pnv_pbcq_update_map(pbcq);
e8ead7d5 176 break;
9ae1329e
CLG
177 default:
178 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
179 addr, val);
180 }
181}
182
183static void pnv_pbcq_spci_xscom_write(void *opaque, hwaddr addr,
184 uint64_t val, unsigned size)
185{
186 PnvPBCQState *pbcq = PNV_PBCQ(opaque);
187 uint32_t reg = addr >> 3;
188
189 switch (reg) {
190 case PBCQ_SPCI_ASB_ADDR:
191 pbcq->spci_regs[reg] = val & 0xfff;
192 break;
193 case PBCQ_SPCI_ASB_STATUS:
194 pbcq->spci_regs[reg] &= ~val;
195 break;
196 case PBCQ_SPCI_ASB_DATA:
197 pnv_phb3_reg_write(pbcq->phb, pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR],
198 val, 8);
199 break;
200 case PBCQ_SPCI_AIB_CAPP_EN:
201 case PBCQ_SPCI_CAPP_SEC_TMR:
202 break;
203 default:
204 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
205 addr, val);
206 }
207}
208
209static const MemoryRegionOps pnv_pbcq_nest_xscom_ops = {
210 .read = pnv_pbcq_nest_xscom_read,
211 .write = pnv_pbcq_nest_xscom_write,
212 .valid.min_access_size = 8,
213 .valid.max_access_size = 8,
214 .impl.min_access_size = 8,
215 .impl.max_access_size = 8,
216 .endianness = DEVICE_BIG_ENDIAN,
217};
218
219static const MemoryRegionOps pnv_pbcq_pci_xscom_ops = {
220 .read = pnv_pbcq_pci_xscom_read,
221 .write = pnv_pbcq_pci_xscom_write,
222 .valid.min_access_size = 8,
223 .valid.max_access_size = 8,
224 .impl.min_access_size = 8,
225 .impl.max_access_size = 8,
226 .endianness = DEVICE_BIG_ENDIAN,
227};
228
229static const MemoryRegionOps pnv_pbcq_spci_xscom_ops = {
230 .read = pnv_pbcq_spci_xscom_read,
231 .write = pnv_pbcq_spci_xscom_write,
232 .valid.min_access_size = 8,
233 .valid.max_access_size = 8,
234 .impl.min_access_size = 8,
235 .impl.max_access_size = 8,
236 .endianness = DEVICE_BIG_ENDIAN,
237};
238
239static void pnv_pbcq_default_bars(PnvPBCQState *pbcq)
240{
241 uint64_t mm0, mm1, reg;
242 PnvPHB3 *phb = pbcq->phb;
243
244 mm0 = 0x3d00000000000ull + 0x4000000000ull * phb->chip_id +
245 0x1000000000ull * phb->phb_id;
246 mm1 = 0x3ff8000000000ull + 0x0200000000ull * phb->chip_id +
247 0x0080000000ull * phb->phb_id;
248 reg = 0x3fffe40000000ull + 0x0000400000ull * phb->chip_id +
249 0x0000100000ull * phb->phb_id;
250
251 pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] = mm0 << 14;
252 pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] = mm1 << 14;
253 pbcq->nest_regs[PBCQ_NEST_PHB_BAR] = reg << 14;
254 pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0] = 0x3fff000000000ull << 14;
255 pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1] = 0x3ffff80000000ull << 14;
256 pbcq->pci_regs[PBCQ_PCI_BAR2] = reg << 14;
257}
258
259static void pnv_pbcq_realize(DeviceState *dev, Error **errp)
260{
261 PnvPBCQState *pbcq = PNV_PBCQ(dev);
262 PnvPHB3 *phb;
263 char name[32];
264
265 assert(pbcq->phb);
266 phb = pbcq->phb;
267
268 /* TODO: Fix OPAL to do that: establish default BAR values */
269 pnv_pbcq_default_bars(pbcq);
270
271 /* Initialize the XSCOM region for the PBCQ registers */
272 snprintf(name, sizeof(name), "xscom-pbcq-nest-%d.%d",
273 phb->chip_id, phb->phb_id);
274 pnv_xscom_region_init(&pbcq->xscom_nest_regs, OBJECT(dev),
275 &pnv_pbcq_nest_xscom_ops, pbcq, name,
276 PNV_XSCOM_PBCQ_NEST_SIZE);
277 snprintf(name, sizeof(name), "xscom-pbcq-pci-%d.%d",
278 phb->chip_id, phb->phb_id);
279 pnv_xscom_region_init(&pbcq->xscom_pci_regs, OBJECT(dev),
280 &pnv_pbcq_pci_xscom_ops, pbcq, name,
281 PNV_XSCOM_PBCQ_PCI_SIZE);
282 snprintf(name, sizeof(name), "xscom-pbcq-spci-%d.%d",
283 phb->chip_id, phb->phb_id);
284 pnv_xscom_region_init(&pbcq->xscom_spci_regs, OBJECT(dev),
285 &pnv_pbcq_spci_xscom_ops, pbcq, name,
286 PNV_XSCOM_PBCQ_SPCI_SIZE);
287}
288
289static int pnv_pbcq_dt_xscom(PnvXScomInterface *dev, void *fdt,
290 int xscom_offset)
291{
292 const char compat[] = "ibm,power8-pbcq";
293 PnvPHB3 *phb = PNV_PBCQ(dev)->phb;
294 char *name;
295 int offset;
296 uint32_t lpc_pcba = PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id;
297 uint32_t reg[] = {
298 cpu_to_be32(lpc_pcba),
299 cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE),
300 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id),
301 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE),
302 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id),
303 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE)
304 };
305
306 name = g_strdup_printf("pbcq@%x", lpc_pcba);
307 offset = fdt_add_subnode(fdt, xscom_offset, name);
308 _FDT(offset);
309 g_free(name);
310
311 _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
312
313 _FDT((fdt_setprop_cell(fdt, offset, "ibm,phb-index", phb->phb_id)));
314 _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", phb->chip_id)));
315 _FDT((fdt_setprop(fdt, offset, "compatible", compat,
316 sizeof(compat))));
317 return 0;
318}
319
320static void phb3_pbcq_instance_init(Object *obj)
321{
322 PnvPBCQState *pbcq = PNV_PBCQ(obj);
323
324 object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
325 (Object **)&pbcq->phb,
326 object_property_allow_set_link,
d2623129 327 OBJ_PROP_LINK_STRONG);
9ae1329e
CLG
328}
329
330static void pnv_pbcq_class_init(ObjectClass *klass, void *data)
331{
332 DeviceClass *dc = DEVICE_CLASS(klass);
333 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
334
335 xdc->dt_xscom = pnv_pbcq_dt_xscom;
336
337 dc->realize = pnv_pbcq_realize;
23a782eb 338 dc->user_creatable = false;
9ae1329e
CLG
339}
340
341static const TypeInfo pnv_pbcq_type_info = {
342 .name = TYPE_PNV_PBCQ,
343 .parent = TYPE_DEVICE,
344 .instance_size = sizeof(PnvPBCQState),
345 .instance_init = phb3_pbcq_instance_init,
346 .class_init = pnv_pbcq_class_init,
347 .interfaces = (InterfaceInfo[]) {
348 { TYPE_PNV_XSCOM_INTERFACE },
349 { }
350 }
351};
352
353static void pnv_pbcq_register_types(void)
354{
355 type_register_static(&pnv_pbcq_type_info);
356}
357
358type_init(pnv_pbcq_register_types)