[PATCH v7 3/9] iommu/exynos: fix page table maintenance

Cho KyongHo pullip.cho at samsung.com
Mon Jul 15 07:21:56 EDT 2013


> -----Original Message-----
> From: Bartlomiej Zolnierkiewicz [mailto:b.zolnierkie at samsung.com]
> Sent: Friday, July 12, 2013 2:38 AM
> 
> Hi,
> 
> Some minor nitpicks below.
> 
> On Friday, July 05, 2013 09:29:18 PM Cho KyongHo wrote:
> > This prevents allocating lv2 page table for the lv1 page table entry
> > that already has 1MB page mapping. In addition some BUG_ON() is
> > changed to WARN_ON().
> >
> > Signed-off-by: Cho KyongHo <pullip.cho at samsung.com>
> > ---
> >  drivers/iommu/exynos-iommu.c |   34 ++++++++++++++++++++++++++--------
> >  1 files changed, 26 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
> > index e3be3e5..2bfe9fa 100644
> > --- a/drivers/iommu/exynos-iommu.c
> > +++ b/drivers/iommu/exynos-iommu.c
> > @@ -862,12 +862,14 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
> >  		pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
> >  		BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1));
> >  		if (!pent)
> > -			return NULL;
> > +			return ERR_PTR(-ENOMEM);
> >
> >  		*sent = mk_lv1ent_page(__pa(pent));
> >  		*pgcounter = NUM_LV2ENTRIES;
> >  		pgtable_flush(pent, pent + NUM_LV2ENTRIES);
> >  		pgtable_flush(sent, sent + 1);
> > +	} else if (lv1ent_section(sent)) {
> > +		return ERR_PTR(-EADDRINUSE);
> >  	}
> >
> >  	return page_entry(sent, iova);
> > @@ -944,16 +946,16 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova,
> >  		pent = alloc_lv2entry(entry, iova,
> >  					&priv->lv2entcnt[lv1ent_offset(iova)]);
> >
> > -		if (!pent)
> > -			ret = -ENOMEM;
> > +		if (IS_ERR(pent))
> > +			ret = PTR_ERR(pent);
> >  		else
> >  			ret = lv2set_page(pent, paddr, size,
> >  					&priv->lv2entcnt[lv1ent_offset(iova)]);
> >  	}
> >
> >  	if (ret) {
> > -		pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n",
> > -							__func__, iova, size);
> > +		pr_err("%s: Failed(%d) to map iova 0x%#x bytes @ %#lx\n",
> > +						__func__, ret, size, iova);
> >  	}
> 
> Intendation is a bit weird, it should be more like:
> 
> 		pr_err("%s: Failed(%d) to map iova 0x%#x bytes @ %#lx\n",
> 			__func__, ret, size, iova);
> 
> to be consistent with the rest of the driver.
> 
> You could have also removed superfluous braces while at it.
> 

Do you think it is better to read the code?
Hmm, I think it is better too.
Thanks.

> >  	spin_unlock_irqrestore(&priv->pgtablelock, flags);
> > @@ -968,6 +970,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain,
> >  	struct sysmmu_drvdata *data;
> >  	unsigned long flags;
> >  	unsigned long *ent;
> > +	size_t err_page;
> >
> >  	BUG_ON(priv->pgtable == NULL);
> >
> > @@ -976,7 +979,8 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain,
> >  	ent = section_entry(priv->pgtable, iova);
> >
> >  	if (lv1ent_section(ent)) {
> > -		BUG_ON(size < SECT_SIZE);
> > +		if (WARN_ON(size < SECT_SIZE))
> > +			goto err;
> >
> >  		*ent = 0;
> >  		pgtable_flush(ent, ent + 1);
> > @@ -1008,7 +1012,8 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain,
> >  	}
> >
> >  	/* lv1ent_large(ent) == true here */
> > -	BUG_ON(size < LPAGE_SIZE);
> > +	if (WARN_ON(size < LPAGE_SIZE))
> > +		goto err;
> >
> >  	memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
> >  	pgtable_flush(ent, ent + SPAGES_PER_LPAGE);
> > @@ -1023,8 +1028,21 @@ done:
> >  		sysmmu_tlb_invalidate_entry(data->dev, iova);
> >  	spin_unlock_irqrestore(&priv->lock, flags);
> >
> > -
> >  	return size;
> > +err:
> > +	spin_unlock_irqrestore(&priv->pgtablelock, flags);
> > +
> > +	err_page = (
> > +		((unsigned long)ent - (unsigned long)priv->pgtable)
> > +			< (NUM_LV1ENTRIES * sizeof(long))
> 
> Maybe you could add LV1TABLE_SIZE define and use it here (there is
> already a LV2TABLE_SIZE define)?

Yes. But, LV2TABLE_SIZE is used in more places than one.
I do not feel that it is needed to define LV1TABLE_SIZE for the single line.

> 
> > +			   ) ?  SECT_SIZE : LPAGE_SIZE;
> 
> It also seems that err_page should be of unsigned long type, no need
> to make it size_t one.
> 

err_page is the page size.
I agree that the name of the variable is not proper to indicate size.

> The above code is quite ugly currently, it could be rewritten into
> something prettier, i.e.:
> 
> 	err_page = (unsigned long)ent - (unsigned long)priv->pgtable;
> 	err_page = (err_page < LV1TABLE_SIZE) ? SECT_SIZE : LPAGE_SIZE;
> 
Ah, this is the reason that you addresses err_page could be unsigned long.
I agree that it is prettier.

> > +	pr_err("%s: Failed due to size(%#lx) @ %#x is"\
> > +		" smaller than page size %#x\n",
> > +		__func__, iova, size, err_page);
> 
> Aren't iova and size arguments interchanged here?
Oh, it is my mistake.

It will should be fixed in the next patchset with the change in
calculation of err_page.
> 
> > +
> > +	       return 0;
> 
> There is an intendation issue here (extra whitespaces).

Yes. Thanks.

> 
> > +
> >  }
> >
> >  static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
> 
> Best regards,
> --
> Bartlomiej Zolnierkiewicz
> Samsung R&D Institute Poland
> Samsung Electronics

Thank you.

Cho KyongHo.




More information about the linux-arm-kernel mailing list