All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yong Wu <yong.wu@mediatek.com>
To: Will Deacon <will.deacon@arm.com>, Robin Murphy <Robin.Murphy@arm.com>
Cc: Mark Rutland <Mark.Rutland@arm.com>,
	Catalin Marinas <Catalin.Marinas@arm.com>,
	"youhua.li@mediatek.com" <youhua.li@mediatek.com>,
	Thierry Reding <treding@nvidia.com>,
	"k.zhang@mediatek.com" <k.zhang@mediatek.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"arnd@arndb.de" <arnd@arndb.de>, Tomasz Figa <tfiga@google.com>,
	Rob Herring <robh+dt@kernel.org>,
	"linux-mediatek@lists.infradead.org"
	<linux-mediatek@lists.infradead.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>,
	"pebolle@tiscali.nl" <pebolle@tiscali.nl>,
	"frederic.chen@mediatek.com" <frederic.chen@mediatek.com>,
	"srv_heupstream@mediatek.com" <srv_heupstream@mediatek.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"iommu@lists.linux-foundation.org"
	<iommu@lists.linux-foundation.org>,
	Daniel
Subject: Re: [PATCH v4 3/6] iommu: add ARM short descriptor page table allocator.
Date: Tue, 22 Sep 2015 22:12:47 +0800	[thread overview]
Message-ID: <1442931167.17514.39.camel@mhfsdcap03> (raw)
In-Reply-To: <1442501662.8145.151.camel@mhfsdcap03>

> > > +static int arm_short_unmap(struct io_pgtable_ops *ops,
> > > +                          unsigned long iova,
> > > +                          size_t size)
> > > +{
> > > +       struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
> > > +       struct io_pgtable_cfg *cfg = &data->iop.cfg;
> > > +       arm_short_iopte *pgd, *pte = NULL;
> > > +       arm_short_iopte curpgd, curpte = 0;
> > > +       phys_addr_t paddr;
> > > +       unsigned int iova_base, blk_size = 0;
> > > +       void *cookie = data->iop.cookie;
> > > +       bool pgtablefree = false;
> > > +
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
> > > +
> > > +       /* Get block size */
> > > +       if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova);
> > > +
> > > +               if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
> > > +                       blk_size = SZ_4K;
> > > +               else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
> > > +                       blk_size = SZ_64K;
> > > +               else
> > > +                       WARN_ON(1);
> 
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
> > > +               blk_size = SZ_1M;
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
> > > +               blk_size = SZ_16M;
> > > +       } else {
> > > +               WARN_ON(1); 
> > > +       }
> > > +
> > > +       iova_base = iova & ~(blk_size - 1);
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova_base);
> > > +       paddr = arm_short_iova_to_phys(ops, iova_base);
> > > +       curpgd = *pgd;
> > > +
> > > +       if (blk_size == SZ_4K || blk_size == SZ_64K) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova_base);
> > > +               curpte = *pte;
> > > +               __arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);
> > > +
> > > +            pgtablefree = _arm_short_whether_free_pgtable(pgd);
> > > +            if (pgtablefree)
> > > +                 __arm_short_set_pte(pgd, 0, 1, cfg);
> > > +       } else if (blk_size == SZ_1M || blk_size == SZ_16M) {
> > > +               __arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
> > > +       }
> > > +
> > > +    cfg->tlb->tlb_add_flush(iova_base, blk_size, true, cookie);
> > > +    cfg->tlb->tlb_sync(cookie);
> > > +
> > > +       if (pgtablefree)/* Free pgtable after tlb-flush */
> > > +              __arm_short_free_pgtable(ARM_SHORT_GET_PGTABLE_VA(curpgd),
> > > +                                        ARM_SHORT_BYTES_PER_PTE, false, cfg);
> > > +
> > > +       if (blk_size > size) { /* Split the block */
> > > +               return arm_short_split_blk_unmap(
> > > +                               ops, iova, paddr, size,
> > > +                               ARM_SHORT_PGD_GET_PROT(curpgd),
> > > +                               ARM_SHORT_PTE_LARGE_GET_PROT(curpte),
> > > +                               blk_size);
> > > +       } else if (blk_size < size) {
> > > +               /* Unmap the block while remap partial again after split */
> > > +               return blk_size +
> > > +                       arm_short_unmap(ops, iova + blk_size, size - blk_size);

Hi Will, Robin,
     I would like to show you a problem I met, The recursion here may
lead to stack overflow while we test FHD video decode.

    From the log, I get the internal variable in the error case: the
"size" is 0x100000, the "iova" is 0xfea00000, but at that time the
"blk_size" is 0x1000 as it was the map of small-page. so it enter the
recursion here.
    
    After check the unmap flow, there is only a iommu_unmap in
__iommu_dma_unmap, and it won't check the physical address align in
iommu_unmap.
so if the iova and size both are SZ_16M or SZ_1M align by chance, it
also enter the arm_short_unmap even though it was the map of small-page.

    So.
    a) Do we need unmap each sg item while iommu_dma_unmap?, like below:

