xref: /openbmc/qemu/hw/pci-host/pnv_phb.c (revision 17c681e92ddd66b8a5c425ea6a1c6ec3a4e079d4)
1 /*
2  * QEMU PowerPC PowerNV Proxy PHB model
3  *
4  * Copyright (c) 2022, 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 
10 #include "qemu/osdep.h"
11 #include "qemu/log.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 
21 
22 static void pnv_phb_realize(DeviceState *dev, Error **errp)
23 {
24     PnvPHB *phb = PNV_PHB(dev);
25     PCIHostState *pci = PCI_HOST_BRIDGE(dev);
26     g_autofree char *phb_typename = NULL;
27 
28     if (!phb->version) {
29         error_setg(errp, "version not specified");
30         return;
31     }
32 
33     switch (phb->version) {
34     case 3:
35         phb_typename = g_strdup(TYPE_PNV_PHB3);
36         break;
37     case 4:
38         phb_typename = g_strdup(TYPE_PNV_PHB4);
39         break;
40     case 5:
41         phb_typename = g_strdup(TYPE_PNV_PHB5);
42         break;
43     default:
44         g_assert_not_reached();
45     }
46 
47     phb->backend = object_new(phb_typename);
48     object_property_add_child(OBJECT(dev), "phb-backend", phb->backend);
49 
50     /* Passthrough child device properties to the proxy device */
51     object_property_set_uint(phb->backend, "index", phb->phb_id, errp);
52     object_property_set_uint(phb->backend, "chip-id", phb->chip_id, errp);
53     object_property_set_link(phb->backend, "phb-base", OBJECT(phb), errp);
54 
55     if (phb->version == 3) {
56         object_property_set_link(phb->backend, "chip",
57                                  OBJECT(phb->chip), errp);
58     } else {
59         object_property_set_link(phb->backend, "pec", OBJECT(phb->pec), errp);
60     }
61 
62     if (!qdev_realize(DEVICE(phb->backend), NULL, errp)) {
63         return;
64     }
65 
66     if (phb->version == 3) {
67         pnv_phb3_bus_init(dev, PNV_PHB3(phb->backend));
68     } else {
69         pnv_phb4_bus_init(dev, PNV_PHB4(phb->backend));
70     }
71 
72     pnv_phb_attach_root_port(pci, phb->phb_id, phb->chip_id);
73 }
74 
75 static const char *pnv_phb_root_bus_path(PCIHostState *host_bridge,
76                                          PCIBus *rootbus)
77 {
78     PnvPHB *phb = PNV_PHB(host_bridge);
79 
80     snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
81              phb->chip_id, phb->phb_id);
82     return phb->bus_path;
83 }
84 
85 static Property pnv_phb_properties[] = {
86     DEFINE_PROP_UINT32("index", PnvPHB, phb_id, 0),
87     DEFINE_PROP_UINT32("chip-id", PnvPHB, chip_id, 0),
88     DEFINE_PROP_UINT32("version", PnvPHB, version, 0),
89 
90     DEFINE_PROP_LINK("chip", PnvPHB, chip, TYPE_PNV_CHIP, PnvChip *),
91 
92     DEFINE_PROP_LINK("pec", PnvPHB, pec, TYPE_PNV_PHB4_PEC,
93                      PnvPhb4PecState *),
94 
95     DEFINE_PROP_END_OF_LIST(),
96 };
97 
98 static void pnv_phb_class_init(ObjectClass *klass, void *data)
99 {
100     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
101     DeviceClass *dc = DEVICE_CLASS(klass);
102 
103     hc->root_bus_path = pnv_phb_root_bus_path;
104     dc->realize = pnv_phb_realize;
105     device_class_set_props(dc, pnv_phb_properties);
106     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
107     dc->user_creatable = false;
108 }
109 
110 static void pnv_phb_root_port_reset(DeviceState *dev)
111 {
112     PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
113     PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
114     PCIDevice *d = PCI_DEVICE(dev);
115     uint8_t *conf = d->config;
116 
117     rpc->parent_reset(dev);
118 
119     if (phb_rp->version == 3) {
120         return;
121     }
122 
123     /* PHB4 and later requires these extra reset steps */
124     pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
125                                PCI_IO_RANGE_MASK & 0xff);
126     pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
127                                  PCI_IO_RANGE_MASK & 0xff);
128     pci_set_word(conf + PCI_MEMORY_BASE, 0);
129     pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
130     pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
131     pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
132     pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
133     pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
134     pci_config_set_interrupt_pin(conf, 0);
135 }
136 
137 static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
138 {
139     PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
140     PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
141     PCIDevice *pci = PCI_DEVICE(dev);
142     uint16_t device_id = 0;
143     Error *local_err = NULL;
144 
145     rpc->parent_realize(dev, &local_err);
146     if (local_err) {
147         error_propagate(errp, local_err);
148         return;
149     }
150 
151     switch (phb_rp->version) {
152     case 3:
153         device_id = PNV_PHB3_DEVICE_ID;
154         break;
155     case 4:
156         device_id = PNV_PHB4_DEVICE_ID;
157         break;
158     case 5:
159         device_id = PNV_PHB5_DEVICE_ID;
160         break;
161     default:
162         g_assert_not_reached();
163     }
164 
165     pci_config_set_device_id(pci->config, device_id);
166     pci_config_set_interrupt_pin(pci->config, 0);
167 }
168 
169 static Property pnv_phb_root_port_properties[] = {
170     DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
171 
172     DEFINE_PROP_END_OF_LIST(),
173 };
174 
175 static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
176 {
177     DeviceClass *dc = DEVICE_CLASS(klass);
178     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
179     PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
180 
181     dc->desc     = "IBM PHB PCIE Root Port";
182 
183     device_class_set_props(dc, pnv_phb_root_port_properties);
184     device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
185                                     &rpc->parent_realize);
186     device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
187                                   &rpc->parent_reset);
188     dc->reset = &pnv_phb_root_port_reset;
189     dc->user_creatable = false;
190 
191     k->vendor_id = PCI_VENDOR_ID_IBM;
192     /* device_id will be written during realize() */
193     k->device_id = 0;
194     k->revision  = 0;
195 
196     rpc->exp_offset = 0x48;
197     rpc->aer_offset = 0x100;
198 }
199 
200 static const TypeInfo pnv_phb_type_info = {
201     .name          = TYPE_PNV_PHB,
202     .parent        = TYPE_PCIE_HOST_BRIDGE,
203     .instance_size = sizeof(PnvPHB),
204     .class_init    = pnv_phb_class_init,
205 };
206 
207 static const TypeInfo pnv_phb_root_port_info = {
208     .name          = TYPE_PNV_PHB_ROOT_PORT,
209     .parent        = TYPE_PCIE_ROOT_PORT,
210     .instance_size = sizeof(PnvPHBRootPort),
211     .class_init    = pnv_phb_root_port_class_init,
212 };
213 
214 static void pnv_phb_register_types(void)
215 {
216     type_register_static(&pnv_phb_type_info);
217     type_register_static(&pnv_phb_root_port_info);
218 }
219 
220 type_init(pnv_phb_register_types)
221