From 8137e49e177db7515ac4c162c4eb0ed5bdd165f4 Mon Sep 17 00:00:00 2001 From: Yonghua Huang Date: Mon, 19 Oct 2020 11:17:44 +0800 Subject: [PATCH] hv: add functions to initialize vmsix capability - add 'vpci_add_capability()' to initialize one PCI capability in config space. - add 'add_vmsix_capability()' to add vmsix capability. Tracked-On: #5407 Signed-off-by: Yonghua Huang Reviewed-by: Li, Fei Reviewed-by: Wang, Yu1 Acked-by: Eddie Dong --- hypervisor/dm/vpci/vmsix.c | 40 +++++++++++++++++++++++++ hypervisor/dm/vpci/vpci.c | 53 ++++++++++++++++++++++++++++++++++ hypervisor/dm/vpci/vpci_priv.h | 11 +++++++ hypervisor/include/dm/vpci.h | 11 +++++++ hypervisor/include/lib/util.h | 3 ++ 5 files changed, 118 insertions(+) diff --git a/hypervisor/dm/vpci/vmsix.c b/hypervisor/dm/vpci/vmsix.c index 3d876fb1c..482121c9d 100644 --- a/hypervisor/dm/vpci/vmsix.c +++ b/hypervisor/dm/vpci/vmsix.c @@ -109,3 +109,43 @@ int32_t vmsix_handle_table_mmio_access(struct io_request *io_req, void *priv_dat (void)rw_vmsix_table((struct pci_vdev *)priv_data, io_req); return 0; } + +/** + * @pre vdev != NULL + */ +int32_t add_vmsix_capability(struct pci_vdev *vdev, uint32_t entry_num, uint8_t bar_num) +{ + uint32_t table_size, i; + struct msixcap msixcap; + int32_t ret = -1; + + if ((bar_num < PCI_BAR_COUNT) && + (entry_num <= min(CONFIG_MAX_MSIX_TABLE_NUM, VMSIX_MAX_TABLE_ENTRY_NUM))) { + + table_size = VMSIX_MAX_ENTRY_TABLE_SIZE; + + vdev->msix.caplen = MSIX_CAPLEN; + vdev->msix.table_bar = bar_num; + vdev->msix.table_offset = 0U; + vdev->msix.table_count = entry_num; + + /* set mask bit of vector control register */ + for (i = 0; i < entry_num; i++) + vdev->msix.table_entries[i].vector_control |= PCIM_MSIX_VCTRL_MASK; + + (void)memset(&msixcap, 0U, sizeof(struct msixcap)); + + msixcap.capid = PCIY_MSIX; + msixcap.msgctrl = entry_num - 1U; + + /* - MSI-X table start at offset 0 */ + msixcap.table_info = bar_num; + msixcap.pba_info = table_size | bar_num; + + vdev->msix.capoff = vpci_add_capability(vdev, (uint8_t *)(&msixcap), sizeof(struct msixcap)); + if (vdev->msix.capoff != 0U) { + ret = 0; + } + } + return ret; +} diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 069d54fda..f2ca56fe9 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -791,3 +791,56 @@ void vpci_update_one_vbar(struct pci_vdev *vdev, uint32_t bar_idx, uint32_t val, vdev->vbars[update_idx].base_gpa = 0UL; } } + +/* + * @brief Add emulated legacy PCI capability support for virtual PCI device + * + * @param vdev Pointer to vdev data structure + * @param capdata Pointer to buffer that holds the capability data to be added. + * @param caplen Length of buffer that holds the capability data to be added. + * + * @pre vdev != NULL + * @pre vdev->vpci != NULL + * + * @return None + */ +uint32_t vpci_add_capability(struct pci_vdev *vdev, uint8_t *capdata, uint8_t caplen) +{ +#define CAP_START_OFFSET PCI_CFG_HEADER_LENGTH + + uint8_t capoff, reallen; + uint16_t sts; + uint32_t ret = 0U; + + reallen = roundup(caplen, 4U); /* dword aligned */ + + sts = pci_vdev_read_vcfg(vdev, PCIR_STATUS, 2U); + if ((sts & PCIM_STATUS_CAPPRESENT) == 0U) { + capoff = CAP_START_OFFSET; + } else { + capoff = vdev->free_capoff; + } + + /* Check if we have enough space */ + if (((uint16_t)capoff + reallen) <= PCI_CONFIG_SPACE_SIZE) { + /* Set the previous capability pointer */ + if ((sts & PCIM_STATUS_CAPPRESENT) == 0U) { + pci_vdev_write_vcfg(vdev, PCIR_CAP_PTR, 1U, capoff); + pci_vdev_write_vcfg(vdev, PCIR_STATUS, 2U, sts|PCIM_STATUS_CAPPRESENT); + } else { + pci_vdev_write_vcfg(vdev, vdev->prev_capoff + 1U, 1U, capoff); + } + + /* Copy the capability */ + (void)memcpy_s((void *)&vdev->cfgdata.data_8[capoff], caplen, (void *)capdata, caplen); + + /* Set the next capability pointer */ + pci_vdev_write_vcfg(vdev, capoff + 1U, 1U, 0U); + + vdev->prev_capoff = capoff; + vdev->free_capoff = capoff + reallen; + ret = capoff; + } + + return ret; +} diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index e91f94294..575e38c65 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -33,6 +33,15 @@ #include #include +/* + * For hypervisor emulated PCI devices, vMSIX Table contains 128 entries + * at most. vMSIX Table begins at an offset of 0, and maps the vMSIX PBA + * beginning at an offset of 2 KB. + */ +#define VMSIX_MAX_TABLE_ENTRY_NUM 128U +#define VMSIX_MAX_ENTRY_TABLE_SIZE 2048U +#define VMSIX_ENTRY_TABLE_PBA_BAR_SIZE 4096U + static inline struct acrn_vm *vpci2vm(const struct acrn_vpci *vpci) { return container_of(vpci, struct acrn_vm, vpci); @@ -144,6 +153,7 @@ void write_vmsi_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, void deinit_vmsi(const struct pci_vdev *vdev); void init_vmsix_pt(struct pci_vdev *vdev); +int32_t add_vmsix_capability(struct pci_vdev *vdev, uint32_t entry_num, uint8_t bar_num); bool write_vmsix_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); void write_pt_vmsix_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); uint32_t rw_vmsix_table(struct pci_vdev *vdev, struct io_request *io_req); @@ -160,6 +170,7 @@ uint32_t sriov_bar_offset(const struct pci_vdev *vdev, uint32_t bar_idx); uint32_t pci_vdev_read_vcfg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes); void pci_vdev_write_vcfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); +uint32_t vpci_add_capability(struct pci_vdev *vdev, uint8_t *capdata, uint8_t caplen); uint32_t pci_vdev_read_vbar(const struct pci_vdev *vdev, uint32_t idx); void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val); diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index 7c856fce3..f530a31f4 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -60,6 +60,14 @@ struct pci_msi { }; /* MSI-X capability structure */ +struct msixcap { + uint8_t capid; + uint8_t nextptr; + uint16_t msgctrl; + uint32_t table_info; /* bar index and offset */ + uint32_t pba_info; /* bar index and offset */ +} __packed; + struct pci_msix { struct msix_table_entry table_entries[CONFIG_MAX_MSIX_TABLE_NUM]; uint64_t mmio_gpa; @@ -115,6 +123,9 @@ struct pci_vdev { uint32_t nr_bars; /* 6 for normal device, 2 for bridge, 1 for cardbus */ struct pci_vbar vbars[PCI_BAR_COUNT]; + uint8_t prev_capoff; /* Offset of previous vPCI capability */ + uint8_t free_capoff; /* Next free offset to add vPCI capability */ + struct pci_msi msi; struct pci_msix msix; struct pci_cap_sriov sriov; diff --git a/hypervisor/include/lib/util.h b/hypervisor/include/lib/util.h index 5f4a96e5f..8ed6c5b08 100644 --- a/hypervisor/include/lib/util.h +++ b/hypervisor/include/lib/util.h @@ -15,6 +15,9 @@ /** Roundup (x/y) to ( x/y + (x%y) ? 1 : 0) **/ #define INT_DIV_ROUNDUP(x, y) ((((x)+(y))-1)/(y)) +/** Roundup (x) to (y) aligned **/ +#define roundup(x, y) (((x) + ((y) - 1UL)) & (~((y) - 1UL))) + #define min(x, y) ((x) < (y)) ? (x) : (y) #define max(x, y) ((x) < (y)) ? (y) : (x)