//===============
static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t
dma_addr)
{
	/* ...and if we can't, then something is horribly, horribly wrong */
+       for_each_sg(sg, s, nents, i)
		BUG_ON(iommu_unmap(domain, pfn << shift, size) < size);
	__free_iova(iovad, iova);
}
//===============
 
    b). I need to add do-while which was suggested to delete from [1] in
arm_short_unmap for this case.

     After I test locally, I prepare to add the do-while like below:
     
//==============================
static int arm_short_unmap(struct io_pgtable_ops *ops,
			   unsigned long iova,
			   size_t size)
{
	struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
	struct io_pgtable_cfg *cfg = &data->iop.cfg;
	arm_short_iopte *pgd, *pte = NULL;
	arm_short_iopte curpgd, curpte = 0;
	unsigned int blk_base, blk_size;
	int unmap_size = 0;
	bool pgtempty;

	do {
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
		blk_size = 0;
		pgtempty = false;

		/* Get block size */
		if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
			pte = arm_short_get_pte_in_pgd(*pgd, iova);

			if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
				blk_size = SZ_4K;
			else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
				blk_size = SZ_64K;
		} else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
			blk_size = SZ_1M;
		} else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
			blk_size = SZ_16M;
		}

		if (WARN_ON(!blk_size))
			return 0;

		blk_base = iova & ~(blk_size - 1);
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(blk_base);
		curpgd = *pgd;

		if (blk_size == SZ_4K || blk_size == SZ_64K) {
			pte = arm_short_get_pte_in_pgd(*pgd, blk_base);
			curpte = *pte;
			__arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);

			pgtempty = __arm_short_pgtable_empty(pgd);
			if (pgtempty)
				__arm_short_set_pte(pgd, 0, 1, cfg);
		} else if (blk_size == SZ_1M || blk_size == SZ_16M) {
			__arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
		}

		cfg->tlb->tlb_add_flush(blk_base, blk_size, true, data->iop.cookie);
		cfg->tlb->tlb_sync(data->iop.cookie);

		if (pgtempty)/* Free lvl2 pgtable after tlb-flush */
			__arm_short_free_pgtable(
					ARM_SHORT_GET_PGTABLE_VA(curpgd),
					ARM_SHORT_BYTES_PER_PTE, false, cfg);

		/*
		 * If the unmap size which is from the pgsize_bitmap is more
		 * than the current blk_size, unmap it continuously.
		 */
		if (blk_size <= size) {
			iova += blk_size;
			size -= blk_size;
			unmap_size += blk_size;
			continue;
		} else { /* Split this block */
			return arm_short_split_blk_unmap(
					ops, iova, size, blk_size,
					ARM_SHORT_PGD_GET_PROT(curpgd),
					ARM_SHORT_PTE_GET_PROT_LARGE(curpte));
		}
	}while (size);

	return unmap_size;
}
//=============================

    Is there any other suggestion?
    Thanks very much.


[1]:http://lists.linuxfoundation.org/pipermail/iommu/2015-June/013322.html

> > > +       }
> > > +
> > > +       return size;
> > > +}
> > > +
> _______________________________________________
> iommu mailing list
> iommu@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu

