Commit 3f7c3209 authored by Robin Murphy's avatar Robin Murphy Committed by Will Deacon
Browse files

iommu: Resolve fwspec ops automatically



There's no real need for callers to resolve ops from a fwnode in order
to then pass both to iommu_fwspec_init() - it's simpler and more sensible
for that to resolve the ops itself. This in turn means we can centralise
the notion of checking for a present driver, and enforce that fwspecs
aren't allocated unless and until we know they will be usable.

Also use this opportunity to modernise with some "new" helpers that
arrived shortly after this code was first written; the generic
fwnode_handle_get() clears up that ugly get/put mismatch, while
of_fwnode_handle() can now abstract those open-coded dereferences.

Tested-by: default avatarJean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/r/0e2727adeb8cd73274425322f2f793561bdc927e.1719919669.git.robin.murphy@arm.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent e7acc36f
Loading
Loading
Loading
Loading
+5 −14
Original line number Diff line number Diff line
@@ -1221,10 +1221,10 @@ static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node)
static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
			    u32 streamid)
{
	const struct iommu_ops *ops;
	struct fwnode_handle *iort_fwnode;

	if (!node)
	/* If there's no SMMU driver at all, give up now */
	if (!node || !iort_iommu_driver_enabled(node->type))
		return -ENODEV;

	iort_fwnode = iort_get_fwnode(node);
@@ -1232,19 +1232,10 @@ static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
		return -ENODEV;

	/*
	 * If the ops look-up fails, this means that either
	 * the SMMU drivers have not been probed yet or that
	 * the SMMU drivers are not built in the kernel;
	 * Depending on whether the SMMU drivers are built-in
	 * in the kernel or not, defer the IOMMU configuration
	 * or just abort it.
	 * If the SMMU drivers are enabled but not loaded/probed
	 * yet, this will defer.
	 */
	ops = iommu_ops_from_fwnode(iort_fwnode);
	if (!ops)
		return iort_iommu_driver_enabled(node->type) ?
		       -EPROBE_DEFER : -ENODEV;

	return acpi_iommu_fwspec_init(dev, streamid, iort_fwnode, ops);
	return acpi_iommu_fwspec_init(dev, streamid, iort_fwnode);
}

struct iort_pci_alias_info {
+3 −5
Original line number Diff line number Diff line
@@ -1577,12 +1577,11 @@ int acpi_dma_get_range(struct device *dev, const struct bus_dma_region **map)

#ifdef CONFIG_IOMMU_API
int acpi_iommu_fwspec_init(struct device *dev, u32 id,
			   struct fwnode_handle *fwnode,
			   const struct iommu_ops *ops)
			   struct fwnode_handle *fwnode)
{
	int ret;

	ret = iommu_fwspec_init(dev, fwnode, ops);
	ret = iommu_fwspec_init(dev, fwnode);
	if (ret)
		return ret;

@@ -1639,8 +1638,7 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
#else /* !CONFIG_IOMMU_API */

int acpi_iommu_fwspec_init(struct device *dev, u32 id,
			   struct fwnode_handle *fwnode,
			   const struct iommu_ops *ops)
			   struct fwnode_handle *fwnode)
{
	return -ENODEV;
}
+2 −9
Original line number Diff line number Diff line
@@ -307,21 +307,14 @@ void __init acpi_viot_init(void)
static int viot_dev_iommu_init(struct device *dev, struct viot_iommu *viommu,
			       u32 epid)
{
	const struct iommu_ops *ops;

	if (!viommu)
	if (!viommu || !IS_ENABLED(CONFIG_VIRTIO_IOMMU))
		return -ENODEV;

	/* We're not translating ourself */
	if (device_match_fwnode(dev, viommu->fwnode))
		return -EINVAL;

	ops = iommu_ops_from_fwnode(viommu->fwnode);
	if (!ops)
		return IS_ENABLED(CONFIG_VIRTIO_IOMMU) ?
			-EPROBE_DEFER : -ENODEV;

	return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode, ops);
	return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode);
}

static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
+1 −2
Original line number Diff line number Diff line
@@ -178,8 +178,7 @@ static int arm_smmu_register_legacy_master(struct device *dev,
		it.cur_count = 1;
	}

	err = iommu_fwspec_init(dev, &smmu_dev->of_node->fwnode,
				&arm_smmu_ops);
	err = iommu_fwspec_init(dev, NULL);
	if (err)
		return err;

+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
	return dev->iommu->iommu_dev->ops;
}

const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode);

int iommu_group_replace_domain(struct iommu_group *group,
			       struct iommu_domain *new_domain);

Loading