Skip to content

Commit

Permalink
iommu: Make of_iommu_set/get_ops() DT agnostic
Browse files Browse the repository at this point in the history
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: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz 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: Will Deacon <will.deacon@arm.com>
  • Loading branch information
Lorenzo Pieralisi authored and Will Deacon committed Nov 29, 2016
1 parent 7936df9 commit e4f10ff
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 41 deletions.
40 changes: 40 additions & 0 deletions drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
39 changes: 0 additions & 39 deletions drivers/iommu/of_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions include/linux/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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 */
12 changes: 10 additions & 2 deletions include/linux/of_iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit e4f10ff

Please sign in to comment.