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 <yonghua.huang@intel.com>
Reviewed-by: Li, Fei <fei1.li@intel.com>
Reviewed-by: Wang, Yu1 <yu1.wang@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Yonghua Huang 2020-10-19 11:17:44 +08:00 committed by wenlingz
parent cdfc82f03b
commit 8137e49e17
5 changed files with 118 additions and 0 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -33,6 +33,15 @@
#include <list.h>
#include <pci.h>
/*
* 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);

View File

@ -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;

View File

@ -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)