[PATCH 3/4] arm64: Add IOMMU dma_ops

Yong Wu yong.wu at mediatek.com
Thu Jun 4 05:29:52 PDT 2015


Hi Robin,
     Sorry to disturb you. When prepare iommu based on this dma-v3. I
meet some problem about how to use the dma-iommu.
     I list some sample code like below:
//========
int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
{
        if (args->args_count != 2) {            
                return -EINVAL;
        }

        /* save the private data from args  
         * the private data is larbid and portid in our platform */
        priv->larbid = args->args[0];
        priv->portid = args->args[1];

        /*list the private data */
        list_add_tail(&priv->client, &head->client);

        /* save the list to dev->archdata->iommu */
        ...
}
static int mtk_iommu_init_fn(struct device_node *np)
{
        of_iommu_set_ops(np, &mtk_iommu_ops);   
        return 0;
}

IOMMU_OF_DECLARE(mtkm4u, "mediatek,mt8173-m4u", mtk_iommu_init_fn);
//=======

Question :
  1: if there are 2 client devices use iommu, it will be like this in
dtsi,
                disp:testiommu at 1400c000 {
                        compatible = "mediatek,mt8173-test";
                        iommus = <&iommu M4U_LARB0_ID 0>,
                                 <&iommu M4U_LARB1_ID 3>;
                };
                disp1:testiommu at 1400D000 {
                        compatible = "mediatek,mt8173-disptest1";
                        iommus = <&iommu M4U_LARB0_ID 8>, 
                                 <&iommu M4U_LARB1_ID 2>;
                };
    Then both devices will enter arch_setup_dma_ops and their parameter
"struct iommu_ops *" is not zero, then it will create two
dma-iommu-domain.
    If we expect all the client device share a iommu domain, then how
should i do?

2. iommu_dma_attach_device will be called automatically in the notify
"__iommu_attach_notifier". But it run before the probe of our iommu
device.
    Then we can't write the register to enable iommu in *_attach_device
because we have not parsed the dtsi at that time.
   ->I have tried to move parse dtsi into mtk_iommu_of_xlate, in order
to read/write register in attach_device.
But it will be warning like this:
(150604_09:43:41.094)WARNING: CPU: 0 PID: 1
at /proj/mtk40525/upstreamdev/chromebook_kernelonly/kernel/mediatek/drivers/base/dd.c:286 driver_probe_device+0x25c/0x29c()

3.In mtk_iommu_probe, we can't get "struct iommu_domain *" from the
current iommu device, we should use it while devm_request_irq.
I have to use the global variable here?!

4.If I don't implement the of_xlate and IOMMU_OF_DECLARE, I call
iommu_dma_create_domain in the mtk_iommu_probe, but I can not
get the "iommu_dma_ops" which is static in arch/arm64/mm/dma-mapping.c
to assign to dev->archdata->dma_ops for the iommu client device.

If i miss something, please tell me and help give some suggestion.
Thanks very much.

On Wed, 2015-05-27 at 15:09 +0100, Robin Murphy wrote:
> Taking some inspiration from the arch/arm code, implement the
> arch-specific side of the DMA mapping ops using the new IOMMU-DMA layer.
> 
> Whilst proliferating per-device private IOMMU data via dev->archdata is
> less than ideal, it will do the job for now, especially since we can't
> easily handle the kind of problematic system topologies in the current
> IOMMU API anyway.
> 
> Signed-off-by: Robin Murphy <robin.murphy at arm.com>
> ---
>  arch/arm64/include/asm/device.h      |   3 +
>  arch/arm64/include/asm/dma-mapping.h |  14 ++
>  arch/arm64/mm/dma-mapping.c          | 342 +++++++++++++++++++++++++++++++++++
>  include/linux/dma-iommu.h            |   4 +-
>  4 files changed, 361 insertions(+), 2 deletions(-)
> 
[snip]
> +struct iommu_dma_notifier_data {
> +	struct list_head list;
> +	struct device *dev;
> +	struct iommu_dma_domain *dma_domain;
> +};
> +static LIST_HEAD(iommu_dma_masters);
> +static DEFINE_MUTEX(iommu_dma_notifier_lock);
> +
> +static int __iommu_attach_notifier(struct notifier_block *nb,
> +				   unsigned long action, void *data)
> +{
> +	struct iommu_dma_notifier_data *master, *tmp;
> +
> +	if (action != BUS_NOTIFY_ADD_DEVICE)
> +		return 0;
> +	/*
> +	 * We expect the list to only contain the most recent addition,
> +	 * which *should* be the same device as @data, so just process the
> +	 * whole thing blindly. If any previous attachments did happen to
> +	 * fail, they get a free retry since the domains are still live.
> +	 */
> +	mutex_lock(&iommu_dma_notifier_lock);
> +	list_for_each_entry_safe(master, tmp, &iommu_dma_masters, list) {
> +		if (iommu_dma_attach_device(master->dev, master->dma_domain)) {
> +			pr_warn("Failed to attach device %s to IOMMU mapping; retaining platform DMA ops\n",
> +				dev_name(master->dev));
> +		} else {
> +			master->dev->archdata.dma_ops = &iommu_dma_ops;
> +			/* it's safe to drop the initial refcount now */
> +			iommu_dma_release_domain(master->dma_domain);
> +			list_del(&master->list);
> +			kfree(master);
> +		}
> +	}
> +	mutex_unlock(&iommu_dma_notifier_lock);
> +	return 0;
> +}
> +
> +static int register_iommu_dma_ops_notifier(struct bus_type *bus)
> +{
> +	int ret;
> +	struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
> +
> +	/*
> +	 * The device must be attached to a domain before its driver probe,
> +	 * in case the driver allocates DMA buffers immediately. However, most
> +	 * IOMMU drivers are currently configuring groups in their add_device
> +	 * callback, so the attach should happen after that. Since the IOMMU
> +	 * core uses a bus notifier for add_device, do the same but with a
> +	 * stupidly low priority to ensure the appropriate ordering.
> +	 *
> +	 * This can hopefully all go away once we have default domains in the
> +	 * IOMMU core.
> +	 */
> +	nb->notifier_call = __iommu_attach_notifier;
> +	nb->priority = INT_MIN;
> +
> +	ret = bus_register_notifier(bus, nb);
> +	if (ret) {
> +		pr_warn("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n",
> +			bus->name);
> +		kfree(nb);
> +	}
> +	return ret;
> +}
> +
> +static int __init arm64_iommu_dma_init(void)
> +{
> +	int ret;
> +
> +	ret = iommu_dma_init();
> +	if (!ret)
> +		ret = register_iommu_dma_ops_notifier(&platform_bus_type);
> +	if (!ret)
> +		ret = register_iommu_dma_ops_notifier(&amba_bustype);
> +	return ret;
> +}
> +arch_initcall(arm64_iommu_dma_init);
> +
> +static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
> +				  const struct iommu_ops *ops)
> +{
> +	struct iommu_dma_notifier_data *iommudata;
> +
> +	if (!ops)
> +		return;
> +
> +	iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL);
> +	if (!iommudata)
> +		return;
> +
> +	iommudata->dev = dev;
> +	iommudata->dma_domain = iommu_dma_create_domain(ops, dma_base, size);
> +	if (!iommudata->dma_domain) {
> +		pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
> +				size, dev_name(dev));
> +		kfree(iommudata);
> +		return;
> +	}
> +	mutex_lock(&iommu_dma_notifier_lock);
> +	list_add(&iommudata->list, &iommu_dma_masters);
> +	mutex_unlock(&iommu_dma_notifier_lock);
> +}
> +





More information about the linux-arm-kernel mailing list