2 * QEMU Generic PCIE-PCI Bridge
4 * Copyright (c) 2017 Aleksandr Bezzubikov
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "qapi/error.h"
12 #include "qemu/module.h"
13 #include "hw/pci/pci.h"
14 #include "hw/pci/pci_bus.h"
15 #include "hw/pci/pci_bridge.h"
16 #include "hw/pci/msi.h"
17 #include "hw/pci/shpc.h"
18 #include "hw/pci/slotid_cap.h"
19 #include "hw/qdev-properties.h"
20 #include "qom/object.h"
22 struct PCIEPCIBridge
{
27 MemoryRegion shpc_bar
;
30 typedef struct PCIEPCIBridge PCIEPCIBridge
;
32 #define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
33 DECLARE_INSTANCE_CHECKER(PCIEPCIBridge
, PCIE_PCI_BRIDGE_DEV
,
34 TYPE_PCIE_PCI_BRIDGE_DEV
)
36 static void pcie_pci_bridge_realize(PCIDevice
*d
, Error
**errp
)
38 PCIBridge
*br
= PCI_BRIDGE(d
);
39 PCIEPCIBridge
*pcie_br
= PCIE_PCI_BRIDGE_DEV(d
);
42 pci_bridge_initfn(d
, TYPE_PCI_BUS
);
44 d
->config
[PCI_INTERRUPT_PIN
] = 0x1;
45 memory_region_init(&pcie_br
->shpc_bar
, OBJECT(d
), "shpc-bar",
47 rc
= shpc_init(d
, &br
->sec_bus
, &pcie_br
->shpc_bar
, 0, errp
);
52 rc
= pcie_cap_init(d
, 0, PCI_EXP_TYPE_PCI_BRIDGE
, 0, errp
);
57 pos
= pci_add_capability(d
, PCI_CAP_ID_PM
, 0, PCI_PM_SIZEOF
, errp
);
62 pci_set_word(d
->config
+ pos
+ PCI_PM_PMC
, 0x3);
64 pcie_cap_arifwd_init(d
);
65 pcie_cap_deverr_init(d
);
67 rc
= pcie_aer_init(d
, PCI_ERR_VER
, 0x100, PCI_ERR_SIZEOF
, errp
);
72 Error
*local_err
= NULL
;
73 if (pcie_br
->msi
!= ON_OFF_AUTO_OFF
) {
74 rc
= msi_init(d
, 0, 1, true, true, &local_err
);
76 assert(rc
== -ENOTSUP
);
77 if (pcie_br
->msi
!= ON_OFF_AUTO_ON
) {
78 error_free(local_err
);
80 /* failed to satisfy user's explicit request for MSI */
81 error_propagate(errp
, local_err
);
86 pci_register_bar(d
, 0, PCI_BASE_ADDRESS_SPACE_MEMORY
|
87 PCI_BASE_ADDRESS_MEM_TYPE_64
, &pcie_br
->shpc_bar
);
96 shpc_cleanup(d
, &pcie_br
->shpc_bar
);
101 static void pcie_pci_bridge_exit(PCIDevice
*d
)
103 PCIEPCIBridge
*bridge_dev
= PCIE_PCI_BRIDGE_DEV(d
);
105 shpc_cleanup(d
, &bridge_dev
->shpc_bar
);
106 pci_bridge_exitfn(d
);
109 static void pcie_pci_bridge_reset(DeviceState
*qdev
)
111 PCIDevice
*d
= PCI_DEVICE(qdev
);
112 pci_bridge_reset(qdev
);
113 if (msi_present(d
)) {
119 static void pcie_pci_bridge_write_config(PCIDevice
*d
,
120 uint32_t address
, uint32_t val
, int len
)
122 pci_bridge_write_config(d
, address
, val
, len
);
123 if (msi_present(d
)) {
124 msi_write_config(d
, address
, val
, len
);
126 shpc_cap_write_config(d
, address
, val
, len
);
129 static Property pcie_pci_bridge_dev_properties
[] = {
130 DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge
, msi
, ON_OFF_AUTO_AUTO
),
131 DEFINE_PROP_END_OF_LIST(),
134 static const VMStateDescription pcie_pci_bridge_dev_vmstate
= {
135 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
136 .priority
= MIG_PRI_PCI_BUS
,
137 .fields
= (VMStateField
[]) {
138 VMSTATE_PCI_DEVICE(parent_obj
, PCIBridge
),
139 SHPC_VMSTATE(shpc
, PCIDevice
, NULL
),
140 VMSTATE_END_OF_LIST()
144 static void pcie_pci_bridge_class_init(ObjectClass
*klass
, void *data
)
146 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
147 DeviceClass
*dc
= DEVICE_CLASS(klass
);
148 HotplugHandlerClass
*hc
= HOTPLUG_HANDLER_CLASS(klass
);
151 k
->vendor_id
= PCI_VENDOR_ID_REDHAT
;
152 k
->device_id
= PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE
;
153 k
->realize
= pcie_pci_bridge_realize
;
154 k
->exit
= pcie_pci_bridge_exit
;
155 k
->config_write
= pcie_pci_bridge_write_config
;
156 dc
->vmsd
= &pcie_pci_bridge_dev_vmstate
;
157 device_class_set_props(dc
, pcie_pci_bridge_dev_properties
);
158 dc
->reset
= &pcie_pci_bridge_reset
;
159 set_bit(DEVICE_CATEGORY_BRIDGE
, dc
->categories
);
160 hc
->plug
= pci_bridge_dev_plug_cb
;
161 hc
->unplug
= pci_bridge_dev_unplug_cb
;
162 hc
->unplug_request
= pci_bridge_dev_unplug_request_cb
;
165 static const TypeInfo pcie_pci_bridge_info
= {
166 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
167 .parent
= TYPE_PCI_BRIDGE
,
168 .instance_size
= sizeof(PCIEPCIBridge
),
169 .class_init
= pcie_pci_bridge_class_init
,
170 .interfaces
= (InterfaceInfo
[]) {
171 { TYPE_HOTPLUG_HANDLER
},
172 { INTERFACE_PCIE_DEVICE
},
177 static void pciepci_register(void)
179 type_register_static(&pcie_pci_bridge_info
);
182 type_init(pciepci_register
);