hv: pci: Add guest cfg header access handling of type 1 device
When guests resume form s3, an error occurs in guest: ``` pcieport 0000:00:1c.0: refused to change power state from D0 to D3hot ``` PCI bridge (type 1 device) will access configuration space header but now acrn is not supported. So add handling support. Tracked-On: #8623 Signed-off-by: Haiwei Li <haiwei.li@intel.com>
This commit is contained in:
parent
2cd0edaf9c
commit
5283c147ef
|
@ -414,22 +414,41 @@ struct cfg_header_perm {
|
|||
*
|
||||
* For each mask, only low 16-bits takes effect.
|
||||
*
|
||||
* If bit x is set the pt_mask, it indicates that the corresponding 4 Bytes register
|
||||
* for bit x is pass through to guest. Otherwise, it's virtualized.
|
||||
* When guest read:
|
||||
* If bit x is set the pt_mask, it indicates that the corresponding 4 Bytes register for bit x is pass through to guest.
|
||||
* Otherwise, bit x is not set the pt_mask, it's virtualized.
|
||||
*
|
||||
* If bit x is set the ro_mask, it indicates that the corresponding 4 Bytes register
|
||||
* for bit x is read-only. Otherwise, it's writable.
|
||||
* When guest write:
|
||||
* If bit x is set the ro_mask, it indicates that the corresponding 4 Bytes register for bit x is not writable.
|
||||
* Otherwise, that is, bit x is not set the ro_mask,
|
||||
* If bit x is set the pt_mask, it indicates that the corresponding 4 Bytes register for bit x is pass through to guest.
|
||||
* If bit x is not set the pt_mask, it's virtualized.
|
||||
*/
|
||||
uint32_t pt_mask;
|
||||
uint32_t ro_mask;
|
||||
/* For type 0 device */
|
||||
uint32_t type0_pt_mask;
|
||||
uint32_t type0_ro_mask;
|
||||
/* For type 1 device */
|
||||
uint32_t type1_pt_mask;
|
||||
uint32_t type1_ro_mask;
|
||||
};
|
||||
|
||||
static const struct cfg_header_perm cfg_hdr_perm = {
|
||||
/* Only Command (0x04-0x05) and Status (0x06-0x07) Registers are pass through */
|
||||
.pt_mask = 0x0002U,
|
||||
.type0_pt_mask = 0x0002U,
|
||||
/* Command (0x04-0x05) and Status (0x06-0x07) Registers and
|
||||
* Base Address Registers (0x10-0x27) are writable */
|
||||
.ro_mask = (uint16_t)~0x03f2U
|
||||
.type0_ro_mask = (uint16_t)~0x03f2U,
|
||||
/* Command (0x04-0x05) and Status (0x06-0x07) Registers and
|
||||
* from Primary Bus Number to I/O Base Limit 16 Bits (0x18-0x33)
|
||||
* are pass through
|
||||
*/
|
||||
.type1_pt_mask = 0x1fc2U,
|
||||
/* Command (0x04-0x05) and Status (0x06-0x07) Registers and
|
||||
* Base Address Registers (0x10-0x17) and
|
||||
* Secondary Status (0x1e-0x1f) are writable
|
||||
* Note: should handle I/O Base (0x1c) specially
|
||||
*/
|
||||
.type1_ro_mask = (uint16_t)~0xb2U
|
||||
};
|
||||
|
||||
|
||||
|
@ -440,6 +459,7 @@ static int32_t read_cfg_header(const struct pci_vdev *vdev,
|
|||
uint32_t offset, uint32_t bytes, uint32_t *val)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint32_t pt_mask;
|
||||
|
||||
if ((offset == PCIR_BIOS) && is_quirk_ptdev(vdev)) {
|
||||
/* the access of PCIR_BIOS is emulated for quirk_ptdev */
|
||||
|
@ -452,8 +472,13 @@ static int32_t read_cfg_header(const struct pci_vdev *vdev,
|
|||
*val = ~0U;
|
||||
}
|
||||
} else {
|
||||
/* ToDo: add cfg_hdr_perm for Type 1 device */
|
||||
if (bitmap32_test(((uint16_t)offset) >> 2U, &cfg_hdr_perm.pt_mask)) {
|
||||
if (is_bridge(vdev->pdev)) {
|
||||
pt_mask = cfg_hdr_perm.type1_pt_mask;
|
||||
} else {
|
||||
pt_mask = cfg_hdr_perm.type0_pt_mask;
|
||||
}
|
||||
|
||||
if (bitmap32_test(((uint16_t)offset) >> 2U, &pt_mask)) {
|
||||
*val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes);
|
||||
|
||||
/* MSE(Memory Space Enable) bit always be set for an assigned VF */
|
||||
|
@ -476,6 +501,7 @@ static int32_t write_cfg_header(struct pci_vdev *vdev,
|
|||
{
|
||||
bool dev_is_bridge = is_bridge(vdev->pdev);
|
||||
int32_t ret = 0;
|
||||
uint32_t pt_mask, ro_mask;
|
||||
|
||||
if ((offset == PCIR_BIOS) && is_quirk_ptdev(vdev)) {
|
||||
/* the access of PCIR_BIOS is emulated for quirk_ptdev */
|
||||
|
@ -507,10 +533,25 @@ static int32_t write_cfg_header(struct pci_vdev *vdev,
|
|||
}
|
||||
}
|
||||
|
||||
/* ToDo: add cfg_hdr_perm for Type 1 device */
|
||||
if (!bitmap32_test(((uint16_t)offset) >> 2U, &cfg_hdr_perm.ro_mask)) {
|
||||
if (bitmap32_test(((uint16_t)offset) >> 2U, &cfg_hdr_perm.pt_mask)) {
|
||||
pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val);
|
||||
if (dev_is_bridge) {
|
||||
ro_mask = cfg_hdr_perm.type1_ro_mask;
|
||||
pt_mask = cfg_hdr_perm.type1_pt_mask;
|
||||
} else {
|
||||
ro_mask = cfg_hdr_perm.type0_ro_mask;
|
||||
pt_mask = cfg_hdr_perm.type0_pt_mask;
|
||||
}
|
||||
|
||||
if (!bitmap32_test(((uint16_t)offset) >> 2U, &ro_mask)) {
|
||||
if (bitmap32_test(((uint16_t)offset) >> 2U, &pt_mask)) {
|
||||
/* I/O Base (0x1c) and I/O Limit (0x1d) are read-only */
|
||||
if (!((offset == PCIR_IO_BASE) && (bytes <= 2)) && (offset != PCIR_IO_LIMIT)) {
|
||||
uint32_t value = val;
|
||||
if ((offset == PCIR_IO_BASE) && (bytes == 4U)) {
|
||||
uint16_t phys_val = (uint16_t)pci_pdev_read_cfg(vdev->pdev->bdf, offset, 2U);
|
||||
value = (val & PCIR_SECSTATUS_LINE_MASK) | phys_val;
|
||||
}
|
||||
pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, value);
|
||||
}
|
||||
} else {
|
||||
pci_vdev_write_vcfg(vdev, offset, bytes, val);
|
||||
}
|
||||
|
|
|
@ -107,8 +107,10 @@
|
|||
#define PCIR_SECBUS_1 0x19U
|
||||
#define PCIR_SUBBUS_1 0x1AU
|
||||
#define PCIR_IO_BASE 0x1CU
|
||||
#define PCIR_IO_LIMIT 0x1DU
|
||||
#define PCIR_MEM_BASE 0x20U
|
||||
#define PCIR_IO_BASE_UPPER_16 0x30U
|
||||
#define PCIR_SECSTATUS_LINE_MASK 0xFFFF0000U
|
||||
|
||||
/* Capability Register Offsets */
|
||||
#define PCICAP_ID 0x0U
|
||||
|
|
Loading…
Reference in New Issue