diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index 356c89038..5e5541202 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -1,12 +1,24 @@ ################################### tell Emacs this is a -*- makefile-gmake -*- # -# Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. # -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. # # tmake for SW Mobile # @@ -33,6 +45,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/mm/allocators/nvgpu_allocator NV_REPOSITORY_COMPONENTS += userspace/units/mm/gmmu/pd_cache NV_REPOSITORY_COMPONENTS += userspace/units/mm/gmmu/page_table NV_REPOSITORY_COMPONENTS += userspace/units/mm/page_table_faults +NV_REPOSITORY_COMPONENTS += userspace/units/mm/vm NV_REPOSITORY_COMPONENTS += userspace/units/fifo/runlist NV_REPOSITORY_COMPONENTS += userspace/units/fuse NV_REPOSITORY_COMPONENTS += userspace/units/list diff --git a/drivers/gpu/nvgpu/libnvgpu-drv.export b/drivers/gpu/nvgpu/libnvgpu-drv.export index 3bb9faec6..afed58b5e 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv.export @@ -164,10 +164,13 @@ nvgpu_spinlock_acquire nvgpu_spinlock_init nvgpu_spinlock_release nvgpu_usermode_writel +nvgpu_vm_area_alloc +nvgpu_vm_area_free nvgpu_vm_find_mapped_buf nvgpu_vm_init nvgpu_vm_map nvgpu_vm_put +nvgpu_vm_unmap nvgpu_writel nvgpu_writel_check set_bit diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index e6e520896..88431c530 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -59,10 +59,11 @@ UNITS := \ $(UNIT_SRC)/mm/gmmu/page_table \ $(UNIT_SRC)/mm/page_table_faults \ $(UNIT_SRC)/mm/nvgpu_mem \ + $(UNIT_SRC)/mm/vm \ $(UNIT_SRC)/fifo/runlist \ $(UNIT_SRC)/list \ $(UNIT_SRC)/enabled \ $(UNIT_SRC)/interface/lock # A test unit. Not really needed any more... -# $(UNIT_SRC)/test \ No newline at end of file +# $(UNIT_SRC)/test diff --git a/userspace/include/unit/unit-requirement-ids.h b/userspace/include/unit/unit-requirement-ids.h index d731c8ba0..f22c139cb 100644 --- a/userspace/include/unit/unit-requirement-ids.h +++ b/userspace/include/unit/unit-requirement-ids.h @@ -37,4 +37,6 @@ #define PAGE_TABLE_REQ1_UID "6439094" +#define VM_REQ1_UID "6434840" + #endif diff --git a/userspace/required_tests.json b/userspace/required_tests.json index a3a30587f..b688ca0c2 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -767,5 +767,19 @@ { "test": "nvgpu_pramin_wr_n_3_sgl", "unit": "pramin" + }, + { + "test": "map_buf", + "req": "NVGPU-RQCD-45.C1", + "vc": "V5", + "uid": "6434840", + "unit": "vm" + }, + { + "test": "map_buf_gpu_va", + "req": "NVGPU-RQCD-45.C2", + "vc": "V5", + "uid": "6434840", + "unit": "vm" } ] \ No newline at end of file diff --git a/userspace/units/mm/vm/Makefile b/userspace/units/mm/vm/Makefile new file mode 100644 index 000000000..355e62cfd --- /dev/null +++ b/userspace/units/mm/vm/Makefile @@ -0,0 +1,26 @@ +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +.SUFFIXES: + +OBJS = vm.o +MODULE = vm + +include ../../Makefile.units diff --git a/userspace/units/mm/vm/Makefile.interface.tmk b/userspace/units/mm/vm/Makefile.interface.tmk new file mode 100644 index 000000000..3b487da15 --- /dev/null +++ b/userspace/units/mm/vm/Makefile.interface.tmk @@ -0,0 +1,35 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=vm + +include $(NV_COMPONENT_DIR)/../../Makefile.units.common.interface.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/mm/vm/Makefile.tmk b/userspace/units/mm/vm/Makefile.tmk new file mode 100644 index 000000000..911ef23d2 --- /dev/null +++ b/userspace/units/mm/vm/Makefile.tmk @@ -0,0 +1,35 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=vm + +include $(NV_COMPONENT_DIR)/../../Makefile.units.common.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/mm/vm/vm.c b/userspace/units/mm/vm/vm.c new file mode 100644 index 000000000..188605b7c --- /dev/null +++ b/userspace/units/mm/vm/vm.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Random CPU physical address for the buffers we'll map */ +#define BUF_CPU_PA 0xEFAD80000000ULL +#define PHYS_ADDR_BITS_HIGH 0x00FFFFFFU +#define PHYS_ADDR_BITS_LOW 0xFFFFFF00U +/* Check if address is aligned at the requested boundary */ +#define IS_ALIGNED(addr, align) ((addr & (align - 1U)) == 0U) + +/* + * Helper function used to create custom SGTs from a list of SGLs. + * The created SGT needs to be explicitly free'd. + */ +static struct nvgpu_sgt *custom_sgt_create(struct unit_module *m, + struct gk20a *g, + struct nvgpu_mem *mem, + struct nvgpu_mem_sgl *sgl_list, + u32 nr_sgls) +{ + int ret = 0; + struct nvgpu_sgt *sgt = NULL; + + if (mem == NULL) { + unit_err(m, "mem is NULL\n"); + goto fail; + } + if (sgl_list == NULL) { + unit_err(m, "sgl_list is NULL\n"); + goto fail; + } + + ret = nvgpu_mem_posix_create_from_list(g, mem, sgl_list, nr_sgls); + if (ret != 0) { + unit_err(m, "Failed to create mem from sgl list\n"); + goto fail; + } + + sgt = nvgpu_sgt_create_from_mem(g, mem); + if (sgt == NULL) { + goto fail; + } + + return sgt; + +fail: + unit_err(m, "Failed to create sgt\n"); + return NULL; +} + +/* + * TODO: This function is copied from the gmmu/page table unit test. Instead of + * duplicating code, share a single implementation of the function. + */ +static inline bool pte_is_valid(u32 *pte) +{ + return ((pte[0] & gmmu_new_pte_valid_true_f()) != 0U); +} + +/* + * TODO: This function is copied from the gmmu/page table unit test. Instead of + * duplicating code, share a single implementation of the function. + */ +static u64 pte_get_phys_addr(struct unit_module *m, u32 *pte) +{ + u64 addr_bits; + + if (pte == NULL) { + unit_err(m, "pte is NULL\n"); + unit_err(m, "Failed to get phys addr\n"); + return 0; + } + + addr_bits = ((u64)(pte[1] & PHYS_ADDR_BITS_HIGH)) << 32; + addr_bits |= (u64)(pte[0] & PHYS_ADDR_BITS_LOW); + addr_bits >>= 8; + return (addr_bits << gmmu_new_pde_address_shift_v()); +} + +/* Initialize test environment */ +static int init_test_env(struct unit_module *m, struct gk20a *g) +{ + struct nvgpu_os_posix *p = nvgpu_os_posix_from_gk20a(g); + if (p == NULL) { + unit_err(m, "posix is NULL\n"); + unit_err(m, "Failed to initialize test environment\n"); + return UNIT_FAIL; + } + p->mm_is_iommuable = true; + + nvgpu_set_enabled(g, NVGPU_MM_UNIFIED_MEMORY, true); + nvgpu_set_enabled(g, NVGPU_HAS_SYNCPOINTS, true); + + g->ops.fb.compression_page_size = gp10b_fb_compression_page_size; + g->ops.fb.tlb_invalidate = gm20b_fb_tlb_invalidate; + + g->ops.mm.get_default_big_page_size = + gp10b_mm_get_default_big_page_size; + g->ops.mm.get_mmu_levels = gp10b_mm_get_mmu_levels; + g->ops.mm.gmmu_map = gk20a_locked_gmmu_map; + g->ops.mm.gmmu_unmap = gk20a_locked_gmmu_unmap; + g->ops.mm.gpu_phys_addr = gv11b_gpu_phys_addr; + + return UNIT_SUCCESS; +} + +/* + * Try mapping a buffer into the GPU virtual address space: + * - Allocate a new CPU buffer + * - If a specific GPU VA was requested, allocate a VM area for a fixed GPU + * VA mapping + * - Map buffer into the GPU virtual address space + * - Verify that the buffer was mapped correctly + * - Unmap buffer + */ +static int map_buffer(struct unit_module *m, + struct gk20a *g, + struct vm_gk20a *vm, + u64 cpu_pa, + u64 gpu_va, + size_t buf_size, + size_t page_size, + size_t alignment) +{ + int ret = UNIT_SUCCESS; + struct nvgpu_mapped_buf *mapped_buf = NULL; + struct nvgpu_mapped_buf *mapped_buf_check = NULL; + struct nvgpu_os_buffer os_buf = {0}; + struct nvgpu_mem_sgl sgl_list[1]; + struct nvgpu_mem mem = {0}; + struct nvgpu_sgt *sgt = NULL; + bool fixed_gpu_va = (gpu_va != 0); + u32 pte[2]; + + if (vm == NULL) { + unit_err(m, "vm is NULL\n"); + ret = UNIT_FAIL; + goto exit; + } + + /* Allocate a CPU buffer */ + os_buf.buf = nvgpu_kzalloc(g, buf_size); + if (os_buf.buf == NULL) { + unit_err(m, "Failed to allocate a CPU buffer\n"); + ret = UNIT_FAIL; + goto free_sgt_os_buf; + } + os_buf.size = buf_size; + + memset(&sgl_list[0], 0, sizeof(sgl_list[0])); + sgl_list[0].phys = cpu_pa; + sgl_list[0].dma = 0; + sgl_list[0].length = buf_size; + + mem.size = buf_size; + mem.cpu_va = os_buf.buf; + + /* Create sgt */ + sgt = custom_sgt_create(m, g, &mem, sgl_list, 1); + if (sgt == NULL) { + ret = UNIT_FAIL; + goto free_sgt_os_buf; + } + + if (fixed_gpu_va) { + size_t num_pages = DIV_ROUND_UP(buf_size, page_size); + u64 gpu_va_copy = gpu_va; + + unit_info(m, "Allocating VM Area for fixed GPU VA mapping\n"); + ret = nvgpu_vm_area_alloc(vm, + num_pages, + page_size, + &gpu_va_copy, + NVGPU_VM_AREA_ALLOC_FIXED_OFFSET); + if (ret != 0) { + unit_err(m, "Failed to allocate a VM area\n"); + ret = UNIT_FAIL; + goto free_sgt_os_buf; + } + if (gpu_va_copy != gpu_va) { + unit_err(m, "VM area created at the wrong GPU VA\n"); + ret = UNIT_FAIL; + goto free_vm_area; + } + } + + mapped_buf = nvgpu_vm_map(vm, + &os_buf, + sgt, + gpu_va, + buf_size, + 0, + gk20a_mem_flag_none, + NVGPU_VM_MAP_CACHEABLE, + 0, + 0, + NULL, + APERTURE_SYSMEM); + if (mapped_buf == NULL) { + unit_err(m, "Failed to map buffer into the GPU virtual address" + " space\n"); + ret = UNIT_FAIL; + goto free_vm_area; + } + + /* Check if we can find the mapped buffer */ + mapped_buf_check = nvgpu_vm_find_mapped_buf(vm, mapped_buf->addr); + if (mapped_buf_check == NULL) { + unit_err(m, "Can't find mapped buffer\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + if (mapped_buf_check->addr != mapped_buf->addr) { + unit_err(m, "Invalid buffer GPU VA\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + /* + * Based on the virtual address returned, lookup the corresponding PTE + */ + ret = __nvgpu_get_pte(g, vm, mapped_buf->addr, pte); + if (ret != 0) { + unit_err(m, "PTE lookup failed\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + /* Check if PTE is valid */ + if (!pte_is_valid(pte)) { + unit_err(m, "Invalid PTE!\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + /* Check if PTE corresponds to the physical address we requested */ + if (pte_get_phys_addr(m, pte) != cpu_pa) { + unit_err(m, "Unexpected physical address in PTE\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + /* Check if the buffer's GPU VA is aligned correctly */ + if (!IS_ALIGNED(mapped_buf->addr, alignment)) { + unit_err(m, "Incorrect buffer GPU VA alignment\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + /* + * If a specific GPU VA was requested, check that the buffer's GPU VA + * matches the requested GPU VA + */ + if (fixed_gpu_va && (mapped_buf->addr != gpu_va)) { + unit_err(m, "Mapped buffer's GPU VA does not match requested" + " GPU VA\n"); + ret = UNIT_FAIL; + goto free_mapped_buf; + } + + ret = UNIT_SUCCESS; + +free_mapped_buf: + if (mapped_buf != NULL) { + nvgpu_vm_unmap(vm, mapped_buf->addr, NULL); + } +free_vm_area: + if (fixed_gpu_va) { + ret = nvgpu_vm_area_free(vm, gpu_va); + if (ret != 0) { + unit_err(m, "Failed to free vm area\n"); + ret = UNIT_FAIL; + } + } +free_sgt_os_buf: + if (sgt != NULL) { + nvgpu_sgt_free(g, sgt); + } + if (os_buf.buf != NULL) { + nvgpu_kfree(g, os_buf.buf); + } + +exit: + if (ret == UNIT_FAIL) { + unit_err(m, "Buffer mapping failed\n"); + } + return ret; +} + +/* + * This is the test for requirement NVGPU-RQCD-45.C1. + * Requirement: The VM unit shall be able to map a buffer of memory such that + * the GPU may access that memory. + * + * This test does the following: + * - Initialize a VM with the following characteristics: + * - 64KB large page support enabled + * - Low hole size = 64MB + * - Address space size = 128GB + * - Kernel reserved space size = 4GB + * - Map a 4KB buffer into the VM + * - Check that the resulting GPU virtual address is aligned to 4KB + * - Unmap the buffer + * - Map a 64KB buffer into the VM + * - Check that the resulting GPU virtual address is aligned to 64KB + * - Unmap the buffer + * - Uninitialize the VM + */ +static int test_map_buf(struct unit_module *m, struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + struct vm_gk20a *vm = NULL; + u64 low_hole = 0; + u64 user_vma = 0; + u64 kernel_reserved = 0; + u64 aperture_size = 0; + bool big_pages = true; + size_t buf_size = 0; + size_t page_size = 0; + size_t alignment = 0; + + if (m == NULL) { + ret = UNIT_FAIL; + goto exit; + } + if (g == NULL) { + unit_err(m, "gk20a is NULL\n"); + ret = UNIT_FAIL; + goto exit; + } + + /* Initialize test environment */ + ret = init_test_env(m, g); + if (ret != UNIT_SUCCESS) { + goto exit; + } + + /* Initialize VM */ + big_pages = true; + low_hole = SZ_1M * 64; + aperture_size = 128 * SZ_1G; + kernel_reserved = 4 * SZ_1G - low_hole; + user_vma = aperture_size - low_hole - kernel_reserved; + unit_info(m, "Initializing VM:\n"); + unit_info(m, " - Low Hole Size = 0x%llx\n", low_hole); + unit_info(m, " - User Aperture Size = 0x%llx\n", user_vma); + unit_info(m, " - Kernel Reserved Size = 0x%llx\n", kernel_reserved); + unit_info(m, " - Total Aperture Size = 0x%llx\n", aperture_size); + vm = nvgpu_vm_init(g, + g->ops.mm.get_default_big_page_size(), + low_hole, + kernel_reserved, + aperture_size, + big_pages, + false, + true, + __func__); + if (vm == NULL) { + unit_err(m, "Failed to init VM\n"); + ret = UNIT_FAIL; + goto exit; + } + + /* Map 4KB buffer */ + buf_size = SZ_4K; + page_size = SZ_4K; + alignment = SZ_4K; + unit_info(m, "Mapping Buffer:\n"); + unit_info(m, " - CPU PA = 0x%llx\n", BUF_CPU_PA); + unit_info(m, " - Buffer Size = 0x%lx\n", buf_size); + unit_info(m, " - Page Size = 0x%lx\n", page_size); + unit_info(m, " - Alignment = 0x%lx\n", alignment); + ret = map_buffer(m, + g, + vm, + BUF_CPU_PA, + 0, + buf_size, + page_size, + alignment); + if (ret != UNIT_SUCCESS) { + unit_err(m, "4KB buffer mapping failed\n"); + goto exit; + } + + /* Map 64KB buffer */ + buf_size = SZ_64K; + page_size = SZ_64K; + alignment = SZ_64K; + unit_info(m, "Mapping Buffer:\n"); + unit_info(m, " - CPU PA = 0x%llx\n", BUF_CPU_PA); + unit_info(m, " - Buffer Size = 0x%lx\n", buf_size); + unit_info(m, " - Page Size = 0x%lx\n", page_size); + unit_info(m, " - Alignment = 0x%lx\n", alignment); + ret = map_buffer(m, + g, + vm, + BUF_CPU_PA, + 0, + buf_size, + page_size, + alignment); + if (ret != UNIT_SUCCESS) { + unit_err(m, "64KB buffer mapping failed\n"); + goto exit; + } + + ret = UNIT_SUCCESS; + +exit: + if (vm != NULL) { + nvgpu_vm_put(vm); + } + + return ret; +} + +/* + * This is the test for requirement NVGPU-RQCD-45.C2. + * Requirement: When a GPU virtual address is passed into the nvgpu_vm_map() + * function the resulting GPU virtual address of the map does/does not match + * the requested GPU virtual address. + * + * This test does the following: + * - Initialize a VM with the following characteristics: + * - 64KB large page support enabled + * - Low hole size = 64MB + * - Address space size = 128GB + * - Kernel reserved space size = 4GB + * - Map a 4KB buffer into the VM at a specific GPU virtual address + * - Check that the resulting GPU virtual address is aligned to 4KB + * - Check that the resulting GPU VA is the same as the requested GPU VA + * - Unmap the buffer + * - Map a 64KB buffer into the VM at a specific GPU virtual address + * - Check that the resulting GPU virtual address is aligned to 64KB + * - Check that the resulting GPU VA is the same as the requested GPU VA + * - Unmap the buffer + * - Uninitialize the VM + */ +static int test_map_buf_gpu_va(struct unit_module *m, + struct gk20a *g, + void *__args) +{ + int ret = UNIT_SUCCESS; + struct vm_gk20a *vm = NULL; + u64 low_hole = 0; + u64 user_vma = 0; + u64 user_vma_limit = 0; + u64 kernel_reserved = 0; + u64 aperture_size = 0; + u64 gpu_va = 0; + bool big_pages = true; + size_t buf_size = 0; + size_t page_size = 0; + size_t alignment = 0; + + if (m == NULL) { + ret = UNIT_FAIL; + goto exit; + } + if (g == NULL) { + unit_err(m, "gk20a is NULL\n"); + ret = UNIT_FAIL; + goto exit; + } + + /* Initialize test environment */ + ret = init_test_env(m, g); + if (ret != UNIT_SUCCESS) { + goto exit; + } + + /* Initialize VM */ + big_pages = true; + low_hole = SZ_1M * 64; + aperture_size = 128 * SZ_1G; + kernel_reserved = 4 * SZ_1G - low_hole; + user_vma = aperture_size - low_hole - kernel_reserved; + user_vma_limit = aperture_size - kernel_reserved; + unit_info(m, "Initializing VM:\n"); + unit_info(m, " - Low Hole Size = 0x%llx\n", low_hole); + unit_info(m, " - User Aperture Size = 0x%llx\n", user_vma); + unit_info(m, " - Kernel Reserved Size = 0x%llx\n", kernel_reserved); + unit_info(m, " - Total Aperture Size = 0x%llx\n", aperture_size); + vm = nvgpu_vm_init(g, + g->ops.mm.get_default_big_page_size(), + low_hole, + kernel_reserved, + aperture_size, + big_pages, + false, + true, + __func__); + if (vm == NULL) { + unit_err(m, "Failed to init VM\n"); + ret = UNIT_FAIL; + goto exit; + } + + /* Map 4KB buffer */ + buf_size = SZ_4K; + page_size = SZ_4K; + alignment = SZ_4K; + /* + * Calculate a valid base GPU VA for the buffer. We're multiplying + * buf_size by 10 just to be on the safe side. + */ + gpu_va = user_vma_limit - buf_size*10; + unit_info(m, "Mapping Buffer:\n"); + unit_info(m, " - CPU PA = 0x%llx\n", BUF_CPU_PA); + unit_info(m, " - GPU VA = 0x%llx\n", gpu_va); + unit_info(m, " - Buffer Size = 0x%lx\n", buf_size); + unit_info(m, " - Page Size = 0x%lx\n", page_size); + unit_info(m, " - Alignment = 0x%lx\n", alignment); + ret = map_buffer(m, + g, + vm, + BUF_CPU_PA, + gpu_va, + buf_size, + page_size, + alignment); + if (ret != UNIT_SUCCESS) { + unit_err(m, "4KB buffer mapping failed\n"); + goto exit; + } + + /* Map 64KB buffer */ + buf_size = SZ_64K; + page_size = SZ_64K; + alignment = SZ_64K; + /* + * Calculate a valid base GPU VA for the buffer. We're multiplying + * buf_size by 10 just to be on the safe side. + */ + gpu_va = user_vma_limit - buf_size*10; + unit_info(m, "Mapping Buffer:\n"); + unit_info(m, " - CPU PA = 0x%llx\n", BUF_CPU_PA); + unit_info(m, " - GPU VA = 0x%llx\n", gpu_va); + unit_info(m, " - Buffer Size = 0x%lx\n", buf_size); + unit_info(m, " - Page Size = 0x%lx\n", page_size); + unit_info(m, " - Alignment = 0x%lx\n", alignment); + ret = map_buffer(m, + g, + vm, + BUF_CPU_PA, + gpu_va, + buf_size, + page_size, + alignment); + if (ret != UNIT_SUCCESS) { + unit_err(m, "64KB buffer mapping failed\n"); + goto exit; + } + + ret = UNIT_SUCCESS; + +exit: + if (vm != NULL) { + nvgpu_vm_put(vm); + } + + return ret; +} + +struct unit_module_test vm_tests[] = { + UNIT_TEST_REQ("NVGPU-RQCD-45.C1", + VM_REQ1_UID, + "V5", + map_buf, + test_map_buf, + NULL), + UNIT_TEST_REQ("NVGPU-RQCD-45.C2", + VM_REQ1_UID, + "V5", + map_buf_gpu_va, + test_map_buf_gpu_va, + NULL), +}; + +UNIT_MODULE(vm, vm_tests, UNIT_PRIO_NVGPU_TEST);