// SPDX-License-Identifier: GPL-2.0 /* * Virtual I/O topology * * The Virtual I/O Translation Table (VIOT) describes the topology of * para-virtual IOMMUs and the endpoints they manage. The OS uses it to * initialize devices in the right order, preventing endpoints from issuing DMA * before their IOMMU is ready. * * When binding a driver to a device, before calling the device driver's probe() * method, the driver infrastructure calls dma_configure(). At that point the * VIOT driver looks for an IOMMU associated to the device in the VIOT table. * If an IOMMU exists and has been initialized, the VIOT driver initializes the * device's IOMMU fwspec, allowing the DMA infrastructure to invoke the IOMMU * ops when the device driver configures DMA mappings. If an IOMMU exists and * hasn't yet been initialized, VIOT returns -EPROBE_DEFER to postpone probing * the device until the IOMMU is available.
*/ #define pr_fmt(fmt) "ACPI: VIOT: " fmt
list_for_each_entry(viommu, &viot_iommus, list) if (viommu->offset == offset) return viommu;
if (viot_check_bounds(hdr)) return NULL;
viommu = kzalloc(sizeof(*viommu), GFP_KERNEL); if (!viommu) return NULL;
viommu->offset = offset; switch (hdr->type) { case ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI: if (hdr->length < sizeof(node->pci)) goto err_free;
ret = viot_get_pci_iommu_fwnode(viommu, node->pci.segment,
node->pci.bdf); break; case ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO: if (hdr->length < sizeof(node->mmio)) goto err_free;
ret = viot_get_mmio_iommu_fwnode(viommu,
node->mmio.base_address); break; default:
ret = -EINVAL;
} if (ret) goto err_free;
if (!ep->viommu) {
pr_warn("No IOMMU node found\n"); /* * A future version of the table may use the node for other * purposes. Keep parsing.
*/
ret = 0; goto err_free;
}
list_add(&ep->list, list); return 0;
err_free:
kfree(ep); return ret;
}
/** * acpi_viot_early_init - Test the presence of VIOT and enable ACS * * If the VIOT does exist, ACS must be enabled. This cannot be * done in acpi_viot_init() which is called after the bus scan
*/ void __init acpi_viot_early_init(void)
{ #ifdef CONFIG_PCI
acpi_status status; struct acpi_table_header *hdr;
status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr); if (ACPI_FAILURE(status)) return;
pci_request_acs();
acpi_put_table(hdr); #endif
}
/** * acpi_viot_init - Parse the VIOT table * * Parse the VIOT table, prepare the list of endpoints to be used during DMA * setup of devices.
*/ void __init acpi_viot_init(void)
{ int i;
acpi_status status; struct acpi_table_header *hdr; struct acpi_viot_header *node;
status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { constchar *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
} return;
}
viot = (void *)hdr;
node = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->node_offset); for (i = 0; i < viot->node_count; i++) { if (viot_parse_node(node)) return;
/** * viot_iommu_configure - Setup IOMMU ops for an endpoint described by VIOT * @dev: the endpoint * * Return: 0 on success, <0 on failure
*/ int viot_iommu_configure(struct device *dev)
{ if (dev_is_pci(dev)) return pci_for_each_dma_alias(to_pci_dev(dev),
viot_pci_dev_iommu_init, dev); elseif (dev_is_platform(dev)) return viot_mmio_dev_iommu_init(to_platform_device(dev)); return -ENODEV;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.