ia64/xen-unstable

changeset 19402:f02a528d2e56

Xen: use proper device ID to search VT-d unit for ARI and SR-IOV device

PCIe Alternative Routing-ID Interpretation (ARI) ECN defines the Extended
Function -- a function whose function number is greater than 7 within an
ARI Device. Intel VT-d spec 1.2 section 8.3.2 specifies that the Extended
Function is under the scope of the same remapping unit as the traditional
function. The hypervisor needs to know if a function is Extended
Function so it can find proper DMAR for it.

And section 8.3.3 specifies that the SR-IOV Virtual Function is under the
scope of the same remapping unit as the Physical Function. The hypervisor
also needs to know if a function is the Virtual Function and which
Physical Function it's associated with for same reason.

Signed-off-by: Yu Zhao <yu.zhao@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Mar 19 10:20:11 2009 +0000 (2009-03-19)
parents e2ada9d65bca
children 44d76cbe74ec
files xen/arch/ia64/xen/hypercall.c xen/arch/x86/physdev.c xen/drivers/passthrough/pci.c xen/drivers/passthrough/vtd/dmar.c xen/drivers/passthrough/vtd/dmar.h xen/drivers/passthrough/vtd/intremap.c xen/drivers/passthrough/vtd/iommu.c xen/include/public/physdev.h xen/include/xen/pci.h
line diff
     1.1 --- a/xen/arch/ia64/xen/hypercall.c	Thu Mar 19 10:10:59 2009 +0000
     1.2 +++ b/xen/arch/ia64/xen/hypercall.c	Thu Mar 19 10:20:11 2009 +0000
     1.3 @@ -674,6 +674,28 @@ long do_physdev_op(int cmd, XEN_GUEST_HA
     1.4              break;
     1.5      }
     1.6  
     1.7 +    case PHYSDEVOP_manage_pci_add_ext: {
     1.8 +        struct physdev_manage_pci_ext manage_pci_ext;
     1.9 +        struct pci_dev_info pdev_info;
    1.10 +
    1.11 +        ret = -EPERM;
    1.12 +        if ( !IS_PRIV(current->domain) )
    1.13 +            break;
    1.14 +
    1.15 +        ret = -EFAULT;
    1.16 +        if ( copy_from_guest(&manage_pci_ext, arg, 1) != 0 )
    1.17 +            break;
    1.18 +
    1.19 +        pdev_info.is_extfn = manage_pci_ext.is_extfn;
    1.20 +        pdev_info.is_virtfn = manage_pci_ext.is_virtfn;
    1.21 +        pdev_info.physfn.bus = manage_pci_ext.physfn.bus;
    1.22 +        pdev_info.physfn.devfn = manage_pci_ext.physfn.devfn;
    1.23 +        ret = pci_add_device_ext(manage_pci_ext.bus,
    1.24 +                                 manage_pci_ext.devfn,
    1.25 +                                 &pdev_info);
    1.26 +            break;
    1.27 +    }
    1.28 +
    1.29      default:
    1.30          ret = -ENOSYS;
    1.31          printk("not implemented do_physdev_op: %d\n", cmd);
     2.1 --- a/xen/arch/x86/physdev.c	Thu Mar 19 10:10:59 2009 +0000
     2.2 +++ b/xen/arch/x86/physdev.c	Thu Mar 19 10:20:11 2009 +0000
     2.3 @@ -421,6 +421,32 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
     2.4          break;
     2.5      }
     2.6  
     2.7 +    case PHYSDEVOP_manage_pci_add_ext: {
     2.8 +        struct physdev_manage_pci_ext manage_pci_ext;
     2.9 +        struct pci_dev_info pdev_info;
    2.10 +
    2.11 +        ret = -EPERM;
    2.12 +        if ( !IS_PRIV(current->domain) )
    2.13 +            break;
    2.14 +
    2.15 +        ret = -EFAULT;
    2.16 +        if ( copy_from_guest(&manage_pci_ext, arg, 1) != 0 )
    2.17 +            break;
    2.18 +
    2.19 +        ret = -EINVAL;
    2.20 +        if ( (manage_pci_ext.is_extfn > 1) || (manage_pci_ext.is_virtfn > 1) )
    2.21 +            break;
    2.22 +
    2.23 +        pdev_info.is_extfn = manage_pci_ext.is_extfn;
    2.24 +        pdev_info.is_virtfn = manage_pci_ext.is_virtfn;
    2.25 +        pdev_info.physfn.bus = manage_pci_ext.physfn.bus;
    2.26 +        pdev_info.physfn.devfn = manage_pci_ext.physfn.devfn;
    2.27 +        ret = pci_add_device_ext(manage_pci_ext.bus,
    2.28 +                                 manage_pci_ext.devfn,
    2.29 +                                 &pdev_info);
    2.30 +        break;
    2.31 +    }
    2.32 +
    2.33      case PHYSDEVOP_restore_msi: {
    2.34          struct physdev_restore_msi restore_msi;
    2.35          struct pci_dev *pdev;
     3.1 --- a/xen/drivers/passthrough/pci.c	Thu Mar 19 10:10:59 2009 +0000
     3.2 +++ b/xen/drivers/passthrough/pci.c	Thu Mar 19 10:20:11 2009 +0000
     3.3 @@ -143,6 +143,47 @@ int pci_remove_device(u8 bus, u8 devfn)
     3.4      return ret;
     3.5  }
     3.6  
     3.7 +int pci_add_device_ext(u8 bus, u8 devfn, struct pci_dev_info *info)
     3.8 +{
     3.9 +    int ret;
    3.10 +    char *pdev_type;
    3.11 +    struct pci_dev *pdev;
    3.12 +
    3.13 +    if (info->is_extfn)
    3.14 +        pdev_type = "Extended Function";
    3.15 +    else if (info->is_virtfn)
    3.16 +        pdev_type = "Virtual Function";
    3.17 +    else
    3.18 +    	return -EINVAL;;
    3.19 +
    3.20 +
    3.21 +    ret = -ENOMEM;
    3.22 +    spin_lock(&pcidevs_lock);
    3.23 +    pdev = alloc_pdev(bus, devfn);
    3.24 +    if ( !pdev )
    3.25 +        goto out;
    3.26 +
    3.27 +    pdev->info = *info;
    3.28 +
    3.29 +    ret = 0;
    3.30 +    if ( !pdev->domain )
    3.31 +    {
    3.32 +        pdev->domain = dom0;
    3.33 +        ret = iommu_add_device(pdev);
    3.34 +        if ( ret )
    3.35 +            goto out;
    3.36 +
    3.37 +        list_add(&pdev->domain_list, &dom0->arch.pdev_list);
    3.38 +    }
    3.39 +
    3.40 +out:
    3.41 +    spin_unlock(&pcidevs_lock);
    3.42 +    printk(XENLOG_DEBUG "PCI add %s %02x:%02x.%x\n", pdev_type,
    3.43 +           bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    3.44 +
    3.45 +    return ret;
    3.46 +}
    3.47 +
    3.48  static void pci_clean_dpci_irqs(struct domain *d)
    3.49  {
    3.50      struct hvm_irq_dpci *hvm_irq_dpci = NULL;
     4.1 --- a/xen/drivers/passthrough/vtd/dmar.c	Thu Mar 19 10:10:59 2009 +0000
     4.2 +++ b/xen/drivers/passthrough/vtd/dmar.c	Thu Mar 19 10:20:11 2009 +0000
     4.3 @@ -152,12 +152,24 @@ static int __init acpi_register_atsr_uni
     4.4      return 0;
     4.5  }
     4.6  
     4.7 -struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn)
     4.8 +struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev)
     4.9  {
    4.10 +    u8 bus, devfn;
    4.11      struct acpi_drhd_unit *drhd;
    4.12      struct acpi_drhd_unit *found = NULL, *include_all = NULL;
    4.13      int i;
    4.14  
    4.15 +    if (pdev->info.is_extfn) {
    4.16 +        bus = pdev->bus;
    4.17 +        devfn = 0;
    4.18 +    } else if (pdev->info.is_virtfn) {
    4.19 +        bus = pdev->info.physfn.bus;
    4.20 +        devfn = PCI_SLOT(pdev->info.physfn.devfn) ? 0 : pdev->info.physfn.devfn;
    4.21 +    } else {
    4.22 +        bus = pdev->bus;
    4.23 +        devfn = pdev->devfn;
    4.24 +    }
    4.25 +
    4.26      list_for_each_entry ( drhd, &acpi_drhd_units, list )
    4.27      {
    4.28          for (i = 0; i < drhd->scope.devices_cnt; i++)
     5.1 --- a/xen/drivers/passthrough/vtd/dmar.h	Thu Mar 19 10:10:59 2009 +0000
     5.2 +++ b/xen/drivers/passthrough/vtd/dmar.h	Thu Mar 19 10:20:11 2009 +0000
     5.3 @@ -79,7 +79,7 @@ struct acpi_atsr_unit {
     5.4          for (idx = 0; (bdf = rmrr->scope.devices[idx]) && \
     5.5                   idx < rmrr->scope.devices_cnt; idx++)
     5.6  
     5.7 -struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn);
     5.8 +struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev);
     5.9  struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u8 bus, u8 devfn);
    5.10  void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec, u16 sub);
    5.11  void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec, u16 sub);
     6.1 --- a/xen/drivers/passthrough/vtd/intremap.c	Thu Mar 19 10:10:59 2009 +0000
     6.2 +++ b/xen/drivers/passthrough/vtd/intremap.c	Thu Mar 19 10:20:11 2009 +0000
     6.3 @@ -450,7 +450,7 @@ void msi_msg_read_remap_rte(
     6.4      struct iommu *iommu = NULL;
     6.5      struct ir_ctrl *ir_ctrl;
     6.6  
     6.7 -    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
     6.8 +    drhd = acpi_find_matched_drhd_unit(pdev);
     6.9      iommu = drhd->iommu;
    6.10  
    6.11      ir_ctrl = iommu_ir_ctrl(iommu);
    6.12 @@ -468,7 +468,7 @@ void msi_msg_write_remap_rte(
    6.13      struct iommu *iommu = NULL;
    6.14      struct ir_ctrl *ir_ctrl;
    6.15  
    6.16 -    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
    6.17 +    drhd = acpi_find_matched_drhd_unit(pdev);
    6.18      iommu = drhd->iommu;
    6.19  
    6.20      ir_ctrl = iommu_ir_ctrl(iommu);
     7.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Thu Mar 19 10:10:59 2009 +0000
     7.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Thu Mar 19 10:20:11 2009 +0000
     7.3 @@ -1193,8 +1193,11 @@ static int domain_context_mapping(struct
     7.4      u16 sec_bus, sub_bus;
     7.5      u32 type;
     7.6      u8 secbus, secdevfn;
     7.7 +    struct pci_dev *pdev = pci_get_pdev(bus, devfn);
     7.8  
     7.9 -    drhd = acpi_find_matched_drhd_unit(bus, devfn);
    7.10 +    BUG_ON(!pdev);
    7.11 +
    7.12 +    drhd = acpi_find_matched_drhd_unit(pdev);
    7.13      if ( !drhd )
    7.14          return -ENODEV;
    7.15  
    7.16 @@ -1319,8 +1322,11 @@ static int domain_context_unmap(struct d
    7.17      int ret = 0;
    7.18      u32 type;
    7.19      u8 secbus, secdevfn;
    7.20 +    struct pci_dev *pdev = pci_get_pdev(bus, devfn);
    7.21  
    7.22 -    drhd = acpi_find_matched_drhd_unit(bus, devfn);
    7.23 +    BUG_ON(!pdev);
    7.24 +
    7.25 +    drhd = acpi_find_matched_drhd_unit(pdev);
    7.26      if ( !drhd )
    7.27          return -ENODEV;
    7.28  
    7.29 @@ -1392,7 +1398,7 @@ static int reassign_device_ownership(
    7.30      if (!pdev)
    7.31          return -ENODEV;
    7.32  
    7.33 -    drhd = acpi_find_matched_drhd_unit(bus, devfn);
    7.34 +    drhd = acpi_find_matched_drhd_unit(pdev);
    7.35      pdev_iommu = drhd->iommu;
    7.36      domain_context_unmap(source, bus, devfn);
    7.37  
    7.38 @@ -1405,7 +1411,7 @@ static int reassign_device_ownership(
    7.39  
    7.40      for_each_pdev ( source, pdev )
    7.41      {
    7.42 -        drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
    7.43 +        drhd = acpi_find_matched_drhd_unit(pdev);
    7.44          if ( drhd->iommu == pdev_iommu )
    7.45          {
    7.46              found = 1;
     8.1 --- a/xen/include/public/physdev.h	Thu Mar 19 10:10:59 2009 +0000
     8.2 +++ b/xen/include/public/physdev.h	Thu Mar 19 10:20:11 2009 +0000
     8.3 @@ -183,6 +183,22 @@ struct physdev_manage_pci {
     8.4  typedef struct physdev_manage_pci physdev_manage_pci_t;
     8.5  DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t);
     8.6  
     8.7 +#define PHYSDEVOP_manage_pci_add_ext    20
     8.8 +struct physdev_manage_pci_ext {
     8.9 +    /* IN */
    8.10 +    uint8_t bus;
    8.11 +    uint8_t devfn;
    8.12 +    unsigned is_extfn;
    8.13 +    unsigned is_virtfn;
    8.14 +    struct {
    8.15 +        uint8_t bus;
    8.16 +        uint8_t devfn;
    8.17 +    } physfn;
    8.18 +};
    8.19 +
    8.20 +typedef struct physdev_manage_pci_ext physdev_manage_pci_ext_t;
    8.21 +DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_ext_t);
    8.22 +
    8.23  #define PHYSDEVOP_restore_msi            19
    8.24  struct physdev_restore_msi {
    8.25      /* IN */
     9.1 --- a/xen/include/xen/pci.h	Thu Mar 19 10:10:59 2009 +0000
     9.2 +++ b/xen/include/xen/pci.h	Thu Mar 19 10:20:11 2009 +0000
     9.3 @@ -31,6 +31,15 @@
     9.4  
     9.5  #define MAX_MSIX_TABLE_ENTRIES  2048
     9.6  #define MAX_MSIX_TABLE_PAGES    8
     9.7 +struct pci_dev_info {
     9.8 +    unsigned is_extfn;
     9.9 +    unsigned is_virtfn;
    9.10 +    struct {
    9.11 +        u8 bus;
    9.12 +        u8 devfn;
    9.13 +    } physfn;
    9.14 +};
    9.15 +
    9.16  struct pci_dev {
    9.17      struct list_head alldevs_list;
    9.18      struct list_head domain_list;
    9.19 @@ -43,6 +52,7 @@ struct pci_dev {
    9.20      struct domain *domain;
    9.21      const u8 bus;
    9.22      const u8 devfn;
    9.23 +    struct pci_dev_info info;
    9.24  };
    9.25  
    9.26  #define for_each_pdev(domain, pdev) \
    9.27 @@ -64,6 +74,7 @@ struct pci_dev *pci_lock_domain_pdev(str
    9.28  void pci_release_devices(struct domain *d);
    9.29  int pci_add_device(u8 bus, u8 devfn);
    9.30  int pci_remove_device(u8 bus, u8 devfn);
    9.31 +int pci_add_device_ext(u8 bus, u8 devfn, struct pci_dev_info *info);
    9.32  struct pci_dev *pci_get_pdev(int bus, int devfn);
    9.33  struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn);
    9.34