xref: /qemu/hw/pci-bridge/pcie_pci_bridge.c (revision a35fe226558ac85436ea01af8977f1834927f53f)
1*a35fe226SAleksandr Bezzubikov /*
2*a35fe226SAleksandr Bezzubikov  * QEMU Generic PCIE-PCI Bridge
3*a35fe226SAleksandr Bezzubikov  *
4*a35fe226SAleksandr Bezzubikov  * Copyright (c) 2017 Aleksandr Bezzubikov
5*a35fe226SAleksandr Bezzubikov  *
6*a35fe226SAleksandr Bezzubikov  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7*a35fe226SAleksandr Bezzubikov  * See the COPYING file in the top-level directory.
8*a35fe226SAleksandr Bezzubikov  */
9*a35fe226SAleksandr Bezzubikov 
10*a35fe226SAleksandr Bezzubikov #include "qemu/osdep.h"
11*a35fe226SAleksandr Bezzubikov #include "qapi/error.h"
12*a35fe226SAleksandr Bezzubikov #include "hw/pci/pci.h"
13*a35fe226SAleksandr Bezzubikov #include "hw/pci/pci_bus.h"
14*a35fe226SAleksandr Bezzubikov #include "hw/pci/pci_bridge.h"
15*a35fe226SAleksandr Bezzubikov #include "hw/pci/msi.h"
16*a35fe226SAleksandr Bezzubikov #include "hw/pci/shpc.h"
17*a35fe226SAleksandr Bezzubikov #include "hw/pci/slotid_cap.h"
18*a35fe226SAleksandr Bezzubikov 
19*a35fe226SAleksandr Bezzubikov typedef struct PCIEPCIBridge {
20*a35fe226SAleksandr Bezzubikov     /*< private >*/
21*a35fe226SAleksandr Bezzubikov     PCIBridge parent_obj;
22*a35fe226SAleksandr Bezzubikov 
23*a35fe226SAleksandr Bezzubikov     OnOffAuto msi;
24*a35fe226SAleksandr Bezzubikov     MemoryRegion shpc_bar;
25*a35fe226SAleksandr Bezzubikov     /*< public >*/
26*a35fe226SAleksandr Bezzubikov } PCIEPCIBridge;
27*a35fe226SAleksandr Bezzubikov 
28*a35fe226SAleksandr Bezzubikov #define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
29*a35fe226SAleksandr Bezzubikov #define PCIE_PCI_BRIDGE_DEV(obj) \
30*a35fe226SAleksandr Bezzubikov         OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV)
31*a35fe226SAleksandr Bezzubikov 
32*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
33*a35fe226SAleksandr Bezzubikov {
34*a35fe226SAleksandr Bezzubikov     PCIBridge *br = PCI_BRIDGE(d);
35*a35fe226SAleksandr Bezzubikov     PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d);
36*a35fe226SAleksandr Bezzubikov     int rc, pos;
37*a35fe226SAleksandr Bezzubikov 
38*a35fe226SAleksandr Bezzubikov     pci_bridge_initfn(d, TYPE_PCI_BUS);
39*a35fe226SAleksandr Bezzubikov 
40*a35fe226SAleksandr Bezzubikov     d->config[PCI_INTERRUPT_PIN] = 0x1;
41*a35fe226SAleksandr Bezzubikov     memory_region_init(&pcie_br->shpc_bar, OBJECT(d), "shpc-bar",
42*a35fe226SAleksandr Bezzubikov                        shpc_bar_size(d));
43*a35fe226SAleksandr Bezzubikov     rc = shpc_init(d, &br->sec_bus, &pcie_br->shpc_bar, 0, errp);
44*a35fe226SAleksandr Bezzubikov     if (rc) {
45*a35fe226SAleksandr Bezzubikov         goto error;
46*a35fe226SAleksandr Bezzubikov     }
47*a35fe226SAleksandr Bezzubikov 
48*a35fe226SAleksandr Bezzubikov     rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, errp);
49*a35fe226SAleksandr Bezzubikov     if (rc < 0) {
50*a35fe226SAleksandr Bezzubikov         goto cap_error;
51*a35fe226SAleksandr Bezzubikov     }
52*a35fe226SAleksandr Bezzubikov 
53*a35fe226SAleksandr Bezzubikov     pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp);
54*a35fe226SAleksandr Bezzubikov     if (pos < 0) {
55*a35fe226SAleksandr Bezzubikov         goto pm_error;
56*a35fe226SAleksandr Bezzubikov     }
57*a35fe226SAleksandr Bezzubikov     d->exp.pm_cap = pos;
58*a35fe226SAleksandr Bezzubikov     pci_set_word(d->config + pos + PCI_PM_PMC, 0x3);
59*a35fe226SAleksandr Bezzubikov 
60*a35fe226SAleksandr Bezzubikov     pcie_cap_arifwd_init(d);
61*a35fe226SAleksandr Bezzubikov     pcie_cap_deverr_init(d);
62*a35fe226SAleksandr Bezzubikov 
63*a35fe226SAleksandr Bezzubikov     rc = pcie_aer_init(d, PCI_ERR_VER, 0x100, PCI_ERR_SIZEOF, errp);
64*a35fe226SAleksandr Bezzubikov     if (rc < 0) {
65*a35fe226SAleksandr Bezzubikov         goto aer_error;
66*a35fe226SAleksandr Bezzubikov     }
67*a35fe226SAleksandr Bezzubikov 
68*a35fe226SAleksandr Bezzubikov     if (pcie_br->msi != ON_OFF_AUTO_OFF) {
69*a35fe226SAleksandr Bezzubikov         rc = msi_init(d, 0, 1, true, true, errp);
70*a35fe226SAleksandr Bezzubikov         if (rc < 0) {
71*a35fe226SAleksandr Bezzubikov             goto msi_error;
72*a35fe226SAleksandr Bezzubikov         }
73*a35fe226SAleksandr Bezzubikov     }
74*a35fe226SAleksandr Bezzubikov     pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
75*a35fe226SAleksandr Bezzubikov                      PCI_BASE_ADDRESS_MEM_TYPE_64, &pcie_br->shpc_bar);
76*a35fe226SAleksandr Bezzubikov     return;
77*a35fe226SAleksandr Bezzubikov 
78*a35fe226SAleksandr Bezzubikov msi_error:
79*a35fe226SAleksandr Bezzubikov     pcie_aer_exit(d);
80*a35fe226SAleksandr Bezzubikov aer_error:
81*a35fe226SAleksandr Bezzubikov pm_error:
82*a35fe226SAleksandr Bezzubikov     pcie_cap_exit(d);
83*a35fe226SAleksandr Bezzubikov cap_error:
84*a35fe226SAleksandr Bezzubikov     shpc_free(d);
85*a35fe226SAleksandr Bezzubikov error:
86*a35fe226SAleksandr Bezzubikov     pci_bridge_exitfn(d);
87*a35fe226SAleksandr Bezzubikov }
88*a35fe226SAleksandr Bezzubikov 
89*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_exit(PCIDevice *d)
90*a35fe226SAleksandr Bezzubikov {
91*a35fe226SAleksandr Bezzubikov     PCIEPCIBridge *bridge_dev = PCIE_PCI_BRIDGE_DEV(d);
92*a35fe226SAleksandr Bezzubikov     pcie_cap_exit(d);
93*a35fe226SAleksandr Bezzubikov     shpc_cleanup(d, &bridge_dev->shpc_bar);
94*a35fe226SAleksandr Bezzubikov     pci_bridge_exitfn(d);
95*a35fe226SAleksandr Bezzubikov }
96*a35fe226SAleksandr Bezzubikov 
97*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_reset(DeviceState *qdev)
98*a35fe226SAleksandr Bezzubikov {
99*a35fe226SAleksandr Bezzubikov     PCIDevice *d = PCI_DEVICE(qdev);
100*a35fe226SAleksandr Bezzubikov     pci_bridge_reset(qdev);
101*a35fe226SAleksandr Bezzubikov     msi_reset(d);
102*a35fe226SAleksandr Bezzubikov     shpc_reset(d);
103*a35fe226SAleksandr Bezzubikov }
104*a35fe226SAleksandr Bezzubikov 
105*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_write_config(PCIDevice *d,
106*a35fe226SAleksandr Bezzubikov         uint32_t address, uint32_t val, int len)
107*a35fe226SAleksandr Bezzubikov {
108*a35fe226SAleksandr Bezzubikov     pci_bridge_write_config(d, address, val, len);
109*a35fe226SAleksandr Bezzubikov     msi_write_config(d, address, val, len);
110*a35fe226SAleksandr Bezzubikov     shpc_cap_write_config(d, address, val, len);
111*a35fe226SAleksandr Bezzubikov }
112*a35fe226SAleksandr Bezzubikov 
113*a35fe226SAleksandr Bezzubikov static Property pcie_pci_bridge_dev_properties[] = {
114*a35fe226SAleksandr Bezzubikov         DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON),
115*a35fe226SAleksandr Bezzubikov         DEFINE_PROP_END_OF_LIST(),
116*a35fe226SAleksandr Bezzubikov };
117*a35fe226SAleksandr Bezzubikov 
118*a35fe226SAleksandr Bezzubikov static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
119*a35fe226SAleksandr Bezzubikov         .name = TYPE_PCIE_PCI_BRIDGE_DEV,
120*a35fe226SAleksandr Bezzubikov         .fields = (VMStateField[]) {
121*a35fe226SAleksandr Bezzubikov             VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
122*a35fe226SAleksandr Bezzubikov             SHPC_VMSTATE(shpc, PCIDevice, NULL),
123*a35fe226SAleksandr Bezzubikov             VMSTATE_END_OF_LIST()
124*a35fe226SAleksandr Bezzubikov         }
125*a35fe226SAleksandr Bezzubikov };
126*a35fe226SAleksandr Bezzubikov 
127*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev,
128*a35fe226SAleksandr Bezzubikov                                       DeviceState *dev, Error **errp)
129*a35fe226SAleksandr Bezzubikov {
130*a35fe226SAleksandr Bezzubikov     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
131*a35fe226SAleksandr Bezzubikov 
132*a35fe226SAleksandr Bezzubikov     if (!shpc_present(pci_hotplug_dev)) {
133*a35fe226SAleksandr Bezzubikov         error_setg(errp, "standard hotplug controller has been disabled for "
134*a35fe226SAleksandr Bezzubikov                    "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
135*a35fe226SAleksandr Bezzubikov         return;
136*a35fe226SAleksandr Bezzubikov     }
137*a35fe226SAleksandr Bezzubikov     shpc_device_hotplug_cb(hotplug_dev, dev, errp);
138*a35fe226SAleksandr Bezzubikov }
139*a35fe226SAleksandr Bezzubikov 
140*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
141*a35fe226SAleksandr Bezzubikov                                                  DeviceState *dev,
142*a35fe226SAleksandr Bezzubikov                                                  Error **errp)
143*a35fe226SAleksandr Bezzubikov {
144*a35fe226SAleksandr Bezzubikov     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
145*a35fe226SAleksandr Bezzubikov 
146*a35fe226SAleksandr Bezzubikov     if (!shpc_present(pci_hotplug_dev)) {
147*a35fe226SAleksandr Bezzubikov         error_setg(errp, "standard hotplug controller has been disabled for "
148*a35fe226SAleksandr Bezzubikov                    "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
149*a35fe226SAleksandr Bezzubikov         return;
150*a35fe226SAleksandr Bezzubikov     }
151*a35fe226SAleksandr Bezzubikov     shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
152*a35fe226SAleksandr Bezzubikov }
153*a35fe226SAleksandr Bezzubikov 
154*a35fe226SAleksandr Bezzubikov static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
155*a35fe226SAleksandr Bezzubikov {
156*a35fe226SAleksandr Bezzubikov     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
157*a35fe226SAleksandr Bezzubikov     DeviceClass *dc = DEVICE_CLASS(klass);
158*a35fe226SAleksandr Bezzubikov     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
159*a35fe226SAleksandr Bezzubikov 
160*a35fe226SAleksandr Bezzubikov     k->is_express = 1;
161*a35fe226SAleksandr Bezzubikov     k->is_bridge = 1;
162*a35fe226SAleksandr Bezzubikov     k->vendor_id = PCI_VENDOR_ID_REDHAT;
163*a35fe226SAleksandr Bezzubikov     k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE;
164*a35fe226SAleksandr Bezzubikov     k->realize = pcie_pci_bridge_realize;
165*a35fe226SAleksandr Bezzubikov     k->exit = pcie_pci_bridge_exit;
166*a35fe226SAleksandr Bezzubikov     k->config_write = pcie_pci_bridge_write_config;
167*a35fe226SAleksandr Bezzubikov     dc->vmsd = &pcie_pci_bridge_dev_vmstate;
168*a35fe226SAleksandr Bezzubikov     dc->props = pcie_pci_bridge_dev_properties;
169*a35fe226SAleksandr Bezzubikov     dc->vmsd = &pcie_pci_bridge_dev_vmstate;
170*a35fe226SAleksandr Bezzubikov     dc->reset = &pcie_pci_bridge_reset;
171*a35fe226SAleksandr Bezzubikov     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
172*a35fe226SAleksandr Bezzubikov     hc->plug = pcie_pci_bridge_hotplug_cb;
173*a35fe226SAleksandr Bezzubikov     hc->unplug_request = pcie_pci_bridge_hot_unplug_request_cb;
174*a35fe226SAleksandr Bezzubikov }
175*a35fe226SAleksandr Bezzubikov 
176*a35fe226SAleksandr Bezzubikov static const TypeInfo pcie_pci_bridge_info = {
177*a35fe226SAleksandr Bezzubikov         .name = TYPE_PCIE_PCI_BRIDGE_DEV,
178*a35fe226SAleksandr Bezzubikov         .parent = TYPE_PCI_BRIDGE,
179*a35fe226SAleksandr Bezzubikov         .instance_size = sizeof(PCIEPCIBridge),
180*a35fe226SAleksandr Bezzubikov         .class_init = pcie_pci_bridge_class_init,
181*a35fe226SAleksandr Bezzubikov         .interfaces = (InterfaceInfo[]) {
182*a35fe226SAleksandr Bezzubikov             { TYPE_HOTPLUG_HANDLER },
183*a35fe226SAleksandr Bezzubikov             { },
184*a35fe226SAleksandr Bezzubikov         }
185*a35fe226SAleksandr Bezzubikov };
186*a35fe226SAleksandr Bezzubikov 
187*a35fe226SAleksandr Bezzubikov static void pciepci_register(void)
188*a35fe226SAleksandr Bezzubikov {
189*a35fe226SAleksandr Bezzubikov     type_register_static(&pcie_pci_bridge_info);
190*a35fe226SAleksandr Bezzubikov }
191*a35fe226SAleksandr Bezzubikov 
192*a35fe226SAleksandr Bezzubikov type_init(pciepci_register);
193