drivers/iommu/fsl_pamu_domain.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iommu/fsl_pamu_domain.c
Extension
.c
Size
12491 bytes
Lines
463
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: implementation source
Status
source 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

if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
			pr_debug("Invalid liodn %d, attach device failed for %pOF\n",
				 liodn[i], dev->of_node);
			ret = -ENODEV;
			break;
		}

		attach_device(dma_domain, liodn[i], dev);
		ret = pamu_set_liodn(dma_domain, dev, liodn[i]);
		if (ret)
			break;
		ret = pamu_enable_liodn(liodn[i]);
		if (ret)
			break;
	}
	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
	return ret;
}

/*
 * FIXME: fsl/pamu is completely broken in terms of how it works with the iommu
 * API. Immediately after probe the HW is left in an IDENTITY translation and
 * the driver provides a non-working UNMANAGED domain that it can switch over
 * to. However it cannot switch back to an IDENTITY translation, instead it
 * switches to what looks like BLOCKING.
 */
static int fsl_pamu_platform_attach(struct iommu_domain *platform_domain,
				    struct device *dev,
				    struct iommu_domain *old)
{
	struct fsl_dma_domain *dma_domain;
	const u32 *prop;
	int len;
	struct pci_dev *pdev = NULL;
	struct pci_controller *pci_ctl;

	/*
	 * Hack to keep things working as they always have, only leaving an
	 * UNMANAGED domain makes it BLOCKING.
	 */
	if (old == platform_domain || !old ||
	    old->type != IOMMU_DOMAIN_UNMANAGED)
		return 0;

	dma_domain = to_fsl_dma_domain(old);

	/*
	 * Use LIODN of the PCI controller while detaching a
	 * PCI device.
	 */
	if (dev_is_pci(dev)) {
		pdev = to_pci_dev(dev);
		pci_ctl = pci_bus_to_host(pdev->bus);
		/*
		 * make dev point to pci controller device
		 * so we can get the LIODN programmed by
		 * u-boot.
		 */
		dev = pci_ctl->parent;
	}

	prop = of_get_property(dev->of_node, "fsl,liodn", &len);
	if (prop)
		detach_device(dev, dma_domain);
	else
		pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
	return 0;
}

static struct iommu_domain_ops fsl_pamu_platform_ops = {
	.attach_dev = fsl_pamu_platform_attach,
};

static struct iommu_domain fsl_pamu_platform_domain = {
	.type = IOMMU_DOMAIN_PLATFORM,
	.ops = &fsl_pamu_platform_ops,
};

/* Set the domain stash attribute */
int fsl_pamu_configure_l1_stash(struct iommu_domain *domain, u32 cpu)
{
	struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&dma_domain->domain_lock, flags);
	dma_domain->stash_id = get_stash_id(PAMU_ATTR_CACHE_L1, cpu);
	if (dma_domain->stash_id == ~(u32)0) {
		pr_debug("Invalid stash attributes\n");
		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);

Annotation

Implementation Notes