2 * QEMU PowerPC PowerNV Proxy PHB model
4 * Copyright (c) 2022, IBM Corporation.
6 * This code is licensed under the GPL version 2 or later. See the
7 * COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
12 #include "qapi/visitor.h"
13 #include "qapi/error.h"
14 #include "hw/pci-host/pnv_phb.h"
15 #include "hw/pci-host/pnv_phb3.h"
16 #include "hw/pci-host/pnv_phb4.h"
17 #include "hw/ppc/pnv.h"
18 #include "hw/qdev-properties.h"
19 #include "qom/object.h"
20 #include "sysemu/sysemu.h"
24 * Set the QOM parent and parent bus of an object child. If the device
25 * state associated with the child has an id, use it as QOM id.
26 * Otherwise use object_typename[index] as QOM id.
28 * This helper does both operations at the same time because seting
29 * a new QOM child will erase the bus parent of the device. This happens
30 * because object_unparent() will call object_property_del_child(),
31 * which in turn calls the property release callback prop->release if
32 * it's defined. In our case this callback is set to
33 * object_finalize_child_property(), which was assigned during the
34 * first object_property_add_child() call. This callback will end up
35 * calling device_unparent(), and this function removes the device
36 * from its parent bus.
38 * The QOM and parent bus to be set arenĀ“t necessarily related, so
39 * let's receive both as arguments.
41 static bool pnv_parent_fixup(Object
*parent
, BusState
*parent_bus
,
42 Object
*child
, int index
,
45 g_autofree
char *default_id
=
46 g_strdup_printf("%s[%d]", object_get_typename(child
), index
);
47 const char *dev_id
= DEVICE(child
)->id
;
49 if (child
->parent
== parent
) {
54 object_unparent(child
);
55 object_property_add_child(parent
, dev_id
? dev_id
: default_id
, child
);
58 if (!qdev_set_parent_bus(DEVICE(child
), parent_bus
, errp
)) {
66 * User created devices won't have the initial setup that default
67 * devices have. This setup consists of assigning a parent device
68 * (chip for PHB3, PEC for PHB4/5) that will be the QOM/bus parent
71 static bool pnv_phb_user_device_init(PnvPHB
*phb
, Error
**errp
)
73 PnvMachineState
*pnv
= PNV_MACHINE(qdev_get_machine());
74 PnvChip
*chip
= pnv_get_chip(pnv
, phb
->chip_id
);
75 Object
*parent
= NULL
;
78 error_setg(errp
, "invalid chip id: %d", phb
->chip_id
);
82 parent
= pnv_chip_add_phb(chip
, phb
, errp
);
88 * Reparent user created devices to the chip to build
89 * correctly the device tree. pnv_xscom_dt() needs every
90 * PHB to be a child of the chip to build the DT correctly.
92 if (!pnv_parent_fixup(parent
, qdev_get_parent_bus(DEVICE(chip
)),
93 OBJECT(phb
), phb
->phb_id
, errp
)) {
100 static void pnv_phb_realize(DeviceState
*dev
, Error
**errp
)
102 PnvPHB
*phb
= PNV_PHB(dev
);
103 PCIHostState
*pci
= PCI_HOST_BRIDGE(dev
);
104 g_autofree
char *phb_typename
= NULL
;
107 error_setg(errp
, "version not specified");
111 switch (phb
->version
) {
113 phb_typename
= g_strdup(TYPE_PNV_PHB3
);
116 phb_typename
= g_strdup(TYPE_PNV_PHB4
);
119 phb_typename
= g_strdup(TYPE_PNV_PHB5
);
122 g_assert_not_reached();
125 phb
->backend
= object_new(phb_typename
);
126 object_property_add_child(OBJECT(dev
), "phb-backend", phb
->backend
);
128 /* Passthrough child device properties to the proxy device */
129 object_property_set_uint(phb
->backend
, "index", phb
->phb_id
, errp
);
130 object_property_set_uint(phb
->backend
, "chip-id", phb
->chip_id
, errp
);
131 object_property_set_link(phb
->backend
, "phb-base", OBJECT(phb
), errp
);
134 * Handle user created devices. User devices will not have a
135 * pointer to a chip (PHB3) and a PEC (PHB4/5).
137 if (!phb
->chip
&& !phb
->pec
) {
138 if (!pnv_phb_user_device_init(phb
, errp
)) {
143 if (phb
->version
== 3) {
144 object_property_set_link(phb
->backend
, "chip",
145 OBJECT(phb
->chip
), errp
);
147 object_property_set_link(phb
->backend
, "pec", OBJECT(phb
->pec
), errp
);
150 if (!qdev_realize(DEVICE(phb
->backend
), NULL
, errp
)) {
154 if (phb
->version
== 3) {
155 pnv_phb3_bus_init(dev
, PNV_PHB3(phb
->backend
));
157 pnv_phb4_bus_init(dev
, PNV_PHB4(phb
->backend
));
160 if (defaults_enabled()) {
161 PCIDevice
*root
= pci_new(PCI_DEVFN(0, 0), TYPE_PNV_PHB_ROOT_PORT
);
163 pci_realize_and_unref(root
, pci
->bus
, errp
);
167 static const char *pnv_phb_root_bus_path(PCIHostState
*host_bridge
,
170 PnvPHB
*phb
= PNV_PHB(host_bridge
);
172 snprintf(phb
->bus_path
, sizeof(phb
->bus_path
), "00%02x:%02x",
173 phb
->chip_id
, phb
->phb_id
);
174 return phb
->bus_path
;
177 static Property pnv_phb_properties
[] = {
178 DEFINE_PROP_UINT32("index", PnvPHB
, phb_id
, 0),
179 DEFINE_PROP_UINT32("chip-id", PnvPHB
, chip_id
, 0),
180 DEFINE_PROP_UINT32("version", PnvPHB
, version
, 0),
182 DEFINE_PROP_LINK("chip", PnvPHB
, chip
, TYPE_PNV_CHIP
, PnvChip
*),
184 DEFINE_PROP_LINK("pec", PnvPHB
, pec
, TYPE_PNV_PHB4_PEC
,
187 DEFINE_PROP_END_OF_LIST(),
190 static void pnv_phb_class_init(ObjectClass
*klass
, void *data
)
192 PCIHostBridgeClass
*hc
= PCI_HOST_BRIDGE_CLASS(klass
);
193 DeviceClass
*dc
= DEVICE_CLASS(klass
);
195 hc
->root_bus_path
= pnv_phb_root_bus_path
;
196 dc
->realize
= pnv_phb_realize
;
197 device_class_set_props(dc
, pnv_phb_properties
);
198 set_bit(DEVICE_CATEGORY_BRIDGE
, dc
->categories
);
199 dc
->user_creatable
= true;
202 static void pnv_phb_root_port_reset(DeviceState
*dev
)
204 PCIERootPortClass
*rpc
= PCIE_ROOT_PORT_GET_CLASS(dev
);
205 PnvPHBRootPort
*phb_rp
= PNV_PHB_ROOT_PORT(dev
);
206 PCIDevice
*d
= PCI_DEVICE(dev
);
207 uint8_t *conf
= d
->config
;
209 rpc
->parent_reset(dev
);
211 if (phb_rp
->version
== 3) {
215 /* PHB4 and later requires these extra reset steps */
216 pci_byte_test_and_set_mask(conf
+ PCI_IO_BASE
,
217 PCI_IO_RANGE_MASK
& 0xff);
218 pci_byte_test_and_clear_mask(conf
+ PCI_IO_LIMIT
,
219 PCI_IO_RANGE_MASK
& 0xff);
220 pci_set_word(conf
+ PCI_MEMORY_BASE
, 0);
221 pci_set_word(conf
+ PCI_MEMORY_LIMIT
, 0xfff0);
222 pci_set_word(conf
+ PCI_PREF_MEMORY_BASE
, 0x1);
223 pci_set_word(conf
+ PCI_PREF_MEMORY_LIMIT
, 0xfff1);
224 pci_set_long(conf
+ PCI_PREF_BASE_UPPER32
, 0x1); /* Hack */
225 pci_set_long(conf
+ PCI_PREF_LIMIT_UPPER32
, 0xffffffff);
226 pci_config_set_interrupt_pin(conf
, 0);
229 static void pnv_phb_root_port_realize(DeviceState
*dev
, Error
**errp
)
231 PCIERootPortClass
*rpc
= PCIE_ROOT_PORT_GET_CLASS(dev
);
232 PnvPHBRootPort
*phb_rp
= PNV_PHB_ROOT_PORT(dev
);
233 PCIBus
*bus
= PCI_BUS(qdev_get_parent_bus(dev
));
234 PCIDevice
*pci
= PCI_DEVICE(dev
);
235 uint16_t device_id
= 0;
236 Error
*local_err
= NULL
;
240 * 'index' will be used both as a PCIE slot value and to calculate
241 * QOM id. 'chip_id' is going to be used as PCIE chassis for the
244 chip_id
= object_property_get_int(OBJECT(bus
), "chip-id", &error_fatal
);
245 index
= object_property_get_int(OBJECT(bus
), "phb-id", &error_fatal
);
247 /* Set unique chassis/slot values for the root port */
248 qdev_prop_set_uint8(dev
, "chassis", chip_id
);
249 qdev_prop_set_uint16(dev
, "slot", index
);
252 * User created root ports are QOM parented to one of
253 * the peripheral containers but it's already at the right
254 * parent bus. Change the QOM parent to be the same as the
255 * parent bus it's already assigned to.
257 if (!pnv_parent_fixup(OBJECT(bus
), BUS(bus
), OBJECT(dev
),
262 rpc
->parent_realize(dev
, &local_err
);
264 error_propagate(errp
, local_err
);
268 switch (phb_rp
->version
) {
270 device_id
= PNV_PHB3_DEVICE_ID
;
273 device_id
= PNV_PHB4_DEVICE_ID
;
276 device_id
= PNV_PHB5_DEVICE_ID
;
279 g_assert_not_reached();
282 pci_config_set_device_id(pci
->config
, device_id
);
283 pci_config_set_interrupt_pin(pci
->config
, 0);
286 static Property pnv_phb_root_port_properties
[] = {
287 DEFINE_PROP_UINT32("version", PnvPHBRootPort
, version
, 0),
289 DEFINE_PROP_END_OF_LIST(),
292 static void pnv_phb_root_port_class_init(ObjectClass
*klass
, void *data
)
294 DeviceClass
*dc
= DEVICE_CLASS(klass
);
295 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
296 PCIERootPortClass
*rpc
= PCIE_ROOT_PORT_CLASS(klass
);
298 dc
->desc
= "IBM PHB PCIE Root Port";
300 device_class_set_props(dc
, pnv_phb_root_port_properties
);
301 device_class_set_parent_realize(dc
, pnv_phb_root_port_realize
,
302 &rpc
->parent_realize
);
303 device_class_set_parent_reset(dc
, pnv_phb_root_port_reset
,
305 dc
->reset
= &pnv_phb_root_port_reset
;
306 dc
->user_creatable
= true;
308 k
->vendor_id
= PCI_VENDOR_ID_IBM
;
309 /* device_id will be written during realize() */
313 rpc
->exp_offset
= 0x48;
314 rpc
->aer_offset
= 0x100;
317 static const TypeInfo pnv_phb_type_info
= {
318 .name
= TYPE_PNV_PHB
,
319 .parent
= TYPE_PCIE_HOST_BRIDGE
,
320 .instance_size
= sizeof(PnvPHB
),
321 .class_init
= pnv_phb_class_init
,
324 static const TypeInfo pnv_phb_root_port_info
= {
325 .name
= TYPE_PNV_PHB_ROOT_PORT
,
326 .parent
= TYPE_PCIE_ROOT_PORT
,
327 .instance_size
= sizeof(PnvPHBRootPort
),
328 .class_init
= pnv_phb_root_port_class_init
,
331 static void pnv_phb_register_types(void)
333 type_register_static(&pnv_phb_type_info
);
334 type_register_static(&pnv_phb_root_port_info
);
337 type_init(pnv_phb_register_types
)