mirror of https://gitee.com/openkylin/linux.git
iommu/vt-d: Add ACPI devices into dmaru->devices[] array
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
832bd85867
commit
ed40356b5f
|
@ -612,6 +612,79 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
|
|||
return dmaru;
|
||||
}
|
||||
|
||||
static void __init dmar_acpi_insert_dev_scope(u8 device_number,
|
||||
struct acpi_device *adev)
|
||||
{
|
||||
struct dmar_drhd_unit *dmaru;
|
||||
struct acpi_dmar_hardware_unit *drhd;
|
||||
struct acpi_dmar_device_scope *scope;
|
||||
struct device *tmp;
|
||||
int i;
|
||||
struct acpi_dmar_pci_path *path;
|
||||
|
||||
for_each_drhd_unit(dmaru) {
|
||||
drhd = container_of(dmaru->hdr,
|
||||
struct acpi_dmar_hardware_unit,
|
||||
header);
|
||||
|
||||
for (scope = (void *)(drhd + 1);
|
||||
(unsigned long)scope < ((unsigned long)drhd) + drhd->header.length;
|
||||
scope = ((void *)scope) + scope->length) {
|
||||
if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_ACPI)
|
||||
continue;
|
||||
if (scope->enumeration_id != device_number)
|
||||
continue;
|
||||
|
||||
path = (void *)(scope + 1);
|
||||
pr_info("ACPI device \"%s\" under DMAR at %llx as %02x:%02x.%d\n",
|
||||
dev_name(&adev->dev), dmaru->reg_base_addr,
|
||||
scope->bus, path->device, path->function);
|
||||
for_each_dev_scope(dmaru->devices, dmaru->devices_cnt, i, tmp)
|
||||
if (tmp == NULL) {
|
||||
dmaru->devices[i].bus = scope->bus;
|
||||
dmaru->devices[i].devfn = PCI_DEVFN(path->device,
|
||||
path->function);
|
||||
rcu_assign_pointer(dmaru->devices[i].dev,
|
||||
get_device(&adev->dev));
|
||||
return;
|
||||
}
|
||||
BUG_ON(i >= dmaru->devices_cnt);
|
||||
}
|
||||
}
|
||||
pr_warn("No IOMMU scope found for ANDD enumeration ID %d (%s)\n",
|
||||
device_number, dev_name(&adev->dev));
|
||||
}
|
||||
|
||||
static int __init dmar_acpi_dev_scope_init(void)
|
||||
{
|
||||
struct acpi_dmar_andd *andd = (void *)dmar_tbl + sizeof(struct acpi_table_dmar);
|
||||
|
||||
while (((unsigned long)andd) <
|
||||
((unsigned long)dmar_tbl) + dmar_tbl->length) {
|
||||
if (andd->header.type == ACPI_DMAR_TYPE_ANDD) {
|
||||
acpi_handle h;
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT,
|
||||
andd->object_name,
|
||||
&h))) {
|
||||
pr_err("Failed to find handle for ACPI object %s\n",
|
||||
andd->object_name);
|
||||
continue;
|
||||
}
|
||||
acpi_bus_get_device(h, &adev);
|
||||
if (!adev) {
|
||||
pr_err("Failed to get device for ACPI object %s\n",
|
||||
andd->object_name);
|
||||
continue;
|
||||
}
|
||||
dmar_acpi_insert_dev_scope(andd->device_number, adev);
|
||||
}
|
||||
andd = ((void *)andd) + andd->header.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init dmar_dev_scope_init(void)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
|
@ -620,6 +693,8 @@ int __init dmar_dev_scope_init(void)
|
|||
if (dmar_dev_scope_status != 1)
|
||||
return dmar_dev_scope_status;
|
||||
|
||||
dmar_acpi_dev_scope_init();
|
||||
|
||||
if (list_empty(&dmar_drhd_units)) {
|
||||
dmar_dev_scope_status = -ENODEV;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue