hv: vpci: refine vPCI BAR initialization

Initialize vBAR configure space when doing vPCI BAR initialization. At this time,
we access the physical device as we needs, no need to cache physical PCI device
BAR information beforehand.

Tracked-On: #3475
Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
Li, Fei1 2019-09-16 21:24:48 +08:00 committed by wenlingz
parent 153a5992f5
commit 535a83e24b
3 changed files with 54 additions and 152 deletions

View File

@ -434,69 +434,72 @@ void vdev_pt_write_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, u
*/
void init_vdev_pt(struct pci_vdev *vdev)
{
enum pci_bar_type type;
uint32_t idx;
struct pci_bar *pbar, *vbar;
struct pci_bar *vbar;
uint16_t pci_command;
uint64_t vbar_base;
uint32_t size32, offset, lo, hi = 0U;
union pci_bdf pbdf;
uint64_t mask;
vdev->nr_bars = vdev->pdev->nr_bars;
ASSERT(vdev->nr_bars > 0U, "vdev->nr_bars should be greater than 0!");
pbdf.value = vdev->pdev->bdf.value;
for (idx = 0U; idx < vdev->nr_bars; idx++) {
pbar = &vdev->pdev->bar[idx];
vbar = &vdev->bar[idx];
offset = pci_bar_offset(idx);
lo = pci_pdev_read_cfg(pbdf, offset, 4U);
vbar->size = 0UL;
vbar->reg.value = pbar->reg.value;
vbar->is_64bit_high = pbar->is_64bit_high;
vbar->base_hpa = pbar->base_hpa;
type = pci_get_bar_type(lo);
if (type == PCIBAR_NONE) {
continue;
}
mask = (type == PCIBAR_IO_SPACE) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
vbar->base_hpa = (uint64_t)lo & mask;
if (pbar->is_64bit_high) {
ASSERT(idx > 0U, "idx for upper 32-bit of the 64-bit bar should be greater than 0!");
if (type == PCIBAR_MEM64) {
hi = pci_pdev_read_cfg(pbdf, offset + 4U, 4U);
vbar->base_hpa |= ((uint64_t)hi << 32U);
}
if (is_sos_vm(vdev->vpci->vm)) {
/* For SOS: vbar base (GPA) = pbar base (HPA) */
vbar_base = vdev->bar[idx - 1U].base_hpa;
} else if (idx > 0U) {
/* For pre-launched VMs: vbar base is predefined in vm_config */
vbar_base = vdev->pci_dev_config->vbar_base[idx - 1U];
} else {
vbar_base = 0UL;
if (vbar->base_hpa != 0UL) {
pci_pdev_write_cfg(pbdf, offset, 4U, ~0U);
size32 = pci_pdev_read_cfg(pbdf, offset, 4U);
pci_pdev_write_cfg(pbdf, offset, 4U, lo);
vbar->size = (uint64_t)size32 & mask;
vbar->reg.value = lo;
if (is_prelaunched_vm(vdev->vpci->vm)) {
lo = (uint32_t)vdev->pci_dev_config->vbar_base[idx];
}
/* Write the upper 32-bit of a 64-bit bar */
vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)(vbar_base >> 32U));
} else {
enum pci_bar_type type = pci_get_bar_type(pbar->reg.value);
switch (type) {
case PCIBAR_MEM32:
case PCIBAR_MEM64:
/**
* If vbar->base is 0 (unassigned), Linux kernel will reprogram the vbar on
* its bar size boundary, so in order to ensure the MMIO vbar allocated by guest
* is 4k aligned, set its size to be 4K aligned.
*/
vbar->size = round_page_up(pbar->size);
if (type == PCIBAR_MEM64) {
idx++;
offset = pci_bar_offset(idx);
pci_pdev_write_cfg(pbdf, offset, 4U, ~0U);
size32 = pci_pdev_read_cfg(pbdf, offset, 4U);
pci_pdev_write_cfg(pbdf, offset, 4U, hi);
if (is_sos_vm(vdev->vpci->vm)) {
/* For SOS: vbar base (GPA) = pbar base (HPA) */
vbar_base = vbar->base_hpa;
} else {
/* For pre-launched VMs: vbar base is predefined in vm_config */
vbar_base = vdev->pci_dev_config->vbar_base[idx];
vbar->size |= ((uint64_t)size32 << 32U);
vbar->size = vbar->size & ~(vbar->size - 1UL);
vbar->size = round_page_up(vbar->size);
vbar = &vdev->bar[idx];
vbar->is_64bit_high = true;
vbar->reg.value = hi;
if (is_prelaunched_vm(vdev->vpci->vm)) {
hi = (uint32_t)(vdev->pci_dev_config->vbar_base[idx - 1U] >> 32U);
}
vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)vbar_base);
break;
case PCIBAR_IO_SPACE:
vbar->size = pbar->size;
vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)vbar->base_hpa);
break;
default:
/* Nothing to do in this case */
break;
vdev_pt_write_vbar(vdev, pci_bar_offset(idx - 1U), lo);
vdev_pt_write_vbar(vdev, pci_bar_offset(idx), hi);
} else {
vbar->size = vbar->size & ~(vbar->size - 1UL);
if (type == PCIBAR_MEM32) {
vbar->size = round_page_up(vbar->size);
}
vdev_pt_write_vbar(vdev, pci_bar_offset(idx), lo);
}
}
}

