PCI: vmd: Use Shadow MEMBAR registers for QEMU/KVM guests

VMD device 28C0 natively assists guest passthrough of the VMD endpoint
through the use of shadow registers that provide Host Physical Addresses
to correctly assign bridge windows. These shadow registers are only
available if VMD config space register 0x70, bit 1 is set.

In order to support this mode in existing VMD devices which don't
natively support the shadow register, it was decided that the hypervisor
could offer the shadow registers in a vendor-specific PCI capability.

QEMU has been modified to create this vendor-specific capability and
supply the shadow membar registers for VMDs which don't natively support
this feature. This patch adds this mode and updates the supported device
list to allow this feature to be used on these VMDs.

Link: https://lore.kernel.org/r/20200528030240.16024-4-jonathan.derrick@intel.com
Signed-off-by: Jon Derrick <jonathan.derrick@intel.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
This commit is contained in:
Jon Derrick 2020-05-27 23:02:40 -04:00 коммит произвёл Lorenzo Pieralisi
Родитель b3a9e3b962
Коммит 51f939b11c
1 изменённых файлов: 38 добавлений и 6 удалений

Просмотреть файл

@ -40,13 +40,19 @@ enum vmd_features {
* membars, in order to allow proper address translation during
* resource assignment to enable guest virtualization
*/
VMD_FEAT_HAS_MEMBAR_SHADOW = (1 << 0),
VMD_FEAT_HAS_MEMBAR_SHADOW = (1 << 0),
/*
* Device may provide root port configuration information which limits
* bus numbering
*/
VMD_FEAT_HAS_BUS_RESTRICTIONS = (1 << 1),
VMD_FEAT_HAS_BUS_RESTRICTIONS = (1 << 1),
/*
* Device contains physical location shadow registers in
* vendor-specific capability space
*/
VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2),
};
/*
@ -454,6 +460,28 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
}
}
if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
int pos = pci_find_capability(vmd->dev, PCI_CAP_ID_VNDR);
u32 reg, regu;
pci_read_config_dword(vmd->dev, pos + 4, &reg);
/* "SHDW" */
if (pos && reg == 0x53484457) {
pci_read_config_dword(vmd->dev, pos + 8, &reg);
pci_read_config_dword(vmd->dev, pos + 12, &regu);
offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
(((u64) regu << 32 | reg) &
PCI_BASE_ADDRESS_MEM_MASK);
pci_read_config_dword(vmd->dev, pos + 16, &reg);
pci_read_config_dword(vmd->dev, pos + 20, &regu);
offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
(((u64) regu << 32 | reg) &
PCI_BASE_ADDRESS_MEM_MASK);
}
}
/*
* Certain VMD devices may have a root port configuration option which
* limits the bus range to between 0-127, 128-255, or 224-255
@ -716,16 +744,20 @@ static int vmd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);
static const struct pci_device_id vmd_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{0,}
};
MODULE_DEVICE_TABLE(pci, vmd_ids);