mirror of https://gitee.com/openkylin/linux.git
vfio/pci: Mask buggy SR-IOV VF INTx support
The SR-IOV spec requires that VFs must report zero for the INTx pin register as VFs are precluded from INTx support. It's much easier for the host kernel to understand whether a device is a VF and therefore whether a non-zero pin register value is bogus than it is to do the same in userspace. Override the INTx count for such devices and virtualize the pin register to provide a consistent view of the device to the user. As this is clearly a spec violation, warn about it to support hardware validation, but also provide a known whitelist as it doesn't do much good to continue complaining if the hardware vendor doesn't plan to fix it. Known devices with this issue: 8086:270c Tested-by: Gage Eads <gage.eads@intel.com> Reviewed-by: Ashok Raj <ashok.raj@intel.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
30ea32ab19
commit
db04264fe9
|
@ -434,10 +434,14 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
|
|||
{
|
||||
if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
|
||||
u8 pin;
|
||||
pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
|
||||
if (IS_ENABLED(CONFIG_VFIO_PCI_INTX) && !vdev->nointx && pin)
|
||||
return 1;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) ||
|
||||
vdev->nointx || vdev->pdev->is_virtfn)
|
||||
return 0;
|
||||
|
||||
pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
|
||||
|
||||
return pin ? 1 : 0;
|
||||
} else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {
|
||||
u8 pos;
|
||||
u16 flags;
|
||||
|
|
|
@ -1611,6 +1611,15 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Nag about hardware bugs, hopefully to have vendors fix them, but at least
|
||||
* to collect a list of dependencies for the VF INTx pin quirk below.
|
||||
*/
|
||||
static const struct pci_device_id known_bogus_vf_intx_pin[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x270c) },
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* For each device we allocate a pci_config_map that indicates the
|
||||
* capability occupying each dword and thus the struct perm_bits we
|
||||
|
@ -1676,6 +1685,24 @@ int vfio_config_init(struct vfio_pci_device *vdev)
|
|||
if (pdev->is_virtfn) {
|
||||
*(__le16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor);
|
||||
*(__le16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device);
|
||||
|
||||
/*
|
||||
* Per SR-IOV spec rev 1.1, 3.4.1.18 the interrupt pin register
|
||||
* does not apply to VFs and VFs must implement this register
|
||||
* as read-only with value zero. Userspace is not readily able
|
||||
* to identify whether a device is a VF and thus that the pin
|
||||
* definition on the device is bogus should it violate this
|
||||
* requirement. We already virtualize the pin register for
|
||||
* other purposes, so we simply need to replace the bogus value
|
||||
* and consider VFs when we determine INTx IRQ count.
|
||||
*/
|
||||
if (vconfig[PCI_INTERRUPT_PIN] &&
|
||||
!pci_match_id(known_bogus_vf_intx_pin, pdev))
|
||||
pci_warn(pdev,
|
||||
"Hardware bug: VF reports bogus INTx pin %d\n",
|
||||
vconfig[PCI_INTERRUPT_PIN]);
|
||||
|
||||
vconfig[PCI_INTERRUPT_PIN] = 0; /* Gratuitous for good VFs */
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx)
|
||||
|
|
Loading…
Reference in New Issue