WARNING: multiple messages have this Message-ID (diff)
From: yong.wu@mediatek.com (Yong Wu)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 3/6] iommu: add ARM short descriptor page table allocator.
Date: Tue, 22 Sep 2015 22:12:47 +0800	[thread overview]
Message-ID: <1442931167.17514.39.camel@mhfsdcap03> (raw)
In-Reply-To: <1442501662.8145.151.camel@mhfsdcap03>

> > > +static int arm_short_unmap(struct io_pgtable_ops *ops,
> > > +                          unsigned long iova,
> > > +                          size_t size)
> > > +{
> > > +       struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
> > > +       struct io_pgtable_cfg *cfg = &data->iop.cfg;
> > > +       arm_short_iopte *pgd, *pte = NULL;
> > > +       arm_short_iopte curpgd, curpte = 0;
> > > +       phys_addr_t paddr;
> > > +       unsigned int iova_base, blk_size = 0;
> > > +       void *cookie = data->iop.cookie;
> > > +       bool pgtablefree = false;
> > > +
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
> > > +
> > > +       /* Get block size */
> > > +       if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova);
> > > +
> > > +               if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
> > > +                       blk_size = SZ_4K;
> > > +               else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
> > > +                       blk_size = SZ_64K;
> > > +               else
> > > +                       WARN_ON(1);
> 
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
> > > +               blk_size = SZ_1M;
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
> > > +               blk_size = SZ_16M;
> > > +       } else {
> > > +               WARN_ON(1); 
> > > +       }
> > > +
> > > +       iova_base = iova & ~(blk_size - 1);
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova_base);
> > > +       paddr = arm_short_iova_to_phys(ops, iova_base);
> > > +       curpgd = *pgd;
> > > +
> > > +       if (blk_size == SZ_4K || blk_size == SZ_64K) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova_base);
> > > +               curpte = *pte;
> > > +               __arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);
> > > +
> > > +            pgtablefree = _arm_short_whether_free_pgtable(pgd);
> > > +            if (pgtablefree)
> > > +                 __arm_short_set_pte(pgd, 0, 1, cfg);
> > > +       } else if (blk_size == SZ_1M || blk_size == SZ_16M) {
> > > +               __arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
> > > +       }
> > > +
> > > +    cfg->tlb->tlb_add_flush(iova_base, blk_size, true, cookie);
> > > +    cfg->tlb->tlb_sync(cookie);
> > > +
> > > +       if (pgtablefree)/* Free pgtable after tlb-flush */
> > > +              __arm_short_free_pgtable(ARM_SHORT_GET_PGTABLE_VA(curpgd),
> > > +                                        ARM_SHORT_BYTES_PER_PTE, false, cfg);
> > > +
> > > +       if (blk_size > size) { /* Split the block */
> > > +               return arm_short_split_blk_unmap(
> > > +                               ops, iova, paddr, size,
> > > +                               ARM_SHORT_PGD_GET_PROT(curpgd),
> > > +                               ARM_SHORT_PTE_LARGE_GET_PROT(curpte),
> > > +                               blk_size);
> > > +       } else if (blk_size < size) {
> > > +               /* Unmap the block while remap partial again after split */
> > > +               return blk_size +
> > > +                       arm_short_unmap(ops, iova + blk_size, size - blk_size);

Hi Will, Robin,
     I would like to show you a problem I met, The recursion here may
lead to stack overflow while we test FHD video decode.

    From the log, I get the internal variable in the error case: the
"size" is 0x100000, the "iova" is 0xfea00000, but at that time the
"blk_size" is 0x1000 as it was the map of small-page. so it enter the
recursion here.
    
    After check the unmap flow, there is only a iommu_unmap in
__iommu_dma_unmap, and it won't check the physical address align in
iommu_unmap.
so if the iova and size both are SZ_16M or SZ_1M align by chance, it
also enter the arm_short_unmap even though it was the map of small-page.

    So.
    a) Do we need unmap each sg item while iommu_dma_unmap?, like below:

//===============
static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t
dma_addr)
{
	/* ...and if we can't, then something is horribly, horribly wrong */
+       for_each_sg(sg, s, nents, i)
		BUG_ON(iommu_unmap(domain, pfn << shift, size) < size);
	__free_iova(iovad, iova);
}
//===============
 
    b). I need to add do-while which was suggested to delete from [1] in
