Re: [PATCH v7 3/5] memory: mediatek: Add SMI driver
On Mon, 2016-01-18 at 11:11 +0100, Matthias Brugger wrote: > > On 18/12/15 09:09, Yong Wu wrote: > > This patch add SMI(Smart Multimedia Interface) driver. This driver > > is responsible to enable/disable iommu and control the power domain > > and clocks of each local arbiter. > > > > Signed-off-by: Yong Wu[...] > > +int mtk_smi_larb_get(struct device *larbdev) > > +{ > > + struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); > > + struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); > > + int ret; > > + > > + /* Enable the smi-common's power and clocks */ > > + ret = mtk_smi_enable(common); > > + if (ret) > > + return ret; > > + > > + /* Enable the larb's power and clocks */ > > + ret = mtk_smi_enable(>smi); > > + if (ret) { > > + mtk_smi_disable(common); > > + return ret; > > + } > > + > > + /* Configure the iommu info */ > > + if (larb->mmu) > > + writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); > > Can there be a larb that does not have a mmu id defined? > Phandles for the iommu need always to have a mtk_m4u_id defined, so I > don't see the case where this can happen? No. In current IC(mt8173), All the larbs have the mmu info register. > Why did you changed this value to a pointer and added the if? I changed it to a pointer in order to support iommu_attach_device/iommu_detach_device dynamically. In our v6, there is a interface called mtk_smi_config_port in which the iommu(M4U) could tell SMI which ports should enable iommu. In this version, we use the additional data of component to finish this job(the third parameter of the mtk_smi_larb_bind). then we could delete that interface. larb->mmu is a pointer that point to the mmu in "struct mtk_smi_iommu smi_imu" of "struct mtk_iommu_data". This "smi_imu" is used to record that which ports has already enabled iommu for each larb and it will be updated during the iommu_attach_device/iommu_detach_device. Why add the if? -> This pointer may be null in the mtk_smi_larb_unbind. I'm also not sure when it will enter mtk_smi_larb_unbind, maybe while the iommu device is removed, then it call component_master_del, or the larb device itself is removed, or some other error case in component. but there really is a path it will be null, so I add this *if*. If you think it is unnecessary, I can delete it. > > > + > > + return 0; > > +} > > + > > +void mtk_smi_larb_put(struct device *larbdev) > > +{ > > + struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); > > + struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); > > + > > Would it make sense to write SMI_LARB_MMU_EN here again to eventually > turn off mmus? I think no. As you know, there may be some modules in one larb, so we cann't write 0 in SMI_LARB_MMU_EN here to turn off mmus for all modules. mtk_smi_larb_get/mtk_smi_larb_put mainly enable/disable the power domain and clocks for this local arbiter. And the larb is a unit here, SMI cann’t detect which module calls mtk_smi_larb_put and disable his special iommu bits. so do mtk_smi_larb_get. I know that the module’s special iommu bit wasn’t wrote to 0 here, but if this module would like to work again, he have to call mtk_smi_larb_get again, and currently all the multimedia modules always works via iommu, we don’t need to write 0 here. > Other then this, the driver looks fine to me. Thanks very much for your reply. I could send the new version if we get a conclusion for the two issue above here, like you really don't like that *if*. > > Regards, > Matthias > > > + mtk_smi_disable(>smi); > > + mtk_smi_disable(common); > > +} > > + > > +static int > > +mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) > > +{ > > + struct mtk_smi_larb *larb = dev_get_drvdata(dev); > > + struct mtk_smi_iommu *smi_iommu = data; > > + unsigned int i; > > + > > + for (i = 0; i < smi_iommu->larb_nr; i++) { > > + if (dev == smi_iommu->larb_imu[i].dev) { > > + larb->mmu = _iommu->larb_imu[i].mmu; > > + return 0; > > + } > > + } > > + return -ENODEV; > > +} > > + > > +static void > > +mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) > > +{ > > + struct mtk_smi_larb *larb = dev_get_drvdata(dev); > > + > > + larb->mmu = NULL; > > +} > > + > > +static const struct component_ops mtk_smi_larb_component_ops = { > > + .bind = mtk_smi_larb_bind, > > + .unbind = mtk_smi_larb_unbind, > > +}; [...] ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v1] iommu/rockchip: reconstruct to support multi slaves
From: ZhengShunQianThere are some IPs, such as video encoder/decoder, contains 2 slave iommus, one for reading and the other for writing. They share the same irq and clock with master. This patch reconstructs to support this case by making them share the same Page Directory, Page Tables and even the register operations. That means every instruction to the reading MMU registers would be duplicated to the writing MMU and vice versa. Signed-off-by: ZhengShunQian --- drivers/iommu/rockchip-iommu.c | 214 ++--- 1 file changed, 135 insertions(+), 79 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index ebf0adb..a6f593a 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -86,7 +86,8 @@ struct rk_iommu_domain { struct rk_iommu { struct device *dev; - void __iomem *base; + void __iomem **bases; + int num_mmu; int irq; struct list_head node; /* entry in rk_iommu_domain.iommus */ struct iommu_domain *domain; /* domain to which iommu is attached */ @@ -271,47 +272,70 @@ static u32 rk_iova_page_offset(dma_addr_t iova) return (u32)(iova & RK_IOVA_PAGE_MASK) >> RK_IOVA_PAGE_SHIFT; } -static u32 rk_iommu_read(struct rk_iommu *iommu, u32 offset) +static u32 rk_iommu_read(void __iomem *base, u32 offset) { - return readl(iommu->base + offset); + return readl(base + offset); } -static void rk_iommu_write(struct rk_iommu *iommu, u32 offset, u32 value) +static void rk_iommu_write(void __iomem *base, u32 offset, u32 value) { - writel(value, iommu->base + offset); + writel(value, base + offset); } static void rk_iommu_command(struct rk_iommu *iommu, u32 command) { - writel(command, iommu->base + RK_MMU_COMMAND); + int i; + + for (i = 0; i < iommu->num_mmu; i++) + writel(command, iommu->bases[i] + RK_MMU_COMMAND); } +static void rk_iommu_base_command(void __iomem *base, u32 command) +{ + writel(command, base + RK_MMU_COMMAND); +} static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova, size_t size) { + int i; + dma_addr_t iova_end = iova + size; /* * TODO(djkurtz): Figure out when it is more efficient to shootdown the * entire iotlb rather than iterate over individual iovas. */ - for (; iova < iova_end; iova += SPAGE_SIZE) - rk_iommu_write(iommu, RK_MMU_ZAP_ONE_LINE, iova); + for (i = 0; i < iommu->num_mmu; i++) + for (; iova < iova_end; iova += SPAGE_SIZE) + rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, iova); } static bool rk_iommu_is_stall_active(struct rk_iommu *iommu) { - return rk_iommu_read(iommu, RK_MMU_STATUS) & RK_MMU_STATUS_STALL_ACTIVE; + bool active = true; + int i; + + for (i = 0; i < iommu->num_mmu; i++) + active &= rk_iommu_read(iommu->bases[i], RK_MMU_STATUS) & + RK_MMU_STATUS_STALL_ACTIVE; + + return active; } static bool rk_iommu_is_paging_enabled(struct rk_iommu *iommu) { - return rk_iommu_read(iommu, RK_MMU_STATUS) & -RK_MMU_STATUS_PAGING_ENABLED; + bool enable = true; + int i; + + for (i = 0; i < iommu->num_mmu; i++) + enable &= rk_iommu_read(iommu->bases[i], RK_MMU_STATUS) & + RK_MMU_STATUS_PAGING_ENABLED; + + return enable; } static int rk_iommu_enable_stall(struct rk_iommu *iommu) { - int ret; + int ret, i; if (rk_iommu_is_stall_active(iommu)) return 0; @@ -324,15 +348,16 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu) ret = rk_wait_for(rk_iommu_is_stall_active(iommu), 1); if (ret) - dev_err(iommu->dev, "Enable stall request timed out, status: %#08x\n", - rk_iommu_read(iommu, RK_MMU_STATUS)); + for (i = 0; i < iommu->num_mmu; i++) + dev_err(iommu->dev, "Enable stall request timed out, status: %#08x\n", + rk_iommu_read(iommu->bases[i], RK_MMU_STATUS)); return ret; } static int rk_iommu_disable_stall(struct rk_iommu *iommu) { - int ret; + int ret, i; if (!rk_iommu_is_stall_active(iommu)) return 0; @@ -341,15 +366,16 @@ static int rk_iommu_disable_stall(struct rk_iommu *iommu) ret = rk_wait_for(!rk_iommu_is_stall_active(iommu), 1); if (ret) - dev_err(iommu->dev, "Disable stall request timed out, status: %#08x\n", - rk_iommu_read(iommu, RK_MMU_STATUS)); + for (i = 0; i < iommu->num_mmu; i++) + dev_err(iommu->dev, "Disable stall
[git pull] IOMMU Updates for Linux v4.5
Hi Linus, The following changes since commit afd2ff9b7e1b367172f18ba7f693dfb62bdcb2dc: Linux 4.4 (2016-01-10 15:01:32 -0800) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git tags/iommu-updates-v4.5 for you to fetch changes up to 32704253dc008dfedead71da016b00d10cd1854f: Merge branches 's390', 'arm/renesas', 'arm/msm', 'arm/shmobile', 'arm/smmu', 'x86/amd' and 'x86/vt-d' into next (2016-01-19 15:30:43 +0100) IOMMU Updates for Linux v4.5 The updates include: * Small code cleanups in the AMD IOMMUv2 driver * Scalability improvements for the DMA-API implementation of the AMD IOMMU driver. This is just a starting point, but already showed some good improvements in my tests. * Removal of the unused Renesas IPMMU/IPMMUI driver * Updates for ARM-SMMU include: * Some fixes to get the driver working nicely on Broadcom hardware * A change to the io-pgtable API to indicate the unit in which to flush (all callers converted, with Ack from Laurent) * Use of devm_* for allocating/freeing the SMMUv3 buffers * Some other small fixes and improvements for other drivers Dan Carpenter (1): iommu/amd: Remove an unneeded condition Geert Uytterhoeven (1): iommu/shmobile: Remove unused Renesas IPMMU/IPMMUI driver Joerg Roedel (28): iommu/amd: Correctly set flags for handle_mm_fault call iommu/amd: Cleanup error handling in do_fault() Merge branch 'for-joerg/arm-smmu/updates' of git://git.kernel.org/.../will/linux into arm/smmu iommu/amd: Warn only once on unexpected pte value iommu/amd: Move 'struct dma_ops_domain' definition to amd_iommu.c iommu/amd: Introduce bitmap_lock in struct aperture_range iommu/amd: Flush IOMMU TLB on __map_single error path iommu/amd: Flush the IOMMU TLB before the addresses are freed iommu/amd: Pass correct shift to iommu_area_alloc() iommu/amd: Add dma_ops_aperture_alloc() function iommu/amd: Move aperture_range.offset to another cache-line iommu/amd: Retry address allocation within one aperture iommu/amd: Flush iommu tlb in dma_ops_aperture_alloc() iommu/amd: Remove 'start' parameter from dma_ops_area_alloc iommu/amd: Rename dma_ops_domain->next_address to next_index iommu/amd: Flush iommu tlb in dma_ops_free_addresses iommu/amd: Iterate over all aperture ranges in dma_ops_area_alloc iommu/amd: Remove need_flush from struct dma_ops_domain iommu/amd: Optimize dma_ops_free_addresses iommu/amd: Allocate new aperture ranges in dma_ops_alloc_addresses iommu/amd: Build io page-tables with cmpxchg64 iommu/amd: Initialize new aperture range before making it visible iommu/amd: Relax locking in dma_ops path iommu/amd: Make dma_ops_domain->next_index percpu iommu/amd: Use trylock to aquire bitmap_lock iommu/amd: Preallocate dma_ops apertures based on dma_mask iommu/vt-d: Fix up error handling in alloc_iommu Merge branches 's390', 'arm/renesas', 'arm/msm', 'arm/shmobile', 'arm/smmu', 'x86/amd' and 'x86/vt-d' into next Julia Lawall (1): iommu/amd: Constify mmu_notifier_ops structures Magnus Damm (1): iommu/ipmmu-vmsa: Include SoC part number in DT binding docs Markus Elfring (1): iommu/arm-smmu: Delete an unnecessary check before free_io_pgtable_ops() Nicholas Krause (1): iommu/vt-d: Check the return value of iommu_device_create() Peng Fan (1): iommu/arm-smmu: Correct group reference count Prem Mallappa (2): iommu/arm-smmu: Fix write to GERRORN register iommu/arm-smmu: Use STE.S1STALLD only when supported Robin Murphy (4): iommu/io-pgtable-arm: Avoid dereferencing bogus PTEs iommu/io-pgtable: Indicate granule for TLB maintenance iommu/arm-smmu: Invalidate TLBs properly iommu/io-pgtable: Make io_pgtable_ops_to_pgtable() macro common Sebastian Ott (1): iommu/s390: Fix sparse warnings Thierry Reding (1): iommu/msm: Use platform_register/unregister_drivers() Will Deacon (5): iommu/arm-smmu: Remove #define for non-existent PRIQ_0_OF field iommu/arm-smmu: Convert DMA buffer allocations to the managed API iommu/arm-smmu: Use incoming shareability attributes in bypass mode iommu/arm-smmu: Handle unknown CERROR values gracefully iommu/io-pgtable-arm: Ensure we free the final level on teardown .../bindings/iommu/renesas,ipmmu-vmsa.txt | 12 +- drivers/iommu/Kconfig | 75 drivers/iommu/Makefile | 2 - drivers/iommu/amd_iommu.c | 396