All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robin Murphy <robin.murphy@arm.com>
To: honghui.zhang@mediatek.com, joro@8bytes.org, treding@nvidia.com,
	mark.rutland@arm.com, matthias.bgg@gmail.com
Cc: catalin.marinas@arm.com, will.deacon@arm.com,
	youlin.pei@mediatek.com, yingjoe.chen@mediatek.com,
	devicetree@vger.kernel.org, kendrick.hsu@mediatek.com,
	kernel@pengutronix.de, arnd@arndb.de, tfiga@google.com,
	robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
	eddie.huang@mediatek.com, linux-arm-kernel@lists.infradead.org,
	pebolle@tiscali.nl, srv_heupstream@mediatek.com,
	erin.lo@mediatek.com, linux-kernel@vger.kernel.org,
	iommu@lists.linux-foundation.org, djkurtz@google.com,
	p.zabel@pengutronix.de, l.stach@pengutronix.de
Subject: Re: [PATCH 4/5] iommu/mediatek: add support for mtk iommu generation one HW
Date: Tue, 10 May 2016 11:28:40 +0100	[thread overview]
Message-ID: <5731B7D8.8040304@arm.com> (raw)
In-Reply-To: <1462780816-5288-5-git-send-email-honghui.zhang@mediatek.com>

On 09/05/16 09:00, honghui.zhang@mediatek.com wrote:
[...]
> +static void *mtk_iommu_alloc_pgt(struct device *dev, size_t size, gfp_t gfp)
> +{
> +	dma_addr_t dma;
> +	void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO);
> +
> +	if (!pages)
> +		return NULL;
> +
> +	dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE);
> +	if (dma_mapping_error(dev, dma))
> +		goto out_free;
> +	/*
> +	 * We depend on the IOMMU being able to work with any physical
> +	 * address directly, so if the DMA layer suggests otherwise by
> +	 * translating or truncating them, that bodes very badly...
> +	 */
> +	if (dma != virt_to_phys(pages))
> +		goto out_unmap;

Given that you've only got a single table to allocate, and at 4MB it has 
a fair chance of failing beyond early boot time, just use 
dma_alloc_coherent() - you don't need to care about the dma <-> phys 
relationship because you don't have multi-level tables to walk. That 
way, you can get rid of all the awkward streaming DMA stuff, and also 
benefit from CMA to avoid allocation failures.

> +	kmemleak_ignore(pages);
> +	return pages;
> +
> +out_unmap:
> +	dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n");
> +	dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
> +out_free:
> +	free_pages_exact(pages, size);
> +	return NULL;
> +
> +}
> +
> +static void mtk_iommu_free_pgt(struct device *dev, void *pages, size_t size)
> +{
> +	dma_unmap_single(dev, (dma_addr_t)virt_to_phys(pages),
> +			 size, DMA_TO_DEVICE);
> +	free_pages_exact(pages, size);
> +}
> +
> +static int mtk_iommu_domain_finalise(struct mtk_iommu_data *data)
> +{
> +	struct mtk_iommu_domain *dom = data->m4u_dom;
> +
> +	spin_lock_init(&dom->pgtlock);
> +
> +	dom->pgt_va = mtk_iommu_alloc_pgt(data->dev,
> +				dom->pgt_size, GFP_KERNEL);
> +	if (!dom->pgt_va)
> +		return -ENOMEM;
> +
> +	dom->pgt_pa = virt_to_phys(dom->pgt_va);
> +
> +	writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
> +
> +	dom->cookie = (void *)data;
> +
> +	return 0;
> +}
> +
> +static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type)
> +{
> +	struct mtk_iommu_domain *dom;
> +
> +	if (type != IOMMU_DOMAIN_UNMANAGED)
> +		return NULL;
> +
> +	dom = kzalloc(sizeof(*dom), GFP_KERNEL);
> +	if (!dom)
> +		return NULL;
> +
> +	/*
> +	 * MTK m4u support 4GB iova address space, and oly support 4K page
> +	 * mapping. So the pagetable size should be exactly as 4M.
> +	 */
> +	dom->pgt_size = SZ_4M;

If the table size is fixed, then why bother having a variable at all?

> +	return &dom->domain;
> +}
> +
> +static void mtk_iommu_domain_free(struct iommu_domain *domain)
> +{
> +	kfree(to_mtk_domain(domain));
> +}
> +

