Thread (20 messages) 20 messages, 4 authors, 2015-10-21

Re: [PATCH v4 5/6] iommu/mediatek: Add mt8173 IOMMU driver

From: Yong Wu <hidden>
Date: 2015-09-15 05:53:22
Also in: linux-arm-kernel, linux-iommu, linux-mediatek, lkml

On Fri, 2015-09-11 at 16:33 +0100, Robin Murphy wrote:
On 03/08/15 11:21, Yong Wu wrote:
quoted
This patch adds support for mediatek m4u (MultiMedia Memory Management
Unit).

Signed-off-by: Yong Wu <yong.wu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
[...]
quoted
+/*
+ * There is only one iommu domain called the m4u domain that
+ * all Multimedia modules share.
+ */
+static struct mtk_iommu_domain *m4udom;
It's a shame this can't be part of the m4u device's mtk_iommu_data, but 
since the way iommu_domain_alloc works makes that impossible, I think we 
have little choice but to use the global and hope your guys never build 
a system with two of these things in ;)
Hi Robin,
   Thanks very much for your review. This gobal variable trouble me very
much. please also help check below.
[...]
quoted
+static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type)
+{
+       struct mtk_iommu_domain *priv;
+
+       if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
+               return NULL;
+
+       if (m4udom)/* The m4u domain exist. */
+               return &m4udom->domain;
     From Joerg's comment[0]: "This is not going to work. If you always
return the same domain the iommu core might re-initialize domain state
(and overwrite changed state)."

     It seems that I have to delete this here. then alloc iommu-domain
every time. and add some workaround code in mtk_iommu_attach_device like
our v3[1](reserve one as the m4u domain and delete the others).
Then the code maybe not very concise, but it could also work in the
future, Is it OK?

[0]:http://lists.linuxfoundation.org/pipermail/iommu/2015-August/014057.html
[1]:http://lists.linuxfoundation.org/pipermail/iommu/2015-July/013631.html
quoted
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return NULL;
+
+       priv->domain.geometry.aperture_start = 0;
+       priv->domain.geometry.aperture_end = DMA_BIT_MASK(32);
+       priv->domain.geometry.force_aperture = true;
My intention is that in the IOMMU_DOMAIN_DMA case you'd call 
iommu_get_dma_cookie(&priv->domain) here as well, that way I can get rid 
of some of the dodgy workarounds in arch_setup_dma_ops which try to 
cover all possible cases (and which I'm now not 100% confident in). I'm 
just about to start trying to fix that up (expect a repost of my series 
in a week or two once -rc1 has landed).
  I will add like this:
  if (type == IOMMU_DOMAIN_DMA && iommu_get_dma_cookie(&priv->domain)) {
       kfree(priv);
       return NULL;
  }
quoted
+
+       m4udom = priv;
+
+       return &priv->domain;
+}
[...]
quoted
+static int mtk_iommu_add_device(struct device *dev)
+{
+       struct iommu_group *group;
+       int ret;
+
+       if (!dev->archdata.iommu) /* Not a iommu client device */
+               return -ENODEV;
+
+       group = iommu_group_get(dev);
+       if (!group) {
+               group = iommu_group_alloc();
+               if (IS_ERR(group)) {
+                       dev_err(dev, "Failed to allocate IOMMU group\n");
+                       return PTR_ERR(group);
+               }
+       }
+
 > +       ret = iommu_group_add_device(group, dev);
quoted
+       if (ret) {
+               dev_err(dev, "Failed to add IOMMU group\n");
+               goto err_group_put;
+       }
I know the rest of the code means that you can't hit it in practice, but 
if you ever did have two client devices in the same group then the 
iommu_group_get() could legitimately succeed for the second device, then 
you'd blow up creating a duplicate sysfs entry by adding the device to 
its own group again. Probably not what you want.
   the "dev" is different while enter this function, That is to say
every client device have its own iommu-group. is it right?
quoted
+
+       ret = iommu_attach_group(&m4udom->domain, group);
+       if (ret)
+               dev_err(dev, "Failed to attach IOMMU group\n");
Similarly here, if two devices did share a group then the group could 
legitimately already be attached to a domain here (by the first device), 
so attaching it again would be wrong. I think it would be nicer to check 
with iommu_get_domain_for_dev() first to see if you need to do anything 
at all (a valid domain from that implies a valid group).
   Here all the devices has their own iommu-group, I only attach the
same iommu-domain for them due to our m4u HW. All the clients are in
M4U-HW's domain and there is only one pagetable here.
quoted
+
+err_group_put:
+       iommu_group_put(group);
+       return ret;
+}
[...]
quoted
+static int mtk_iommu_probe(struct platform_device *pdev)
+{
+       struct mtk_iommu_data   *data;
+       struct device           *dev = &pdev->dev;
+       void __iomem            *protect;
+       int                     ret;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       /* Protect memory. HW will access here while translation fault.*/
+       protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL);
+       if (!protect)
+               return -ENOMEM;
+       data->protect_base = virt_to_phys(protect);
+
+       ret = mtk_iommu_parse_dt(pdev, data);
+       if (ret)
+               return ret;
+
+       if (!m4udom)/* There is no iommu client */
+               return 0;
I don't quite follow this: m4udom is apparently only created by someone 
calling domain_alloc() - how can you guarantee that happens before this 
driver is probed? - but if they then go and try to attach the device to 
their new domain, it's going to end up in mtk_hw_init() poking the 
hardware of the m4u device that can't have even probed yet.
    I think the probe will run always earlier than mtk_hw_init.
    In the mtk_iommu_attach_device below, I add iommu_group_get to
guarantee the sequence.
//==================
static int mtk_iommu_attach_device(struct iommu_domain *domain,
				   struct device *dev)
{
	struct mtk_iommu_domain *priv = to_mtk_domain(domain);
	struct iommu_group *group;
	int ret;

	group = iommu_group_get(dev);
	if (!group)
		return 0;
	iommu_group_put(group);

	ret = mtk_iommu_init_domain_context(priv);
	if (ret)
		return ret;

	return mtk_iommu_config(priv, dev, true);
}
//======================
   After the probe done, It will enter bus_set_iommu->
mtk_iommu_add_device where will create iommu group for it.
then enter iommu_attach_group->mtk_iommu_attach_device again.
is this ok here?

About "how can you guarantee that happens before this 
driver is probed?"
->Sorry, I can't guarantee this. The domain_alloc is called by
arch_setup_dma_ops in the DMA core, I will change this depend on the
next DMA.
I can only imagine it currently works by sheer chance due to the 
horrible arch_setup_dma_ops delayed attachment workaround, so even if I 
can't remove that completely when I look at it next week I'm liable to 
change it in a way that breaks this badly ;)

Robin.
quoted
+
+       data->dev = dev;
+       m4udom->data = data;
+       dev_set_drvdata(dev, m4udom);
+
+       return 0;
+}
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help