xref: /qemu/hw/pci-bridge/pci_expander_bridge.c (revision bfa3ab61)
1 /*
2  * PCI Expander Bridge Device Emulation
3  *
4  * Copyright (C) 2015 Red Hat Inc
5  *
6  * Authors:
7  *   Marcel Apfelbaum <marcel@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12 
13 #include "hw/pci/pci.h"
14 #include "hw/pci/pci_bus.h"
15 #include "hw/pci/pci_host.h"
16 #include "hw/pci/pci_bus.h"
17 #include "hw/i386/pc.h"
18 #include "qemu/range.h"
19 #include "qemu/error-report.h"
20 #include "sysemu/numa.h"
21 
22 #define TYPE_PXB_BUS "pxb-bus"
23 #define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
24 
25 typedef struct PXBBus {
26     /*< private >*/
27     PCIBus parent_obj;
28     /*< public >*/
29 
30     char bus_path[8];
31 } PXBBus;
32 
33 #define TYPE_PXB_DEVICE "pxb"
34 #define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
35 
36 typedef struct PXBDev {
37     /*< private >*/
38     PCIDevice parent_obj;
39     /*< public >*/
40 
41     uint8_t bus_nr;
42     uint16_t numa_node;
43 } PXBDev;
44 
45 #define TYPE_PXB_HOST "pxb-host"
46 
47 static int pxb_bus_num(PCIBus *bus)
48 {
49     PXBDev *pxb = PXB_DEV(bus->parent_dev);
50 
51     return pxb->bus_nr;
52 }
53 
54 static bool pxb_is_root(PCIBus *bus)
55 {
56     return true; /* by definition */
57 }
58 
59 static uint16_t pxb_bus_numa_node(PCIBus *bus)
60 {
61     PXBDev *pxb = PXB_DEV(bus->parent_dev);
62 
63     return pxb->numa_node;
64 }
65 
66 static void pxb_bus_class_init(ObjectClass *class, void *data)
67 {
68     PCIBusClass *pbc = PCI_BUS_CLASS(class);
69 
70     pbc->bus_num = pxb_bus_num;
71     pbc->is_root = pxb_is_root;
72     pbc->numa_node = pxb_bus_numa_node;
73 }
74 
75 static const TypeInfo pxb_bus_info = {
76     .name          = TYPE_PXB_BUS,
77     .parent        = TYPE_PCI_BUS,
78     .instance_size = sizeof(PXBBus),
79     .class_init    = pxb_bus_class_init,
80 };
81 
82 static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
83                                           PCIBus *rootbus)
84 {
85     PXBBus *bus = PXB_BUS(rootbus);
86 
87     snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
88     return bus->bus_path;
89 }
90 
91 static void pxb_host_class_init(ObjectClass *class, void *data)
92 {
93     DeviceClass *dc = DEVICE_CLASS(class);
94     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
95 
96     dc->fw_name = "pci";
97     hc->root_bus_path = pxb_host_root_bus_path;
98 }
99 
100 static const TypeInfo pxb_host_info = {
101     .name          = TYPE_PXB_HOST,
102     .parent        = TYPE_PCI_HOST_BRIDGE,
103     .class_init    = pxb_host_class_init,
104 };
105 
106 /*
107  * Registers the PXB bus as a child of the i440fx root bus.
108  *
109  * Returns 0 on successs, -1 if i440fx host was not
110  * found or the bus number is already in use.
111  */
112 static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
113 {
114     PCIBus *bus = dev->bus;
115     int pxb_bus_num = pci_bus_num(pxb_bus);
116 
117     if (bus->parent_dev) {
118         error_report("PXB devices can be attached only to root bus.");
119         return -1;
120     }
121 
122     QLIST_FOREACH(bus, &bus->child, sibling) {
123         if (pci_bus_num(bus) == pxb_bus_num) {
124             error_report("Bus %d is already in use.", pxb_bus_num);
125             return -1;
126         }
127     }
128     QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
129 
130     return 0;
131 }
132 
133 static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
134 {
135     PCIDevice *pxb = pci_dev->bus->parent_dev;
136 
137     /*
138      * The bios does not index the pxb slot number when
139      * it computes the IRQ because it resides on bus 0
140      * and not on the current bus.
141      * However QEMU routes the irq through bus 0 and adds
142      * the pxb slot to the IRQ computation of the PXB
143      * device.
144      *
145      * Synchronize between bios and QEMU by canceling
146      * pxb's effect.
147      */
148     return pin - PCI_SLOT(pxb->devfn);
149 }
150 
151 static int pxb_dev_initfn(PCIDevice *dev)
152 {
153     PXBDev *pxb = PXB_DEV(dev);
154     DeviceState *ds, *bds;
155     PCIBus *bus;
156     const char *dev_name = NULL;
157 
158     if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
159         pxb->numa_node >= nb_numa_nodes) {
160         error_report("Illegal numa node %d.", pxb->numa_node);
161         return -EINVAL;
162     }
163 
164     if (dev->qdev.id && *dev->qdev.id) {
165         dev_name = dev->qdev.id;
166     }
167 
168     ds = qdev_create(NULL, TYPE_PXB_HOST);
169     bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
170 
171     bus->parent_dev = dev;
172     bus->address_space_mem = dev->bus->address_space_mem;
173     bus->address_space_io = dev->bus->address_space_io;
174     bus->map_irq = pxb_map_irq_fn;
175 
176     bds = qdev_create(BUS(bus), "pci-bridge");
177     bds->id = dev_name;
178     qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
179 
180     PCI_HOST_BRIDGE(ds)->bus = bus;
181 
182     if (pxb_register_bus(dev, bus)) {
183         return -EINVAL;
184     }
185 
186     qdev_init_nofail(ds);
187     qdev_init_nofail(bds);
188 
189     pci_word_test_and_set_mask(dev->config + PCI_STATUS,
190                                PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
191     pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
192 
193     return 0;
194 }
195 
196 static Property pxb_dev_properties[] = {
197     /* Note: 0 is not a legal a PXB bus number. */
198     DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
199     DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
200     DEFINE_PROP_END_OF_LIST(),
201 };
202 
203 static void pxb_dev_class_init(ObjectClass *klass, void *data)
204 {
205     DeviceClass *dc = DEVICE_CLASS(klass);
206     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
207 
208     k->init = pxb_dev_initfn;
209     k->vendor_id = PCI_VENDOR_ID_REDHAT;
210     k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
211     k->class_id = PCI_CLASS_BRIDGE_HOST;
212 
213     dc->desc = "PCI Expander Bridge";
214     dc->props = pxb_dev_properties;
215 }
216 
217 static const TypeInfo pxb_dev_info = {
218     .name          = TYPE_PXB_DEVICE,
219     .parent        = TYPE_PCI_DEVICE,
220     .instance_size = sizeof(PXBDev),
221     .class_init    = pxb_dev_class_init,
222 };
223 
224 static void pxb_register_types(void)
225 {
226     type_register_static(&pxb_bus_info);
227     type_register_static(&pxb_host_info);
228     type_register_static(&pxb_dev_info);
229 }
230 
231 type_init(pxb_register_types)
232