Merge tag 'vfio-v4.4-rc1' of git://github.com/awilliam/linux-vfio
Pull VFIO updates from Alex Williamson: - Use kernel interfaces for VPD emulation (Alex Williamson) - Platform fix for releasing IRQs (Eric Auger) - Type1 IOMMU always advertises PAGE_SIZE support when smaller mapping sizes are available (Eric Auger) - Platform fixes for incorrectly using copies of structures rather than pointers to structures (James Morse) - Rework platform reset modules, fix leak, and add AMD xgbe reset module (Eric Auger) - Fix vfio_device_get_from_name() return value (Joerg Roedel) - No-IOMMU interface (Alex Williamson) - Fix potential out of bounds array access in PCI config handling (Dan Carpenter) * tag 'vfio-v4.4-rc1' of git://github.com/awilliam/linux-vfio: vfio/pci: make an array larger vfio: Include No-IOMMU mode vfio: Fix bug in vfio_device_get_from_name() VFIO: platform: reset: AMD xgbe reset module vfio: platform: reset: calxedaxgmac: fix ioaddr leak vfio: platform: add dev_info on device reset vfio: platform: use list of registered reset function vfio: platform: add compat in vfio_platform_device vfio: platform: reset: calxedaxgmac: add reset function registration vfio: platform: introduce module_vfio_reset_handler macro vfio: platform: add capability to register a reset function vfio: platform: introduce vfio-platform-base module vfio/platform: store mapped memory in region, instead of an on-stack copy vfio/type1: handle case where IOMMU does not support PAGE_SIZE size VFIO: platform: clear IRQ_NOAUTOEN when de-assigning the IRQ vfio/pci: Use kernel VPD access functions vfio: Whitelist PCI bridges
This commit is contained in:
@@ -940,13 +940,13 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
group = iommu_group_get(&pdev->dev);
|
||||
group = vfio_iommu_group_get(&pdev->dev);
|
||||
if (!group)
|
||||
return -EINVAL;
|
||||
|
||||
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
||||
if (!vdev) {
|
||||
iommu_group_put(group);
|
||||
vfio_iommu_group_put(group, &pdev->dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -957,7 +957,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
|
||||
ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
|
||||
if (ret) {
|
||||
iommu_group_put(group);
|
||||
vfio_iommu_group_put(group, &pdev->dev);
|
||||
kfree(vdev);
|
||||
return ret;
|
||||
}
|
||||
@@ -993,7 +993,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
|
||||
if (!vdev)
|
||||
return;
|
||||
|
||||
iommu_group_put(pdev->dev.iommu_group);
|
||||
vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
|
||||
kfree(vdev);
|
||||
|
||||
if (vfio_pci_is_vga(pdev)) {
|
||||
|
@@ -46,7 +46,7 @@
|
||||
* 0: Removed from the user visible capability list
|
||||
* FF: Variable length
|
||||
*/
|
||||
static u8 pci_cap_length[] = {
|
||||
static const u8 pci_cap_length[PCI_CAP_ID_MAX + 1] = {
|
||||
[PCI_CAP_ID_BASIC] = PCI_STD_HEADER_SIZEOF, /* pci config header */
|
||||
[PCI_CAP_ID_PM] = PCI_PM_SIZEOF,
|
||||
[PCI_CAP_ID_AGP] = PCI_AGP_SIZEOF,
|
||||
@@ -74,7 +74,7 @@ static u8 pci_cap_length[] = {
|
||||
* 0: Removed or masked from the user visible capabilty list
|
||||
* FF: Variable length
|
||||
*/
|
||||
static u16 pci_ext_cap_length[] = {
|
||||
static const u16 pci_ext_cap_length[PCI_EXT_CAP_ID_MAX + 1] = {
|
||||
[PCI_EXT_CAP_ID_ERR] = PCI_ERR_ROOT_COMMAND,
|
||||
[PCI_EXT_CAP_ID_VC] = 0xFF,
|
||||
[PCI_EXT_CAP_ID_DSN] = PCI_EXT_CAP_DSN_SIZEOF,
|
||||
@@ -671,6 +671,73 @@ static int __init init_pci_cap_pm_perm(struct perm_bits *perm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfio_vpd_config_write(struct vfio_pci_device *vdev, int pos,
|
||||
int count, struct perm_bits *perm,
|
||||
int offset, __le32 val)
|
||||
{
|
||||
struct pci_dev *pdev = vdev->pdev;
|
||||
__le16 *paddr = (__le16 *)(vdev->vconfig + pos - offset + PCI_VPD_ADDR);
|
||||
__le32 *pdata = (__le32 *)(vdev->vconfig + pos - offset + PCI_VPD_DATA);
|
||||
u16 addr;
|
||||
u32 data;
|
||||
|
||||
/*
|
||||
* Write through to emulation. If the write includes the upper byte
|
||||
* of PCI_VPD_ADDR, then the PCI_VPD_ADDR_F bit is written and we
|
||||
* have work to do.
|
||||
*/
|
||||
count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
|
||||
if (count < 0 || offset > PCI_VPD_ADDR + 1 ||
|
||||
offset + count <= PCI_VPD_ADDR + 1)
|
||||
return count;
|
||||
|
||||
addr = le16_to_cpu(*paddr);
|
||||
|
||||
if (addr & PCI_VPD_ADDR_F) {
|
||||
data = le32_to_cpu(*pdata);
|
||||
if (pci_write_vpd(pdev, addr & ~PCI_VPD_ADDR_F, 4, &data) != 4)
|
||||
return count;
|
||||
} else {
|
||||
if (pci_read_vpd(pdev, addr, 4, &data) != 4)
|
||||
return count;
|
||||
*pdata = cpu_to_le32(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Toggle PCI_VPD_ADDR_F in the emulated PCI_VPD_ADDR register to
|
||||
* signal completion. If an error occurs above, we assume that not
|
||||
* toggling this bit will induce a driver timeout.
|
||||
*/
|
||||
addr ^= PCI_VPD_ADDR_F;
|
||||
*paddr = cpu_to_le16(addr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Permissions for Vital Product Data capability */
|
||||
static int __init init_pci_cap_vpd_perm(struct perm_bits *perm)
|
||||
{
|
||||
if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_VPD]))
|
||||
return -ENOMEM;
|
||||
|
||||
perm->writefn = vfio_vpd_config_write;
|
||||
|
||||
/*
|
||||
* We always virtualize the next field so we can remove
|
||||
* capabilities from the chain if we want to.
|
||||
*/
|
||||
p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
|
||||
|
||||
/*
|
||||
* Both the address and data registers are virtualized to
|
||||
* enable access through the pci_vpd_read/write functions
|
||||
*/
|
||||
p_setw(perm, PCI_VPD_ADDR, (u16)ALL_VIRT, (u16)ALL_WRITE);
|
||||
p_setd(perm, PCI_VPD_DATA, ALL_VIRT, ALL_WRITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Permissions for PCI-X capability */
|
||||
static int __init init_pci_cap_pcix_perm(struct perm_bits *perm)
|
||||
{
|
||||
@@ -790,6 +857,7 @@ void vfio_pci_uninit_perm_bits(void)
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_BASIC]);
|
||||
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_PM]);
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_VPD]);
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_PCIX]);
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_EXP]);
|
||||
free_perm_bits(&cap_perms[PCI_CAP_ID_AF]);
|
||||
@@ -807,7 +875,7 @@ int __init vfio_pci_init_perm_bits(void)
|
||||
|
||||
/* Capabilities */
|
||||
ret |= init_pci_cap_pm_perm(&cap_perms[PCI_CAP_ID_PM]);
|
||||
cap_perms[PCI_CAP_ID_VPD].writefn = vfio_raw_config_write;
|
||||
ret |= init_pci_cap_vpd_perm(&cap_perms[PCI_CAP_ID_VPD]);
|
||||
ret |= init_pci_cap_pcix_perm(&cap_perms[PCI_CAP_ID_PCIX]);
|
||||
cap_perms[PCI_CAP_ID_VNDR].writefn = vfio_raw_config_write;
|
||||
ret |= init_pci_cap_exp_perm(&cap_perms[PCI_CAP_ID_EXP]);
|
||||
|
Referens i nytt ärende
Block a user