arm_short_unmap for this case.

     After I test locally, I prepare to add the do-while like below:
     
//==============================
static int arm_short_unmap(struct io_pgtable_ops *ops,
			   unsigned long iova,
			   size_t size)
{
	struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
	struct io_pgtable_cfg *cfg = &data->iop.cfg;
	arm_short_iopte *pgd, *pte = NULL;
	arm_short_iopte curpgd, curpte = 0;
	unsigned int blk_base, blk_size;
	int unmap_size = 0;
	bool pgtempty;

	do {
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
		blk_size = 0;
		pgtempty = false;

		/* Get block size */
		if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
			pte = arm_short_get_pte_in_pgd(*pgd, iova);

			if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
				blk_size = SZ_4K;
			else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
				blk_size = SZ_64K;
		} else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
			blk_size = SZ_1M;
		} else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
			blk_size = SZ_16M;
		}

		if (WARN_ON(!blk_size))
			return 0;

		blk_base = iova & ~(blk_size - 1);
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(blk_base);
		curpgd = *pgd;

		if (blk_size == SZ_4K || blk_size == SZ_64K) {
			pte = arm_short_get_pte_in_pgd(*pgd, blk_base);
			curpte = *pte;
			__arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);

			pgtempty = __arm_short_pgtable_empty(pgd);
			if (pgtempty)
				__arm_short_set_pte(pgd, 0, 1, cfg);
		} else if (blk_size == SZ_1M || blk_size == SZ_16M) {
			__arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
		}

		cfg->tlb->tlb_add_flush(blk_base, blk_size, true, data->iop.cookie);
		cfg->tlb->tlb_sync(data->iop.cookie);

		if (pgtempty)/* Free lvl2 pgtable after tlb-flush */
			__arm_short_free_pgtable(
					ARM_SHORT_GET_PGTABLE_VA(curpgd),
					ARM_SHORT_BYTES_PER_PTE, false, cfg);

		/*
		 * If the unmap size which is from the pgsize_bitmap is more
		 * than the current blk_size, unmap it continuously.
		 */
		if (blk_size <= size) {
			iova += blk_size;
			size -= blk_size;
			unmap_size += blk_size;
			continue;
		} else { /* Split this block */
			return arm_short_split_blk_unmap(
					ops, iova, size, blk_size,
					ARM_SHORT_PGD_GET_PROT(curpgd),
					ARM_SHORT_PTE_GET_PROT_LARGE(curpte));
		}
	}while (size);

	return unmap_size;
}
//=============================

    Is there any other suggestion?
    Thanks very much.


[1]:http://lists.linuxfoundation.org/pipermail/iommu/2015-June/013322.html

> > > +       }
> > > +
> > > +       return size;
> > > +}
> > > +
> _______________________________________________
> iommu mailing list
> iommu at lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu

WARNING: multiple messages have this Message-ID (diff)
From: Yong Wu <yong.wu@mediatek.com>
To: Will Deacon <will.deacon@arm.com>, Robin Murphy <Robin.Murphy@arm.com>
Cc: Mark Rutland <Mark.Rutland@arm.com>,
	Catalin Marinas <Catalin.Marinas@arm.com>,
	"youhua.li@mediatek.com" <youhua.li@mediatek.com>,
	Thierry Reding <treding@nvidia.com>,
	"k.zhang@mediatek.com" <k.zhang@mediatek.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"arnd@arndb.de" <arnd@arndb.de>, Tomasz Figa <tfiga@google.com>,
	Rob Herring <robh+dt@kernel.org>,
	"linux-mediatek@lists.infradead.org" 
	<linux-mediatek@lists.infradead.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	"linux-arm-kernel@lists.infradead.org" 
	<linux-arm-kernel@lists.infradead.org>,
	"pebolle@tiscali.nl" <pebolle@tiscali.nl>,
	"frederic.chen@mediatek.com" <frederic.chen@mediatek.com>,
	"srv_heupstream@mediatek.com" <srv_heupstream@mediatek.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"iommu@lists.linux-foundation.org"
	<iommu@lists.linux-foundation.org>,
	Daniel Kurtz <djkurtz@google.com>,
	Sasha Hauer <kernel@pengutronix.de>,
	Lucas Stach <l.stach@pengutronix.de>
