mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-24 10:34:43 +03:00
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:
committed by
mobile promotions
parent
5714f5eaaf
commit
aff9d46c00
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user