[PATCH] kernel/dma: export dma_alloc_from_contiguous to modules
From: Miles Chen This change exports dma_alloc_from_contiguous and dma_release_from_contiguous to modules. Currently, we can add a reserve a memory node in dts files, make it a CMA memory by setting compatible = "shared-dma-pool", and setup the dev->cma_area by using of_reserved_mem_device_init_by_idx(). Export dma_alloc_from_contiguous and dma_release_from_contiguous, so we can allocate/free from/to dev->cma_area in kernel modules. Signed-off-by: Miles Chen --- kernel/dma/contiguous.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c index b2a87905846d..d5920bdedc77 100644 --- a/kernel/dma/contiguous.c +++ b/kernel/dma/contiguous.c @@ -197,6 +197,7 @@ struct page *dma_alloc_from_contiguous(struct device *dev, size_t count, return cma_alloc(dev_get_cma_area(dev), count, align, no_warn); } +EXPORT_SYMBOL_GPL(dma_alloc_from_contiguous); /** * dma_release_from_contiguous() - release allocated pages @@ -213,6 +214,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, { return cma_release(dev_get_cma_area(dev), pages, count); } +EXPORT_SYMBOL_GPL(dma_release_from_contiguous); /* * Support for reserved memory regions defined in device tree -- 2.18.0
[RFC PATCH] iommu: io-pgtable: Drop WARN for empty PTEs on unmap
If a region has been mapped sparsely (such as on page faults), the user has to keep track of what was mapped or not in order to avoid warnings when unmapping the entire region. Remove the WARN on empty PTEs to allow unmapping sparsely mapped regions. Cc: Will Deacon Cc: Robin Murphy Cc: Joerg Roedel Cc: linux-arm-ker...@lists.infradead.org Cc: iommu@lists.linux-foundation.org Signed-off-by: Rob Herring --- This is needed for large (up to 1GB AIUI) scratch buffers on panfrost which are mapped on demand on GPU page faults and can be unmapped on memory pressure. Alternatively, I'd need to have a bitmap of mapped pages to track what is mapped or not. Dropping the WARN seems like a much simpler solution. This will need to go thru the DRM tree once I've gotten the panfrost side finished, but wanted some early feedback. Rob drivers/iommu/io-pgtable-arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 4e21efbc4459..43971638a5aa 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -611,7 +611,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, ptep += ARM_LPAE_LVL_IDX(iova, lvl, data); pte = READ_ONCE(*ptep); - if (WARN_ON(!pte)) + if (!pte) return 0; /* If the size matches this level, we're in the right place */ -- 2.20.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH] iommu/amd: fix a crash in iova_magazine_free_pfns
When a system is under heavy memory pressure, the allocation in alloc_iova_fast() could still fail even flush_rcache=true, and then causes dma_ops_alloc_iova() return 0. pqi_scsi_queue_command pqi_raid_submit_scsi_cmd_with_io_request scsi_dma_map map_sg dma_ops_alloc_iova alloc_iova_fast Later, map_sg()->iommu_map_page() would probably fail due to the invalid PFN 0, and call free_iova_fast()->iova_rcache_insert() to insert it to the rcache. Finally, it will trigger the BUG_ON(!iova) here. kernel BUG at drivers/iommu/iova.c:801! Workqueue: kblockd blk_mq_run_work_fn RIP: 0010:iova_magazine_free_pfns+0x7d/0xc0 Call Trace: free_cpu_cached_iovas+0xbd/0x150 alloc_iova_fast+0x8c/0xba dma_ops_alloc_iova.isra.6+0x65/0xa0 map_sg+0x8c/0x2a0 scsi_dma_map+0xc6/0x160 pqi_aio_submit_io+0x1f6/0x440 [smartpqi] pqi_scsi_queue_command+0x90c/0xdd0 [smartpqi] scsi_queue_rq+0x79c/0x1200 blk_mq_dispatch_rq_list+0x4dc/0xb70 blk_mq_sched_dispatch_requests+0x249/0x310 __blk_mq_run_hw_queue+0x128/0x200 blk_mq_run_work_fn+0x27/0x30 process_one_work+0x522/0xa10 worker_thread+0x63/0x5b0 kthread+0x1d2/0x1f0 ret_from_fork+0x22/0x40 Fix it by validating the return from the 2nd alloc_iova_fast() in dma_ops_alloc_iova(), so map_sg() could handle the error condition immediately. Signed-off-by: Qian Cai --- drivers/iommu/amd_iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 73740b969e62..f24c689b4e01 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -1697,6 +1697,8 @@ static unsigned long dma_ops_alloc_iova(struct device *dev, if (!pfn) pfn = alloc_iova_fast(&dma_dom->iovad, pages, IOVA_PFN(dma_mask), true); + if (!pfn) + return DMA_MAPPING_ERROR; return (pfn << PAGE_SHIFT); } -- 1.8.3.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH] dma-direct: Force unencrypted DMA under SME for certain DMA masks
From: Tom Lendacky If a device doesn't support DMA to a physical address that includes the encryption bit (currently bit 47, so 48-bit DMA), then the DMA must occur to unencrypted memory. SWIOTLB is used to satisfy that requirement if an IOMMU is not active (enabled or configured in passthrough mode). However, commit fafadcd16595 ("swiotlb: don't dip into swiotlb pool for coherent allocations") modified the coherent allocation support in SWIOTLB to use the DMA direct coherent allocation support. When an IOMMU is not active, this resulted in dma_alloc_coherent() failing for devices that didn't support DMA addresses that included the encryption bit. Addressing this requires changes to the force_dma_unencrypted() function in kernel/dma/direct.c. Since the function is now non-trivial and SME/SEV specific, update the DMA direct support to add an arch override for the force_dma_unencrypted() function. The arch override is selected when CONFIG_AMD_MEM_ENCRYPT is set. The arch override function resides in the arch/x86/mm/mem_encrypt.c file and forces unencrypted DMA when either SEV is active or SME is active and the device does not support DMA to physical addresses that include the encryption bit. Fixes: fafadcd16595 ("swiotlb: don't dip into swiotlb pool for coherent allocations") Suggested-by: Christoph Hellwig Signed-off-by: Tom Lendacky --- Based on tree git://git.infradead.org/users/hch/dma-mapping.git for-next arch/x86/Kconfig | 1 + arch/x86/mm/mem_encrypt.c | 30 ++ kernel/dma/Kconfig| 3 +++ kernel/dma/direct.c | 19 ++- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2bbbd4d1ba31..12e02a8f9de7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1508,6 +1508,7 @@ config AMD_MEM_ENCRYPT depends on X86_64 && CPU_SUP_AMD select DYNAMIC_PHYSICAL_MASK select ARCH_USE_MEMREMAP_PROT + select ARCH_HAS_FORCE_DMA_UNENCRYPTED ---help--- Say yes to enable support for the encryption of system memory. This requires an AMD processor that supports Secure Memory diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 51f50a7a07ef..c7a88b837c43 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -18,6 +18,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -351,6 +355,32 @@ bool sev_active(void) } EXPORT_SYMBOL(sev_active); +/* Override for DMA direct allocation check - ARCH_HAS_FORCE_DMA_UNENCRYPTED */ +bool force_dma_unencrypted(struct device *dev) +{ + /* +* For SEV, all DMA must be to unencrypted addresses. +*/ + if (sev_active()) + return true; + + /* +* For SME, all DMA must be to unencrypted addresses if the +* device does not support DMA to addresses that include the +* encryption mask. +*/ + if (sme_active()) { + u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask)); + u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask, + dev->bus_dma_mask); + + if (dma_dev_mask <= dma_enc_mask) + return true; + } + + return false; +} + /* Architecture __weak replacement functions */ void __init mem_encrypt_free_decrypted_mem(void) { diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig index 70f8f8d9200e..9decbba255fc 100644 --- a/kernel/dma/Kconfig +++ b/kernel/dma/Kconfig @@ -48,6 +48,9 @@ config ARCH_HAS_DMA_COHERENT_TO_PFN config ARCH_HAS_DMA_MMAP_PGPROT bool +config ARCH_HAS_FORCE_DMA_UNENCRYPTED + bool + config DMA_NONCOHERENT_CACHE_SYNC bool diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index b90e1aede743..fb37374dae75 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -23,13 +23,14 @@ #define ARCH_ZONE_DMA_BITS 24 #endif -/* - * For AMD SEV all DMA must be to unencrypted addresses. - */ -static inline bool force_dma_unencrypted(void) +#ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED +bool force_dma_unencrypted(struct device *dev); +#else +static inline bool force_dma_unencrypted(struct device *dev) { - return sev_active(); + return false; } +#endif static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) { @@ -46,7 +47,7 @@ static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) static inline dma_addr_t phys_to_dma_direct(struct device *dev, phys_addr_t phys) { - if (force_dma_unencrypted()) + if (force_dma_unencrypted(dev)) return __phys_to_dma(dev, phys); return phys_to_dma(dev, phys); } @@ -67,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask)
[PATCH v2] iommu: add support for drivers that manage iommu explicitly
From: Rob Clark Avoid attaching any non-driver managed domain if the driver indicates that it manages the iommu directly. This avoids a problem on devices where the bootloader takes the SMMU out of bypass and enables scanout, such as is the case on snapdragon aarch64 laptops and newer snapdragon android devices. Attaching an IDENTITY or DMA domain before the driver has a chance to intervene will break efifb scanout and start triggering iommu faults. If the driver manages the iommu directly (as does drm/msm), it can shut down scanout when it is ready to take over the display, before attaching an UNMANAGED domain. Signed-off-by: Rob Clark --- v2. Move the check into arm_smmu_attach_dev() (as I *think* this is what Robin preferred; update commit msg to focus on the display related issue that this solves. We also need Bjorn's patch set to inherit SMR and CB config during init: https://www.spinics.net/lists/arm-kernel/msg732246.html drivers/iommu/arm-smmu.c | 11 +++ include/linux/device.h | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 1a5efa7c8767..4a80710124db 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1411,6 +1411,17 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return -ENXIO; } + /* +* If driver is going to manage iommu directly, then avoid +* attaching any non driver managed domain. There could +* be already active dma underway (ie. scanout in case of +* bootloader enabled display), and interfering with that +* will make things go *boom* +*/ + if ((domain->type != IOMMU_DOMAIN_UNMANAGED) && + dev->driver && dev->driver->driver_manages_iommu) + return 0; + /* * FIXME: The arch/arm DMA API code tries to attach devices to its own * domains between of_xlate() and add_device() - we have no way to cope diff --git a/include/linux/device.h b/include/linux/device.h index e138baabe01e..d98aa4d3c8c3 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -282,7 +282,8 @@ struct device_driver { struct module *owner; const char *mod_name; /* used for built-in modules */ - bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ + bool suppress_bind_attrs:1; /* disables bind/unbind via sysfs */ + bool driver_manages_iommu:1;/* driver manages IOMMU explicitly */ enum probe_type probe_type; const struct of_device_id *of_match_table; -- 2.20.1
Re: [RESEND PATCH v2 2/3] iommu/io-pgtable-arm: Add support for AARCH64 split pagetables
On Wed, Jul 10, 2019 at 05:45:37PM +0100, Robin Murphy wrote: > Hi Jordan, > > On 08/07/2019 20:00, Jordan Crouse wrote: > >Add a new sub-format ARM_64_LPAE_SPLIT_S1 to create and set up split > >pagetables (TTBR0 and TTBR1). The initialization function sets up the > >correct va_size and sign extension bits and programs the TCR registers. > >Split pagetable formats use their own own map/unmap wrappers to ensure > >that the correct pagetable is selected based on the incoming iova but > >most of the heavy lifting is common to the other formats. > > I'm somewhat concerned that this implementation is very closely tied to the > current Adreno use-case, and won't easily generalise in future to other > potential TTBR1 uses which have been tossed around, like > SMMUv3-without-substream-ID. I haven't heard about these use-cases. I figured v3 would be all PASID all the time. If you have details, I can see if I can avoid painting v3 into a corner. > Furthermore, even for the Adreno pretend-PASID case it appears to be a bit > too fragile for comfort - given that a DOMAIN_ATTR_SPLIT_TABLES domain > doesn't look any different from a regular one from the users' point of view, > what's to stop them making "without PASID" mappings in the lower half of the > address space, and thus unwittingly pulling the rug out from under their own > feet upon attaching an aux domain? In fact allocating a TTBR0 table at all > for the main domain seems like little more than a waste of memory. That makes sense. Would it work better if we made a type ARM_64_LPAE_TTBR1_S1 that only allocated memory for TTBR1 and set TBR.EDP0 to trigger faults for TTBR0? Then we could get rid of most of the extra stuff in io-pgtable-arm.c and I think that would meet most of your concerns. Jordan > > > >Signed-off-by: Jordan Crouse > >--- > > > > drivers/iommu/io-pgtable-arm.c | 261 > > + > > drivers/iommu/io-pgtable.c | 1 + > > include/linux/io-pgtable.h | 2 + > > 3 files changed, 240 insertions(+), 24 deletions(-) > > > >diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c > >index 161a7d56..aec35e5 100644 > >--- a/drivers/iommu/io-pgtable-arm.c > >+++ b/drivers/iommu/io-pgtable-arm.c > >@@ -118,7 +118,12 @@ > > #define ARM_LPAE_TCR_TG0_64K (1 << 14) > > #define ARM_LPAE_TCR_TG0_16K (2 << 14) > >+#define ARM_LPAE_TCR_TG1_4K (0 << 30) > >+#define ARM_LPAE_TCR_TG1_64K(1 << 30) > >+#define ARM_LPAE_TCR_TG1_16K(2 << 30) > >+ > > #define ARM_LPAE_TCR_SH0_SHIFT 12 > >+#define ARM_LPAE_TCR_SH1_SHIFT 28 > > #define ARM_LPAE_TCR_SH0_MASK 0x3 > > #define ARM_LPAE_TCR_SH_NS 0 > > #define ARM_LPAE_TCR_SH_OS 2 > >@@ -126,6 +131,8 @@ > > #define ARM_LPAE_TCR_ORGN0_SHIFT 10 > > #define ARM_LPAE_TCR_IRGN0_SHIFT 8 > >+#define ARM_LPAE_TCR_ORGN1_SHIFT26 > >+#define ARM_LPAE_TCR_IRGN1_SHIFT24 > > #define ARM_LPAE_TCR_RGN_MASK 0x3 > > #define ARM_LPAE_TCR_RGN_NC0 > > #define ARM_LPAE_TCR_RGN_WBWA 1 > >@@ -136,6 +143,7 @@ > > #define ARM_LPAE_TCR_SL0_MASK 0x3 > > #define ARM_LPAE_TCR_T0SZ_SHIFT0 > >+#define ARM_LPAE_TCR_T1SZ_SHIFT 16 > > #define ARM_LPAE_TCR_SZ_MASK 0xf > > #define ARM_LPAE_TCR_PS_SHIFT 16 > >@@ -152,6 +160,14 @@ > > #define ARM_LPAE_TCR_PS_48_BIT 0x5ULL > > #define ARM_LPAE_TCR_PS_52_BIT 0x6ULL > >+#define ARM_LPAE_TCR_SEP_SHIFT 47 > >+#define ARM_LPAE_TCR_SEP_31 (0x0ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_35 (0x1ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_39 (0x2ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_41 (0x3ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_43 (0x4ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_UPSTREAM (0x7ULL << ARM_LPAE_TCR_SEP_SHIFT) > > This is a specific detail of SMMUv2, and nothing to do with the LPAE/AArch64 > VMSA formats. > > >+ > > #define ARM_LPAE_MAIR_ATTR_SHIFT(n)((n) << 3) > > #define ARM_LPAE_MAIR_ATTR_MASK0xff > > #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 > >@@ -179,11 +195,12 @@ struct arm_lpae_io_pgtable { > > struct io_pgtable iop; > > int levels; > >+u32 sep; > > size_t pgd_size; > > unsigned long pg_shift; > > unsigned long bits_per_level; > >-void*pgd; > >+void*pgd[2]; > > }; > > typedef u64 arm_lpae_iopte; > >@@ -426,7 +443,8 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > >arm_lpae_io_pgtable *data, > > arm_lpae_iopte pte; > > if (data->iop.fmt == ARM_64_LPAE_S1 || > >-data->iop.fmt == ARM_32_LPAE_S1) { > >+data->io
Re: [RESEND PATCH v2 2/3] iommu/io-pgtable-arm: Add support for AARCH64 split pagetables
Hi Jordan, On 08/07/2019 20:00, Jordan Crouse wrote: Add a new sub-format ARM_64_LPAE_SPLIT_S1 to create and set up split pagetables (TTBR0 and TTBR1). The initialization function sets up the correct va_size and sign extension bits and programs the TCR registers. Split pagetable formats use their own own map/unmap wrappers to ensure that the correct pagetable is selected based on the incoming iova but most of the heavy lifting is common to the other formats. I'm somewhat concerned that this implementation is very closely tied to the current Adreno use-case, and won't easily generalise in future to other potential TTBR1 uses which have been tossed around, like SMMUv3-without-substream-ID. Furthermore, even for the Adreno pretend-PASID case it appears to be a bit too fragile for comfort - given that a DOMAIN_ATTR_SPLIT_TABLES domain doesn't look any different from a regular one from the users' point of view, what's to stop them making "without PASID" mappings in the lower half of the address space, and thus unwittingly pulling the rug out from under their own feet upon attaching an aux domain? In fact allocating a TTBR0 table at all for the main domain seems like little more than a waste of memory. Signed-off-by: Jordan Crouse --- drivers/iommu/io-pgtable-arm.c | 261 + drivers/iommu/io-pgtable.c | 1 + include/linux/io-pgtable.h | 2 + 3 files changed, 240 insertions(+), 24 deletions(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 161a7d56..aec35e5 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -118,7 +118,12 @@ #define ARM_LPAE_TCR_TG0_64K (1 << 14) #define ARM_LPAE_TCR_TG0_16K (2 << 14) +#define ARM_LPAE_TCR_TG1_4K (0 << 30) +#define ARM_LPAE_TCR_TG1_64K (1 << 30) +#define ARM_LPAE_TCR_TG1_16K (2 << 30) + #define ARM_LPAE_TCR_SH0_SHIFT12 +#define ARM_LPAE_TCR_SH1_SHIFT 28 #define ARM_LPAE_TCR_SH0_MASK 0x3 #define ARM_LPAE_TCR_SH_NS0 #define ARM_LPAE_TCR_SH_OS2 @@ -126,6 +131,8 @@ #define ARM_LPAE_TCR_ORGN0_SHIFT 10 #define ARM_LPAE_TCR_IRGN0_SHIFT 8 +#define ARM_LPAE_TCR_ORGN1_SHIFT 26 +#define ARM_LPAE_TCR_IRGN1_SHIFT 24 #define ARM_LPAE_TCR_RGN_MASK 0x3 #define ARM_LPAE_TCR_RGN_NC 0 #define ARM_LPAE_TCR_RGN_WBWA 1 @@ -136,6 +143,7 @@ #define ARM_LPAE_TCR_SL0_MASK 0x3 #define ARM_LPAE_TCR_T0SZ_SHIFT 0 +#define ARM_LPAE_TCR_T1SZ_SHIFT16 #define ARM_LPAE_TCR_SZ_MASK 0xf #define ARM_LPAE_TCR_PS_SHIFT 16 @@ -152,6 +160,14 @@ #define ARM_LPAE_TCR_PS_48_BIT0x5ULL #define ARM_LPAE_TCR_PS_52_BIT0x6ULL +#define ARM_LPAE_TCR_SEP_SHIFT 47 +#define ARM_LPAE_TCR_SEP_31(0x0ULL << ARM_LPAE_TCR_SEP_SHIFT) +#define ARM_LPAE_TCR_SEP_35(0x1ULL << ARM_LPAE_TCR_SEP_SHIFT) +#define ARM_LPAE_TCR_SEP_39(0x2ULL << ARM_LPAE_TCR_SEP_SHIFT) +#define ARM_LPAE_TCR_SEP_41(0x3ULL << ARM_LPAE_TCR_SEP_SHIFT) +#define ARM_LPAE_TCR_SEP_43(0x4ULL << ARM_LPAE_TCR_SEP_SHIFT) +#define ARM_LPAE_TCR_SEP_UPSTREAM (0x7ULL << ARM_LPAE_TCR_SEP_SHIFT) This is a specific detail of SMMUv2, and nothing to do with the LPAE/AArch64 VMSA formats. + #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) #define ARM_LPAE_MAIR_ATTR_MASK 0xff #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 @@ -179,11 +195,12 @@ struct arm_lpae_io_pgtable { struct io_pgtable iop; int levels; + u32 sep; size_t pgd_size; unsigned long pg_shift; unsigned long bits_per_level; - void *pgd; + void*pgd[2]; }; typedef u64 arm_lpae_iopte; @@ -426,7 +443,8 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, arm_lpae_iopte pte; if (data->iop.fmt == ARM_64_LPAE_S1 || - data->iop.fmt == ARM_32_LPAE_S1) { + data->iop.fmt == ARM_32_LPAE_S1 || + data->iop.fmt == ARM_64_LPAE_SPLIT_S1) { pte = ARM_LPAE_PTE_nG; if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) pte |= ARM_LPAE_PTE_AP_RDONLY; @@ -470,11 +488,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, return pte; } -static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, - phys_addr_t paddr, size_t size, int iommu_prot) +static int _arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, + phys_addr_t paddr, size_t size, int iommu_prot, + arm_lpae_iopte *ptep) { - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); -
Re: [RESEND PATCH v2 3/3] iommu/arm-smmu: Add support for DOMAIN_ATTR_SPLIT_TABLES
On 08/07/2019 20:00, Jordan Crouse wrote: When DOMAIN_ATTR_SPLIT_TABLES is specified for pass ARM_64_LPAE_SPLIT_S1 to io_pgtable_ops to allocate and initialize TTBR0 and TTBR1 pagetables. v3: Moved all the pagetable specific work into io-pgtable-arm in a previous patch. Signed-off-by: Jordan Crouse --- drivers/iommu/arm-smmu.c | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 653b6b3..7a6b4bb 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -257,6 +257,7 @@ struct arm_smmu_domain { boolnon_strict; struct mutexinit_mutex; /* Protects smmu pointer */ spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */ + u32 attributes; struct iommu_domain domain; }; @@ -832,7 +833,11 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ias = smmu->va_size; oas = smmu->ipa_size; if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) { - fmt = ARM_64_LPAE_S1; + if (smmu_domain->attributes & + (1 << DOMAIN_ATTR_SPLIT_TABLES)) + fmt = ARM_64_LPAE_SPLIT_S1; + else + fmt = ARM_64_LPAE_S1; } else if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_L) { fmt = ARM_32_LPAE_S1; ias = min(ias, 32UL); @@ -1582,6 +1587,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); return 0; + case DOMAIN_ATTR_SPLIT_TABLES: + *(int *)data = !!(smmu_domain->attributes & + (1 << DOMAIN_ATTR_SPLIT_TABLES)); I'm not really a fan of always claiming to support this but silently ignoring it depending on hardware/kernel configuration - it seems somewhat tricky to make callers properly robust against making false assumptions (e.g. consider if the system is booted with "arm-smmu.force_stage=2"). Robin. + return 0; default: return -ENODEV; } @@ -1622,6 +1631,11 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, else smmu_domain->stage = ARM_SMMU_DOMAIN_S1; break; + case DOMAIN_ATTR_SPLIT_TABLES: + if (*((int *)data)) + smmu_domain->attributes |= + (1 << DOMAIN_ATTR_SPLIT_TABLES); + break; default: ret = -ENODEV; } ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 07/21] iommu/io-pgtable-arm-v7s: Extend MediaTek 4GB Mode
On Sat, Jun 29, 2019 at 10:09:13AM +0800, Yong Wu wrote: > MediaTek extend the arm v7s descriptor to support the dram over 4GB. > > In the mt2712 and mt8173, it's called "4GB mode", the physical address > is from 0x4000_ to 0x1_3fff_, but from EMI point of view, it > is remapped to high address from 0x1__ to 0x1__, the > bit32 is always enabled. thus, in the M4U, we always enable the bit9 > for all PTEs which means to enable bit32 of physical address. > > but in mt8183, M4U support the dram from 0x4000_ to 0x3__ > which isn't remaped. We extend the PTEs: the bit9 represent bit32 of > PA and the bit4 represent bit33 of PA. Meanwhile the iova still is > 32bits. What happens if bit4 is set in the pte for mt2712 or mt8173? Perhaps the io-pgtable backend should be allowing oas > 32 when IO_PGTABLE_QUIRK_ARM_MTK_4GB is set, and then enforcing that itself. > In order to unify code, in the "4GB mode", we add the bit32 for the > physical address manually in our driver. > > Correspondingly, Adding bit32 and bit33 for the PA in the iova_to_phys > has to been moved into v7s. > > Regarding whether the pagetable address could be over 4GB, the mt8183 > support it while the previous mt8173 don't. thus keep it as is. > > Signed-off-by: Yong Wu > Reviewed-by: Robin Murphy > Reviewed-by: Evan Green > --- > Comparing with the previous one: > 1). Add a new patch "iommu/mediatek: Fix iova_to_phys PA start for 4GB > mode" before this one. Thus rebase it. > A little difference: in the 4gb mode, we add bit32 for PA. and the PA got > from iova_to_phys always have bit32 here, thus we should adjust it to locate > the valid pa. > 2). Add this code suggested from Evan. > if (!data->plat_data->has_4gb_mode) > data->enable_4GB = false; > --- > drivers/iommu/io-pgtable-arm-v7s.c | 31 --- > drivers/iommu/mtk_iommu.c | 29 ++--- > drivers/iommu/mtk_iommu.h | 1 + > 3 files changed, 43 insertions(+), 18 deletions(-) > > diff --git a/drivers/iommu/io-pgtable-arm-v7s.c > b/drivers/iommu/io-pgtable-arm-v7s.c > index 94c38db..4077822 100644 > --- a/drivers/iommu/io-pgtable-arm-v7s.c > +++ b/drivers/iommu/io-pgtable-arm-v7s.c > @@ -123,7 +123,9 @@ > #define ARM_V7S_TEX_MASK 0x7 > #define ARM_V7S_ATTR_TEX(val)(((val) & ARM_V7S_TEX_MASK) << > ARM_V7S_TEX_SHIFT) > > -#define ARM_V7S_ATTR_MTK_4GB BIT(9) /* MTK extend it for 4GB mode */ > +/* MediaTek extend the two bits below for over 4GB mode */ > +#define ARM_V7S_ATTR_MTK_PA_BIT32BIT(9) > +#define ARM_V7S_ATTR_MTK_PA_BIT33BIT(4) > > /* *well, except for TEX on level 2 large pages, of course :( */ > #define ARM_V7S_CONT_PAGE_TEX_SHIFT 6 > @@ -190,13 +192,22 @@ static dma_addr_t __arm_v7s_dma_addr(void *pages) > static arm_v7s_iopte paddr_to_iopte(phys_addr_t paddr, int lvl, > struct io_pgtable_cfg *cfg) > { > - return paddr & ARM_V7S_LVL_MASK(lvl); > + arm_v7s_iopte pte = paddr & ARM_V7S_LVL_MASK(lvl); > + > + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) { > + if (paddr & BIT_ULL(32)) > + pte |= ARM_V7S_ATTR_MTK_PA_BIT32; > + if (paddr & BIT_ULL(33)) > + pte |= ARM_V7S_ATTR_MTK_PA_BIT33; > + } > + return pte; > } > > static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int lvl, > struct io_pgtable_cfg *cfg) > { > arm_v7s_iopte mask; > + phys_addr_t paddr; > > if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) > mask = ARM_V7S_TABLE_MASK; > @@ -205,7 +216,14 @@ static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int > lvl, > else > mask = ARM_V7S_LVL_MASK(lvl); > > - return pte & mask; > + paddr = pte & mask; > + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) { > + if (pte & ARM_V7S_ATTR_MTK_PA_BIT32) > + paddr |= BIT_ULL(32); > + if (pte & ARM_V7S_ATTR_MTK_PA_BIT33) > + paddr |= BIT_ULL(33); > + } > + return paddr; I think this relies on CONFIG_PHYS_ADDR_T_64BIT, which isn't always set on 32-bit ARM. Will
VFIO/IOMMU/PCI Linux Plumbers 2019 MC - Call for Topics
Hi, following the official LPC19 VFIO/IOMMU/PCI microconference acceptance notification: https://www.linuxplumbersconf.org/blog/2019/vfio-iommu-pci-microconference-accepted-into-2019-linux-plumbers-conference/ I am sending out a call for sessions proposals open to all developers interested/involved in Linux kernel VFIO/IOMMU/PCI development. The LPC19 blog page provides a list of topics that we put forward for the microconference submission: https://www.linuxplumbersconf.org/blog/2019/vfio-iommu-pci-microconference-accepted-into-2019-linux-plumbers-conference/ The blog page is there to provide a list of topics that we considered key and it should not be considered final, actually it is a starting point to define a possible schedule structure. Session proposals for the LPC19 VFIO/IOMMU/PCI microconference are warmly encouraged and can be submitted here through the common Call for Proposals LPC19 web page (please choose VFIO/IOMMU/PCI MC topic in the "Track" submenu): https://www.linuxplumbersconf.org/event/4/abstracts/ Anyone involved in VFIO/IOMMU/PCI kernel development, if you wish to add sessions and attend the microconference consider yourself welcome, for any questions just reply to this thread or drop me a line. Looking forward to meeting you all in Lisbon for this interesting track ! Lorenzo ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu