iommu: Make of_iommu_set/get_ops() DT agnostic
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Mon, 21 Nov 2016 10:01:36 +0000 (10:01 +0000)
committerWill Deacon <will.deacon@arm.com>
Tue, 29 Nov 2016 15:57:43 +0000 (15:57 +0000)
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>
drivers/iommu/iommu.c
drivers/iommu/of_iommu.c
include/linux/iommu.h
include/linux/of_iommu.h

index 9a2f1960873b65e01b29ff5f1d84148ce4bae094..8d3e847d4845f5f73921c8c56e362a22d143ec8f 100644 (file)
@@ -1615,6 +1615,46 @@ out:
        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)
 {
index 5b82862f571f2ef5a324a03d99e9a453a4f6175e..0f57ddc4ecc274cbbe2be26618ec9fa90234ea9d 100644 (file)
@@ -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;
index 436dc21318af776bd6c5a7ce8eae35aac995d349..f2960e4de3440b55a2678a2aebf8bf40194c08bd 100644 (file)
@@ -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 */
index e80b9c762a03593ba47c905d34f6996f7a772bc0..6a7fc50510999eb330982c3d7b4452cb373063e2 100644 (file)
@@ -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;