[...]

> +static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
> +			 phys_addr_t paddr, size_t size, int prot)
> +{
> +	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> +	struct mtk_iommu_data *data = dom->cookie;
> +	unsigned int page_num = size >> MTK_IOMMU_PAGE_SHIFT;

Since you only advertise a single page size, this will always be 1, so 
you could either get rid of the loop here...

> +	unsigned long flags;
> +	unsigned int i;
> +	u32 *pgt_base_iova;
> +	u32 pabase = (u32)paddr;
> +	int map_size = 0;
> +
> +	spin_lock_irqsave(&dom->pgtlock, flags);
> +	pgt_base_iova = dom->pgt_va + (iova  >> MTK_IOMMU_PAGE_SHIFT);
> +	for (i = 0; i < page_num; i++) {
> +		pgt_base_iova[i] = pabase | F_DESC_VALID | F_DESC_NONSEC;
> +		pabase += MTK_IOMMU_PAGE_SIZE;
> +		map_size += MTK_IOMMU_PAGE_SIZE;
> +	}
> +	dma_sync_single_for_device(data->dev,
> +			dom->pgt_pa + (iova >> MTK_IOMMU_PAGE_SHIFT),
> +			(size >> MTK_IOMMU_PAGE_SHIFT) * sizeof(u32),
> +			DMA_TO_DEVICE);
> +	spin_unlock_irqrestore(&dom->pgtlock, flags);
> +
> +	mtk_iommu_tlb_flush_range(data, iova, size);
> +
> +	return map_size;
> +}

[...]

> +static struct iommu_ops mtk_iommu_ops = {
> +	.domain_alloc	= mtk_iommu_domain_alloc,
> +	.domain_free	= mtk_iommu_domain_free,
> +	.attach_dev	= mtk_iommu_attach_device,
> +	.detach_dev	= mtk_iommu_detach_device,
> +	.map		= mtk_iommu_map,
> +	.unmap		= mtk_iommu_unmap,
> +	.map_sg		= default_iommu_map_sg,
> +	.iova_to_phys	= mtk_iommu_iova_to_phys,
> +	.add_device	= mtk_iommu_add_device,
> +	.remove_device	= mtk_iommu_remove_device,
> +	.device_group	= mtk_iommu_device_group,
> +	.pgsize_bitmap	= MTK_IOMMU_PAGE_SIZE,
> +};

...or perhaps advertise .pgsize_bitmap = ~0UL << MTK_IOMMU_PAGE_SHIFT 
here, so you actually can handle multiple entries at once for larger 
mappings - given how simple the page table format is that doesn't seem 
too unreasonable, especially since it should give you a big efficiency 
win in terms of TLB maintenance.

Robin.

WARNING: multiple messages have this Message-ID (diff)
From: robin.murphy@arm.com (Robin Murphy)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 4/5] iommu/mediatek: add support for mtk iommu generation one HW
Date: Tue, 10 May 2016 11:28:40 +0100	[thread overview]
Message-ID: <5731B7D8.8040304@arm.com> (raw)
In-Reply-To: <1462780816-5288-5-git-send-email-honghui.zhang@mediatek.com>

On 09/05/16 09:00, honghui.zhang at mediatek.com wrote:
[...]
> +static void *mtk_iommu_alloc_pgt(struct device *dev, size_t size, gfp_t gfp)
> +{
> +	dma_addr_t dma;
> +	void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO);
> +
> +	if (!pages)
> +		return NULL;
> +
> +	dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE);
> +	if (dma_mapping_error(dev, dma))
> +		goto out_free;
> +	/*
> +	 * We depend on the IOMMU being able to work with any physical
> +	 * address directly, so if the DMA layer suggests otherwise by
> +	 * translating or truncating them, that bodes very badly...
> +	 */
> +	if (dma != virt_to_phys(pages))
> +		goto out_unmap;

Given that you've only got a single table to allocate, and at 4MB it has 
a fair chance of failing beyond early boot time, just use 
dma_alloc_coherent() - you don't need to care about the dma <-> phys 
relationship because you don't have multi-level tables to walk. That 
way, you can get rid of all the awkward streaming DMA stuff, and also 
benefit from CMA to avoid allocation failures.

