aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2009-04-03 20:45:37 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-04-04 05:43:31 -0400
commit276dbf997043cbf38f0087624e0f9c51742c8885 (patch)
treeeface2519a6ad4c25c2864ee1ee69361ea3f594c
parent924b6231edfaf1e764ffb4f97ea382bf4facff58 (diff)
intel-iommu: Handle PCI domains appropriately.
We were comparing {bus,devfn} and assuming that a match meant it was the same device. It doesn't -- the same {bus,devfn} can exist in multiple PCI domains. Include domain number in device identification (and call it 'segment' in most places, because there's already a lot of references to 'domain' which means something else, and this code is infected with ACPI thinking already). Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/pci/dmar.c1
-rw-r--r--drivers/pci/intel-iommu.c76
-rw-r--r--include/linux/dmar.h1
3 files changed, 50 insertions, 28 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 3fbe6af7ad71..25a00ce4f24d 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -180,6 +180,7 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
180 dmaru->hdr = header; 180 dmaru->hdr = header;
181 drhd = (struct acpi_dmar_hardware_unit *)header; 181 drhd = (struct acpi_dmar_hardware_unit *)header;
182 dmaru->reg_base_addr = drhd->address; 182 dmaru->reg_base_addr = drhd->address;
183 dmaru->segment = drhd->segment;
183 dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ 184 dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
184 185
185 ret = alloc_iommu(dmaru); 186 ret = alloc_iommu(dmaru);
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 6262c198e56e..fd7472f28674 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -248,7 +248,8 @@ struct dmar_domain {
248struct device_domain_info { 248struct device_domain_info {
249 struct list_head link; /* link to domain siblings */ 249 struct list_head link; /* link to domain siblings */
250 struct list_head global; /* link to global list */ 250 struct list_head global; /* link to global list */
251 u8 bus; /* PCI bus numer */ 251 int segment; /* PCI domain */
252 u8 bus; /* PCI bus number */
252 u8 devfn; /* PCI devfn number */ 253 u8 devfn; /* PCI devfn number */
253 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ 254 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
254 struct dmar_domain *domain; /* pointer to domain */ 255 struct dmar_domain *domain; /* pointer to domain */
@@ -468,7 +469,7 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
468 domain_update_iommu_snooping(domain); 469 domain_update_iommu_snooping(domain);
469} 470}
470 471
471static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn) 472static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
472{ 473{
473 struct dmar_drhd_unit *drhd = NULL; 474 struct dmar_drhd_unit *drhd = NULL;
474 int i; 475 int i;
@@ -476,6 +477,8 @@ static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
476 for_each_drhd_unit(drhd) { 477 for_each_drhd_unit(drhd) {
477 if (drhd->ignored) 478 if (drhd->ignored)
478 continue; 479 continue;
480 if (segment != drhd->segment)
481 continue;
479 482
480 for (i = 0; i < drhd->devices_cnt; i++) { 483 for (i = 0; i < drhd->devices_cnt; i++) {
481 if (drhd->devices[i] && 484 if (drhd->devices[i] &&
@@ -1318,7 +1321,7 @@ static void domain_exit(struct dmar_domain *domain)
1318} 1321}
1319 1322
1320static int domain_context_mapping_one(struct dmar_domain *domain, 1323static int domain_context_mapping_one(struct dmar_domain *domain,
1321 u8 bus, u8 devfn) 1324 int segment, u8 bus, u8 devfn)
1322{ 1325{
1323 struct context_entry *context; 1326 struct context_entry *context;
1324 unsigned long flags; 1327 unsigned long flags;
@@ -1333,7 +1336,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
1333 bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); 1336 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
1334 BUG_ON(!domain->pgd); 1337 BUG_ON(!domain->pgd);
1335 1338
1336 iommu = device_to_iommu(bus, devfn); 1339 iommu = device_to_iommu(segment, bus, devfn);
1337 if (!iommu) 1340 if (!iommu)
1338 return -ENODEV; 1341 return -ENODEV;
1339 1342
@@ -1423,8 +1426,8 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
1423 int ret; 1426 int ret;
1424 struct pci_dev *tmp, *parent; 1427 struct pci_dev *tmp, *parent;
1425 1428
1426 ret = domain_context_mapping_one(domain, pdev->bus->number, 1429 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
1427 pdev->devfn); 1430 pdev->bus->number, pdev->devfn);
1428 if (ret) 1431 if (ret)
1429 return ret; 1432 return ret;
1430 1433
@@ -1435,18 +1438,23 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
1435 /* Secondary interface's bus number and devfn 0 */ 1438 /* Secondary interface's bus number and devfn 0 */
1436 parent = pdev->bus->self; 1439 parent = pdev->bus->self;
1437 while (parent != tmp) { 1440 while (parent != tmp) {
1438 ret = domain_context_mapping_one(domain, parent->bus->number, 1441 ret = domain_context_mapping_one(domain,
1439 parent->devfn); 1442 pci_domain_nr(parent->bus),
1443 parent->bus->number,
1444 parent->devfn);
1440 if (ret) 1445 if (ret)
1441 return ret; 1446 return ret;
1442 parent = parent->bus->self; 1447 parent = parent->bus->self;
1443 } 1448 }
1444 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ 1449 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1445 return domain_context_mapping_one(domain, 1450 return domain_context_mapping_one(domain,
1446 tmp->subordinate->number, 0); 1451 pci_domain_nr(tmp->subordinate),
1452 tmp->subordinate->number, 0);
1447 else /* this is a legacy PCI bridge */ 1453 else /* this is a legacy PCI bridge */
1448 return domain_context_mapping_one(domain, 1454 return domain_context_mapping_one(domain,
1449 tmp->bus->number, tmp->devfn); 1455 pci_domain_nr(tmp->bus),
1456 tmp->bus->number,
1457 tmp->devfn);
1450} 1458}
1451 1459
1452static int domain_context_mapped(struct pci_dev *pdev) 1460static int domain_context_mapped(struct pci_dev *pdev)
@@ -1455,12 +1463,12 @@ static int domain_context_mapped(struct pci_dev *pdev)
1455 struct pci_dev *tmp, *parent; 1463 struct pci_dev *tmp, *parent;
1456 struct intel_iommu *iommu; 1464 struct intel_iommu *iommu;
1457 1465
1458 iommu = device_to_iommu(pdev->bus->number, pdev->devfn); 1466 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1467 pdev->devfn);
1459 if (!iommu) 1468 if (!iommu)
1460 return -ENODEV; 1469 return -ENODEV;
1461 1470
1462 ret = device_context_mapped(iommu, 1471 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
1463 pdev->bus->number, pdev->devfn);
1464 if (!ret) 1472 if (!ret)
1465 return ret; 1473 return ret;
1466 /* dependent device mapping */ 1474 /* dependent device mapping */
@@ -1471,17 +1479,17 @@ static int domain_context_mapped(struct pci_dev *pdev)
1471 parent = pdev->bus->self; 1479 parent = pdev->bus->self;
1472 while (parent != tmp) { 1480 while (parent != tmp) {
1473 ret = device_context_mapped(iommu, parent->bus->number, 1481 ret = device_context_mapped(iommu, parent->bus->number,
1474 parent->devfn); 1482 parent->devfn);
1475 if (!ret) 1483 if (!ret)
1476 return ret; 1484 return ret;
1477 parent = parent->bus->self; 1485 parent = parent->bus->self;
1478 } 1486 }
1479 if (tmp->is_pcie) 1487 if (tmp->is_pcie)
1480 return device_context_mapped(iommu, 1488 return device_context_mapped(iommu, tmp->subordinate->number,
1481 tmp->subordinate->number, 0); 1489 0);
1482 else 1490 else
1483 return device_context_mapped(iommu, 1491 return device_context_mapped(iommu, tmp->bus->number,
1484 tmp->bus->number, tmp->devfn); 1492 tmp->devfn);
1485} 1493}
1486 1494
1487static int 1495static int
@@ -1548,7 +1556,7 @@ static void domain_remove_dev_info(struct dmar_domain *domain)
1548 info->dev->dev.archdata.iommu = NULL; 1556 info->dev->dev.archdata.iommu = NULL;
1549 spin_unlock_irqrestore(&device_domain_lock, flags); 1557 spin_unlock_irqrestore(&device_domain_lock, flags);
1550 1558
1551 iommu = device_to_iommu(info->bus, info->devfn); 1559 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
1552 iommu_detach_dev(iommu, info->bus, info->devfn); 1560 iommu_detach_dev(iommu, info->bus, info->devfn);
1553 free_devinfo_mem(info); 1561 free_devinfo_mem(info);
1554 1562
@@ -1583,11 +1591,14 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1583 struct pci_dev *dev_tmp; 1591 struct pci_dev *dev_tmp;
1584 unsigned long flags; 1592 unsigned long flags;
1585 int bus = 0, devfn = 0; 1593 int bus = 0, devfn = 0;
1594 int segment;
1586 1595
1587 domain = find_domain(pdev); 1596 domain = find_domain(pdev);
1588 if (domain) 1597 if (domain)
1589 return domain; 1598 return domain;
1590 1599
1600 segment = pci_domain_nr(pdev->bus);
1601
1591 dev_tmp = pci_find_upstream_pcie_bridge(pdev); 1602 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1592 if (dev_tmp) { 1603 if (dev_tmp) {
1593 if (dev_tmp->is_pcie) { 1604 if (dev_tmp->is_pcie) {
@@ -1599,7 +1610,8 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1599 } 1610 }
1600 spin_lock_irqsave(&device_domain_lock, flags); 1611 spin_lock_irqsave(&device_domain_lock, flags);
1601 list_for_each_entry(info, &device_domain_list, global) { 1612 list_for_each_entry(info, &device_domain_list, global) {
1602 if (info->bus == bus && info->devfn == devfn) { 1613 if (info->segment == segment &&
1614 info->bus == bus && info->devfn == devfn) {
1603 found = info->domain; 1615 found = info->domain;
1604 break; 1616 break;
1605 } 1617 }
@@ -1637,6 +1649,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1637 domain_exit(domain); 1649 domain_exit(domain);
1638 goto error; 1650 goto error;
1639 } 1651 }
1652 info->segment = segment;
1640 info->bus = bus; 1653 info->bus = bus;
1641 info->devfn = devfn; 1654 info->devfn = devfn;
1642 info->dev = NULL; 1655 info->dev = NULL;
@@ -1648,7 +1661,8 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1648 found = NULL; 1661 found = NULL;
1649 spin_lock_irqsave(&device_domain_lock, flags); 1662 spin_lock_irqsave(&device_domain_lock, flags);
1650 list_for_each_entry(tmp, &device_domain_list, global) { 1663 list_for_each_entry(tmp, &device_domain_list, global) {
1651 if (tmp->bus == bus && tmp->devfn == devfn) { 1664 if (tmp->segment == segment &&
1665 tmp->bus == bus && tmp->devfn == devfn) {
1652 found = tmp->domain; 1666 found = tmp->domain;
1653 break; 1667 break;
1654 } 1668 }
@@ -1668,6 +1682,7 @@ found_domain:
1668 info = alloc_devinfo_mem(); 1682 info = alloc_devinfo_mem();
1669 if (!info) 1683 if (!info)
1670 goto error; 1684 goto error;
1685 info->segment = segment;
1671 info->bus = pdev->bus->number; 1686 info->bus = pdev->bus->number;
1672 info->devfn = pdev->devfn; 1687 info->devfn = pdev->devfn;
1673 info->dev = pdev; 1688 info->dev = pdev;
@@ -2808,6 +2823,7 @@ static int vm_domain_add_dev_info(struct dmar_domain *domain,
2808 if (!info) 2823 if (!info)
2809 return -ENOMEM; 2824 return -ENOMEM;
2810 2825
2826 info->segment = pci_domain_nr(pdev->bus);
2811 info->bus = pdev->bus->number; 2827 info->bus = pdev->bus->number;
2812 info->devfn = pdev->devfn; 2828 info->devfn = pdev->devfn;
2813 info->dev = pdev; 2829 info->dev = pdev;
@@ -2837,15 +2853,15 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
2837 parent = pdev->bus->self; 2853 parent = pdev->bus->self;
2838 while (parent != tmp) { 2854 while (parent != tmp) {
2839 iommu_detach_dev(iommu, parent->bus->number, 2855 iommu_detach_dev(iommu, parent->bus->number,
2840 parent->devfn); 2856 parent->devfn);
2841 parent = parent->bus->self; 2857 parent = parent->bus->self;
2842 } 2858 }
2843 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ 2859 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
2844 iommu_detach_dev(iommu, 2860 iommu_detach_dev(iommu,
2845 tmp->subordinate->number, 0); 2861 tmp->subordinate->number, 0);
2846 else /* this is a legacy PCI bridge */ 2862 else /* this is a legacy PCI bridge */
2847 iommu_detach_dev(iommu, 2863 iommu_detach_dev(iommu, tmp->bus->number,
2848 tmp->bus->number, tmp->devfn); 2864 tmp->devfn);
2849 } 2865 }
2850} 2866}
2851 2867
@@ -2858,13 +2874,15 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
2858 int found = 0; 2874 int found = 0;
2859 struct list_head *entry, *tmp; 2875 struct list_head *entry, *tmp;
2860 2876
2861 iommu = device_to_iommu(pdev->bus->number, pdev->devfn); 2877 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
2878 pdev->devfn);
2862 if (!iommu) 2879 if (!iommu)
2863 return; 2880 return;
2864 2881
2865 spin_lock_irqsave(&device_domain_lock, flags); 2882 spin_lock_irqsave(&device_domain_lock, flags);
2866 list_for_each_safe(entry, tmp, &domain->devices) { 2883 list_for_each_safe(entry, tmp, &domain->devices) {
2867 info = list_entry(entry, struct device_domain_info, link); 2884 info = list_entry(entry, struct device_domain_info, link);
2885 /* No need to compare PCI domain; it has to be the same */
2868 if (info->bus == pdev->bus->number && 2886 if (info->bus == pdev->bus->number &&
2869 info->devfn == pdev->devfn) { 2887 info->devfn == pdev->devfn) {
2870 list_del(&info->link); 2888 list_del(&info->link);
@@ -2889,7 +2907,8 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
2889 * owned by this domain, clear this iommu in iommu_bmp 2907 * owned by this domain, clear this iommu in iommu_bmp
2890 * update iommu count and coherency 2908 * update iommu count and coherency
2891 */ 2909 */
2892 if (device_to_iommu(info->bus, info->devfn) == iommu) 2910 if (iommu == device_to_iommu(info->segment, info->bus,
2911 info->devfn))
2893 found = 1; 2912 found = 1;
2894 } 2913 }
2895 2914
@@ -2922,7 +2941,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
2922 2941
2923 spin_unlock_irqrestore(&device_domain_lock, flags1); 2942 spin_unlock_irqrestore(&device_domain_lock, flags1);
2924 2943
2925 iommu = device_to_iommu(info->bus, info->devfn); 2944 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
2926 iommu_detach_dev(iommu, info->bus, info->devfn); 2945 iommu_detach_dev(iommu, info->bus, info->devfn);
2927 iommu_detach_dependent_devices(iommu, info->dev); 2946 iommu_detach_dependent_devices(iommu, info->dev);
2928 2947
@@ -3110,7 +3129,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
3110 } 3129 }
3111 } 3130 }
3112 3131
3113 iommu = device_to_iommu(pdev->bus->number, pdev->devfn); 3132 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3133 pdev->devfn);
3114 if (!iommu) 3134 if (!iommu)
3115 return -ENODEV; 3135 return -ENODEV;
3116 3136
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 4a0ce6f27e1b..e397dc342cda 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -34,6 +34,7 @@ struct dmar_drhd_unit {
34 u64 reg_base_addr; /* register base address*/ 34 u64 reg_base_addr; /* register base address*/
35 struct pci_dev **devices; /* target device array */ 35 struct pci_dev **devices; /* target device array */
36 int devices_cnt; /* target device count */ 36 int devices_cnt; /* target device count */
37 u16 segment; /* PCI domain */
37 u8 ignored:1; /* ignore drhd */ 38 u8 ignored:1; /* ignore drhd */
38 u8 include_all:1; 39 u8 include_all:1;
39 struct intel_iommu *iommu; 40 struct intel_iommu *iommu;