drivers/iommu/of_iommu.c

Source file repositories/reference/linux-study-clean/drivers/iommu/of_iommu.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/of_iommu.c
Extension
.c
Size
6885 bytes
Lines
271
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct of_pci_iommu_alias_info {
	struct device *dev;
	struct device_node *np;
};

static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
{
	struct of_pci_iommu_alias_info *info = data;
	u32 input_id = alias;

	return of_iommu_configure_dev_id(info->np, info->dev, &input_id);
}

static int of_iommu_configure_device(struct device_node *master_np,
				     struct device *dev, const u32 *id)
{
	return (id) ? of_iommu_configure_dev_id(master_np, dev, id) :
		      of_iommu_configure_dev(master_np, dev);
}

static void of_pci_check_device_ats(struct device *dev, struct device_node *np)
{
	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);

	if (fwspec && of_property_read_bool(np, "ats-supported"))
		fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS;
}

/*
 * Returns:
 *  0 on success, an iommu was configured
 *  -ENODEV if the device does not have any IOMMU
 *  -EPROBEDEFER if probing should be tried again
 *  -errno fatal errors
 */
int of_iommu_configure(struct device *dev, struct device_node *master_np,
		       const u32 *id)
{
	bool dev_iommu_present;
	int err;

	if (!master_np)
		return -ENODEV;

	/* Serialise to make dev->iommu stable under our potential fwspec */
	mutex_lock(&iommu_probe_device_lock);
	if (dev_iommu_fwspec_get(dev)) {
		mutex_unlock(&iommu_probe_device_lock);
		return 0;
	}
	dev_iommu_present = dev->iommu;

	/*
	 * We don't currently walk up the tree looking for a parent IOMMU.
	 * See the `Notes:' section of
	 * Documentation/devicetree/bindings/iommu/iommu.txt
	 */
	if (dev_is_pci(dev)) {
		struct of_pci_iommu_alias_info info = {
			.dev = dev,
			.np = master_np,
		};

		pci_request_acs();
		err = pci_for_each_dma_alias(to_pci_dev(dev),
					     of_pci_iommu_init, &info);
		of_pci_check_device_ats(dev, master_np);
	} else {
		err = of_iommu_configure_device(master_np, dev, id);
	}

	if (err && dev_iommu_present)
		iommu_fwspec_free(dev);
	else if (err && dev->iommu)
		dev_iommu_free(dev);
	mutex_unlock(&iommu_probe_device_lock);

	/*
	 * If we're not on the iommu_probe_device() path (as indicated by the
	 * initial dev->iommu) then try to simulate it. This should no longer
	 * happen unless of_dma_configure() is being misused outside bus code.
	 */
	if (!err && dev->bus && !dev_iommu_present)
		err = iommu_probe_device(dev);

	if (err && err != -EPROBE_DEFER)
		dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);

	return err;
}

Annotation

Implementation Notes