mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
video: tegra: nvmap: Add hugetlbfs support
- For NvRmHeap_GpuMem, we are switching from a carveout to huge pages obtained from hugetlbfs. - Allocate a handle from VA using get_user_pages, when allocation is requested from GPU heap. - Introduce a new field to indicate that the pages are allocated from hugetlbfs. This field will be useful while returning the correct heap while querying the handle params for a handle which was created using hugetlbfs. - Update the query heap API for GpuMem heap to return the huge pages memory values from meminfo. Bug 4510173 Change-Id: I0dbef4c4e95969f8e3975a6dc58f10255db0635e Signed-off-by: Ketan Patil <ketanp@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3174720 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
9c92d38302
commit
8c52af9b59
@@ -247,7 +247,8 @@ static void alloc_handle(struct nvmap_client *client,
|
|||||||
static int alloc_handle_from_va(struct nvmap_client *client,
|
static int alloc_handle_from_va(struct nvmap_client *client,
|
||||||
struct nvmap_handle *h,
|
struct nvmap_handle *h,
|
||||||
ulong vaddr,
|
ulong vaddr,
|
||||||
u32 flags)
|
u32 flags,
|
||||||
|
unsigned int heap_mask)
|
||||||
{
|
{
|
||||||
size_t nr_page = h->size >> PAGE_SHIFT;
|
size_t nr_page = h->size >> PAGE_SHIFT;
|
||||||
struct page **pages;
|
struct page **pages;
|
||||||
@@ -276,6 +277,8 @@ static int alloc_handle_from_va(struct nvmap_client *client,
|
|||||||
h->heap_type = NVMAP_HEAP_IOVMM;
|
h->heap_type = NVMAP_HEAP_IOVMM;
|
||||||
h->heap_pgalloc = true;
|
h->heap_pgalloc = true;
|
||||||
h->from_va = true;
|
h->from_va = true;
|
||||||
|
if (heap_mask & NVMAP_HEAP_CARVEOUT_GPU)
|
||||||
|
h->has_hugetlbfs_pages = true;
|
||||||
mb();
|
mb();
|
||||||
h->alloc = true;
|
h->alloc = true;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -424,7 +427,8 @@ out:
|
|||||||
int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
||||||
struct nvmap_handle *h,
|
struct nvmap_handle *h,
|
||||||
ulong addr,
|
ulong addr,
|
||||||
unsigned int flags)
|
unsigned int flags,
|
||||||
|
unsigned int heap_mask)
|
||||||
{
|
{
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
int tag;
|
int tag;
|
||||||
@@ -455,7 +459,7 @@ int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
|||||||
client->task->pid, task_comm);
|
client->task->pid, task_comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = alloc_handle_from_va(client, h, addr, flags);
|
err = alloc_handle_from_va(client, h, addr, flags, heap_mask);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("alloc_handle_from_va failed %d", err);
|
pr_err("alloc_handle_from_va failed %d", err);
|
||||||
nvmap_handle_put(h);
|
nvmap_handle_put(h);
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
|||||||
bool is_ro = false;
|
bool is_ro = false;
|
||||||
int err;
|
int err;
|
||||||
long dmabuf_ref = 0;
|
long dmabuf_ref = 0;
|
||||||
|
size_t old_size;
|
||||||
|
|
||||||
if (copy_from_user(&op, arg, sizeof(op)))
|
if (copy_from_user(&op, arg, sizeof(op)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
@@ -219,6 +220,16 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
|||||||
if (IS_ERR_OR_NULL(handle))
|
if (IS_ERR_OR_NULL(handle))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (op.heap_mask & NVMAP_HEAP_CARVEOUT_GPU) {
|
||||||
|
/*
|
||||||
|
* In case of Gpu carveout, the handle size needs to be aligned to 2MB.
|
||||||
|
*/
|
||||||
|
old_size = handle->size;
|
||||||
|
handle->size = ALIGN_2MB(handle->size);
|
||||||
|
err = nvmap_alloc_handle_from_va(client, handle, op.va, op.flags, op.heap_mask);
|
||||||
|
goto alloc_op_done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_nvmap_memory_available(handle->size, op.heap_mask, op.numa_nid)) {
|
if (!is_nvmap_memory_available(handle->size, op.heap_mask, op.numa_nid)) {
|
||||||
nvmap_handle_put(handle);
|
nvmap_handle_put(handle);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -234,6 +245,7 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
|||||||
op.flags & (~NVMAP_HANDLE_KIND_SPECIFIED),
|
op.flags & (~NVMAP_HANDLE_KIND_SPECIFIED),
|
||||||
NVMAP_IVM_INVALID_PEER);
|
NVMAP_IVM_INVALID_PEER);
|
||||||
|
|
||||||
|
alloc_op_done:
|
||||||
if (!err && !is_nvmap_id_ro(client, op.handle, &is_ro)) {
|
if (!err && !is_nvmap_id_ro(client, op.handle, &is_ro)) {
|
||||||
mutex_lock(&handle->lock);
|
mutex_lock(&handle->lock);
|
||||||
dmabuf = is_ro ? handle->dmabuf_ro : handle->dmabuf;
|
dmabuf = is_ro ? handle->dmabuf_ro : handle->dmabuf;
|
||||||
@@ -249,6 +261,8 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
|||||||
is_ro ? "RO" : "RW");
|
is_ro ? "RO" : "RW");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((op.heap_mask & NVMAP_HEAP_CARVEOUT_GPU) && err)
|
||||||
|
handle->size = old_size;
|
||||||
nvmap_handle_put(handle);
|
nvmap_handle_put(handle);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -426,7 +440,7 @@ int nvmap_ioctl_create_from_va(struct file *filp, void __user *arg)
|
|||||||
handle = ref->handle;
|
handle = ref->handle;
|
||||||
|
|
||||||
err = nvmap_alloc_handle_from_va(client, handle,
|
err = nvmap_alloc_handle_from_va(client, handle,
|
||||||
op.va, op.flags);
|
op.va, op.flags, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
nvmap_free_handle(client, handle, is_ro);
|
nvmap_free_handle(client, handle, is_ro);
|
||||||
return err;
|
return err;
|
||||||
@@ -978,6 +992,19 @@ int nvmap_ioctl_get_handle_parameters(struct file *filp, void __user *arg)
|
|||||||
if (!handle->alloc) {
|
if (!handle->alloc) {
|
||||||
op.heap = 0;
|
op.heap = 0;
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* When users specify GPU heap to allocate from, it means the
|
||||||
|
* allocation is done from hugetlbfs. But the heap_type stored
|
||||||
|
* in handle struct would still be IOVMM heap, as the pages are
|
||||||
|
* from system memory and not from any carveout. Also, a lot
|
||||||
|
* of nvmap APIs treat carveout and system memory in different ways
|
||||||
|
* hence it's necessary to store IOVMM heap in heap_type, but while
|
||||||
|
* querying the handle params, return GPU heap for such handles to
|
||||||
|
* be consistent.
|
||||||
|
*/
|
||||||
|
if (handle->has_hugetlbfs_pages)
|
||||||
|
op.heap = NVMAP_HEAP_CARVEOUT_GPU;
|
||||||
|
else
|
||||||
op.heap = handle->heap_type;
|
op.heap = handle->heap_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,8 +1018,10 @@ int nvmap_ioctl_get_handle_parameters(struct file *filp, void __user *arg)
|
|||||||
* If heap type is IOVMM, check if it has flag set for contiguous memory
|
* If heap type is IOVMM, check if it has flag set for contiguous memory
|
||||||
* allocation request. Otherwise, if handle belongs to any carveout
|
* allocation request. Otherwise, if handle belongs to any carveout
|
||||||
* then all allocations are contiguous, hence set contig flag to true.
|
* then all allocations are contiguous, hence set contig flag to true.
|
||||||
|
* When the handle is allocated from hugetlbfs, then return contig as false,
|
||||||
|
* since the entire buffer may not be contiguous.
|
||||||
*/
|
*/
|
||||||
if (handle->alloc &&
|
if (handle->alloc && !handle->has_hugetlbfs_pages &&
|
||||||
((handle->heap_type == NVMAP_HEAP_IOVMM &&
|
((handle->heap_type == NVMAP_HEAP_IOVMM &&
|
||||||
handle->userflags & NVMAP_HANDLE_PHYS_CONTIG) ||
|
handle->userflags & NVMAP_HANDLE_PHYS_CONTIG) ||
|
||||||
handle->heap_type != NVMAP_HEAP_IOVMM)) {
|
handle->heap_type != NVMAP_HEAP_IOVMM)) {
|
||||||
@@ -1194,6 +1223,58 @@ static int compute_memory_stat(u64 *total, u64 *free, int numa_id)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function calculates HugePages_Total and HugePages_Free by parsing
|
||||||
|
* /sys/devices/system/node/nodeX/meminfo file
|
||||||
|
*/
|
||||||
|
static int compute_hugetlbfs_stat(u64 *total, u64 *free, int numa_id)
|
||||||
|
{
|
||||||
|
struct file *file;
|
||||||
|
char meminfo_path[64] = {'\0'};
|
||||||
|
u8 *buf;
|
||||||
|
loff_t pos = 0;
|
||||||
|
char *buffer, *ptr;
|
||||||
|
unsigned int huge_total, huge_free;
|
||||||
|
bool total_found = false, free_found = false;
|
||||||
|
int nid, rc;
|
||||||
|
|
||||||
|
sprintf(meminfo_path, "/sys/devices/system/node/node%d/meminfo", numa_id);
|
||||||
|
file = filp_open(meminfo_path, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(file)) {
|
||||||
|
pr_err("Could not open file:%s\n", meminfo_path);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = nvmap_altalloc(MEMINFO_SIZE * sizeof(*buf));
|
||||||
|
if (!buf) {
|
||||||
|
pr_err("Memory allocation failed\n");
|
||||||
|
filp_close(file, NULL);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = kernel_read(file, buf, MEMINFO_SIZE - 1, &pos);
|
||||||
|
buf[rc] = '\n';
|
||||||
|
filp_close(file, NULL);
|
||||||
|
buffer = buf;
|
||||||
|
ptr = buf;
|
||||||
|
while ((ptr = strsep(&buffer, "\n")) != NULL) {
|
||||||
|
if (!ptr[0])
|
||||||
|
continue;
|
||||||
|
else if (sscanf(ptr, "Node %d HugePages_Total: %u\n", &nid, &huge_total) == 2)
|
||||||
|
total_found = true;
|
||||||
|
else if (sscanf(ptr, "Node %d HugePages_Free: %u\n", &nid, &huge_free) == 2)
|
||||||
|
free_found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvmap_altfree(buf, MEMINFO_SIZE * sizeof(*buf));
|
||||||
|
if (nid == numa_id && total_found && free_found) {
|
||||||
|
*total = (u64)huge_total * SIZE_2MB;
|
||||||
|
*free = (u64)huge_free * SIZE_2MB;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function calculates allocatable free memory using following formula:
|
* This function calculates allocatable free memory using following formula:
|
||||||
* free_mem = avail mem - cma free
|
* free_mem = avail mem - cma free
|
||||||
@@ -1271,7 +1352,22 @@ static int nvmap_query_heap_params(void __user *arg, bool is_numa_aware)
|
|||||||
/* To Do: select largest free block */
|
/* To Do: select largest free block */
|
||||||
op.largest_free_block = PAGE_SIZE;
|
op.largest_free_block = PAGE_SIZE;
|
||||||
|
|
||||||
if (type & NVMAP_HEAP_CARVEOUT_MASK) {
|
/*
|
||||||
|
* Special case: GPU heap
|
||||||
|
* When user is querying the GPU heap, that means the buffer was allocated from
|
||||||
|
* hugetlbfs, so we need to return the HugePages_Total, HugePages_Free values
|
||||||
|
*/
|
||||||
|
if (type & NVMAP_HEAP_CARVEOUT_GPU) {
|
||||||
|
if (!is_numa_aware)
|
||||||
|
numa_id = 0;
|
||||||
|
|
||||||
|
ret = compute_hugetlbfs_stat(&op.total, &op.free, numa_id);
|
||||||
|
if (ret)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
op.largest_free_block = SIZE_2MB;
|
||||||
|
op.granule_size = SIZE_2MB;
|
||||||
|
} else if (type & NVMAP_HEAP_CARVEOUT_MASK) {
|
||||||
for (i = 0; i < nvmap_dev->nr_carveouts; i++) {
|
for (i = 0; i < nvmap_dev->nr_carveouts; i++) {
|
||||||
if ((type & nvmap_dev->heaps[i].heap_bit) &&
|
if ((type & nvmap_dev->heaps[i].heap_bit) &&
|
||||||
(is_numa_aware ?
|
(is_numa_aware ?
|
||||||
|
|||||||
@@ -43,6 +43,9 @@
|
|||||||
|
|
||||||
#include <linux/fdtable.h>
|
#include <linux/fdtable.h>
|
||||||
|
|
||||||
|
#define SIZE_2MB 0x200000
|
||||||
|
#define ALIGN_2MB(size) ((size + SIZE_2MB - 1) & ~(SIZE_2MB - 1))
|
||||||
|
|
||||||
#define DMA_ERROR_CODE (~(dma_addr_t)0)
|
#define DMA_ERROR_CODE (~(dma_addr_t)0)
|
||||||
|
|
||||||
#define __DMA_ATTR(attrs) attrs
|
#define __DMA_ATTR(attrs) attrs
|
||||||
@@ -251,6 +254,7 @@ struct nvmap_handle {
|
|||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
int numa_id;
|
int numa_id;
|
||||||
u64 serial_id;
|
u64 serial_id;
|
||||||
|
bool has_hugetlbfs_pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvmap_handle_info {
|
struct nvmap_handle_info {
|
||||||
@@ -513,7 +517,8 @@ int nvmap_alloc_handle(struct nvmap_client *client,
|
|||||||
int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
||||||
struct nvmap_handle *h,
|
struct nvmap_handle *h,
|
||||||
ulong addr,
|
ulong addr,
|
||||||
unsigned int flags);
|
unsigned int flags,
|
||||||
|
unsigned int heap_mask);
|
||||||
|
|
||||||
void nvmap_free_handle(struct nvmap_client *c, struct nvmap_handle *h, bool is_ro);
|
void nvmap_free_handle(struct nvmap_client *c, struct nvmap_handle *h, bool is_ro);
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ struct nvmap_alloc_handle {
|
|||||||
__u32 flags; /* wb/wc/uc/iwb etc. */
|
__u32 flags; /* wb/wc/uc/iwb etc. */
|
||||||
__u32 align; /* min alignment necessary */
|
__u32 align; /* min alignment necessary */
|
||||||
__s32 numa_nid; /* NUMA node id */
|
__s32 numa_nid; /* NUMA node id */
|
||||||
|
__u64 va; /* virtual address to get huge pages from */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvmap_alloc_ivm_handle {
|
struct nvmap_alloc_ivm_handle {
|
||||||
|
|||||||
Reference in New Issue
Block a user