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,
|
||||
struct nvmap_handle *h,
|
||||
ulong vaddr,
|
||||
u32 flags)
|
||||
u32 flags,
|
||||
unsigned int heap_mask)
|
||||
{
|
||||
size_t nr_page = h->size >> PAGE_SHIFT;
|
||||
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_pgalloc = true;
|
||||
h->from_va = true;
|
||||
if (heap_mask & NVMAP_HEAP_CARVEOUT_GPU)
|
||||
h->has_hugetlbfs_pages = true;
|
||||
mb();
|
||||
h->alloc = true;
|
||||
return ret;
|
||||
@@ -424,7 +427,8 @@ out:
|
||||
int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
||||
struct nvmap_handle *h,
|
||||
ulong addr,
|
||||
unsigned int flags)
|
||||
unsigned int flags,
|
||||
unsigned int heap_mask)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
int tag;
|
||||
@@ -455,7 +459,7 @@ int nvmap_alloc_handle_from_va(struct nvmap_client *client,
|
||||
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) {
|
||||
pr_err("alloc_handle_from_va failed %d", err);
|
||||
nvmap_handle_put(h);
|
||||
|
||||
@@ -200,6 +200,7 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
||||
bool is_ro = false;
|
||||
int err;
|
||||
long dmabuf_ref = 0;
|
||||
size_t old_size;
|
||||
|
||||
if (copy_from_user(&op, arg, sizeof(op)))
|
||||
return -EFAULT;
|
||||
@@ -219,6 +220,16 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
||||
if (IS_ERR_OR_NULL(handle))
|
||||
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)) {
|
||||
nvmap_handle_put(handle);
|
||||
return -ENOMEM;
|
||||
@@ -234,6 +245,7 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
|
||||
op.flags & (~NVMAP_HANDLE_KIND_SPECIFIED),
|
||||
NVMAP_IVM_INVALID_PEER);
|
||||
|
||||
alloc_op_done:
|
||||
if (!err && !is_nvmap_id_ro(client, op.handle, &is_ro)) {
|
||||
mutex_lock(&handle->lock);
|
||||
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");
|
||||
}
|
||||
|
||||
if ((op.heap_mask & NVMAP_HEAP_CARVEOUT_GPU) && err)
|
||||
handle->size = old_size;
|
||||
nvmap_handle_put(handle);
|
||||
return err;
|
||||
}
|
||||
@@ -426,7 +440,7 @@ int nvmap_ioctl_create_from_va(struct file *filp, void __user *arg)
|
||||
handle = ref->handle;
|
||||
|
||||
err = nvmap_alloc_handle_from_va(client, handle,
|
||||
op.va, op.flags);
|
||||
op.va, op.flags, 0);
|
||||
if (err) {
|
||||
nvmap_free_handle(client, handle, is_ro);
|
||||
return err;
|
||||
@@ -978,6 +992,19 @@ int nvmap_ioctl_get_handle_parameters(struct file *filp, void __user *arg)
|
||||
if (!handle->alloc) {
|
||||
op.heap = 0;
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* allocation request. Otherwise, if handle belongs to any carveout
|
||||
* 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->userflags & NVMAP_HANDLE_PHYS_CONTIG) ||
|
||||
handle->heap_type != NVMAP_HEAP_IOVMM)) {
|
||||
@@ -1194,6 +1223,58 @@ static int compute_memory_stat(u64 *total, u64 *free, int numa_id)
|
||||
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:
|
||||
* 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 */
|
||||
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++) {
|
||||
if ((type & nvmap_dev->heaps[i].heap_bit) &&
|
||||
(is_numa_aware ?
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
|
||||
#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_ATTR(attrs) attrs
|
||||
@@ -251,6 +254,7 @@ struct nvmap_handle {
|
||||
wait_queue_head_t waitq;
|
||||
int numa_id;
|
||||
u64 serial_id;
|
||||
bool has_hugetlbfs_pages;
|
||||
};
|
||||
|
||||
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,
|
||||
struct nvmap_handle *h,
|
||||
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);
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ struct nvmap_alloc_handle {
|
||||
__u32 flags; /* wb/wc/uc/iwb etc. */
|
||||
__u32 align; /* min alignment necessary */
|
||||
__s32 numa_nid; /* NUMA node id */
|
||||
__u64 va; /* virtual address to get huge pages from */
|
||||
};
|
||||
|
||||
struct nvmap_alloc_ivm_handle {
|
||||
|
||||
Reference in New Issue
Block a user