aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2014-03-07 18:15:42 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2014-03-24 10:06:30 -0400
commited40356b5fcf1ce28e026ab39c5b2b6939068b50 (patch)
treecb29ea716434701c0b155cd9e51f84b6f5b5af4c
parent832bd858674023b2415c7585db3beba345ef807f (diff)
iommu/vt-d: Add ACPI devices into dmaru->devices[] array
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/iommu/dmar.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index c1e2e0c82e69..7ea086f61073 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -612,6 +612,79 @@ out:
612 return dmaru; 612 return dmaru;
613} 613}
614 614
615static void __init dmar_acpi_insert_dev_scope(u8 device_number,
616 struct acpi_device *adev)
617{
618 struct dmar_drhd_unit *dmaru;
619 struct acpi_dmar_hardware_unit *drhd;
620 struct acpi_dmar_device_scope *scope;
621 struct device *tmp;
622 int i;
623 struct acpi_dmar_pci_path *path;
624
625 for_each_drhd_unit(dmaru) {
626 drhd = container_of(dmaru->hdr,
627 struct acpi_dmar_hardware_unit,
628 header);
629
630 for (scope = (void *)(drhd + 1);
631 (unsigned long)scope < ((unsigned long)drhd) + drhd->header.length;
632 scope = ((void *)scope) + scope->length) {
633 if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_ACPI)
634 continue;
635 if (scope->enumeration_id != device_number)
636 continue;
637
638 path = (void *)(scope + 1);
639 pr_info("ACPI device \"%s\" under DMAR at %llx as %02x:%02x.%d\n",
640 dev_name(&adev->dev), dmaru->reg_base_addr,
641 scope->bus, path->device, path->function);
642 for_each_dev_scope(dmaru->devices, dmaru->devices_cnt, i, tmp)
643 if (tmp == NULL) {
644 dmaru->devices[i].bus = scope->bus;
645 dmaru->devices[i].devfn = PCI_DEVFN(path->device,
646 path->function);
647 rcu_assign_pointer(dmaru->devices[i].dev,
648 get_device(&adev->dev));
649 return;
650 }
651 BUG_ON(i >= dmaru->devices_cnt);
652 }
653 }
654 pr_warn("No IOMMU scope found for ANDD enumeration ID %d (%s)\n",
655 device_number, dev_name(&adev->dev));
656}
657
658static int __init dmar_acpi_dev_scope_init(void)
659{
660 struct acpi_dmar_andd *andd = (void *)dmar_tbl + sizeof(struct acpi_table_dmar);
661
662 while (((unsigned long)andd) <
663 ((unsigned long)dmar_tbl) + dmar_tbl->length) {
664 if (andd->header.type == ACPI_DMAR_TYPE_ANDD) {
665 acpi_handle h;
666 struct acpi_device *adev;
667
668 if (!ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT,
669 andd->object_name,
670 &h))) {
671 pr_err("Failed to find handle for ACPI object %s\n",
672 andd->object_name);
673 continue;
674 }
675 acpi_bus_get_device(h, &adev);
676 if (!adev) {
677 pr_err("Failed to get device for ACPI object %s\n",
678 andd->object_name);
679 continue;
680 }
681 dmar_acpi_insert_dev_scope(andd->device_number, adev);
682 }
683 andd = ((void *)andd) + andd->header.length;
684 }
685 return 0;
686}
687
615int __init dmar_dev_scope_init(void) 688int __init dmar_dev_scope_init(void)
616{ 689{
617 struct pci_dev *dev = NULL; 690 struct pci_dev *dev = NULL;
@@ -620,6 +693,8 @@ int __init dmar_dev_scope_init(void)
620 if (dmar_dev_scope_status != 1) 693 if (dmar_dev_scope_status != 1)
621 return dmar_dev_scope_status; 694 return dmar_dev_scope_status;
622 695
696 dmar_acpi_dev_scope_init();
697
623 if (list_empty(&dmar_drhd_units)) { 698 if (list_empty(&dmar_drhd_units)) {
624 dmar_dev_scope_status = -ENODEV; 699 dmar_dev_scope_status = -ENODEV;
625 } else { 700 } else {