Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed40356b authored by David Woodhouse's avatar David Woodhouse
Browse files

iommu/vt-d: Add ACPI devices into dmaru->devices[] array

parent 832bd858
Loading
Loading
Loading
Loading
+75 −0
Original line number Diff line number Diff line
@@ -612,6 +612,79 @@ out:
	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 {