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:
Linus Torvalds
2015-11-13 17:05:32 -08:00
förälder f3996e6ac6 222e684ca7
incheckning 934f98d7e8
17 ändrade filer med 615 tillägg och 89 borttagningar

Visa fil

@@ -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)) {

Visa fil

@@ -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]);