Skip to content

Commit

Permalink
hw/pci: introduce bridge-only vendor-specific capability to provide s…
Browse files Browse the repository at this point in the history
…ome 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 Bezzubikov <zuban32s@gmail.com>
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
Tested-by: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
zuban32 authored and mstsirkin committed Sep 8, 2017
1 parent a35fe22 commit 70e1ee5
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
46 changes: 46 additions & 0 deletions hw/pci/pci_bridge.c
Expand Up @@ -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 *)&cap + 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,
Expand Down
25 changes: 25 additions & 0 deletions include/hw/pci/pci_bridge.h
Expand Up @@ -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 */

0 comments on commit 70e1ee5

Please sign in to comment.