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