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 "hw/pci/pci.h"
13 #include "hw/pci/pci_bus.h"
14 #include "hw/pci/pci_bridge.h"
15 #include "hw/pci/msi.h"
16 #include "hw/pci/shpc.h"
17 #include "hw/pci/slotid_cap.h"
19 typedef struct PCIEPCIBridge
{
24 MemoryRegion shpc_bar
;
28 #define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
29 #define PCIE_PCI_BRIDGE_DEV(obj) \
30 OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV)
32 static void pcie_pci_bridge_realize(PCIDevice
*d
, Error
**errp
)
34 PCIBridge
*br
= PCI_BRIDGE(d
);
35 PCIEPCIBridge
*pcie_br
= PCIE_PCI_BRIDGE_DEV(d
);
38 pci_bridge_initfn(d
, TYPE_PCI_BUS
);
40 d
->config
[PCI_INTERRUPT_PIN
] = 0x1;
41 memory_region_init(&pcie_br
->shpc_bar
, OBJECT(d
), "shpc-bar",
43 rc
= shpc_init(d
, &br
->sec_bus
, &pcie_br
->shpc_bar
, 0, errp
);
48 rc
= pcie_cap_init(d
, 0, PCI_EXP_TYPE_PCI_BRIDGE
, 0, errp
);
53 pos
= pci_add_capability(d
, PCI_CAP_ID_PM
, 0, PCI_PM_SIZEOF
, errp
);
58 pci_set_word(d
->config
+ pos
+ PCI_PM_PMC
, 0x3);
60 pcie_cap_arifwd_init(d
);
61 pcie_cap_deverr_init(d
);
63 rc
= pcie_aer_init(d
, PCI_ERR_VER
, 0x100, PCI_ERR_SIZEOF
, errp
);
68 Error
*local_err
= NULL
;
69 if (pcie_br
->msi
!= ON_OFF_AUTO_OFF
) {
70 rc
= msi_init(d
, 0, 1, true, true, &local_err
);
72 assert(rc
== -ENOTSUP
);
73 if (pcie_br
->msi
!= ON_OFF_AUTO_ON
) {
74 error_free(local_err
);
76 /* failed to satisfy user's explicit request for MSI */
77 error_propagate(errp
, local_err
);
82 pci_register_bar(d
, 0, PCI_BASE_ADDRESS_SPACE_MEMORY
|
83 PCI_BASE_ADDRESS_MEM_TYPE_64
, &pcie_br
->shpc_bar
);
92 shpc_cleanup(d
, &pcie_br
->shpc_bar
);
97 static void pcie_pci_bridge_exit(PCIDevice
*d
)
99 PCIEPCIBridge
*bridge_dev
= PCIE_PCI_BRIDGE_DEV(d
);
101 shpc_cleanup(d
, &bridge_dev
->shpc_bar
);
102 pci_bridge_exitfn(d
);
105 static void pcie_pci_bridge_reset(DeviceState
*qdev
)
107 PCIDevice
*d
= PCI_DEVICE(qdev
);
108 pci_bridge_reset(qdev
);
109 if (msi_present(d
)) {
115 static void pcie_pci_bridge_write_config(PCIDevice
*d
,
116 uint32_t address
, uint32_t val
, int len
)
118 pci_bridge_write_config(d
, address
, val
, len
);
119 if (msi_present(d
)) {
120 msi_write_config(d
, address
, val
, len
);
122 shpc_cap_write_config(d
, address
, val
, len
);
125 static Property pcie_pci_bridge_dev_properties
[] = {
126 DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge
, msi
, ON_OFF_AUTO_AUTO
),
127 DEFINE_PROP_END_OF_LIST(),
130 static const VMStateDescription pcie_pci_bridge_dev_vmstate
= {
131 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
132 .priority
= MIG_PRI_PCI_BUS
,
133 .fields
= (VMStateField
[]) {
134 VMSTATE_PCI_DEVICE(parent_obj
, PCIBridge
),
135 SHPC_VMSTATE(shpc
, PCIDevice
, NULL
),
136 VMSTATE_END_OF_LIST()
140 static void pcie_pci_bridge_class_init(ObjectClass
*klass
, void *data
)
142 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
143 DeviceClass
*dc
= DEVICE_CLASS(klass
);
144 HotplugHandlerClass
*hc
= HOTPLUG_HANDLER_CLASS(klass
);
147 k
->vendor_id
= PCI_VENDOR_ID_REDHAT
;
148 k
->device_id
= PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE
;
149 k
->realize
= pcie_pci_bridge_realize
;
150 k
->exit
= pcie_pci_bridge_exit
;
151 k
->config_write
= pcie_pci_bridge_write_config
;
152 dc
->vmsd
= &pcie_pci_bridge_dev_vmstate
;
153 dc
->props
= pcie_pci_bridge_dev_properties
;
154 dc
->reset
= &pcie_pci_bridge_reset
;
155 set_bit(DEVICE_CATEGORY_BRIDGE
, dc
->categories
);
156 hc
->plug
= pci_bridge_dev_plug_cb
;
157 hc
->unplug
= pci_bridge_dev_unplug_cb
;
158 hc
->unplug_request
= pci_bridge_dev_unplug_request_cb
;
161 static const TypeInfo pcie_pci_bridge_info
= {
162 .name
= TYPE_PCIE_PCI_BRIDGE_DEV
,
163 .parent
= TYPE_PCI_BRIDGE
,
164 .instance_size
= sizeof(PCIEPCIBridge
),
165 .class_init
= pcie_pci_bridge_class_init
,
166 .interfaces
= (InterfaceInfo
[]) {
167 { TYPE_HOTPLUG_HANDLER
},
168 { INTERFACE_PCIE_DEVICE
},
173 static void pciepci_register(void)
175 type_register_static(&pcie_pci_bridge_info
);
178 type_init(pciepci_register
);