ia64/xen-unstable

changeset 18944:d238101c1832

VT-d: Fix PCI-X device assignment

When assign PCI device, current code just map its bridge and its
secondary bus number and devfn 0. It doesn't work for PCI-x device
assignment, because the request may be the source-id in the original
PCI-X transaction or the source-id provided by the bridge. It needs to
map the device itself, and its upstream bridges till PCIe-to-PCI/PCI-x
bridge.

In addition, add description for DEV_TYPE_PCIe_BRIDGE and
DEV_TYPE_PCI_BRIDGE for understandability.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Dec 19 13:42:04 2008 +0000 (2008-12-19)
parents 8c35da364ab3
children 2312cc25232b
files xen/drivers/passthrough/vtd/iommu.c
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Thu Dec 18 17:18:28 2008 +0000
     1.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Fri Dec 19 13:42:04 2008 +0000
     1.3 @@ -1129,8 +1129,8 @@ static int domain_context_mapping_one(
     1.4  
     1.5  enum {
     1.6      DEV_TYPE_PCIe_ENDPOINT,
     1.7 -    DEV_TYPE_PCIe_BRIDGE,
     1.8 -    DEV_TYPE_PCI_BRIDGE,
     1.9 +    DEV_TYPE_PCIe_BRIDGE,    // PCIe root port, switch
    1.10 +    DEV_TYPE_PCI_BRIDGE,     // PCIe-to-PCI/PCIx bridge, PCI-to-PCI bridge
    1.11      DEV_TYPE_PCI,
    1.12  };
    1.13  
    1.14 @@ -1144,7 +1144,8 @@ int pdev_type(u8 bus, u8 devfn)
    1.15      class_device = pci_conf_read16(bus, d, f, PCI_CLASS_DEVICE);
    1.16      if ( class_device == PCI_CLASS_BRIDGE_PCI )
    1.17      {
    1.18 -        pos = pci_find_next_cap(bus, devfn, PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP);
    1.19 +        pos = pci_find_next_cap(bus, devfn,
    1.20 +                                PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP);
    1.21          if ( !pos )
    1.22              return DEV_TYPE_PCI_BRIDGE;
    1.23          creg = pci_conf_read16(bus, d, f, pos + PCI_EXP_FLAGS);
    1.24 @@ -1206,7 +1207,7 @@ static int domain_context_mapping(struct
    1.25  {
    1.26      struct acpi_drhd_unit *drhd;
    1.27      int ret = 0;
    1.28 -    u16 sec_bus, sub_bus, ob, odf;
    1.29 +    u16 sec_bus, sub_bus;
    1.30      u32 type;
    1.31      u8 secbus;
    1.32  
    1.33 @@ -1220,15 +1221,13 @@ static int domain_context_mapping(struct
    1.34      switch ( type )
    1.35      {
    1.36      case DEV_TYPE_PCIe_BRIDGE:
    1.37 +        break;
    1.38 +
    1.39      case DEV_TYPE_PCI_BRIDGE:
    1.40          sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
    1.41                                   PCI_SECONDARY_BUS);
    1.42          sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
    1.43                                   PCI_SUBORDINATE_BUS);
    1.44 -        /*dmar_scope_add_buses(&drhd->scope, sec_bus, sub_bus);*/
    1.45 -
    1.46 -        if ( type == DEV_TYPE_PCIe_BRIDGE )
    1.47 -            break;
    1.48  
    1.49          spin_lock(&bus2bridge_lock);
    1.50          for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ )
    1.51 @@ -1249,25 +1248,25 @@ static int domain_context_mapping(struct
    1.52  
    1.53      case DEV_TYPE_PCI:
    1.54          gdprintk(XENLOG_INFO VTDPREFIX,
    1.55 -                 "domain_context_mapping:PCI:  bdf = %x:%x.%x\n",
    1.56 +                 "domain_context_mapping:PCI: bdf = %x:%x.%x\n",
    1.57                   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    1.58  
    1.59 -        ob = bus; odf = devfn;
    1.60 -        if ( !find_pcie_endpoint(&bus, &devfn, &secbus) )
    1.61 +        ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
    1.62 +        if ( ret )
    1.63 +           break;
    1.64 +
    1.65 +        secbus = bus;
    1.66 +        /* dependent devices mapping */
    1.67 +        while ( bus2bridge[bus].map )
    1.68          {
    1.69 -            gdprintk(XENLOG_WARNING VTDPREFIX,
    1.70 -                     "domain_context_mapping:invalid\n");
    1.71 -            break;
    1.72 +            secbus = bus;
    1.73 +            devfn = bus2bridge[bus].devfn;
    1.74 +            bus = bus2bridge[bus].bus;
    1.75 +            ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
    1.76 +            if ( ret )
    1.77 +                return ret;
    1.78          }
    1.79  
    1.80 -        if ( ob != bus || odf != devfn )
    1.81 -            gdprintk(XENLOG_INFO VTDPREFIX,
    1.82 -                     "domain_context_mapping:map:  "
    1.83 -                     "bdf = %x:%x.%x -> %x:%x.%x\n",
    1.84 -                     ob, PCI_SLOT(odf), PCI_FUNC(odf),
    1.85 -                     bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    1.86 -
    1.87 -        ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
    1.88          if ( secbus != bus )
    1.89              /*
    1.90               * The source-id for transactions on non-PCIe buses seem
    1.91 @@ -1276,7 +1275,7 @@ static int domain_context_mapping(struct
    1.92               * these scanarios is not particularly well documented
    1.93               * anywhere.
    1.94               */
    1.95 -            domain_context_mapping_one(domain, drhd->iommu, secbus, 0);
    1.96 +            ret = domain_context_mapping_one(domain, drhd->iommu, secbus, 0);
    1.97          break;
    1.98  
    1.99      default:
   1.100 @@ -1332,7 +1331,6 @@ static int domain_context_unmap_one(
   1.101  static int domain_context_unmap(struct domain *domain, u8 bus, u8 devfn)
   1.102  {
   1.103      struct acpi_drhd_unit *drhd;
   1.104 -    u16 sec_bus, sub_bus;
   1.105      int ret = 0;
   1.106      u32 type;
   1.107      u8 secbus;
   1.108 @@ -1346,24 +1344,37 @@ static int domain_context_unmap(struct d
   1.109      {
   1.110      case DEV_TYPE_PCIe_BRIDGE:
   1.111      case DEV_TYPE_PCI_BRIDGE:
   1.112 -        sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
   1.113 -                                 PCI_SECONDARY_BUS);
   1.114 -        sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
   1.115 -                                 PCI_SUBORDINATE_BUS);
   1.116 -        /*dmar_scope_remove_buses(&drhd->scope, sec_bus, sub_bus);*/
   1.117 -        if ( DEV_TYPE_PCI_BRIDGE )
   1.118 -            ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
   1.119          break;
   1.120  
   1.121      case DEV_TYPE_PCIe_ENDPOINT:
   1.122 +        gdprintk(XENLOG_INFO VTDPREFIX,
   1.123 +                 "domain_context_unmap:PCIe: bdf = %x:%x.%x\n",
   1.124 +                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
   1.125          ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
   1.126          break;
   1.127  
   1.128      case DEV_TYPE_PCI:
   1.129 -        if ( find_pcie_endpoint(&bus, &devfn, &secbus) )
   1.130 +        gdprintk(XENLOG_INFO VTDPREFIX,
   1.131 +                 "domain_context_unmap:PCI: bdf = %x:%x.%x\n",
   1.132 +                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
   1.133 +        ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
   1.134 +        if ( ret )
   1.135 +            break;
   1.136 +
   1.137 +        secbus = bus;
   1.138 +        /* dependent devices unmapping */
   1.139 +        while ( bus2bridge[bus].map )
   1.140 +        {
   1.141 +            secbus = bus;
   1.142 +            devfn = bus2bridge[bus].devfn;
   1.143 +            bus = bus2bridge[bus].bus;
   1.144              ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
   1.145 +            if ( ret )
   1.146 +                return ret;
   1.147 +        }
   1.148 +
   1.149          if ( bus != secbus )
   1.150 -            domain_context_unmap_one(domain, drhd->iommu, secbus, 0);
   1.151 +            ret = domain_context_unmap_one(domain, drhd->iommu, secbus, 0);
   1.152          break;
   1.153  
   1.154      default: