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

Commit e4f10ffe authored by Lorenzo Pieralisi's avatar Lorenzo Pieralisi Committed by Will Deacon
Browse files

iommu: Make of_iommu_set/get_ops() DT agnostic



The of_iommu_{set/get}_ops() API is used to associate a device
tree node with a specific set of IOMMU operations. The same
kernel interface is required on systems booting with ACPI, where
devices are not associated with a device tree node, therefore
the interface requires generalization.

The struct device fwnode member represents the fwnode token associated
with the device and the struct it points at is firmware specific;
regardless, it is initialized on both ACPI and DT systems and makes an
ideal candidate to use it to associate a set of IOMMU operations to a
given device, through its struct device.fwnode member pointer, paving
the way for representing per-device iommu_ops (ie an iommu instance
associated with a device).

Convert the DT specific of_iommu_{set/get}_ops() interface to
use struct device.fwnode as a look-up token, making the interface
usable on ACPI systems and rename the data structures and the
registration API so that they are made to represent their usage
more clearly.

Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Reviewed-by: default avatarRobin Murphy <robin.murphy@arm.com>
Reviewed-by: default avatarTomasz Nowicki <tn@semihalf.com>
Tested-by: default avatarHanjun Guo <hanjun.guo@linaro.org>
Tested-by: default avatarTomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 7936df92
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -1615,6 +1615,46 @@ int iommu_request_dm_for_dev(struct device *dev)
	return ret;
}

struct iommu_instance {
	struct list_head list;
	struct fwnode_handle *fwnode;
	const struct iommu_ops *ops;
};
static LIST_HEAD(iommu_instance_list);
static DEFINE_SPINLOCK(iommu_instance_lock);

void iommu_register_instance(struct fwnode_handle *fwnode,
			     const struct iommu_ops *ops)
{
	struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);

	if (WARN_ON(!iommu))
		return;

	of_node_get(to_of_node(fwnode));
	INIT_LIST_HEAD(&iommu->list);
	iommu->fwnode = fwnode;
	iommu->ops = ops;
	spin_lock(&iommu_instance_lock);
	list_add_tail(&iommu->list, &iommu_instance_list);
	spin_unlock(&iommu_instance_lock);
}

const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
{
	struct iommu_instance *instance;
	const struct iommu_ops *ops = NULL;

	spin_lock(&iommu_instance_lock);
	list_for_each_entry(instance, &iommu_instance_list, list)
		if (instance->fwnode == fwnode) {
			ops = instance->ops;
			break;
		}
	spin_unlock(&iommu_instance_lock);
	return ops;
}

int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
		      const struct iommu_ops *ops)
{
+0 −39
Original line number Diff line number Diff line
@@ -96,45 +96,6 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
}
EXPORT_SYMBOL_GPL(of_get_dma_window);

struct of_iommu_node {
	struct list_head list;
	struct device_node *np;
	const struct iommu_ops *ops;
};
static LIST_HEAD(of_iommu_list);
static DEFINE_SPINLOCK(of_iommu_lock);

void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops)
{
	struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);

	if (WARN_ON(!iommu))
		return;

	of_node_get(np);
	INIT_LIST_HEAD(&iommu->list);
	iommu->np = np;
	iommu->ops = ops;
	spin_lock(&of_iommu_lock);
	list_add_tail(&iommu->list, &of_iommu_list);
	spin_unlock(&of_iommu_lock);
}

const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
{
	struct of_iommu_node *node;
	const struct iommu_ops *ops = NULL;

	spin_lock(&of_iommu_lock);
	list_for_each_entry(node, &of_iommu_list, list)
		if (node->np == np) {
			ops = node->ops;
			break;
		}
	spin_unlock(&of_iommu_lock);
	return ops;
}

static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
	struct of_phandle_args *iommu_spec = data;
+14 −0
Original line number Diff line number Diff line
@@ -351,6 +351,9 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
		      const struct iommu_ops *ops);
void iommu_fwspec_free(struct device *dev);
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
void iommu_register_instance(struct fwnode_handle *fwnode,
			     const struct iommu_ops *ops);
const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode);

#else /* CONFIG_IOMMU_API */

@@ -580,6 +583,17 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
	return -ENODEV;
}

static inline void iommu_register_instance(struct fwnode_handle *fwnode,
					   const struct iommu_ops *ops)
{
}

static inline
const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
{
	return NULL;
}

#endif /* CONFIG_IOMMU_API */

#endif /* __LINUX_IOMMU_H */
+10 −2
Original line number Diff line number Diff line
@@ -31,8 +31,16 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,

#endif	/* CONFIG_OF_IOMMU */

void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops);
const struct iommu_ops *of_iommu_get_ops(struct device_node *np);
static inline void of_iommu_set_ops(struct device_node *np,
				    const struct iommu_ops *ops)
{
	iommu_register_instance(&np->fwnode, ops);
}

static inline const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
{
	return iommu_get_instance(&np->fwnode);
}

extern struct of_device_id __iommu_of_table;