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 <alexw@nvidia.com>
Reviewed-on: http://git-master/r/1464080
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
This commit is contained in:
Alex Waterman
2017-04-12 11:19:09 -07:00
committed by mobile promotions
parent 5714f5eaaf
commit aff9d46c00
4 changed files with 87 additions and 0 deletions

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
/*