From 1fddf943d8d0e67ad30fa44d86114a254de853f9 Mon Sep 17 00:00:00 2001 From: Li Fei1 Date: Thu, 19 Dec 2019 23:29:50 +0800 Subject: [PATCH] hv: vpci: restore PCI BARs when doing AF FLR ACRN hypervisor should trap guest doing PCI AF FLR. Besides, it should save some status before doing the FLR and restore them later, only BARs values for now. This patch will trap guest Conventional PCI Advanced Features Control Register write operation if the device supports Conventional PCI Advanced Features Capability and check whether it wants to do device AF FLR. If it does, call pdev_do_flr to do the job. Tracked-On: #3465 Signed-off-by: Li Fei1 --- hypervisor/dm/vpci/pci_pt.c | 2 ++ hypervisor/dm/vpci/vpci.c | 5 +++-- hypervisor/hw/pci.c | 11 ++++++++--- hypervisor/include/dm/vpci.h | 3 +++ hypervisor/include/hw/pci.h | 10 ++++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index 124eb056e..424869019 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -235,6 +235,8 @@ void init_vdev_pt(struct pci_vdev *vdev) vdev->has_flr = vdev->pdev->has_flr; vdev->pcie_capoff = vdev->pdev->pcie_capoff; + vdev->has_af_flr = vdev->pdev->has_af_flr; + vdev->af_capoff = vdev->pdev->af_capoff; for (idx = 0U; idx < vdev->nr_bars; idx++) { vbar = &vdev->bar[idx]; diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 9f146653b..561bf4c98 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -337,8 +337,9 @@ static int32_t vpci_write_pt_dev_cfg(struct pci_vdev *vdev, uint32_t offset, vmsi_write_cfg(vdev, offset, bytes, val); } else if (msixcap_access(vdev, offset)) { vmsix_write_cfg(vdev, offset, bytes, val); - } else if (vdev->has_flr && ((vdev->pcie_capoff + PCIR_PCIE_DEVCTRL) == offset) && - ((val & PCIM_PCIE_FLR) != 0U)) { + } else if ((vdev->has_flr && ((vdev->pcie_capoff + PCIR_PCIE_DEVCTRL) == offset) && + ((val & PCIM_PCIE_FLR) != 0U)) || (vdev->has_af_flr && + ((vdev->af_capoff + PCIR_AF_CTRL) == offset) && ((val & PCIM_AF_FLR) != 0U))) { /* Assume that guest write FLR must be 4 bytes aligned */ pdev_do_flr(vdev->pdev->bdf, offset, bytes, val); } else { diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index 1da24fcdb..f364cab51 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -418,7 +418,7 @@ static void pci_read_cap(struct pci_pdev *pdev) uint32_t msgctrl; uint32_t len, offset, idx; uint32_t table_info; - uint32_t pcie_devcap; + uint32_t pcie_devcap, val; ptr = (uint8_t)pci_pdev_read_cfg(pdev->bdf, PCIR_CAP_PTR, 1U); @@ -426,7 +426,7 @@ static void pci_read_cap(struct pci_pdev *pdev) cap = (uint8_t)pci_pdev_read_cfg(pdev->bdf, ptr + PCICAP_ID, 1U); /* Ignore all other Capability IDs for now */ - if ((cap == PCIY_MSI) || (cap == PCIY_MSIX) || (cap == PCIY_PCIE)) { + if ((cap == PCIY_MSI) || (cap == PCIY_MSIX) || (cap == PCIY_PCIE) || (cap == PCIY_AF)) { offset = ptr; if (cap == PCIY_MSI) { pdev->msi_capoff = offset; @@ -451,11 +451,16 @@ static void pci_read_cap(struct pci_pdev *pdev) for (idx = 0U; idx < len; idx++) { pdev->msix.cap[idx] = (uint8_t)pci_pdev_read_cfg(pdev->bdf, offset + idx, 1U); } - } else { + } else if (cap == PCIY_PCIE) { /* PCI Express Capability */ pdev->pcie_capoff = offset; pcie_devcap = pci_pdev_read_cfg(pdev->bdf, offset + PCIR_PCIE_DEVCAP, 4U); pdev->has_flr = ((pcie_devcap & PCIM_PCIE_FLRCAP) != 0U) ? true : false; + } else { + /* Conventional PCI Advanced Features Capability */ + pdev->af_capoff = offset; + val = pci_pdev_read_cfg(pdev->bdf, offset, 4U); + pdev->has_af_flr = ((val & PCIM_AF_FLR_CAP) != 0U) ? true : false; } } diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index 1e3642417..dfe970962 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -102,6 +102,9 @@ struct pci_vdev { bool has_flr; uint32_t pcie_capoff; + bool has_af_flr; + uint32_t af_capoff; + /* Pointer to corresponding PCI device's vm_config */ struct acrn_vm_pci_dev_config *pci_dev_config; diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index 95dd936dc..a43aeaa54 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -138,6 +138,12 @@ #define PCIM_PCIE_FLRCAP (0x1U << 28U) #define PCIM_PCIE_FLR (0x1U << 15U) +/* Conventional PCI Advanced Features Capability */ +#define PCIY_AF 0x13U +#define PCIM_AF_FLR_CAP (0x1U << 25U) +#define PCIR_AF_CTRL 0x4U +#define PCIM_AF_FLR 0x1U + #define HOST_BRIDGE_BDF 0U #define PCI_STD_NUM_BARS 6U @@ -189,6 +195,10 @@ struct pci_pdev { /* Function Level Reset Capability */ bool has_flr; uint32_t pcie_capoff; + + /* Conventional PCI Advanced Features FLR Capability */ + bool has_af_flr; + uint32_t af_capoff; }; static inline uint32_t pci_bar_offset(uint32_t idx)