From aff9d46c00a2a82c93d6cc43d790584e7e474d0e Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Wed, 12 Apr 2017 11:19:09 -0700 Subject: gpu: nvgpu: Add __nvgpu_mem_create_from_pages() Add a function to create a nvgpu_mem from a list of arbitrary pages. This API is useful for pages not necessarily allocated by the Linux page allocator. It is useful for making nvgpu_mems that represent carveouts or other things like that. JIRA NVGPU-12 JIRA NVGPU-30 Change-Id: Ibcb6432f077a6b0ecf9d183248e47a1f9ecb3ddd Signed-off-by: Alex Waterman Reviewed-on: http://git-master/r/1464080 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom Reviewed-by: svccoveritychecker --- drivers/gpu/nvgpu/common/linux/dma.c | 8 +++++ drivers/gpu/nvgpu/common/linux/nvgpu_mem.c | 38 +++++++++++++++++++++++ drivers/gpu/nvgpu/include/nvgpu/linux/nvgpu_mem.h | 31 ++++++++++++++++++ drivers/gpu/nvgpu/include/nvgpu/nvgpu_mem.h | 10 ++++++ 4 files changed, 87 insertions(+) diff --git a/drivers/gpu/nvgpu/common/linux/dma.c b/drivers/gpu/nvgpu/common/linux/dma.c index abcf36f1..eb2d0ac4 100644 --- a/drivers/gpu/nvgpu/common/linux/dma.c +++ b/drivers/gpu/nvgpu/common/linux/dma.c @@ -335,6 +335,7 @@ static void nvgpu_dma_free_sys(struct gk20a *g, struct nvgpu_mem *mem) struct device *d = dev_from_gk20a(g); if (!(mem->mem_flags & NVGPU_MEM_FLAG_SHADOW_COPY) && + !(mem->mem_flags & __NVGPU_MEM_FLAG_NO_DMA) && (mem->cpu_va || mem->priv.pages)) { if (mem->priv.flags) { DEFINE_DMA_ATTRS(dma_attrs); @@ -358,6 +359,13 @@ static void nvgpu_dma_free_sys(struct gk20a *g, struct nvgpu_mem *mem) mem->priv.pages = NULL; } + /* + * When this flag is set we expect that pages is still populated but not + * by the DMA API. + */ + if (mem->mem_flags & __NVGPU_MEM_FLAG_NO_DMA) + nvgpu_kfree(g, mem->priv.pages); + if (mem->priv.sgt) nvgpu_free_sgtable(g, &mem->priv.sgt); diff --git a/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c b/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c index b46dbb6b..58488067 100644 --- a/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c +++ b/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c @@ -297,3 +297,41 @@ int nvgpu_mem_create_from_mem(struct gk20a *g, return ret; } + +int __nvgpu_mem_create_from_pages(struct gk20a *g, struct nvgpu_mem *dest, + struct page **pages, int nr_pages) +{ + struct sg_table *sgt; + struct page **our_pages = + nvgpu_kmalloc(g, sizeof(struct page *) * nr_pages); + + if (!our_pages) + return -ENOMEM; + + memcpy(our_pages, pages, sizeof(struct page *) * nr_pages); + + if (nvgpu_get_sgtable_from_pages(g, &sgt, pages, 0, + nr_pages * PAGE_SIZE)) { + nvgpu_kfree(g, our_pages); + return -ENOMEM; + } + + /* + * If we are making an SGT from physical pages we can be reasonably + * certain that this should bypass the SMMU - thus we set the DMA (aka + * IOVA) address to 0. This tells the GMMU mapping code to not make a + * mapping directed to the SMMU. + */ + sg_dma_address(sgt->sgl) = 0; + + dest->mem_flags = __NVGPU_MEM_FLAG_NO_DMA; + dest->aperture = APERTURE_SYSMEM; + dest->skip_wmb = 0; + dest->size = PAGE_SIZE * nr_pages; + + dest->priv.flags = 0; + dest->priv.pages = our_pages; + dest->priv.sgt = sgt; + + return 0; +} diff --git a/drivers/gpu/nvgpu/include/nvgpu/linux/nvgpu_mem.h b/drivers/gpu/nvgpu/include/nvgpu/linux/nvgpu_mem.h index 8b1e646e..9c52811e 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/linux/nvgpu_mem.h +++ b/drivers/gpu/nvgpu/include/nvgpu/linux/nvgpu_mem.h @@ -20,10 +20,41 @@ struct page; struct sg_table; +struct gk20a; +struct nvgpu_mem; + struct nvgpu_mem_priv { struct page **pages; struct sg_table *sgt; unsigned long flags; }; +/** + * __nvgpu_mem_create_from_pages - Create an nvgpu_mem from physical pages. + * + * @g - The GPU. + * @dest - nvgpu_mem to initialize. + * @pages - A list of page pointers. + * @nr_pages - The number of pages in @pages. + * + * Create a new nvgpu_mem struct from a pre-existing list of physical pages. The + * pages need not be contiguous (the underlying scatter gather list will help + * with that). However, note, this API will explicitly make it so that the GMMU + * mapping code bypasses SMMU access for the passed pages. This allows one to + * make mem_descs that describe MMIO regions or other non-DRAM things. + * + * This only works for SYSMEM (or other things like SYSMEM - basically just not + * VIDMEM). Also, this API is only available for Linux as it heavily depends on + * the notion of struct %page. + * + * The resulting nvgpu_mem should be released with the nvgpu_dma_free() or the + * nvgpu_dma_unmap_free() function depending on whether or not the resulting + * nvgpu_mem has been mapped. The underlying pages themselves must be cleaned up + * by the caller of this API. + * + * Returns 0 on success, or a relevant error otherwise. + */ +int __nvgpu_mem_create_from_pages(struct gk20a *g, struct nvgpu_mem *dest, + struct page **pages, int nr_pages); + #endif diff --git a/drivers/gpu/nvgpu/include/nvgpu/nvgpu_mem.h b/drivers/gpu/nvgpu/include/nvgpu/nvgpu_mem.h index b01fbec5..66d04ab8 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/nvgpu_mem.h +++ b/drivers/gpu/nvgpu/include/nvgpu/nvgpu_mem.h @@ -68,6 +68,16 @@ struct nvgpu_mem { * therefor zeroed (to prevent leaking information in VIDMEM buffers). */ #define NVGPU_MEM_FLAG_USER_MEM (1 << 2) + + /* + * Internal flag that specifies this struct has not been made with DMA + * memory and as a result should not try to use the DMA routines for + * freeing the backing memory. + * + * However, this will not stop the DMA API from freeing other parts of + * nvgpu_mem in a system specific way. + */ +#define __NVGPU_MEM_FLAG_NO_DMA (1 << 3) unsigned long mem_flags; /* -- cgit v1.2.2