From mboxrd@z Thu Jan 1 00:00:00 1970 From: Robin Murphy Subject: [PATCH v4 5/8] iommu/of: Introduce iommu_fwspec Date: Fri, 1 Jul 2016 17:50:14 +0100 Message-ID: <7947dbaa0e0d4ace8eebe8de1fe5810fe05f7734.1467388950.git.robin.murphy@arm.com> References: Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: iommu-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Errors-To: iommu-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org To: will.deacon-5wv7dgnIgG8@public.gmane.org, joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, thunder.leizhen-hv44wF8Li93QT0dZR+AlfA@public.gmane.org List-Id: devicetree@vger.kernel.org Introduce a common structure to hold the per-device firmware data that non-architectural IOMMU drivers generally need to keep track of. Initially this is DT-specific to complement the existing of_iommu support code, but will generalise further once other firmware methods (e.g. ACPI IORT) come along. Ultimately the aim is to promote the fwspec to a first-class member of struct device, and handle the init/free automatically in the firmware code. That way we can have API calls look for dev->fwspec->iommu_ops before falling back to dev->bus->iommu_ops, and thus gracefully handle those troublesome multi-IOMMU systems which we currently cannot. To start with, though, make use of the existing archdata field and delegate the init/free to drivers to allow an incremental conversion rather than the impractical pain of trying to attempt everything in one go. Suggested-by: Will Deacon Signed-off-by: Robin Murphy --- v4: Move dev_iommu_fwspec() definition out-of-line. drivers/iommu/of_iommu.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of_iommu.h | 15 ++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 1fe1f620f79d..4618e89d6a37 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -216,3 +216,55 @@ void __init of_iommu_init(void) of_node_full_name(np)); } } + +int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np) +{ + struct iommu_fwspec *fwspec = dev->archdata.iommu; + + if (fwspec) + return 0; + + fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL); + if (!fwspec) + return -ENOMEM; + + fwspec->iommu_np = of_node_get(iommu_np); + fwspec->iommu_ops = of_iommu_get_ops(iommu_np); + dev->archdata.iommu = fwspec; + return 0; +} + +void iommu_fwspec_free(struct device *dev) +{ + struct iommu_fwspec *fwspec = dev->archdata.iommu; + + if (fwspec) { + of_node_put(fwspec->iommu_np); + kfree(fwspec); + } +} + +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids) +{ + struct iommu_fwspec *fwspec = dev->archdata.iommu; + size_t size; + + if (!fwspec) + return -EINVAL; + + size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + 1]); + fwspec = krealloc(dev->archdata.iommu, size, GFP_KERNEL); + if (!fwspec) + return -ENOMEM; + + while (num_ids--) + fwspec->ids[fwspec->num_ids++] = *ids++; + + dev->archdata.iommu = fwspec; + return 0; +} + +inline struct iommu_fwspec *dev_iommu_fwspec(struct device *dev) +{ + return dev->archdata.iommu; +} diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index bd02b44902d0..308791fca32d 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -15,6 +15,14 @@ extern void of_iommu_init(void); extern const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np); +struct iommu_fwspec { + const struct iommu_ops *iommu_ops; + struct device_node *iommu_np; + void *iommu_priv; + unsigned int num_ids; + u32 ids[]; +}; + #else static inline int of_get_dma_window(struct device_node *dn, const char *prefix, @@ -31,8 +39,15 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev, return NULL; } +struct iommu_fwspec; + #endif /* CONFIG_OF_IOMMU */ +int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np); +void iommu_fwspec_free(struct device *dev); +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids); +struct iommu_fwspec *dev_iommu_fwspec(struct device *dev); + 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); -- 2.8.1.dirty