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"
21 typedef struct PCIEPCIBridge
{
26 MemoryRegion shpc_bar
;
30 #define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
31 #define PCIE_PCI_BRIDGE_DEV(obj) \
32 OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV)
34 static void pcie_pci_bridge_realize(PCIDevice
*d
, Error
**errp
)
36 PCIBridge
*br
= PCI_BRIDGE(d
);
37 PCIEPCIBridge
*pcie_br
= PCIE_PCI_BRIDGE_DEV(d
);
40 pci_bridge_initfn(d
, TYPE_PCI_BUS
);
42 d
->config
[PCI_INTERRUPT_PIN
] = 0x1;
43 memory_region_init(&pcie_br
->shpc_bar
, OBJECT(d
), "shpc-bar",
45 rc
= shpc_init(d
, &br
->sec_bus
, &pcie_br
->shpc_bar
, 0, errp
);
50 rc
= pcie_cap_init(d
, 0, PCI_EXP_TYPE_PCI_BRIDGE
, 0, errp
);
55 pos
= pci_add_capability(d
, PCI_CAP_ID_PM
, 0, PCI_PM_SIZEOF
, errp
);
60 pci_set_word(d
->config
+ pos
+ PCI_PM_PMC
, 0x3);
62 pcie_cap_arifwd_init(d
);
63 pcie_cap_deverr_init(d
);
65 rc
= pcie_aer_init(d
, PCI_ERR_VER
, 0x100, PCI_ERR_SIZEOF
, errp
);
70 Error
*local_err
= NULL
;
71 if (pcie_br
->msi
!= ON_OFF_AUTO_OFF
) {
72 rc
= msi_init(d
, 0, 1, true, true, &local_err
);
74 assert(rc
== -ENOTSUP
);
75 if (pcie_br
->msi
!= ON_OFF_AUTO_ON
) {
76 error_free(local_err
);
78 /* failed to satisfy user's explicit request for MSI */
79 error_propagate(errp
, local_err
);
84 pci_register_bar(d
, 0, PCI_BASE_ADDRESS_SPACE_MEMORY
|
85 PCI_BASE_ADDRESS_MEM_TYPE_64
, &pcie_br
->shpc_bar
);
94 shpc_cleanup(d
, &pcie_br
->shpc_bar
);
99 static void pcie_pci_bridge_exit(PCIDevice
*d
)
101 PCIEPCIBridge
*bridge_dev
= PCIE_PCI_BRIDGE_DEV(d
);
103 shpc_cleanup(d
, &bridge_dev
->shpc_bar
);
104 pci_bridge_exitfn(d
);
107 static void pcie_pci_bridge_reset(DeviceState
*qdev
)
109 PCIDevice
*d
= PCI_DEVICE(qdev
);
110 pci_bridge_reset(qdev
);
111 if (msi_present(d
)) {
117 static void pcie_pci_bridge_write_config(PCIDevice
*d
,
118 uint32_t address
, uint32_t val
, int len
)
120 pci_bridge_write_config(d
, address
, val
, len
);
121 if (msi_present(d
)) {
122 msi_write_config(d
, address
, val
, len
);
124 shpc_cap_write_config(d
, address
, val
, len
);
127 static Property pcie_pci_bridge_dev_properties
[] = {
128 DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge
, msi
, ON_OFF_AUTO_AUTO
),
129 DEFINE_PROP_END_OF_LIST(),
132 static const VMStateDescription pcie_pci_bridge_dev_vmstate
= {
133 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
134 .priority
= MIG_PRI_PCI_BUS
,
135 .fields
= (VMStateField
[]) {
136 VMSTATE_PCI_DEVICE(parent_obj
, PCIBridge
),
137 SHPC_VMSTATE(shpc
, PCIDevice
, NULL
),
138 VMSTATE_END_OF_LIST()
142 static void pcie_pci_bridge_class_init(ObjectClass
*klass
, void *data
)
144 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
145 DeviceClass
*dc
= DEVICE_CLASS(klass
);
146 HotplugHandlerClass
*hc
= HOTPLUG_HANDLER_CLASS(klass
);
149 k
->vendor_id
= PCI_VENDOR_ID_REDHAT
;
150 k
->device_id
= PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE
;
151 k
->realize
= pcie_pci_bridge_realize
;
152 k
->exit
= pcie_pci_bridge_exit
;
153 k
->config_write
= pcie_pci_bridge_write_config
;
154 dc
->vmsd
= &pcie_pci_bridge_dev_vmstate
;
155 device_class_set_props(dc
, pcie_pci_bridge_dev_properties
);
156 dc
->reset
= &pcie_pci_bridge_reset
;
157 set_bit(DEVICE_CATEGORY_BRIDGE
, dc
->categories
);
158 hc
->plug
= pci_bridge_dev_plug_cb
;
159 hc
->unplug
= pci_bridge_dev_unplug_cb
;
160 hc
->unplug_request
= pci_bridge_dev_unplug_request_cb
;
163 static const TypeInfo pcie_pci_bridge_info
= {
164 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
165 .parent
= TYPE_PCI_BRIDGE
,
166 .instance_size
= sizeof(PCIEPCIBridge
),
167 .class_init
= pcie_pci_bridge_class_init
,
168 .interfaces
= (InterfaceInfo
[]) {
169 { TYPE_HOTPLUG_HANDLER
},
170 { INTERFACE_PCIE_DEVICE
},
175 static void pciepci_register(void)
177 type_register_static(&pcie_pci_bridge_info
);
180 type_init(pciepci_register
);