[SeaBIOS] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure
On PCI init PCI bridge devices may need some extra info about bus number to reserve, IO, memory and prefetchable memory limits. QEMU can provide this with special vendor-specific PCI capability. This capability is intended to be used only for Red Hat PCI bridges, i.e. QEMU cooperation. Signed-off-by: Aleksandr Bezzubikov--- src/fw/dev-pci.h | 53 + 1 file changed, 53 insertions(+) create mode 100644 src/fw/dev-pci.h diff --git a/src/fw/dev-pci.h b/src/fw/dev-pci.h new file mode 100644 index 000..0dc5556 --- /dev/null +++ b/src/fw/dev-pci.h @@ -0,0 +1,53 @@ +#ifndef _PCI_CAP_H +#define _PCI_CAP_H + +#include "types.h" + +/* + * + * QEMU-specific vendor(Red Hat)-specific capability. + * It's intended to provide some hints for firmware to init PCI devices. + * + * Its structure is shown below: + * + * Header: + * + * u8 id; Standard PCI Capability Header field + * u8 next; Standard PCI Capability Header field + * u8 len; Standard PCI Capability Header field + * u8 type; Red Hat vendor-specific capability type + * Data: + * + * u32 bus_res; minimum bus number to reserve; + * this is necessary for PCI Express Root Ports + * to support PCI bridges hotplug + * u64 io; IO space to reserve + * u32 mem; non-prefetchable memory to reserve + * + * At most of the following two fields may be set to a value + * different from 0xFF...F: + * u32 prefetchable_mem_32; prefetchable memory to reserve (32-bit MMIO) + * u64 prefetchable_mem_64; prefetchable memory to reserve (64-bit MMIO) + * + * If any field value in Data section is 0xFF...F, + * it means that such kind of reservation is not needed and must be ignored. + * +*/ + +/* Offset of vendor-specific capability type field */ +#define PCI_CAP_REDHAT_TYPE_OFFSET 3 + +/* List of valid Red Hat vendor-specific capability types */ +#define REDHAT_CAP_RESOURCE_RESERVE 1 + + +/* Offsets of RESOURCE_RESERVE capability fields */ +#define RES_RESERVE_BUS_RES4 +#define RES_RESERVE_IO 8 +#define RES_RESERVE_MEM16 +#define RES_RESERVE_PREF_MEM_3220 +#define RES_RESERVE_PREF_MEM_6424 +#define RES_RESERVE_CAP_SIZE 32 + +#endif /* _PCI_CAP_H */ + -- 2.7.4 ___ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios
Re: [SeaBIOS] [PATCH v6 0/4] Generic PCIE-PCI Bridge
2017-08-13 18:49 GMT+03:00 Aleksandr Bezzubikov: > This series introduces a new device - Generic PCI Express to PCI bridge, > and also makes all necessary changes to enable hotplug of the bridge itself > and any device into the bridge. > > Changes v5->v6: > 1. Fix indentation in the cap creation function (addresses Marcel's comment) > 2. Simplify capability pref_mem_* fields assignment (addresses Marcel's > comment) > 3. Documentation fixes: > - fix mutually exclusive fields definition (addresses Laszlo's > comment) > - fix pcie-pci-bridge usage example (addresses Marcel's comment) > > Changes v4->v5: > 1. Change PCIE-PCI Bridge license (addresses Marcel's comment) > 2. The capability layout changes (adress Laszlo' comments): > - separate pref_mem into pref_mem_32 and pref_mem_64 fields (SeaBIOS side > has the same changes) > - accordingly change the Generic Root Port's properties > 3. Do not add the capability to the root port if no valid values are provided > (adresses Michael's comment) > 4. Rename the capability type to 'RESOURCE_RESERVE' (addresses Marcel's > comment) > 5. Remove shpc_present check function (addresses Marcel's comment) > 6. Fix the 4th patch message (adresses Michael's comment) > 7. Patch for SHPC enabling in _OSC method has been already merged > > Changes v3->v4: > 1. PCIE-PCI Bridge device: "msi_enable"->"msi", "shpc"->"shpc_bar", remove > local_err, >make "msi" property OnOffAuto, shpc_present() is still here >to avoid SHPC_VMSTATE refactoring (address Marcel's comments). > 2. Change QEMU PCI capability layout (SeaBIOS side has the same changes): > - change reservation fields types: bus_res - uint32_t, others - uint64_t > - rename 'non_pref' and 'pref' fields > - interpret -1 value as 'ignore' > 3. Use parent_realize in Generic PCI Express Root Port properly. > 4. Fix documentation: fully replace the DMI-PCI bridge references with the > new PCIE-PCI bridge, > "PCIE"->"PCI Express", small mistakes and typos - address Laszlo's and > Marcel's comments. > 5. Rename QEMU PCI cap creation fucntion - addresses Marcel's comment. > > Changes v2->v3: > (0). 'do_not_use' capability field flag is still _not_ in here since we > haven't come to consesus on it yet. > 1. Merge commits 5 (bus_reserve property creation) and 6 (property usage) > together - addresses Michael's comment. > 2. Add 'bus_reserve' property and QEMU PCI capability only to Generic PCIE > Root Port - addresses Michael's and Marcel's comments. > 3. Change 'bus_reserve' property's default value to 0 - addresses Michael's > comment. > 4. Rename QEMU bridge-specific PCI capability creation function - addresses > Michael's comment. > 5. Init the whole QEMU PCI capability with zeroes - addresses Michael's and > Laszlo's comments. > 6. Change QEMU PCI capability layout (SeaBIOS side has the same changes) > - add 'type' field to distinguish multiple > RedHat-specific capabilities - addresses Michael's comment > - do not mimiс PCI Config space register layout, but use mutually exclusive > differently > sized fields for IO and prefetchable memory limits - addresses Laszlo's > comment > 7. Correct error handling in PCIE-PCI bridge realize function. > 8. Replace a '2' constant with PCI_CAP_FLAGS in the capability creation > function - addresses Michael's comment. > 9. Remove a comment on _OSC which isn't correct anymore - address Marcel's > comment. > 10. Add documentation for the Generic PCIE-PCI Bridge and QEMU PCI capability > - addresses Michael's comment. > > Changes v1->v2: > 1. Enable SHPC for the bridge. > 2. Enable SHPC support for the Q35 machine (ACPI stuff). > 3. Introduce PCI capability to help firmware on the system init. >This allows the bridge to be hotpluggable. Now it's supported >only for pcie-root-port. Now it's supposed to used with >SeaBIOS only, look at the SeaBIOS corresponding series >"Allow RedHat PCI bridges reserve more buses than necessary during init". > > Aleksandr Bezzubikov (4): > hw/pci: introduce pcie-pci-bridge device > hw/pci: introduce bridge-only vendor-specific capability to provide > some hints to firmware > hw/pci: add QEMU-specific PCI capability to the Generic PCI Express > Root Port > docs: update documentation considering PCIE-PCI bridge > > docs/pcie.txt | 49 +- > docs/pcie_pci_bridge.txt | 114 ++ > hw/pci-bridge/Makefile.objs| 2 +- > hw/pci-bridge/gen_pcie_root_port.c | 36 +++ > hw/pci-bridge/pcie_pci_bridge.c| 192 > + > hw/pci/pci_bridge.c| 46 + > include/hw/pci/pci.h | 1 + > include/hw/pci/pci_bridge.h| 25 + > include/hw/pci/pcie_port.h | 1 + > 9 files changed, 442 insertions(+), 24 deletions(-) > create mode 100644 docs/pcie_pci_bridge.txt > create mode 100644
[SeaBIOS] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init
In case of Red Hat Generic PCIE Root Port reserve additional buses and/or IO/MEM/PREF space, which values are provided in a vendor-specific capability. Signed-off-by: Aleksandr Bezzubikov--- src/fw/pciinit.c | 99 +--- src/hw/pci_ids.h | 3 ++ 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 864954f..620b187 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -15,6 +15,7 @@ #include "hw/pcidevice.h" // pci_probe_devices #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL #include "hw/pci_regs.h" // PCI_COMMAND +#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE #include "list.h" // struct hlist_node #include "malloc.h" // free #include "output.h" // dprintf @@ -522,6 +523,32 @@ static void pci_bios_init_platform(void) } } +static u8 pci_find_resource_reserve_capability(u16 bdf) +{ +if (pci_config_readw(bdf, PCI_VENDOR_ID) == PCI_VENDOR_ID_REDHAT && +pci_config_readw(bdf, PCI_DEVICE_ID) == +PCI_DEVICE_ID_REDHAT_ROOT_PORT) { +u8 cap = 0; +do { +cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap); +} while (cap && + pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) != +REDHAT_CAP_RESOURCE_RESERVE); +if (cap) { +u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS); +if (cap_len < RES_RESERVE_CAP_SIZE) { +dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n", +cap_len); +} +} else { +dprintf(1, "PCI: invalid QEMU resource reserve cap offset\n"); +} +return cap; +} else { +dprintf(1, "PCI: QEMU resource reserve cap not found\n"); +return 0; +} +} / * Bus initialization @@ -578,9 +605,28 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus) pci_bios_init_bus_rec(secbus, pci_bus); if (subbus != *pci_bus) { +u8 res_bus = 0; +u8 cap = pci_find_resource_reserve_capability(bdf); + +if (cap) { +u32 tmp_res_bus = pci_config_readl(bdf, +cap + RES_RESERVE_BUS_RES); +if (tmp_res_bus != (u32)-1) { +res_bus = tmp_res_bus & 0xFF; +if ((u8)(res_bus + secbus) < secbus || +(u8)(res_bus + secbus) < res_bus) { +dprintf(1, "PCI: bus_reserve value %d is invalid\n", +res_bus); +res_bus = 0; +} +} +res_bus = (*pci_bus > secbus + res_bus) ? *pci_bus +: secbus + res_bus; +} dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", -subbus, *pci_bus); -subbus = *pci_bus; +subbus, res_bus); +subbus = res_bus; +*pci_bus = res_bus; } else { dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); } @@ -844,20 +890,65 @@ static int pci_bios_check_devices(struct pci_bus *busses) */ parent = [0]; int type; -u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0); +u16 bdf = s->bus_dev->bdf; +u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0); +u8 qemu_cap = pci_find_resource_reserve_capability(bdf); + int hotplug_support = pci_bus_hotplug_support(s, pcie_cap); for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { u64 align = (type == PCI_REGION_TYPE_IO) ? PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; if (!pci_bridge_has_region(s->bus_dev, type)) continue; +u64 size = 0; +if (qemu_cap) { +u32 tmp_size; +u64 tmp_size_64; +switch(type) { +case PCI_REGION_TYPE_IO: +tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO) | +(u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO + 4) << 32); +if (tmp_size_64 != (u64)-1) { +size = tmp_size_64; +} +break; +case PCI_REGION_TYPE_MEM: +tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_MEM); +if (tmp_size != (u32)-1) { +size = tmp_size; +} +break; +case PCI_REGION_TYPE_PREFMEM: +tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_32); +tmp_size_64 = (pci_config_readl(bdf, qemu_cap +
[SeaBIOS] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device
Refactor pci_find_capability function to get bdf instead of a whole pci_device* as the only necessary field for this function is still bdf. Signed-off-by: Aleksandr BezzubikovReviewed-by: Marcel Apfelbaum --- src/fw/pciinit.c| 4 ++-- src/hw/pci.c| 25 + src/hw/pci.h| 1 + src/hw/pcidevice.c | 24 src/hw/pcidevice.h | 1 - src/hw/virtio-pci.c | 6 +++--- 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 08221e6..864954f 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -762,7 +762,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap) return downstream_port && slot_implemented; } -shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0); +shpc_cap = pci_find_capability(bus->bus_dev->bdf, PCI_CAP_ID_SHPC, 0); return !!shpc_cap; } @@ -844,7 +844,7 @@ static int pci_bios_check_devices(struct pci_bus *busses) */ parent = [0]; int type; -u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0); +u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0); int hotplug_support = pci_bus_hotplug_support(s, pcie_cap); for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { u64 align = (type == PCI_REGION_TYPE_IO) ? diff --git a/src/hw/pci.c b/src/hw/pci.c index 8e3d617..50d9d2d 100644 --- a/src/hw/pci.c +++ b/src/hw/pci.c @@ -58,6 +58,30 @@ pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on) pci_config_writew(bdf, addr, val); } +u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap) +{ +int i; +u16 status = pci_config_readw(bdf, PCI_STATUS); + +if (!(status & PCI_STATUS_CAP_LIST)) +return 0; + +if (cap == 0) { +/* find first */ +cap = pci_config_readb(bdf, PCI_CAPABILITY_LIST); +} else { +/* find next */ +cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT); +} +for (i = 0; cap && i <= 0xff; i++) { +if (pci_config_readb(bdf, cap + PCI_CAP_LIST_ID) == cap_id) +return cap; +cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT); +} + +return 0; +} + // Helper function for foreachbdf() macro - return next device int pci_next(int bdf, int bus) @@ -107,3 +131,4 @@ pci_reboot(void) outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */ udelay(50); } + diff --git a/src/hw/pci.h b/src/hw/pci.h index ee6e196..2e30e28 100644 --- a/src/hw/pci.h +++ b/src/hw/pci.h @@ -39,6 +39,7 @@ u32 pci_config_readl(u16 bdf, u32 addr); u16 pci_config_readw(u16 bdf, u32 addr); u8 pci_config_readb(u16 bdf, u32 addr); void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on); +u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap); int pci_next(int bdf, int bus); int pci_probe_host(void); void pci_reboot(void); diff --git a/src/hw/pcidevice.c b/src/hw/pcidevice.c index cfebf66..8853cf7 100644 --- a/src/hw/pcidevice.c +++ b/src/hw/pcidevice.c @@ -134,30 +134,6 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg) return NULL; } -u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap) -{ -int i; -u16 status = pci_config_readw(pci->bdf, PCI_STATUS); - -if (!(status & PCI_STATUS_CAP_LIST)) -return 0; - -if (cap == 0) { -/* find first */ -cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST); -} else { -/* find next */ -cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT); -} -for (i = 0; cap && i <= 0xff; i++) { -if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id) -return cap; -cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT); -} - -return 0; -} - // Enable PCI bus-mastering (ie, DMA) support on a pci device void pci_enable_busmaster(struct pci_device *pci) diff --git a/src/hw/pcidevice.h b/src/hw/pcidevice.h index 354b549..225d545 100644 --- a/src/hw/pcidevice.h +++ b/src/hw/pcidevice.h @@ -69,7 +69,6 @@ int pci_init_device(const struct pci_device_id *ids , struct pci_device *pci, void *arg); struct pci_device *pci_find_init_device(const struct pci_device_id *ids , void *arg); -u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap); void pci_enable_busmaster(struct pci_device *pci); u16 pci_enable_iobar(struct pci_device *pci, u32 addr); void *pci_enable_membar(struct pci_device *pci, u32 addr); diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index e5c2c33..96f9c6b 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -19,7 +19,7 @@ #include "malloc.h" // free #include "output.h" // dprintf #include "pci.h" // pci_config_readl -#include "pcidevice.h" // pci_find_capability +#include "pcidevice.h" // struct pci_device #include
[SeaBIOS] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability
Now PCI bridges get a bus range number on a system init, basing on currently plugged devices. That's why when one wants to hotplug another bridge, it needs his child bus, which the parent is unable to provide (speaking about virtual device). The suggested workaround is to have vendor-specific capability in Red Hat PCI bridges that contains number of additional bus to reserve (as well as IO/MEM/PREF space limit hints) on BIOS PCI init. So this capability is intended only for pure QEMU->SeaBIOS usage. Considering all aforesaid, this series is directly connected with QEMU series "Generic PCIE-PCI Bridge". Although the new PCI capability is supposed to contain various limits along with bus number to reserve, now only its full layout is proposed. And only bus_reserve field is used in QEMU and BIOS. Limits usage is still a subject for implementation as now the main goal of this series to provide necessary support from the firmware side to PCIE-PCI bridge hotplug. Changes v5->v6: 1. Remove unnecessary indents and line breaks (addresses Marcel's comments) 2. Count IO/MEM/PREF region size as a maximum of necessary size and one provide in RESOURCE_RESERVE capability (addresses Marcel's comment). 3. Make the cap debug message more detailed (addresses Marcel's comment). 4. Change pref_32 and pref_64 cap fields comment. Changes v4->v5: 1. Rename capability-related #defines 2. Move capability IO/MEM/PREF fields values usage to the regions creation stage (addresses Marcel's comment) 3. The capability layout change: separate pref_mem into pref_mem_32 and pref_mem_64 fields (QEMU side has the same changes) (addresses Laszlo's comment) 4. Extract the capability lookup and check to the separate function (addresses Marcel's comment) - despite of Marcel's comment do not extract field check for -1 since it increases code length and doesn't look nice because of different field types 5. Fix the capability's comment (addresses Marcel's comment) 6. Fix the 3rd patch message Changes v3->v4: 1. Use all QEMU PCI capability fields - addresses Michael's comment 2. Changes of the capability layout (QEMU side has the same changes): - change reservation fields types: bus_res - uint32_t, others - uint64_t - interpret -1 value as 'ignore' Changes v2->v3: 1. Merge commit 2 (Red Hat vendor ID) into commit 4 - addresses Marcel's comment, and add Generic PCIE Root Port device ID - addresses Michael's comment. 2. Changes of the capability layout (QEMU side has the same changes): - add 'type' field to distinguish multiple RedHat-specific capabilities - addresses Michael's comment - do not mimiс PCI Config space register layout, but use mutually exclusive differently sized fields for IO and prefetchable memory limits - addresses Laszlo's comment - use defines instead of structure and offsetof - addresses Michael's comment 3. Interpret 'bus_reserve' field as a minimum necessary range to reserve - addresses Gerd's comment 4. pci_find_capability moved to pci.c - addresses Kevin's comment 5. Move capability layout header to src/fw/dev-pci.h - addresses Kevin's comment 6. Add the capability documentation - addresses Michael's comment 7. Add capability length and bus_reserve field sanity checks - addresses Michael's comment Changes v1->v2: 1. New #define for Red Hat vendor added (addresses Konrad's comment). 2. Refactored pci_find_capability function (addresses Marcel's comment). 3. Capability reworked: - data type added; - reserve space in a structure for IO, memory and prefetchable memory limits. Aleksandr Bezzubikov (3): pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device pci: add QEMU-specific PCI capability structure pci: enable RedHat PCI bridges to reserve additional resource on PCI init src/fw/dev-pci.h| 53 +++ src/fw/pciinit.c| 101 +--- src/hw/pci.c| 25 + src/hw/pci.h| 1 + src/hw/pci_ids.h| 3 ++ src/hw/pcidevice.c | 24 - src/hw/pcidevice.h | 1 - src/hw/virtio-pci.c | 6 ++-- 8 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 src/fw/dev-pci.h -- 2.7.4 ___ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios
[SeaBIOS] [PATCH v6 3/4] hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port
To enable hotplugging of a newly created pcie-pci-bridge, we need to tell firmware (e.g. SeaBIOS) to reserve additional buses or IO/MEM/PREF space for pcie-root-port. Additional bus reservation allows us to hotplug pcie-pci-bridge into this root port. The number of buses and IO/MEM/PREF space to reserve are provided to the device via a corresponding property, and to the firmware via new PCI capability. The properties' default values are -1 to keep default behavior unchanged. Signed-off-by: Aleksandr BezzubikovReviewed-by: Marcel Apfelbaum --- hw/pci-bridge/gen_pcie_root_port.c | 36 include/hw/pci/pcie_port.h | 1 + 2 files changed, 37 insertions(+) diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index cb694d6..bd65479 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -16,6 +16,8 @@ #include "hw/pci/pcie_port.h" #define TYPE_GEN_PCIE_ROOT_PORT"pcie-root-port" +#define GEN_PCIE_ROOT_PORT(obj) \ +OBJECT_CHECK(GenPCIERootPort, (obj), TYPE_GEN_PCIE_ROOT_PORT) #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 @@ -26,6 +28,13 @@ typedef struct GenPCIERootPort { /*< public >*/ bool migrate_msix; + +/* additional resources to reserve on firmware init */ +uint32_t bus_reserve; +uint64_t io_reserve; +uint32_t mem_reserve; +uint32_t pref32_reserve; +uint64_t pref64_reserve; } GenPCIERootPort; static uint8_t gen_rp_aer_vector(const PCIDevice *d) @@ -60,6 +69,24 @@ static bool gen_rp_test_migrate_msix(void *opaque, int version_id) return rp->migrate_msix; } +static void gen_rp_realize(DeviceState *dev, Error **errp) +{ +PCIDevice *d = PCI_DEVICE(dev); +GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d); +PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); + +rpc->parent_realize(dev, errp); + +int rc = pci_bridge_qemu_reserve_cap_init(d, 0, grp->bus_reserve, +grp->io_reserve, grp->mem_reserve, grp->pref32_reserve, +grp->pref64_reserve, errp); + +if (rc < 0) { +rpc->parent_class.exit(d); +return; +} +} + static const VMStateDescription vmstate_rp_dev = { .name = "pcie-root-port", .version_id = 1, @@ -78,6 +105,11 @@ static const VMStateDescription vmstate_rp_dev = { static Property gen_rp_props[] = { DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort, migrate_msix, true), +DEFINE_PROP_UINT32("bus-reserve", GenPCIERootPort, bus_reserve, -1), +DEFINE_PROP_UINT64("io-reserve", GenPCIERootPort, io_reserve, -1), +DEFINE_PROP_UINT32("mem-reserve", GenPCIERootPort, mem_reserve, -1), +DEFINE_PROP_UINT32("pref32-reserve", GenPCIERootPort, pref32_reserve, -1), +DEFINE_PROP_UINT64("pref64-reserve", GenPCIERootPort, pref64_reserve, -1), DEFINE_PROP_END_OF_LIST() }; @@ -92,6 +124,10 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Express Root Port"; dc->vmsd = _rp_dev; dc->props = gen_rp_props; + +rpc->parent_realize = dc->realize; +dc->realize = gen_rp_realize; + rpc->aer_vector = gen_rp_aer_vector; rpc->interrupts_init = gen_rp_interrupts_init; rpc->interrupts_uninit = gen_rp_interrupts_uninit; diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index 1333266..0736014 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -65,6 +65,7 @@ void pcie_chassis_del_slot(PCIESlot *s); typedef struct PCIERootPortClass { PCIDeviceClass parent_class; +DeviceRealize parent_realize; uint8_t (*aer_vector)(const PCIDevice *dev); int (*interrupts_init)(PCIDevice *dev, Error **errp); -- 2.7.4 ___ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios
[SeaBIOS] [PATCH v6 1/4] hw/pci: introduce pcie-pci-bridge device
Introduce a new PCIExpress-to-PCI Bridge device, which is a hot-pluggable PCI Express device and supports devices hot-plug with SHPC. This device is intended to replace the DMI-to-PCI Bridge. Signed-off-by: Aleksandr BezzubikovReviewed-by: Marcel Apfelbaum --- hw/pci-bridge/Makefile.objs | 2 +- hw/pci-bridge/pcie_pci_bridge.c | 192 include/hw/pci/pci.h| 1 + 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 hw/pci-bridge/pcie_pci_bridge.c diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs index c4683cf..666db37 100644 --- a/hw/pci-bridge/Makefile.objs +++ b/hw/pci-bridge/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += pci_bridge_dev.o +common-obj-y += pci_bridge_dev.o pcie_pci_bridge.o common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o common-obj-$(CONFIG_PXB) += pci_expander_bridge.o common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c new file mode 100644 index 000..9aa5cc3 --- /dev/null +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -0,0 +1,192 @@ +/* + * QEMU Generic PCIE-PCI Bridge + * + * Copyright (c) 2017 Aleksandr Bezzubikov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/msi.h" +#include "hw/pci/shpc.h" +#include "hw/pci/slotid_cap.h" + +typedef struct PCIEPCIBridge { +/*< private >*/ +PCIBridge parent_obj; + +OnOffAuto msi; +MemoryRegion shpc_bar; +/*< public >*/ +} PCIEPCIBridge; + +#define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge" +#define PCIE_PCI_BRIDGE_DEV(obj) \ +OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV) + +static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp) +{ +PCIBridge *br = PCI_BRIDGE(d); +PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d); +int rc, pos; + +pci_bridge_initfn(d, TYPE_PCI_BUS); + +d->config[PCI_INTERRUPT_PIN] = 0x1; +memory_region_init(_br->shpc_bar, OBJECT(d), "shpc-bar", + shpc_bar_size(d)); +rc = shpc_init(d, >sec_bus, _br->shpc_bar, 0, errp); +if (rc) { +goto error; +} + +rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, errp); +if (rc < 0) { +goto cap_error; +} + +pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp); +if (pos < 0) { +goto pm_error; +} +d->exp.pm_cap = pos; +pci_set_word(d->config + pos + PCI_PM_PMC, 0x3); + +pcie_cap_arifwd_init(d); +pcie_cap_deverr_init(d); + +rc = pcie_aer_init(d, PCI_ERR_VER, 0x100, PCI_ERR_SIZEOF, errp); +if (rc < 0) { +goto aer_error; +} + +if (pcie_br->msi != ON_OFF_AUTO_OFF) { +rc = msi_init(d, 0, 1, true, true, errp); +if (rc < 0) { +goto msi_error; +} +} +pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, _br->shpc_bar); +return; + +msi_error: +pcie_aer_exit(d); +aer_error: +pm_error: +pcie_cap_exit(d); +cap_error: +shpc_free(d); +error: +pci_bridge_exitfn(d); +} + +static void pcie_pci_bridge_exit(PCIDevice *d) +{ +PCIEPCIBridge *bridge_dev = PCIE_PCI_BRIDGE_DEV(d); +pcie_cap_exit(d); +shpc_cleanup(d, _dev->shpc_bar); +pci_bridge_exitfn(d); +} + +static void pcie_pci_bridge_reset(DeviceState *qdev) +{ +PCIDevice *d = PCI_DEVICE(qdev); +pci_bridge_reset(qdev); +msi_reset(d); +shpc_reset(d); +} + +static void pcie_pci_bridge_write_config(PCIDevice *d, +uint32_t address, uint32_t val, int len) +{ +pci_bridge_write_config(d, address, val, len); +msi_write_config(d, address, val, len); +shpc_cap_write_config(d, address, val, len); +} + +static Property pcie_pci_bridge_dev_properties[] = { +DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON), +DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription pcie_pci_bridge_dev_vmstate = { +.name = TYPE_PCIE_PCI_BRIDGE_DEV, +.fields = (VMStateField[]) { +VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), +SHPC_VMSTATE(shpc, PCIDevice, NULL), +VMSTATE_END_OF_LIST() +} +}; + +static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ +PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev); + +if (!shpc_present(pci_hotplug_dev)) { +error_setg(errp, "standard hotplug controller has been disabled for " + "this %s", TYPE_PCIE_PCI_BRIDGE_DEV); +return; +} +
[SeaBIOS] [PATCH v6 4/4] docs: update documentation considering PCIE-PCI bridge
Signed-off-by: Aleksandr BezzubikovReviewed-by: Laszlo Ersek Reviewed-by: Marcel Apfelbaum --- docs/pcie.txt| 49 ++-- docs/pcie_pci_bridge.txt | 114 +++ 2 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 docs/pcie_pci_bridge.txt diff --git a/docs/pcie.txt b/docs/pcie.txt index 5bada24..76b85ec 100644 --- a/docs/pcie.txt +++ b/docs/pcie.txt @@ -46,7 +46,7 @@ Place only the following kinds of devices directly on the Root Complex: (2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express hierarchies. -(3) DMI-PCI Bridges (i82801b11-bridge), for starting legacy PCI +(3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI hierarchies. (4) Extra Root Complexes (pxb-pcie), if multiple PCI Express Root Buses @@ -55,18 +55,18 @@ Place only the following kinds of devices directly on the Root Complex: pcie.0 bus ||| | - --- -- -- -- - | PCI Dev | | PCIe Root Port | | DMI-PCI Bridge | | pxb-pcie | - --- -- -- -- + --- -- --- -- + | PCI Dev | | PCIe Root Port | | PCIe-PCI Bridge | | pxb-pcie | + --- -- --- -- 2.1.1 To plug a device into pcie.0 as a Root Complex Integrated Endpoint use: -device [,bus=pcie.0] 2.1.2 To expose a new PCI Express Root Bus use: -device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z] - Only PCI Express Root Ports and DMI-PCI bridges can be connected - to the pcie.1 bus: + PCI Express Root Ports and PCI Express to PCI bridges can be + connected to the pcie.1 bus: -device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ - -device i82801b11-bridge,id=dmi_pci_bridge1,bus=pcie.1 + -device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1 2.2 PCI Express only hierarchy @@ -130,24 +130,24 @@ Notes: Legacy PCI devices can be plugged into pcie.0 as Integrated Endpoints, but, as mentioned in section 5, doing so means the legacy PCI device in question will be incapable of hot-unplugging. -Besides that use DMI-PCI Bridges (i82801b11-bridge) in combination -with PCI-PCI Bridges (pci-bridge) to start PCI hierarchies. +Besides that use PCI Express to PCI Bridges (pcie-pci-bridge) in +combination with PCI-PCI Bridges (pci-bridge) to start PCI hierarchies. -Prefer flat hierarchies. For most scenarios a single DMI-PCI Bridge +Prefer flat hierarchies. For most scenarios a single PCI Express to PCI Bridge (having 32 slots) and several PCI-PCI Bridges attached to it (each supporting also 32 slots) will support hundreds of legacy devices. -The recommendation is to populate one PCI-PCI Bridge under the DMI-PCI Bridge -until is full and then plug a new PCI-PCI Bridge... +The recommendation is to populate one PCI-PCI Bridge under the +PCI Express to PCI Bridge until is full and then plug a new PCI-PCI Bridge... pcie.0 bus -- || - --- -- - | PCI Dev | | DMI-PCI BRIDGE | - ---- + --- --- + | PCI Dev | | PCIe-PCI Bridge | + --- --- || ---- - | PCI-PCI Bridge || PCI-PCI Bridge | ... + | PCI-PCI Bridge || PCI-PCI Bridge | ---- | | --- --- @@ -157,11 +157,11 @@ until is full and then plug a new PCI-PCI Bridge... 2.3.1 To plug a PCI device into pcie.0 as an Integrated Endpoint use: -device [,bus=pcie.0] 2.3.2 Plugging a PCI device into a PCI-PCI Bridge: - -device i82801b11-bridge,id=dmi_pci_bridge1[,bus=pcie.0] \ - -device pci-bridge,id=pci_bridge1,bus=dmi_pci_bridge1[,chassis_nr=x][,addr=y] \ + -device pcie-pci-bridge,id=pcie_pci_bridge1[,bus=pcie.0] \ + -device pci-bridge,id=pci_bridge1,bus=pcie_pci_bridge1[,chassis_nr=x][,addr=y] \ -device ,bus=pci_bridge1[,addr=x] Note that 'addr' cannot be 0 unless shpc=off parameter is passed to - the PCI Bridge. + the PCI Bridge/PCI Express to PCI Bridge.
[SeaBIOS] [PATCH v6 2/4] hw/pci: introduce bridge-only vendor-specific capability to provide some hints to firmware
On PCI init PCI bridges may need some extra info about bus number, IO, memory and prefetchable memory to reserve. QEMU can provide this with a special vendor-specific PCI capability. Signed-off-by: Aleksandr BezzubikovReviewed-by: Marcel Apfelbaum --- hw/pci/pci_bridge.c | 46 + include/hw/pci/pci_bridge.h | 25 2 files changed, 71 insertions(+) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 720119b..17feae5 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -408,6 +408,52 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, br->bus_name = bus_name; } + +int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, + uint32_t bus_reserve, uint64_t io_reserve, + uint32_t mem_non_pref_reserve, + uint32_t mem_pref_32_reserve, + uint64_t mem_pref_64_reserve, + Error **errp) +{ +if (mem_pref_32_reserve != (uint32_t)-1 && +mem_pref_64_reserve != (uint64_t)-1) { +error_setg(errp, + "PCI resource reserve cap: PREF32 and PREF64 conflict"); +return -EINVAL; +} + +if (bus_reserve == (uint32_t)-1 && +io_reserve == (uint64_t)-1 && +mem_non_pref_reserve == (uint32_t)-1 && +mem_pref_32_reserve == (uint32_t)-1 && +mem_pref_64_reserve == (uint64_t)-1) { +return 0; +} + +size_t cap_len = sizeof(PCIBridgeQemuCap); +PCIBridgeQemuCap cap = { +.len = cap_len, +.type = REDHAT_PCI_CAP_RESOURCE_RESERVE, +.bus_res = bus_reserve, +.io = io_reserve, +.mem = mem_non_pref_reserve, +.mem_pref_32 = mem_pref_32_reserve, +.mem_pref_64 = mem_pref_64_reserve +}; + +int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, +cap_offset, cap_len, errp); +if (offset < 0) { +return offset; +} + +memcpy(dev->config + offset + PCI_CAP_FLAGS, + (char *) + PCI_CAP_FLAGS, + cap_len - PCI_CAP_FLAGS); +return 0; +} + static const TypeInfo pci_bridge_type_info = { .name = TYPE_PCI_BRIDGE, .parent = TYPE_PCI_DEVICE, diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index ff7cbaa..1acadc2 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -67,4 +67,29 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, #define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ #define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ +typedef struct PCIBridgeQemuCap { +uint8_t id; /* Standard PCI capability header field */ +uint8_t next; /* Standard PCI capability header field */ +uint8_t len;/* Standard PCI vendor-specific capability header field */ +uint8_t type; /* Red Hat vendor-specific capability type. + Types are defined with REDHAT_PCI_CAP_ prefix */ + +uint32_t bus_res; /* Minimum number of buses to reserve */ +uint64_t io;/* IO space to reserve */ +uint32_t mem; /* Non-prefetchable memory to reserve */ +/* At most one of the following two fields may be set to a value + * different from -1 */ +uint32_t mem_pref_32; /* Prefetchable memory to reserve (32-bit MMIO) */ +uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */ +} PCIBridgeQemuCap; + +#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1 + +int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, + uint32_t bus_reserve, uint64_t io_reserve, + uint32_t mem_non_pref_reserve, + uint32_t mem_pref_32_reserve, + uint64_t mem_pref_64_reserve, + Error **errp); + #endif /* QEMU_PCI_BRIDGE_H */ -- 2.7.4 ___ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios
[SeaBIOS] [PATCH v6 0/4] Generic PCIE-PCI Bridge
This series introduces a new device - Generic PCI Express to PCI bridge, and also makes all necessary changes to enable hotplug of the bridge itself and any device into the bridge. Changes v5->v6: 1. Fix indentation in the cap creation function (addresses Marcel's comment) 2. Simplify capability pref_mem_* fields assignment (addresses Marcel's comment) 3. Documentation fixes: - fix mutually exclusive fields definition (addresses Laszlo's comment) - fix pcie-pci-bridge usage example (addresses Marcel's comment) Changes v4->v5: 1. Change PCIE-PCI Bridge license (addresses Marcel's comment) 2. The capability layout changes (adress Laszlo' comments): - separate pref_mem into pref_mem_32 and pref_mem_64 fields (SeaBIOS side has the same changes) - accordingly change the Generic Root Port's properties 3. Do not add the capability to the root port if no valid values are provided (adresses Michael's comment) 4. Rename the capability type to 'RESOURCE_RESERVE' (addresses Marcel's comment) 5. Remove shpc_present check function (addresses Marcel's comment) 6. Fix the 4th patch message (adresses Michael's comment) 7. Patch for SHPC enabling in _OSC method has been already merged Changes v3->v4: 1. PCIE-PCI Bridge device: "msi_enable"->"msi", "shpc"->"shpc_bar", remove local_err, make "msi" property OnOffAuto, shpc_present() is still here to avoid SHPC_VMSTATE refactoring (address Marcel's comments). 2. Change QEMU PCI capability layout (SeaBIOS side has the same changes): - change reservation fields types: bus_res - uint32_t, others - uint64_t - rename 'non_pref' and 'pref' fields - interpret -1 value as 'ignore' 3. Use parent_realize in Generic PCI Express Root Port properly. 4. Fix documentation: fully replace the DMI-PCI bridge references with the new PCIE-PCI bridge, "PCIE"->"PCI Express", small mistakes and typos - address Laszlo's and Marcel's comments. 5. Rename QEMU PCI cap creation fucntion - addresses Marcel's comment. Changes v2->v3: (0). 'do_not_use' capability field flag is still _not_ in here since we haven't come to consesus on it yet. 1. Merge commits 5 (bus_reserve property creation) and 6 (property usage) together - addresses Michael's comment. 2. Add 'bus_reserve' property and QEMU PCI capability only to Generic PCIE Root Port - addresses Michael's and Marcel's comments. 3. Change 'bus_reserve' property's default value to 0 - addresses Michael's comment. 4. Rename QEMU bridge-specific PCI capability creation function - addresses Michael's comment. 5. Init the whole QEMU PCI capability with zeroes - addresses Michael's and Laszlo's comments. 6. Change QEMU PCI capability layout (SeaBIOS side has the same changes) - add 'type' field to distinguish multiple RedHat-specific capabilities - addresses Michael's comment - do not mimiс PCI Config space register layout, but use mutually exclusive differently sized fields for IO and prefetchable memory limits - addresses Laszlo's comment 7. Correct error handling in PCIE-PCI bridge realize function. 8. Replace a '2' constant with PCI_CAP_FLAGS in the capability creation function - addresses Michael's comment. 9. Remove a comment on _OSC which isn't correct anymore - address Marcel's comment. 10. Add documentation for the Generic PCIE-PCI Bridge and QEMU PCI capability - addresses Michael's comment. Changes v1->v2: 1. Enable SHPC for the bridge. 2. Enable SHPC support for the Q35 machine (ACPI stuff). 3. Introduce PCI capability to help firmware on the system init. This allows the bridge to be hotpluggable. Now it's supported only for pcie-root-port. Now it's supposed to used with SeaBIOS only, look at the SeaBIOS corresponding series "Allow RedHat PCI bridges reserve more buses than necessary during init". Aleksandr Bezzubikov (4): hw/pci: introduce pcie-pci-bridge device hw/pci: introduce bridge-only vendor-specific capability to provide some hints to firmware hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port docs: update documentation considering PCIE-PCI bridge docs/pcie.txt | 49 +- docs/pcie_pci_bridge.txt | 114 ++ hw/pci-bridge/Makefile.objs| 2 +- hw/pci-bridge/gen_pcie_root_port.c | 36 +++ hw/pci-bridge/pcie_pci_bridge.c| 192 + hw/pci/pci_bridge.c| 46 + include/hw/pci/pci.h | 1 + include/hw/pci/pci_bridge.h| 25 + include/hw/pci/pcie_port.h | 1 + 9 files changed, 442 insertions(+), 24 deletions(-) create mode 100644 docs/pcie_pci_bridge.txt create mode 100644 hw/pci-bridge/pcie_pci_bridge.c -- 2.7.4 ___ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios
Re: [SeaBIOS] [PATCH v5 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init
On 11/08/2017 2:21, Aleksandr Bezzubikov wrote: In case of Red Hat Generic PCIE Root Port reserve additional buses and/or IO/MEM/PREF space, which values are provided in a vendor-specific capability. Signed-off-by: Aleksandr Bezzubikov--- src/fw/dev-pci.h | 2 +- src/fw/pciinit.c | 125 +-- src/hw/pci_ids.h | 3 ++ 3 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/fw/dev-pci.h b/src/fw/dev-pci.h index cf16b2e..99ccc12 100644 --- a/src/fw/dev-pci.h +++ b/src/fw/dev-pci.h @@ -38,7 +38,7 @@ #define PCI_CAP_REDHAT_TYPE_OFFSET 3 /* List of valid Red Hat vendor-specific capability types */ -#define REDHAT_CAP_RESOURCE_RESERVE1 +#define REDHAT_CAP_RESOURCE_RESERVE 1 /* Offsets of RESOURCE_RESERVE capability fields */ diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 864954f..d9aef56 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -15,6 +15,7 @@ #include "hw/pcidevice.h" // pci_probe_devices #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL #include "hw/pci_regs.h" // PCI_COMMAND +#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE #include "list.h" // struct hlist_node #include "malloc.h" // free #include "output.h" // dprintf @@ -522,6 +523,32 @@ static void pci_bios_init_platform(void) } } +static u8 pci_find_resource_reserve_capability(u16 bdf) +{ +if (pci_config_readw(bdf, PCI_VENDOR_ID) == PCI_VENDOR_ID_REDHAT && +pci_config_readw(bdf, PCI_DEVICE_ID) == +PCI_DEVICE_ID_REDHAT_ROOT_PORT) { +u8 cap = 0; +do { +cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap); +} while (cap && + pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) != +REDHAT_CAP_RESOURCE_RESERVE); +if (cap) { +u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS); +if (cap_len < RES_RESERVE_CAP_SIZE) { +dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n", +cap_len); +} +} else { +dprintf(1, "PCI: invalid QEMU resource reserve cap offset\n"); +} +return cap; +} else { +dprintf(1, "PCI: QEMU resource reserve cap not found\n"); +return 0; +} +} / * Bus initialization @@ -578,9 +605,28 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus) pci_bios_init_bus_rec(secbus, pci_bus); if (subbus != *pci_bus) { +u8 res_bus = 0; +u8 cap = pci_find_resource_reserve_capability(bdf); + +if (cap) { +u32 tmp_res_bus = pci_config_readl(bdf, +cap + RES_RESERVE_BUS_RES); +if (tmp_res_bus != (u32)-1) { +res_bus = tmp_res_bus & 0xFF; +if ((u8)(res_bus + secbus) < secbus || +(u8)(res_bus + secbus) < res_bus) { +dprintf(1, "PCI: bus_reserve value %d is invalid\n", +res_bus); +res_bus = 0; +} +} +res_bus = (*pci_bus > secbus + res_bus) ? *pci_bus +: secbus + res_bus; +} dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", -subbus, *pci_bus); -subbus = *pci_bus; +subbus, res_bus); +subbus = res_bus; +*pci_bus = res_bus; } else { dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); } @@ -844,22 +890,74 @@ static int pci_bios_check_devices(struct pci_bus *busses) */ parent = [0]; int type; -u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0); +u16 bdf = s->bus_dev->bdf; +u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0); +u8 qemu_cap = pci_find_resource_reserve_capability(bdf); + int hotplug_support = pci_bus_hotplug_support(s, pcie_cap); for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { u64 align = (type == PCI_REGION_TYPE_IO) ? -PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; +PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; if (!pci_bridge_has_region(s->bus_dev, type)) continue; -if (pci_region_align(>r[type]) > align) - align = pci_region_align(>r[type]); -u64 sum = pci_region_sum(>r[type]); -int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO); -if (!sum && hotplug_support && !resource_optional) -sum = align; /* reserve min size for hot-plug */ -u64 size = ALIGN(sum, align); -int is64 =
Re: [SeaBIOS] [PATCH v5 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init
On 11/08/2017 2:21, Aleksandr Bezzubikov wrote: In case of Red Hat Generic PCIE Root Port reserve additional buses and/or IO/MEM/PREF space, which values are provided in a vendor-specific capability. Hi Aleksandr, Signed-off-by: Aleksandr Bezzubikov--- src/fw/dev-pci.h | 2 +- src/fw/pciinit.c | 125 +-- src/hw/pci_ids.h | 3 ++ 3 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/fw/dev-pci.h b/src/fw/dev-pci.h index cf16b2e..99ccc12 100644 --- a/src/fw/dev-pci.h +++ b/src/fw/dev-pci.h @@ -38,7 +38,7 @@ #define PCI_CAP_REDHAT_TYPE_OFFSET 3 /* List of valid Red Hat vendor-specific capability types */ -#define REDHAT_CAP_RESOURCE_RESERVE1 +#define REDHAT_CAP_RESOURCE_RESERVE 1 Do you need the above chunk? If not, please get rid if it. /* Offsets of RESOURCE_RESERVE capability fields */ diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 864954f..d9aef56 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -15,6 +15,7 @@ #include "hw/pcidevice.h" // pci_probe_devices #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL #include "hw/pci_regs.h" // PCI_COMMAND +#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE #include "list.h" // struct hlist_node #include "malloc.h" // free #include "output.h" // dprintf @@ -522,6 +523,32 @@ static void pci_bios_init_platform(void) } } +static u8 pci_find_resource_reserve_capability(u16 bdf) +{ +if (pci_config_readw(bdf, PCI_VENDOR_ID) == PCI_VENDOR_ID_REDHAT && +pci_config_readw(bdf, PCI_DEVICE_ID) == +PCI_DEVICE_ID_REDHAT_ROOT_PORT) { +u8 cap = 0; +do { +cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap); +} while (cap && + pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) != +REDHAT_CAP_RESOURCE_RESERVE); +if (cap) { +u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS); +if (cap_len < RES_RESERVE_CAP_SIZE) { +dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n", +cap_len); +} +} else { +dprintf(1, "PCI: invalid QEMU resource reserve cap offset\n"); +} +return cap; +} else { +dprintf(1, "PCI: QEMU resource reserve cap not found\n"); +return 0; +} +} / * Bus initialization @@ -578,9 +605,28 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus) pci_bios_init_bus_rec(secbus, pci_bus); if (subbus != *pci_bus) { +u8 res_bus = 0; +u8 cap = pci_find_resource_reserve_capability(bdf); + +if (cap) { +u32 tmp_res_bus = pci_config_readl(bdf, +cap + RES_RESERVE_BUS_RES); +if (tmp_res_bus != (u32)-1) { +res_bus = tmp_res_bus & 0xFF; +if ((u8)(res_bus + secbus) < secbus || +(u8)(res_bus + secbus) < res_bus) { +dprintf(1, "PCI: bus_reserve value %d is invalid\n", +res_bus); +res_bus = 0; +} +} +res_bus = (*pci_bus > secbus + res_bus) ? *pci_bus +: secbus + res_bus; +} dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", -subbus, *pci_bus); -subbus = *pci_bus; +subbus, res_bus); +subbus = res_bus; +*pci_bus = res_bus; } else { dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); } @@ -844,22 +890,74 @@ static int pci_bios_check_devices(struct pci_bus *busses) */ parent = [0]; int type; -u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0); +u16 bdf = s->bus_dev->bdf; +u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0); +u8 qemu_cap = pci_find_resource_reserve_capability(bdf); + int hotplug_support = pci_bus_hotplug_support(s, pcie_cap); for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { u64 align = (type == PCI_REGION_TYPE_IO) ? -PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; +PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; The above chunk is also not needed. if (!pci_bridge_has_region(s->bus_dev, type)) continue; -if (pci_region_align(>r[type]) > align) - align = pci_region_align(>r[type]); -u64 sum = pci_region_sum(>r[type]); -int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO); -if (!sum && hotplug_support && !resource_optional) -sum = align; /*
Re: [SeaBIOS] [PATCH v5 4/4] docs: update documentation considering PCIE-PCI bridge
On 11/08/2017 2:31, Aleksandr Bezzubikov wrote: Signed-off-by: Aleksandr Bezzubikov--- docs/pcie.txt| 49 ++-- docs/pcie_pci_bridge.txt | 115 +++ 2 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 docs/pcie_pci_bridge.txt diff --git a/docs/pcie.txt b/docs/pcie.txt index 5bada24..76b85ec 100644 --- a/docs/pcie.txt +++ b/docs/pcie.txt @@ -46,7 +46,7 @@ Place only the following kinds of devices directly on the Root Complex: (2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express hierarchies. -(3) DMI-PCI Bridges (i82801b11-bridge), for starting legacy PCI +(3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI hierarchies. (4) Extra Root Complexes (pxb-pcie), if multiple PCI Express Root Buses @@ -55,18 +55,18 @@ Place only the following kinds of devices directly on the Root Complex: pcie.0 bus ||| | - --- -- -- -- - | PCI Dev | | PCIe Root Port | | DMI-PCI Bridge | | pxb-pcie | - --- -- -- -- + --- -- --- -- + | PCI Dev | | PCIe Root Port | | PCIe-PCI Bridge | | pxb-pcie | + --- -- --- -- 2.1.1 To plug a device into pcie.0 as a Root Complex Integrated Endpoint use: -device [,bus=pcie.0] 2.1.2 To expose a new PCI Express Root Bus use: -device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z] - Only PCI Express Root Ports and DMI-PCI bridges can be connected - to the pcie.1 bus: + PCI Express Root Ports and PCI Express to PCI bridges can be + connected to the pcie.1 bus: -device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ - -device i82801b11-bridge,id=dmi_pci_bridge1,bus=pcie.1 + -device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1 2.2 PCI Express only hierarchy @@ -130,24 +130,24 @@ Notes: Legacy PCI devices can be plugged into pcie.0 as Integrated Endpoints, but, as mentioned in section 5, doing so means the legacy PCI device in question will be incapable of hot-unplugging. -Besides that use DMI-PCI Bridges (i82801b11-bridge) in combination -with PCI-PCI Bridges (pci-bridge) to start PCI hierarchies. +Besides that use PCI Express to PCI Bridges (pcie-pci-bridge) in +combination with PCI-PCI Bridges (pci-bridge) to start PCI hierarchies. -Prefer flat hierarchies. For most scenarios a single DMI-PCI Bridge +Prefer flat hierarchies. For most scenarios a single PCI Express to PCI Bridge (having 32 slots) and several PCI-PCI Bridges attached to it (each supporting also 32 slots) will support hundreds of legacy devices. -The recommendation is to populate one PCI-PCI Bridge under the DMI-PCI Bridge -until is full and then plug a new PCI-PCI Bridge... +The recommendation is to populate one PCI-PCI Bridge under the +PCI Express to PCI Bridge until is full and then plug a new PCI-PCI Bridge... pcie.0 bus -- || - --- -- - | PCI Dev | | DMI-PCI BRIDGE | - ---- + --- --- + | PCI Dev | | PCIe-PCI Bridge | + --- --- || ---- - | PCI-PCI Bridge || PCI-PCI Bridge | ... + | PCI-PCI Bridge || PCI-PCI Bridge | ---- | | --- --- @@ -157,11 +157,11 @@ until is full and then plug a new PCI-PCI Bridge... 2.3.1 To plug a PCI device into pcie.0 as an Integrated Endpoint use: -device [,bus=pcie.0] 2.3.2 Plugging a PCI device into a PCI-PCI Bridge: - -device i82801b11-bridge,id=dmi_pci_bridge1[,bus=pcie.0] \ - -device pci-bridge,id=pci_bridge1,bus=dmi_pci_bridge1[,chassis_nr=x][,addr=y] \ + -device pcie-pci-bridge,id=pcie_pci_bridge1[,bus=pcie.0] \ + -device pci-bridge,id=pci_bridge1,bus=pcie_pci_bridge1[,chassis_nr=x][,addr=y] \ -device ,bus=pci_bridge1[,addr=x] Note that 'addr' cannot be 0 unless shpc=off parameter is passed to - the PCI Bridge. + the PCI Bridge/PCI Express to PCI
Re: [SeaBIOS] [PATCH v5 2/4] hw/pci: introduce bridge-only vendor-specific capability to provide some hints to firmware
On 11/08/2017 2:31, Aleksandr Bezzubikov wrote: On PCI init PCI bridges may need some extra info about bus number, IO, memory and prefetchable memory to reserve. QEMU can provide this with a special vendor-specific PCI capability. Hi Aleksandr, I only have a few very small comments, other than that it looks OK to me. Signed-off-by: Aleksandr BezzubikovReviewed-by: Marcel Apfelbaum --- hw/pci/pci_bridge.c | 54 + include/hw/pci/pci_bridge.h | 24 2 files changed, 78 insertions(+) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 720119b..2495a51 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -408,6 +408,60 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, br->bus_name = bus_name; } + +int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, > + uint32_t bus_reserve, uint64_t io_reserve, Please pay attention to indentation, the above line should be aligned with the above (" + uint32_t mem_non_pref_reserve, + uint32_t mem_pref_32_reserve, + uint64_t mem_pref_64_reserve, + Error **errp) +{ +if (mem_pref_32_reserve != (uint32_t)-1 && +mem_pref_64_reserve != (uint64_t) -1) { Same here +error_setg(errp, + "PCI resource reserve cap: PREF32 and PREF64 conflict"); +return -EINVAL; +} + +if (bus_reserve == (uint32_t)-1 && +io_reserve == (uint64_t)-1 && +mem_non_pref_reserve == (uint32_t)-1 && +mem_pref_32_reserve == (uint32_t)-1 && +mem_pref_64_reserve == (uint64_t)-1) { and here (please go over all the file) +return 0; +} + +size_t cap_len = sizeof(PCIBridgeQemuCap); +PCIBridgeQemuCap cap = { +.len = cap_len, +.type = REDHAT_PCI_CAP_RESOURCE_RESERVE, +.bus_res = bus_reserve, +.io = io_reserve, +.mem = mem_non_pref_reserve, +.mem_pref_32 = (uint32_t)-1, +.mem_pref_64 = (uint64_t)-1 Why not use the values of mem_pref_32_reserve and mem_pref_64_reserve ? You already have checked they are mutually exclusive. +}; + +if (mem_pref_32_reserve != (uint32_t)-1 && +mem_pref_64_reserve == (uint64_t)-1) { +cap.mem_pref_32 = mem_pref_32_reserve; +} else if (mem_pref_32_reserve == (uint32_t)-1 && +mem_pref_64_reserve != (uint64_t)-1) { +cap.mem_pref_64 = mem_pref_64_reserve; +} So it seems you don't need the above code at all, right? With the above minor comments, please keep my R-b tag. Thanks, Marcel + +int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, +cap_offset, cap_len, errp); +if (offset < 0) { +return offset; +} + +memcpy(dev->config + offset + PCI_CAP_FLAGS, +(char *) + PCI_CAP_FLAGS, +cap_len - PCI_CAP_FLAGS); +return 0; +} + static const TypeInfo pci_bridge_type_info = { .name = TYPE_PCI_BRIDGE, .parent = TYPE_PCI_DEVICE, diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index ff7cbaa..2d8c635 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -67,4 +67,28 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, #define PCI_BRIDGE_CTL_DISCARD_STATUS0x400 /* Discard timer status */ #define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ +typedef struct PCIBridgeQemuCap { +uint8_t id; /* Standard PCI capability header field */ +uint8_t next; /* Standard PCI capability header field */ +uint8_t len;/* Standard PCI vendor-specific capability header field */ +uint8_t type; /* Red Hat vendor-specific capability type. + Types are defined with REDHAT_PCI_CAP_ prefix */ + +uint32_t bus_res; /* Minimum number of buses to reserve */ +uint64_t io;/* IO space to reserve */ +uint32_t mem; /* Non-prefetchable memory to reserve */ +/* This two fields are mutually exclusive */ +uint32_t mem_pref_32; /* Prefetchable memory to reserve (32-bit MMIO) */ +uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */ +} PCIBridgeQemuCap; + +#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1 + +int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, + uint32_t bus_reserve, uint64_t io_reserve, + uint32_t mem_non_pref_reserve, + uint32_t mem_pref_32_reserve, + uint64_t mem_pref_64_reserve, + Error **errp); + #endif /* QEMU_PCI_BRIDGE_H */
Re: [SeaBIOS] [PATCH v5 1/4] hw/pci: introduce pcie-pci-bridge device
On 11/08/2017 2:31, Aleksandr Bezzubikov wrote: Introduce a new PCIExpress-to-PCI Bridge device, which is a hot-pluggable PCI Express device and supports devices hot-plug with SHPC. This device is intended to replace the DMI-to-PCI Bridge. Signed-off-by: Aleksandr Bezzubikov--- hw/pci-bridge/Makefile.objs | 2 +- hw/pci-bridge/pcie_pci_bridge.c | 192 include/hw/pci/pci.h| 1 + 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 hw/pci-bridge/pcie_pci_bridge.c diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs index c4683cf..666db37 100644 --- a/hw/pci-bridge/Makefile.objs +++ b/hw/pci-bridge/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += pci_bridge_dev.o +common-obj-y += pci_bridge_dev.o pcie_pci_bridge.o common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o common-obj-$(CONFIG_PXB) += pci_expander_bridge.o common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c new file mode 100644 index 000..9aa5cc3 --- /dev/null +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -0,0 +1,192 @@ +/* + * QEMU Generic PCIE-PCI Bridge + * + * Copyright (c) 2017 Aleksandr Bezzubikov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/msi.h" +#include "hw/pci/shpc.h" +#include "hw/pci/slotid_cap.h" + +typedef struct PCIEPCIBridge { +/*< private >*/ +PCIBridge parent_obj; + +OnOffAuto msi; +MemoryRegion shpc_bar; +/*< public >*/ +} PCIEPCIBridge; + +#define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge" +#define PCIE_PCI_BRIDGE_DEV(obj) \ +OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV) + +static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp) +{ +PCIBridge *br = PCI_BRIDGE(d); +PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d); +int rc, pos; + +pci_bridge_initfn(d, TYPE_PCI_BUS); + +d->config[PCI_INTERRUPT_PIN] = 0x1; +memory_region_init(_br->shpc_bar, OBJECT(d), "shpc-bar", + shpc_bar_size(d)); +rc = shpc_init(d, >sec_bus, _br->shpc_bar, 0, errp); +if (rc) { +goto error; +} + +rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, errp); +if (rc < 0) { +goto cap_error; +} + +pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp); +if (pos < 0) { +goto pm_error; +} +d->exp.pm_cap = pos; +pci_set_word(d->config + pos + PCI_PM_PMC, 0x3); + +pcie_cap_arifwd_init(d); +pcie_cap_deverr_init(d); + +rc = pcie_aer_init(d, PCI_ERR_VER, 0x100, PCI_ERR_SIZEOF, errp); +if (rc < 0) { +goto aer_error; +} + +if (pcie_br->msi != ON_OFF_AUTO_OFF) { +rc = msi_init(d, 0, 1, true, true, errp); +if (rc < 0) { +goto msi_error; +} +} +pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, _br->shpc_bar); +return; + +msi_error: +pcie_aer_exit(d); +aer_error: +pm_error: +pcie_cap_exit(d); +cap_error: +shpc_free(d); +error: +pci_bridge_exitfn(d); +} + +static void pcie_pci_bridge_exit(PCIDevice *d) +{ +PCIEPCIBridge *bridge_dev = PCIE_PCI_BRIDGE_DEV(d); +pcie_cap_exit(d); +shpc_cleanup(d, _dev->shpc_bar); +pci_bridge_exitfn(d); +} + +static void pcie_pci_bridge_reset(DeviceState *qdev) +{ +PCIDevice *d = PCI_DEVICE(qdev); +pci_bridge_reset(qdev); +msi_reset(d); +shpc_reset(d); +} + +static void pcie_pci_bridge_write_config(PCIDevice *d, +uint32_t address, uint32_t val, int len) +{ +pci_bridge_write_config(d, address, val, len); +msi_write_config(d, address, val, len); +shpc_cap_write_config(d, address, val, len); +} + +static Property pcie_pci_bridge_dev_properties[] = { +DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON), +DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription pcie_pci_bridge_dev_vmstate = { +.name = TYPE_PCIE_PCI_BRIDGE_DEV, +.fields = (VMStateField[]) { +VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), +SHPC_VMSTATE(shpc, PCIDevice, NULL), +VMSTATE_END_OF_LIST() +} +}; + +static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ +PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev); + +if (!shpc_present(pci_hotplug_dev)) { +error_setg(errp, "standard hotplug controller has been disabled for " + "this %s", TYPE_PCIE_PCI_BRIDGE_DEV); +return; +} +