diff --git a/hypervisor/dm/vpci/vroot_port.c b/hypervisor/dm/vpci/vroot_port.c index f9acac45f..fa73884a7 100644 --- a/hypervisor/dm/vpci/vroot_port.c +++ b/hypervisor/dm/vpci/vroot_port.c @@ -40,10 +40,32 @@ static void init_vrp(struct pci_vdev *vdev) /* capability pointer */ pci_vdev_write_vcfg(vdev, PCIR_CAP_PTR, 1U, PCIE_CAP_VPOS); - /* pcie capability registers */ - pci_vdev_write_vcfg(vdev, PCIE_CAP_VPOS + PCICAP_ID, 1U, 0x10); + /* pcie capability registers */ + pci_vdev_write_vcfg(vdev, PCIE_CAP_VPOS + PCICAP_ID, 1U, PCIY_PCIE); + + /* bits (3:0): capability version = 010b + * bits (7:4) device/port type = 0100b (root port of pci-e) + * bits (8) -- slot implemented = 1b + */ pci_vdev_write_vcfg(vdev, PCIE_CAP_VPOS + PCICAP_EXP_CAP, 2U, 0x0142); + /* It seems important that passthru device's max payload settings match + * the settings on the native device otherwise passthru device may not work. + * So we have to set vrp's max payload capacity as native root port + * otherwise we may accidentally change passthru device's max payload since + * during guest OS's pci device enumeration, pass-thru device will renegotiate + * its max payload's setting with vrp. + */ + pci_vdev_write_vcfg(vdev, PCIE_CAP_VPOS + PCIR_PCIE_DEVCAP, 4U, + vdev->pci_dev_config->vrp_max_payload); + + /* In theory, we don't need to program dev ctr's max payload and hopefully OS + * will program it but we cannot always rely on OS to program + * this register. + */ + pci_vdev_write_vcfg(vdev, PCIE_CAP_VPOS + PCIR_PCIE_DEVCTRL, 2U, + (vdev->pci_dev_config->vrp_max_payload << 5) & PCIM_PCIE_DEV_CTRL_MAX_PAYLOAD); + vdev->parent_user = NULL; vdev->user = vdev; } @@ -114,6 +136,7 @@ int32_t create_vrp(struct acrn_vm *vm, struct acrn_emul_dev *dev) if (dev_config->vrp_sec_bus == vrp_config->secondary_bus) { dev_config->vbdf.value = dev->slot; dev_config->pbdf.value = vrp_config->phy_bdf; + dev_config->vrp_max_payload = vrp_config->max_payload; dev_config->vdev_ops = &vrp_ops; vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL); diff --git a/hypervisor/include/arch/x86/asm/vm_config.h b/hypervisor/include/arch/x86/asm/vm_config.h index 5e146f0ad..d179bdd90 100644 --- a/hypervisor/include/arch/x86/asm/vm_config.h +++ b/hypervisor/include/arch/x86/asm/vm_config.h @@ -154,6 +154,7 @@ struct acrn_vm_pci_dev_config { struct target_vuart t_vuart; uint16_t vuart_idx; uint16_t vrp_sec_bus; /* use virtual root port's secondary bus as unique identification */ + uint8_t vrp_max_payload; /* vrp's dev cap's max payload */ uint64_t vbar_base[PCI_BAR_COUNT]; /* vbar base address of PCI device, which is power-on default value */ struct pci_pdev *pdev; /* the physical PCI device if it's a PT device */ const struct pci_vdev_ops *vdev_ops; /* operations for PCI CFG read/write */ diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index 749358748..dca0c58c4 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -185,6 +185,7 @@ #define PCIY_PCIE 0x10U #define PCIR_PCIE_DEVCAP 0x04U #define PCIR_PCIE_DEVCTRL 0x08U +#define PCIM_PCIE_DEV_CTRL_MAX_PAYLOAD 0x00E0U #define PCIM_PCIE_FLRCAP (0x1U << 28U) #define PCIM_PCIE_FLR (0x1U << 15U) diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h index ba5000662..ae4a26771 100644 --- a/hypervisor/include/public/acrn_common.h +++ b/hypervisor/include/public/acrn_common.h @@ -672,6 +672,7 @@ struct acrn_intr_monitor { struct vrp_config { uint16_t phy_bdf; + uint8_t max_payload; /* dev cap's max payload */ uint8_t primary_bus; uint8_t secondary_bus; uint8_t subordinate_bus;