> +	kmemleak_ignore(pages);
> +	return pages;
> +
> +out_unmap:
> +	dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n");
> +	dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
> +out_free:
> +	free_pages_exact(pages, size);
> +	return NULL;
> +
> +}
> +
> +static void mtk_iommu_free_pgt(struct device *dev, void *pages, size_t size)
> +{
> +	dma_unmap_single(dev, (dma_addr_t)virt_to_phys(pages),
> +			 size, DMA_TO_DEVICE);
> +	free_pages_exact(pages, size);
> +}
> +
> +static int mtk_iommu_domain_finalise(struct mtk_iommu_data *data)
> +{
> +	struct mtk_iommu_domain *dom = data->m4u_dom;
> +
> +	spin_lock_init(&dom->pgtlock);
> +
> +	dom->pgt_va = mtk_iommu_alloc_pgt(data->dev,
> +				dom->pgt_size, GFP_KERNEL);
> +	if (!dom->pgt_va)
> +		return -ENOMEM;
> +
> +	dom->pgt_pa = virt_to_phys(dom->pgt_va);
> +
> +	writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
> +
> +	dom->cookie = (void *)data;
> +
> +	return 0;
> +}
> +
> +static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type)
> +{
> +	struct mtk_iommu_domain *dom;
> +
> +	if (type != IOMMU_DOMAIN_UNMANAGED)
> +		return NULL;
> +
> +	dom = kzalloc(sizeof(*dom), GFP_KERNEL);
> +	if (!dom)
> +		return NULL;
> +
> +	/*
> +	 * MTK m4u support 4GB iova address space, and oly support 4K page
> +	 * mapping. So the pagetable size should be exactly as 4M.
> +	 */
> +	dom->pgt_size = SZ_4M;

If the table size is fixed, then why bother having a variable at all?

> +	return &dom->domain;
> +}
> +
> +static void mtk_iommu_domain_free(struct iommu_domain *domain)
> +{
> +	kfree(to_mtk_domain(domain));
> +}
> +

[...]

> +static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
> +			 phys_addr_t paddr, size_t size, int prot)
> +{
> +	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> +	struct mtk_iommu_data *data = dom->cookie;
> +	unsigned int page_num = size >> MTK_IOMMU_PAGE_SHIFT;

Since you only advertise a single page size, this will always be 1, so 
you could either get rid of the loop here...

> +	unsigned long flags;
> +	unsigned int i;
> +	u32 *pgt_base_iova;
> +	u32 pabase = (u32)paddr;
> +	int map_size = 0;
> +
> +	spin_lock_irqsave(&dom->pgtlock, flags);
> +	pgt_base_iova = dom->pgt_va + (iova  >> MTK_IOMMU_PAGE_SHIFT);
> +	for (i = 0; i < page_num; i++) {
> +		pgt_base_iova[i] = pabase | F_DESC_VALID | F_DESC_NONSEC;
> +		pabase += MTK_IOMMU_PAGE_SIZE;
> +		map_size += MTK_IOMMU_PAGE_SIZE;
> +	}
> +	dma_sync_single_for_device(data->dev,
> +			dom->pgt_pa + (iova >> MTK_IOMMU_PAGE_SHIFT),
> +			(size >> MTK_IOMMU_PAGE_SHIFT) * sizeof(u32),
> +			DMA_TO_DEVICE);
> +	spin_unlock_irqrestore(&dom->pgtlock, flags);
> +
> +	mtk_iommu_tlb_flush_range(data, iova, size);
> +
> +	return map_size;
> +}

[...]

> +static struct iommu_ops mtk_iommu_ops = {
> +	.domain_alloc	= mtk_iommu_domain_alloc,
> +	.domain_free	= mtk_iommu_domain_free,
> +	.attach_dev	= mtk_iommu_attach_device,
> +	.detach_dev	= mtk_iommu_detach_device,
> +	.map		= mtk_iommu_map,
> +	.unmap		= mtk_iommu_unmap,
> +	.map_sg		= default_iommu_map_sg,
> +	.iova_to_phys	= mtk_iommu_iova_to_phys,
> +	.add_device	= mtk_iommu_add_device,
> +	.remove_device	= mtk_iommu_remove_device,
> +	.device_group	= mtk_iommu_device_group,
> +	.pgsize_bitmap	= MTK_IOMMU_PAGE_SIZE,
> +};

