hv: pci: restore bus and memory/IO info after reset

After some kind of reset, such as s3, pci bridge tries to restore the
bus and memory/IO info (from 0x18 to 0x32, except for Secondary Latency
Timer 0x1b) to resume device state.

This patch is to restore these info by hypervisor.

Tracked-On: #8623
Signed-off-by: Haiwei Li <haiwei.li@intel.com>
This commit is contained in:
Haiwei Li 2023-09-08 10:12:15 +08:00 committed by acrnsi-robot
parent 81935737ff
commit 2cd0edaf9c
4 changed files with 69 additions and 4 deletions

View File

@ -315,6 +315,53 @@ void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val)
}
}
/*
* @pre vdev != NULL
* @pre vdev->pdev != NULL
*/
void vdev_bridge_pt_restore_space(struct pci_vdev *vdev)
{
struct pci_pdev *pdev = vdev->pdev;
uint32_t pre_val;
uint32_t offset;
/* I/O Base (0x1c) and I/O Limit (0x1d) */
pre_val = pci_vdev_read_vcfg(vdev, PCIR_IO_BASE, 2U);
if (pre_val != pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_IO_BASE, 2U)) {
pci_pdev_write_cfg(pdev->bdf, PCIR_IO_BASE, 2U, pre_val);
}
/* From Memory Base (0x20) to I/O Base Limit 16 Bits (0x32) */
for (offset = PCIR_MEM_BASE; offset < PCIR_IO_BASE_UPPER_16; offset += 4) {
pre_val = pci_vdev_read_vcfg(vdev, offset, 4U);
if (pre_val != pci_pdev_read_cfg(vdev->pdev->bdf, offset, 4U)) {
pci_pdev_write_cfg(pdev->bdf, offset, 4U, pre_val);
}
}
}
/*
* @pre vdev != NULL
* @pre vdev->pdev != NULL
*/
void vdev_bridge_pt_restore_bus(struct pci_vdev *vdev)
{
struct pci_pdev *pdev = vdev->pdev;
uint32_t pre_val;
/* Primary Bus Number (0x18) and Secondary Bus Number (0x19) */
pre_val = pci_vdev_read_vcfg(vdev, PCIR_PRIBUS_1, 2U);
if (pre_val != pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_PRIBUS_1, 2U)) {
pci_pdev_write_cfg(pdev->bdf, PCIR_PRIBUS_1, 2U, pre_val);
}
/* Subordinate Bus Number (0x1a) */
pre_val = pci_vdev_read_vcfg(vdev, PCIR_SUBBUS_1, 1U);
if (pre_val != pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_SUBBUS_1, 1U)) {
pci_pdev_write_cfg(pdev->bdf, PCIR_SUBBUS_1, 1U, pre_val);
}
}
/**
* PCI base address register (bar) virtualization:
*

View File

@ -474,6 +474,7 @@ static int32_t read_cfg_header(const struct pci_vdev *vdev,
static int32_t write_cfg_header(struct pci_vdev *vdev,
uint32_t offset, uint32_t bytes, uint32_t val)
{
bool dev_is_bridge = is_bridge(vdev->pdev);
int32_t ret = 0;
if ((offset == PCIR_BIOS) && is_quirk_ptdev(vdev)) {
@ -489,10 +490,20 @@ static int32_t write_cfg_header(struct pci_vdev *vdev,
#define PCIM_SPACE_EN (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)
uint16_t phys_cmd = (uint16_t)pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U);
/* check whether need to restore BAR because some kind of reset */
if (((phys_cmd & PCIM_SPACE_EN) == 0U) && ((val & PCIM_SPACE_EN) != 0U) &&
pdev_need_bar_restore(vdev->pdev)) {
pdev_restore_bar(vdev->pdev);
if (((phys_cmd & PCIM_SPACE_EN) == 0U) && ((val & PCIM_SPACE_EN) != 0U)) {
/* check whether need to restore BAR because some kind of reset */
if (pdev_need_bar_restore(vdev->pdev)) {
pdev_restore_bar(vdev->pdev);
}
/* check whether need to restore bridge mem/IO related registers because some kind of reset */
if (dev_is_bridge) {
vdev_bridge_pt_restore_space(vdev);
}
}
/* check whether need to restore Primary/Secondary/Subordinate Bus Number registers because some kind of reset */
if (dev_is_bridge && ((phys_cmd & PCIM_CMD_BUSEN) == 0U) && ((val & PCIM_CMD_BUSEN) != 0U)) {
vdev_bridge_pt_restore_bus(vdev);
}
}

View File

@ -177,6 +177,9 @@ uint32_t vpci_add_capability(struct pci_vdev *vdev, uint8_t *capdata, uint8_t ca
void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val);
void vdev_bridge_pt_restore_space(struct pci_vdev *vdev);
void vdev_bridge_pt_restore_bus(struct pci_vdev *vdev);
void vdev_pt_hide_sriov_cap(struct pci_vdev *vdev);
int32_t check_pt_dev_pio_bars(struct pci_vdev *vdev);

View File

@ -69,6 +69,7 @@
#define PCIR_COMMAND 0x04U
#define PCIM_CMD_PORTEN 0x01U
#define PCIM_CMD_MEMEN 0x02U
#define PCIM_CMD_BUSEN 0x04U
#define PCIM_CMD_INTxDIS 0x400U
#define PCIR_STATUS 0x06U
#define PCIM_STATUS_CAPPRESENT 0x0010U
@ -105,6 +106,9 @@
#define PCIR_PRIBUS_1 0x18U
#define PCIR_SECBUS_1 0x19U
#define PCIR_SUBBUS_1 0x1AU
#define PCIR_IO_BASE 0x1CU
#define PCIR_MEM_BASE 0x20U
#define PCIR_IO_BASE_UPPER_16 0x30U
/* Capability Register Offsets */
#define PCICAP_ID 0x0U