View File

@ -213,106 +213,6 @@ static uint32_t pci_pdev_get_nr_bars(uint8_t hdr_type)
return nr_bars;
}
/* Get the base address of the raw bar value (val) */
static inline uint32_t pci_pdev_get_bar_base(uint32_t bar_val)
{
uint32_t base;
union pci_bar_reg reg;
/* set raw bar value */
reg.value = bar_val;
/* Extract base address portion from the raw bar value */
if (reg.bits.io.is_io != 0U) {
/* IO bar, BITS 31-2 = base address, 4-byte aligned */
base = (uint32_t)(reg.bits.io.base);
base <<= 2U;
} else {
/* MMIO bar, BITS 31-4 = base address, 16-byte aligned */
base = (uint32_t)(reg.bits.mem.base);
base <<= 4U;
}
return base;
}
/*
* @pre bar != NULL
*/
static uint32_t pci_pdev_read_bar(union pci_bdf bdf, uint32_t idx, struct pci_bar *bar)
{
uint64_t base, size;
enum pci_bar_type type;
uint32_t bar_lo, bar_hi, size_lo;
bar->reg.value = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U);
base = 0UL;
size = 0UL;
type = pci_get_bar_type(bar->reg.value);
bar_hi = 0U;
if (type != PCIBAR_NONE) {
bar_lo = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U);
base = (uint64_t)pci_pdev_get_bar_base(bar_lo);
if (type == PCIBAR_MEM64) {
bar_hi = pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U);
base |= ((uint64_t)bar_hi << 32U);
}
if (base != 0UL) {
/* Sizing the BAR */
if ((type == PCIBAR_MEM64) && (idx < (PCI_BAR_COUNT - 1U))) {
pci_pdev_write_cfg(bdf, pci_bar_offset(idx + 1U), 4U, ~0U);
size = (uint64_t)pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U);
size <<= 32U;
}
pci_pdev_write_cfg(bdf, pci_bar_offset(idx), 4U, ~0U);
size_lo = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U);
size |= (uint64_t)pci_pdev_get_bar_base(size_lo);
if (size != 0UL) {
size = size & ~(size - 1U);
}
/* Restore the BAR */
pci_pdev_write_cfg(bdf, pci_bar_offset(idx), 4U, bar_lo);
if (type == PCIBAR_MEM64) {
pci_pdev_write_cfg(bdf, pci_bar_offset(idx + 1U), 4U, bar_hi);
}
}
}
bar->size = size;
bar->base_hpa = base;
return (type == PCIBAR_MEM64)?2U:1U;
}
/*
* @pre nr_bars <= PCI_BAR_COUNT
*/
static void pci_pdev_read_bars(union pci_bdf bdf, uint32_t nr_bars, struct pci_bar *bar)
{
uint32_t idx = 0U;
uint32_t bar_step;
while (idx < nr_bars) {
bar_step = pci_pdev_read_bar(bdf, idx, &bar[idx]);
if ((bar_step == 2U) && ((idx + 1U) < nr_bars)) {
/* Upper 32-bit of a 64-bit bar: */
bar[idx + 1U].is_64bit_high = true;
bar[idx + 1U].reg.value = pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U);
}
idx += bar_step;
}
}
/*
* @pre ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_NORMAL) || ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) || ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_CARDBUS)
*/
@ -411,8 +311,6 @@ static void fill_pdev(uint16_t pbdf, struct pci_pdev *pdev)
pdev->nr_bars = pci_pdev_get_nr_bars(hdr_type);
pci_pdev_read_bars(pdev->bdf, pdev->nr_bars, &pdev->bar[0]);
if ((pci_pdev_read_cfg(pdev->bdf, PCIR_STATUS, 2U) & PCIM_STATUS_CAPPRESENT) != 0U) {
pci_read_cap(pdev, hdr_type);
}

View File

@ -85,6 +85,8 @@
#define PCIM_BAR_MEM_BASE 0xFFFFFFF0U
#define PCIR_CAP_PTR 0x34U
#define PCIR_CAP_PTR_CARDBUS 0x14U
#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
/* config registers for header type 1 (PCI-to-PCI bridge) devices */
#define PCIR_PRIBUS_1 0x18U
@ -209,7 +211,6 @@ struct pci_msix_cap {
struct pci_pdev {
/* The bar info of the physical PCI device. */
uint32_t nr_bars; /* 6 for normal device, 2 for bridge, 1 for cardbus */
struct pci_bar bar[PCI_BAR_COUNT];
/* The bus/device/function triple of the physical PCI device. */
union pci_bdf bdf;