...or perhaps advertise .pgsize_bitmap = ~0UL << MTK_IOMMU_PAGE_SHIFT 
here, so you actually can handle multiple entries@once for larger 
mappings - given how simple the page table format is that doesn't seem 
too unreasonable, especially since it should give you a big efficiency 
win in terms of TLB maintenance.

Robin.

  reply	other threads:[~2016-05-10 10:28 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-09  8:00 [PATCH 0/5] MT2701 iommu support honghui.zhang
2016-05-09  8:00 ` honghui.zhang
2016-05-09  8:00 ` honghui.zhang at mediatek.com
2016-05-09  8:00 ` [PATCH 4/5] iommu/mediatek: add support for mtk iommu generation one HW honghui.zhang
2016-05-09  8:00   ` honghui.zhang
2016-05-09  8:00   ` honghui.zhang at mediatek.com
2016-05-10 10:28   ` Robin Murphy [this message]
2016-05-10 10:28     ` Robin Murphy
2016-05-12 11:26     ` Honghui Zhang (张洪辉)
2016-05-12 11:26       ` Honghui Zhang (张洪辉)
     [not found]     ` <5731B7D8.8040304-5wv7dgnIgG8@public.gmane.org>
2016-05-12 12:41       ` Honghui Zhang
2016-05-12 12:41         ` Honghui Zhang
2016-05-12 12:41         ` Honghui Zhang
     [not found] ` <1462780816-5288-1-git-send-email-honghui.zhang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2016-05-09  8:00   ` [PATCH 1/5] dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi honghui.zhang-NuS5LvNUpcJWk0Htik3J/w
2016-05-09  8:00     ` honghui.zhang
2016-05-09  8:00     ` honghui.zhang at mediatek.com
     [not found]     ` <1462780816-5288-2-git-send-email-honghui.zhang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2016-05-09 20:22       ` Rob Herring
2016-05-09 20:22         ` Rob Herring
2016-05-09 20:22         ` Rob Herring
2016-05-10  1:13         ` Honghui Zhang (张洪辉)
2016-05-10  1:13           ` Honghui Zhang (张洪辉)
2016-05-09  8:00   ` [PATCH 2/5] iommu/mediatek: move the common struct into header file honghui.zhang-NuS5LvNUpcJWk0Htik3J/w
2016-05-09  8:00     ` honghui.zhang
2016-05-09  8:00     ` honghui.zhang at mediatek.com
2016-05-09  8:00   ` [PATCH 3/5] memory/mediatek: add support for mt2701 honghui.zhang-NuS5LvNUpcJWk0Htik3J/w
2016-05-09  8:00     ` honghui.zhang
2016-05-09  8:00     ` honghui.zhang at mediatek.com
2016-05-09  8:00   ` [PATCH 5/5] ARM: dts: mt2701: add iommu/smi dtsi node " honghui.zhang-NuS5LvNUpcJWk0Htik3J/w
2016-05-09  8:00     ` honghui.zhang
2016-05-09  8:00     ` honghui.zhang at mediatek.com

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=5731B7D8.8040304@arm.com \
    --to=robin.murphy@arm.com \
    --cc=arnd@arndb.de \
    --cc=catalin.marinas@arm.com \
    --cc=devicetree@vger.kernel.org \
    --cc=djkurtz@google.com \
    --cc=eddie.huang@mediatek.com \
    --cc=erin.lo@mediatek.com \
    --cc=honghui.zhang@mediatek.com \
    --cc=iommu@lists.linux-foundation.org \
    --cc=joro@8bytes.org \
    --cc=kendrick.hsu@mediatek.com \
    --cc=kernel@pengutronix.de \
    --cc=l.stach@pengutronix.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=mark.rutland@arm.com \
    --cc=matthias.bgg@gmail.com \
    --cc=p.zabel@pengutronix.de \
    --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=yingjoe.chen@mediatek.com \
    --cc=youlin.pei@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.