Merge branch 'remotes/lorenzo/pci/vmd'

- Program IRTE with Requester ID of VMD endpoint, not child device (Jon
  Derrick)

- Disable VMD MSI-X remapping when possible so children can use more MSI-X
  vectors (Jon Derrick)

* remotes/lorenzo/pci/vmd:
  PCI: vmd: Disable MSI-X remapping when possible
  iommu/vt-d: Use Real PCI DMA device for IRTE
This commit is contained in:
Bjorn Helgaas 2021-05-04 10:43:29 -05:00
commit 04dcc048f3
2 changed files with 53 additions and 13 deletions

View File

@ -1280,7 +1280,8 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
break;
case X86_IRQ_ALLOC_TYPE_PCI_MSI:
case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
set_msi_sid(irte,
pci_real_dma_dev(msi_desc_to_pci_dev(info->desc)));
break;
default:
BUG_ON(1);

View File

@ -28,6 +28,7 @@
#define BUS_RESTRICT_CAP(vmcap) (vmcap & 0x1)
#define PCI_REG_VMCONFIG 0x44
#define BUS_RESTRICT_CFG(vmcfg) ((vmcfg >> 8) & 0x3)
#define VMCONFIG_MSI_REMAP 0x2
#define PCI_REG_VMLOCK 0x70
#define MB2_SHADOW_EN(vmlock) (vmlock & 0x2)
@ -59,6 +60,13 @@ enum vmd_features {
* be used for MSI remapping
*/
VMD_FEAT_OFFSET_FIRST_VECTOR = (1 << 3),
/*
* Device can bypass remapping MSI-X transactions into its MSI-X table,
* avoiding the requirement of a VMD MSI domain for child device
* interrupt handling.
*/
VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4),
};
/*
@ -306,6 +314,16 @@ static struct msi_domain_info vmd_msi_domain_info = {
.chip = &vmd_msi_controller,
};
static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
{
u16 reg;
pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
(reg | VMCONFIG_MSI_REMAP);
pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
}
static int vmd_create_irq_domain(struct vmd_dev *vmd)
{
struct fwnode_handle *fn;
@ -325,6 +343,13 @@ static int vmd_create_irq_domain(struct vmd_dev *vmd)
static void vmd_remove_irq_domain(struct vmd_dev *vmd)
{
/*
* Some production BIOS won't enable remapping between soft reboots.
* Ensure remapping is restored before unloading the driver.
*/
if (!vmd->msix_count)
vmd_set_msi_remapping(vmd, true);
if (vmd->irq_domain) {
struct fwnode_handle *fn = vmd->irq_domain->fwnode;
@ -679,15 +704,32 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
sd->node = pcibus_to_node(vmd->dev->bus);
ret = vmd_create_irq_domain(vmd);
if (ret)
return ret;
/*
* Override the irq domain bus token so the domain can be distinguished
* from a regular PCI/MSI domain.
* Currently MSI remapping must be enabled in guest passthrough mode
* due to some missing interrupt remapping plumbing. This is probably
* acceptable because the guest is usually CPU-limited and MSI
* remapping doesn't become a performance bottleneck.
*/
irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
if (!(features & VMD_FEAT_CAN_BYPASS_MSI_REMAP) ||
offset[0] || offset[1]) {
ret = vmd_alloc_irqs(vmd);
if (ret)
return ret;
vmd_set_msi_remapping(vmd, true);
ret = vmd_create_irq_domain(vmd);
if (ret)
return ret;
/*
* Override the IRQ domain bus token so the domain can be
* distinguished from a regular PCI/MSI domain.
*/
irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
} else {
vmd_set_msi_remapping(vmd, false);
}
pci_add_resource(&resources, &vmd->resources[0]);
pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]);
@ -753,10 +795,6 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (features & VMD_FEAT_OFFSET_FIRST_VECTOR)
vmd->first_vec = 1;
err = vmd_alloc_irqs(vmd);
if (err)
return err;
spin_lock_init(&vmd->cfg_lock);
pci_set_drvdata(dev, vmd);
err = vmd_enable_domain(vmd, features);
@ -825,7 +863,8 @@ static const struct pci_device_id vmd_ids[] = {
.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,},
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_CAN_BYPASS_MSI_REMAP,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS |