Loading Documentation/DMA-attributes.txt +10 −0 Original line number Diff line number Diff line Loading @@ -143,3 +143,13 @@ So, this provides a way for drivers to avoid those error messages on calls where allocation failures are not a problem, and shouldn't bother the logs. NOTE: At the moment DMA_ATTR_NO_WARN is only implemented on PowerPC. DMA_ATTR_PRIVILEGED ------------------------------ Some advanced peripherals such as remote processors and GPUs perform accesses to DMA buffers in both privileged "supervisor" and unprivileged "user" modes. This attribute is used to indicate to the DMA-mapping subsystem that the buffer is fully accessible at the elevated privilege level (and ideally inaccessible or at least read-only at the lesser-privileged levels). arch/arm/mm/dma-mapping.c +30 −30 Original line number Diff line number Diff line Loading @@ -1171,6 +1171,25 @@ core_initcall(dma_debug_do_init); #ifdef CONFIG_ARM_DMA_USE_IOMMU static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs) { int prot = 0; if (attrs & DMA_ATTR_PRIVILEGED) prot |= IOMMU_PRIV; switch (dir) { case DMA_BIDIRECTIONAL: return prot | IOMMU_READ | IOMMU_WRITE; case DMA_TO_DEVICE: return prot | IOMMU_READ; case DMA_FROM_DEVICE: return prot | IOMMU_WRITE; default: return prot; } } /* IOMMU */ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping); Loading Loading @@ -1394,7 +1413,8 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot, * Create a mapping in device IO address space for specified pages */ static dma_addr_t __iommu_create_mapping(struct device *dev, struct page **pages, size_t size) __iommu_create_mapping(struct device *dev, struct page **pages, size_t size, unsigned long attrs) { struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; Loading @@ -1419,7 +1439,7 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size) len = (j - i) << PAGE_SHIFT; ret = iommu_map(mapping->domain, iova, phys, len, IOMMU_READ|IOMMU_WRITE); __dma_info_to_prot(DMA_BIDIRECTIONAL, attrs)); if (ret < 0) goto fail; iova += len; Loading Loading @@ -1476,7 +1496,8 @@ static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs) } static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp, dma_addr_t *handle, int coherent_flag) dma_addr_t *handle, int coherent_flag, unsigned long attrs) { struct page *page; void *addr; Loading @@ -1488,7 +1509,7 @@ static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp, if (!addr) return NULL; *handle = __iommu_create_mapping(dev, &page, size); *handle = __iommu_create_mapping(dev, &page, size, attrs); if (*handle == DMA_ERROR_CODE) goto err_mapping; Loading Loading @@ -1522,7 +1543,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, if (coherent_flag == COHERENT || !gfpflags_allow_blocking(gfp)) return __iommu_alloc_simple(dev, size, gfp, handle, coherent_flag); coherent_flag, attrs); /* * Following is a work-around (a.k.a. hack) to prevent pages Loading @@ -1537,7 +1558,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, if (!pages) return NULL; *handle = __iommu_create_mapping(dev, pages, size); *handle = __iommu_create_mapping(dev, pages, size, attrs); if (*handle == DMA_ERROR_CODE) goto err_buffer; Loading Loading @@ -1672,27 +1693,6 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, GFP_KERNEL); } static int __dma_direction_to_prot(enum dma_data_direction dir) { int prot; switch (dir) { case DMA_BIDIRECTIONAL: prot = IOMMU_READ | IOMMU_WRITE; break; case DMA_TO_DEVICE: prot = IOMMU_READ; break; case DMA_FROM_DEVICE: prot = IOMMU_WRITE; break; default: prot = 0; } return prot; } /* * Map a part of the scatter-gather list into contiguous io address space */ Loading Loading @@ -1722,7 +1722,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); prot = __dma_direction_to_prot(dir); prot = __dma_info_to_prot(dir, attrs); ret = iommu_map(mapping->domain, iova, phys, len, prot); if (ret < 0) Loading Loading @@ -1930,7 +1930,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p if (dma_addr == DMA_ERROR_CODE) return dma_addr; prot = __dma_direction_to_prot(dir); prot = __dma_info_to_prot(dir, attrs); ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot); if (ret < 0) Loading Loading @@ -2036,7 +2036,7 @@ static dma_addr_t arm_iommu_map_resource(struct device *dev, if (dma_addr == DMA_ERROR_CODE) return dma_addr; prot = __dma_direction_to_prot(dir) | IOMMU_MMIO; prot = __dma_info_to_prot(dir, attrs) | IOMMU_MMIO; ret = iommu_map(mapping->domain, dma_addr, addr, len, prot); if (ret < 0) Loading arch/arm64/mm/dma-mapping.c +3 −3 Original line number Diff line number Diff line Loading @@ -558,7 +558,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size, unsigned long attrs) { bool coherent = is_device_dma_coherent(dev); int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent); int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs); size_t iosize = size; void *addr; Loading Loading @@ -712,7 +712,7 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page, unsigned long attrs) { bool coherent = is_device_dma_coherent(dev); int prot = dma_direction_to_prot(dir, coherent); int prot = dma_info_to_prot(dir, coherent, attrs); dma_addr_t dev_addr = iommu_dma_map_page(dev, page, offset, size, prot); if (!iommu_dma_mapping_error(dev, dev_addr) && Loading Loading @@ -770,7 +770,7 @@ static int __iommu_map_sg_attrs(struct device *dev, struct scatterlist *sgl, __iommu_sync_sg_for_device(dev, sgl, nelems, dir); return iommu_dma_map_sg(dev, sgl, nelems, dma_direction_to_prot(dir, coherent)); dma_info_to_prot(dir, coherent, attrs)); } static void __iommu_unmap_sg_attrs(struct device *dev, Loading drivers/dma/pl330.c +3 −2 Original line number Diff line number Diff line Loading @@ -1867,9 +1867,10 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) * Alloc MicroCode buffer for 'chans' Channel threads. * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN) */ pl330->mcode_cpu = dma_alloc_coherent(pl330->ddma.dev, pl330->mcode_cpu = dma_alloc_attrs(pl330->ddma.dev, chans * pl330->mcbufsz, &pl330->mcode_bus, GFP_KERNEL); &pl330->mcode_bus, GFP_KERNEL, DMA_ATTR_PRIVILEGED); if (!pl330->mcode_cpu) { dev_err(pl330->ddma.dev, "%s:%d Can't allocate memory!\n", __func__, __LINE__); Loading drivers/iommu/arm-smmu-v3.c +1 −6 Original line number Diff line number Diff line Loading @@ -269,9 +269,6 @@ #define STRTAB_STE_1_SHCFG_INCOMING 1UL #define STRTAB_STE_1_SHCFG_SHIFT 44 #define STRTAB_STE_1_PRIVCFG_UNPRIV 2UL #define STRTAB_STE_1_PRIVCFG_SHIFT 48 #define STRTAB_STE_2_S2VMID_SHIFT 0 #define STRTAB_STE_2_S2VMID_MASK 0xffffUL #define STRTAB_STE_2_VTCR_SHIFT 32 Loading Loading @@ -1076,9 +1073,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, #ifdef CONFIG_PCI_ATS STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT | #endif STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT | STRTAB_STE_1_PRIVCFG_UNPRIV << STRTAB_STE_1_PRIVCFG_SHIFT); STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT); if (smmu->features & ARM_SMMU_FEAT_STALLS) dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD); Loading Loading
Documentation/DMA-attributes.txt +10 −0 Original line number Diff line number Diff line Loading @@ -143,3 +143,13 @@ So, this provides a way for drivers to avoid those error messages on calls where allocation failures are not a problem, and shouldn't bother the logs. NOTE: At the moment DMA_ATTR_NO_WARN is only implemented on PowerPC. DMA_ATTR_PRIVILEGED ------------------------------ Some advanced peripherals such as remote processors and GPUs perform accesses to DMA buffers in both privileged "supervisor" and unprivileged "user" modes. This attribute is used to indicate to the DMA-mapping subsystem that the buffer is fully accessible at the elevated privilege level (and ideally inaccessible or at least read-only at the lesser-privileged levels).
arch/arm/mm/dma-mapping.c +30 −30 Original line number Diff line number Diff line Loading @@ -1171,6 +1171,25 @@ core_initcall(dma_debug_do_init); #ifdef CONFIG_ARM_DMA_USE_IOMMU static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs) { int prot = 0; if (attrs & DMA_ATTR_PRIVILEGED) prot |= IOMMU_PRIV; switch (dir) { case DMA_BIDIRECTIONAL: return prot | IOMMU_READ | IOMMU_WRITE; case DMA_TO_DEVICE: return prot | IOMMU_READ; case DMA_FROM_DEVICE: return prot | IOMMU_WRITE; default: return prot; } } /* IOMMU */ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping); Loading Loading @@ -1394,7 +1413,8 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot, * Create a mapping in device IO address space for specified pages */ static dma_addr_t __iommu_create_mapping(struct device *dev, struct page **pages, size_t size) __iommu_create_mapping(struct device *dev, struct page **pages, size_t size, unsigned long attrs) { struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; Loading @@ -1419,7 +1439,7 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size) len = (j - i) << PAGE_SHIFT; ret = iommu_map(mapping->domain, iova, phys, len, IOMMU_READ|IOMMU_WRITE); __dma_info_to_prot(DMA_BIDIRECTIONAL, attrs)); if (ret < 0) goto fail; iova += len; Loading Loading @@ -1476,7 +1496,8 @@ static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs) } static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp, dma_addr_t *handle, int coherent_flag) dma_addr_t *handle, int coherent_flag, unsigned long attrs) { struct page *page; void *addr; Loading @@ -1488,7 +1509,7 @@ static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp, if (!addr) return NULL; *handle = __iommu_create_mapping(dev, &page, size); *handle = __iommu_create_mapping(dev, &page, size, attrs); if (*handle == DMA_ERROR_CODE) goto err_mapping; Loading Loading @@ -1522,7 +1543,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, if (coherent_flag == COHERENT || !gfpflags_allow_blocking(gfp)) return __iommu_alloc_simple(dev, size, gfp, handle, coherent_flag); coherent_flag, attrs); /* * Following is a work-around (a.k.a. hack) to prevent pages Loading @@ -1537,7 +1558,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, if (!pages) return NULL; *handle = __iommu_create_mapping(dev, pages, size); *handle = __iommu_create_mapping(dev, pages, size, attrs); if (*handle == DMA_ERROR_CODE) goto err_buffer; Loading Loading @@ -1672,27 +1693,6 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, GFP_KERNEL); } static int __dma_direction_to_prot(enum dma_data_direction dir) { int prot; switch (dir) { case DMA_BIDIRECTIONAL: prot = IOMMU_READ | IOMMU_WRITE; break; case DMA_TO_DEVICE: prot = IOMMU_READ; break; case DMA_FROM_DEVICE: prot = IOMMU_WRITE; break; default: prot = 0; } return prot; } /* * Map a part of the scatter-gather list into contiguous io address space */ Loading Loading @@ -1722,7 +1722,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); prot = __dma_direction_to_prot(dir); prot = __dma_info_to_prot(dir, attrs); ret = iommu_map(mapping->domain, iova, phys, len, prot); if (ret < 0) Loading Loading @@ -1930,7 +1930,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p if (dma_addr == DMA_ERROR_CODE) return dma_addr; prot = __dma_direction_to_prot(dir); prot = __dma_info_to_prot(dir, attrs); ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot); if (ret < 0) Loading Loading @@ -2036,7 +2036,7 @@ static dma_addr_t arm_iommu_map_resource(struct device *dev, if (dma_addr == DMA_ERROR_CODE) return dma_addr; prot = __dma_direction_to_prot(dir) | IOMMU_MMIO; prot = __dma_info_to_prot(dir, attrs) | IOMMU_MMIO; ret = iommu_map(mapping->domain, dma_addr, addr, len, prot); if (ret < 0) Loading
arch/arm64/mm/dma-mapping.c +3 −3 Original line number Diff line number Diff line Loading @@ -558,7 +558,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size, unsigned long attrs) { bool coherent = is_device_dma_coherent(dev); int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent); int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs); size_t iosize = size; void *addr; Loading Loading @@ -712,7 +712,7 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page, unsigned long attrs) { bool coherent = is_device_dma_coherent(dev); int prot = dma_direction_to_prot(dir, coherent); int prot = dma_info_to_prot(dir, coherent, attrs); dma_addr_t dev_addr = iommu_dma_map_page(dev, page, offset, size, prot); if (!iommu_dma_mapping_error(dev, dev_addr) && Loading Loading @@ -770,7 +770,7 @@ static int __iommu_map_sg_attrs(struct device *dev, struct scatterlist *sgl, __iommu_sync_sg_for_device(dev, sgl, nelems, dir); return iommu_dma_map_sg(dev, sgl, nelems, dma_direction_to_prot(dir, coherent)); dma_info_to_prot(dir, coherent, attrs)); } static void __iommu_unmap_sg_attrs(struct device *dev, Loading
drivers/dma/pl330.c +3 −2 Original line number Diff line number Diff line Loading @@ -1867,9 +1867,10 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) * Alloc MicroCode buffer for 'chans' Channel threads. * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN) */ pl330->mcode_cpu = dma_alloc_coherent(pl330->ddma.dev, pl330->mcode_cpu = dma_alloc_attrs(pl330->ddma.dev, chans * pl330->mcbufsz, &pl330->mcode_bus, GFP_KERNEL); &pl330->mcode_bus, GFP_KERNEL, DMA_ATTR_PRIVILEGED); if (!pl330->mcode_cpu) { dev_err(pl330->ddma.dev, "%s:%d Can't allocate memory!\n", __func__, __LINE__); Loading
drivers/iommu/arm-smmu-v3.c +1 −6 Original line number Diff line number Diff line Loading @@ -269,9 +269,6 @@ #define STRTAB_STE_1_SHCFG_INCOMING 1UL #define STRTAB_STE_1_SHCFG_SHIFT 44 #define STRTAB_STE_1_PRIVCFG_UNPRIV 2UL #define STRTAB_STE_1_PRIVCFG_SHIFT 48 #define STRTAB_STE_2_S2VMID_SHIFT 0 #define STRTAB_STE_2_S2VMID_MASK 0xffffUL #define STRTAB_STE_2_VTCR_SHIFT 32 Loading Loading @@ -1076,9 +1073,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, #ifdef CONFIG_PCI_ATS STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT | #endif STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT | STRTAB_STE_1_PRIVCFG_UNPRIV << STRTAB_STE_1_PRIVCFG_SHIFT); STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT); if (smmu->features & ARM_SMMU_FEAT_STALLS) dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD); Loading