Subject: Re: [PATCH v4 3/6] iommu: add ARM short descriptor page table allocator.
Date: Tue, 22 Sep 2015 22:12:47 +0800	[thread overview]
Message-ID: <1442931167.17514.39.camel@mhfsdcap03> (raw)
In-Reply-To: <1442501662.8145.151.camel@mhfsdcap03>

> > > +static int arm_short_unmap(struct io_pgtable_ops *ops,
> > > +                          unsigned long iova,
> > > +                          size_t size)
> > > +{
> > > +       struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
> > > +       struct io_pgtable_cfg *cfg = &data->iop.cfg;
> > > +       arm_short_iopte *pgd, *pte = NULL;
> > > +       arm_short_iopte curpgd, curpte = 0;
> > > +       phys_addr_t paddr;
> > > +       unsigned int iova_base, blk_size = 0;
> > > +       void *cookie = data->iop.cookie;
> > > +       bool pgtablefree = false;
> > > +
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
> > > +
> > > +       /* Get block size */
> > > +       if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova);
> > > +
> > > +               if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
> > > +                       blk_size = SZ_4K;
> > > +               else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
> > > +                       blk_size = SZ_64K;
> > > +               else
> > > +                       WARN_ON(1);
> 
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
> > > +               blk_size = SZ_1M;
> > > +       } else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
> > > +               blk_size = SZ_16M;
> > > +       } else {
> > > +               WARN_ON(1); 
> > > +       }
> > > +
> > > +       iova_base = iova & ~(blk_size - 1);
> > > +       pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova_base);
> > > +       paddr = arm_short_iova_to_phys(ops, iova_base);
> > > +       curpgd = *pgd;
> > > +
> > > +       if (blk_size == SZ_4K || blk_size == SZ_64K) {
> > > +               pte = arm_short_get_pte_in_pgd(*pgd, iova_base);
> > > +               curpte = *pte;
> > > +               __arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);
> > > +
> > > +            pgtablefree = _arm_short_whether_free_pgtable(pgd);
> > > +            if (pgtablefree)
> > > +                 __arm_short_set_pte(pgd, 0, 1, cfg);
> > > +       } else if (blk_size == SZ_1M || blk_size == SZ_16M) {
> > > +               __arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
> > > +       }
> > > +
> > > +    cfg->tlb->tlb_add_flush(iova_base, blk_size, true, cookie);
> > > +    cfg->tlb->tlb_sync(cookie);
> > > +
> > > +       if (pgtablefree)/* Free pgtable after tlb-flush */
> > > +              __arm_short_free_pgtable(ARM_SHORT_GET_PGTABLE_VA(curpgd),
> > > +                                        ARM_SHORT_BYTES_PER_PTE, false, cfg);
> > > +
> > > +       if (blk_size > size) { /* Split the block */
> > > +               return arm_short_split_blk_unmap(
> > > +                               ops, iova, paddr, size,
> > > +                               ARM_SHORT_PGD_GET_PROT(curpgd),
> > > +                               ARM_SHORT_PTE_LARGE_GET_PROT(curpte),
> > > +                               blk_size);
> > > +       } else if (blk_size < size) {
> > > +               /* Unmap the block while remap partial again after split */
> > > +               return blk_size +
> > > +                       arm_short_unmap(ops, iova + blk_size, size - blk_size);

Hi Will, Robin,
     I would like to show you a problem I met, The recursion here may
lead to stack overflow while we test FHD video decode.

    From the log, I get the internal variable in the error case: the
"size" is 0x100000, the "iova" is 0xfea00000, but at that time the
"blk_size" is 0x1000 as it was the map of small-page. so it enter the
recursion here.
    
    After check the unmap flow, there is only a iommu_unmap in
__iommu_dma_unmap, and it won't check the physical address align in
iommu_unmap.
so if the iova and size both are SZ_16M or SZ_1M align by chance, it
also enter the arm_short_unmap even though it was the map of small-page.

    So.
    a) Do we need unmap each sg item while iommu_dma_unmap?, like below:

//===============
static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t
dma_addr)
{
	/* ...and if we can't, then something is horribly, horribly wrong */
+       for_each_sg(sg, s, nents, i)
		BUG_ON(iommu_unmap(domain, pfn << shift, size) < size);
	__free_iova(iovad, iova);
}
//===============
 
    b). I need to add do-while which was suggested to delete from [1] in
arm_short_unmap for this case.

     After I test locally, I prepare to add the do-while like below:
     
//==============================
static int arm_short_unmap(struct io_pgtable_ops *ops,
			   unsigned long iova,
			   size_t size)
{
	struct arm_short_io_pgtable *data = io_pgtable_ops_to_data(ops);
	struct io_pgtable_cfg *cfg = &data->iop.cfg;
	arm_short_iopte *pgd, *pte = NULL;
	arm_short_iopte curpgd, curpte = 0;
	unsigned int blk_base, blk_size;
	int unmap_size = 0;
	bool pgtempty;

	do {
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(iova);
		blk_size = 0;
		pgtempty = false;

		/* Get block size */
		if (ARM_SHORT_PGD_TYPE_IS_PGTABLE(*pgd)) {
			pte = arm_short_get_pte_in_pgd(*pgd, iova);

			if (ARM_SHORT_PTE_TYPE_IS_SMALLPAGE(*pte))
				blk_size = SZ_4K;
			else if (ARM_SHORT_PTE_TYPE_IS_LARGEPAGE(*pte))
				blk_size = SZ_64K;
		} else if (ARM_SHORT_PGD_TYPE_IS_SECTION(*pgd)) {
			blk_size = SZ_1M;
		} else if (ARM_SHORT_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
			blk_size = SZ_16M;
		}

		if (WARN_ON(!blk_size))
			return 0;

		blk_base = iova & ~(blk_size - 1);
		pgd = (arm_short_iopte *)data->pgd + ARM_SHORT_PGD_IDX(blk_base);
		curpgd = *pgd;

		if (blk_size == SZ_4K || blk_size == SZ_64K) {
			pte = arm_short_get_pte_in_pgd(*pgd, blk_base);
			curpte = *pte;
			__arm_short_set_pte(pte, 0, blk_size / SZ_4K, cfg);

			pgtempty = __arm_short_pgtable_empty(pgd);
			if (pgtempty)
				__arm_short_set_pte(pgd, 0, 1, cfg);
		} else if (blk_size == SZ_1M || blk_size == SZ_16M) {
			__arm_short_set_pte(pgd, 0, blk_size / SZ_1M, cfg);
		}

		cfg->tlb->tlb_add_flush(blk_base, blk_size, true, data->iop.cookie);
		cfg->tlb->tlb_sync(data->iop.cookie);

		if (pgtempty)/* Free lvl2 pgtable after tlb-flush */
			__arm_short_free_pgtable(
					ARM_SHORT_GET_PGTABLE_VA(curpgd),
					ARM_SHORT_BYTES_PER_PTE, false, cfg);

		/*
		 * If the unmap size which is from the pgsize_bitmap is more
		 * than the current blk_size, unmap it continuously.
		 */
		if (blk_size <= size) {
			iova += blk_size;
			size -= blk_size;
			unmap_size += blk_size;
			continue;
		} else { /* Split this block */
			return arm_short_split_blk_unmap(
					ops, iova, size, blk_size,
					ARM_SHORT_PGD_GET_PROT(curpgd),
					ARM_SHORT_PTE_GET_PROT_LARGE(curpte));
		}
	}while (size);

	return unmap_size;
}
//=============================

    Is there any other suggestion?
    Thanks very much.


[1]:http://lists.linuxfoundation.org/pipermail/iommu/2015-June/013322.html

> > > +       }
> > > +
> > > +       return size;
> > > +}
> > > +
> _______________________________________________
> iommu mailing list
> iommu@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu



  reply	other threads:[~2015-09-22 14:12 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-03 10:21 [PATCH v4 0/6] MT8173 IOMMU SUPPORT Yong Wu
2015-08-03 10:21 ` Yong Wu
2015-08-03 10:21 ` Yong Wu
     [not found] ` <1438597279-2937-1-git-send-email-yong.wu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-08-03 10:21   ` [PATCH v4 1/6] dt-bindings: iommu: Add binding for mediatek IOMMU Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21   ` [PATCH v4 2/6] dt-bindings: mediatek: Add smi dts binding Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21   ` [PATCH v4 3/6] iommu: add ARM short descriptor page table allocator Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu
     [not found]     ` <1438597279-2937-4-git-send-email-yong.wu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-09-16 15:58       ` Will Deacon
2015-09-16 15:58         ` Will Deacon
2015-09-16 15:58         ` Will Deacon
     [not found]         ` <20150916155824.GM28771-5wv7dgnIgG8@public.gmane.org>
2015-09-17 14:54           ` Yong Wu
2015-09-17 14:54             ` Yong Wu
2015-09-17 14:54             ` Yong Wu
2015-09-22 14:12             ` Yong Wu [this message]
2015-09-22 14:12               ` Yong Wu
2015-09-22 14:12               ` Yong Wu
2015-10-09 15:57               ` Will Deacon
2015-10-09 15:57                 ` Will Deacon
2015-10-09 15:57                 ` Will Deacon
     [not found]                 ` <20151009155750.GS26278-5wv7dgnIgG8@public.gmane.org>
2015-10-09 17:41                   ` Robin Murphy
2015-10-09 17:41                     ` Robin Murphy
2015-10-09 17:41                     ` Robin Murphy
     [not found]                     ` <5617FC5F.60505-5wv7dgnIgG8@public.gmane.org>
2015-10-09 18:19                       ` Will Deacon
2015-10-09 18:19                         ` Will Deacon
2015-10-09 18:19                         ` Will Deacon
     [not found]                         ` <20151009181929.GU26278-5wv7dgnIgG8@public.gmane.org>
2015-10-21 10:34                           ` Yong Wu
2015-10-21 10:34                             ` Yong Wu
2015-10-21 10:34                             ` Yong Wu
2015-08-03 10:21   ` [PATCH v4 4/6] memory: mediatek: Add SMI driver Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu
     [not found]     ` <1438597279-2937-5-git-send-email-yong.wu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-08-11 14:56       ` Joerg Roedel
2015-08-11 14:56         ` Joerg Roedel
2015-08-11 14:56         ` Joerg Roedel
2015-08-12 12:39         ` Yong Wu
2015-08-12 12:39           ` Yong Wu
2015-08-12 12:39           ` Yong Wu
2015-08-03 10:21   ` [PATCH v4 5/6] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu
     [not found]     ` <1438597279-2937-6-git-send-email-yong.wu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-08-11 15:39       ` Joerg Roedel
2015-08-11 15:39         ` Joerg Roedel
2015-08-11 15:39         ` Joerg Roedel
     [not found]         ` <20150811153947.GF14980-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
2015-08-12 12:28           ` Yong Wu
2015-08-12 12:28             ` Yong Wu
2015-08-12 12:28             ` Yong Wu
2015-09-11 15:33       ` Robin Murphy
2015-09-11 15:33         ` Robin Murphy
2015-09-11 15:33         ` Robin Murphy
     [not found]         ` <55F2F450.5090809-5wv7dgnIgG8@public.gmane.org>
2015-09-15  5:53           ` Yong Wu
2015-09-15  5:53             ` Yong Wu
2015-09-15  5:53             ` Yong Wu
2015-08-03 10:21   ` [PATCH v4 6/6] dts: mt8173: Add iommu/smi nodes for mt8173 Yong Wu
2015-08-03 10:21     ` Yong Wu
2015-08-03 10:21     ` Yong Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1442931167.17514.39.camel@mhfsdcap03 \
    --to=yong.wu@mediatek.com \
    --cc=Catalin.Marinas@arm.com \
    --cc=Mark.Rutland@arm.com \
    --cc=Robin.Murphy@arm.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=frederic.chen@mediatek.com \
    --cc=iommu@lists.linux-foundation.org \
    --cc=k.zhang@mediatek.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=pebolle@tiscali.nl \
    --cc=robh+dt@kernel.org \
    --cc=srv_heupstream@mediatek.com \
    --cc=tfiga@google.com \
    --cc=treding@nvidia.com \
    --cc=will.deacon@arm.com \
    --cc=youhua.li@mediatek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.