From c2b63150cd947557b8d17637258b988459b8e0ec Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Wed, 10 May 2017 00:41:18 +0100 Subject: gpu: nvgpu: Unify vm_init for vGPU and regular GPU Unify the initialization routines for the vGPU and regular GPU paths. This helps avoid any further code divergence. This also assumes that the code running on the regular GPU essentially works for the vGPU. The only addition is that the regular GPU path calls an API in the vGPU code that sends the necessary RM server message. JIRA NVGPU-12 JIRA NVGPU-30 Change-Id: I37af1993fd8b50f666ae27524d382cce49cf28f7 Signed-off-by: Alex Waterman Reviewed-on: http://git-master/r/1480226 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/as.c | 63 +++++++++- drivers/gpu/nvgpu/common/mm/vm.c | 27 +++- drivers/gpu/nvgpu/gk20a/gk20a.h | 2 - drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 62 ---------- drivers/gpu/nvgpu/gk20a/mm_gk20a.h | 2 - drivers/gpu/nvgpu/gm20b/mm_gm20b.c | 1 - drivers/gpu/nvgpu/include/nvgpu/vgpu/vm.h | 25 ++++ drivers/gpu/nvgpu/include/nvgpu/vm.h | 5 +- drivers/gpu/nvgpu/vgpu/mm_vgpu.c | 197 +++++------------------------- 9 files changed, 143 insertions(+), 241 deletions(-) create mode 100644 drivers/gpu/nvgpu/include/nvgpu/vgpu/vm.h (limited to 'drivers') diff --git a/drivers/gpu/nvgpu/common/as.c b/drivers/gpu/nvgpu/common/as.c index 3182642a..481fb807 100644 --- a/drivers/gpu/nvgpu/common/as.c +++ b/drivers/gpu/nvgpu/common/as.c @@ -16,8 +16,10 @@ #include #include +#include #include "gk20a/gk20a.h" +#include "gk20a/platform_gk20a.h" /* dumb allocator... */ static int generate_as_share_id(struct gk20a_as *as) @@ -32,6 +34,51 @@ static void release_as_share_id(struct gk20a_as *as, int id) return; } +/* address space interfaces for the gk20a module */ +static int gk20a_vm_alloc_share(struct gk20a_as_share *as_share, + u32 big_page_size, u32 flags) +{ + struct gk20a_as *as = as_share->as; + struct gk20a *g = gk20a_from_as(as); + struct mm_gk20a *mm = &g->mm; + struct vm_gk20a *vm; + char name[32]; + int err; + const bool userspace_managed = + (flags & NVGPU_GPU_IOCTL_ALLOC_AS_FLAGS_USERSPACE_MANAGED) != 0; + + gk20a_dbg_fn(""); + + if (big_page_size == 0) { + big_page_size = + gk20a_get_platform(g->dev)->default_big_page_size; + } else { + if (!is_power_of_2(big_page_size)) + return -EINVAL; + + if (!(big_page_size & g->gpu_characteristics.available_big_page_sizes)) + return -EINVAL; + } + + vm = nvgpu_kzalloc(g, sizeof(*vm)); + if (!vm) + return -ENOMEM; + + as_share->vm = vm; + vm->as_share = as_share; + vm->enable_ctag = true; + + snprintf(name, sizeof(name), "as_%d", as_share->id); + + err = nvgpu_init_vm(mm, vm, big_page_size, + big_page_size << 10, + mm->channel.kernel_size, + mm->channel.user_size + mm->channel.kernel_size, + !mm->disable_bigpage, userspace_managed, name); + + return err; +} + int gk20a_as_alloc_share(struct gk20a *g, u32 big_page_size, u32 flags, struct gk20a_as_share **out) @@ -56,7 +103,7 @@ int gk20a_as_alloc_share(struct gk20a *g, err = gk20a_busy(g); if (err) goto failed; - err = g->ops.mm.vm_alloc_share(as_share, big_page_size, flags); + err = gk20a_vm_alloc_share(as_share, big_page_size, flags); gk20a_idle(g); if (err) @@ -70,6 +117,20 @@ failed: return err; } +int gk20a_vm_release_share(struct gk20a_as_share *as_share) +{ + struct vm_gk20a *vm = as_share->vm; + + gk20a_dbg_fn(""); + + vm->as_share = NULL; + as_share->vm = NULL; + + nvgpu_vm_put(vm); + + return 0; +} + /* * channels and the device nodes call this to release. * once the ref_cnt hits zero the share is deleted. diff --git a/drivers/gpu/nvgpu/common/mm/vm.c b/drivers/gpu/nvgpu/common/mm/vm.c index b957e755..171a67ca 100644 --- a/drivers/gpu/nvgpu/common/mm/vm.c +++ b/drivers/gpu/nvgpu/common/mm/vm.c @@ -24,6 +24,8 @@ #include #include +#include + #include "gk20a/gk20a.h" #include "gk20a/mm_gk20a.h" @@ -209,10 +211,11 @@ static int nvgpu_init_sema_pool(struct vm_gk20a *vm) * @vm - The VM to init. * @big_page_size - Size of big pages associated with this VM. * @low_hole - The size of the low hole (unaddressable memory at the bottom of - * the address space. + * the address space). * @kernel_reserved - Space reserved for kernel only allocations. * @aperture_size - Total size of the aperture. - * @big_pages - Ignored. Will be set based on other passed params. + * @big_pages - If true then big pages are possible in the VM. Note this does + * not guarantee that big pages will be possible. * @name - Name of the address space. * * This function initializes an address space according to the following map: @@ -284,10 +287,21 @@ int nvgpu_init_vm(struct mm_gk20a *mm, vm->userspace_managed = userspace_managed; vm->mmu_levels = g->ops.mm.get_mmu_levels(g, vm->big_page_size); +#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION + if (g->is_virtual && userspace_managed) { + nvgpu_err(g, "vGPU: no userspace managed addr space support"); + return -ENOSYS; + } + if (g->is_virtual && vgpu_vm_init(g, vm)) { + nvgpu_err(g, "Failed to init vGPU VM!"); + return -ENOMEM; + } +#endif + /* Initialize the page table data structures. */ err = nvgpu_vm_init_page_tables(vm); if (err) - return err; + goto clean_up_vgpu_vm; /* Setup vma limits. */ if (kernel_reserved + low_hole < aperture_size) { @@ -445,6 +459,11 @@ clean_up_page_tables: /* Cleans up nvgpu_vm_init_page_tables() */ nvgpu_vfree(g, vm->pdb.entries); free_gmmu_pages(vm, &vm->pdb); +clean_up_vgpu_vm: +#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION + if (g->is_virtual) + vgpu_vm_remove(vm); +#endif return err; } @@ -503,7 +522,7 @@ void __nvgpu_vm_remove(struct vm_gk20a *vm) #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION if (g->is_virtual) - nvgpu_vm_remove_vgpu(vm); + vgpu_vm_remove(vm); #endif nvgpu_mutex_release(&vm->update_gmmu_lock); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 4fc626e8..a02215d2 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -672,8 +672,6 @@ struct gpu_ops { int rw_flag, bool sparse, struct vm_gk20a_mapping_batch *batch); - int (*vm_alloc_share)(struct gk20a_as_share *as_share, - u32 big_page_size, u32 flags); int (*vm_bind_channel)(struct gk20a_as_share *as_share, struct channel_gk20a *ch); int (*fb_flush)(struct gk20a *g); diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index ec020d5f..87e6f30c 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c @@ -702,8 +702,6 @@ int gk20a_init_mm_setup_sw(struct gk20a *g) if (err) return err; - /* set vm_alloc_share op here as gk20a_as_alloc_share needs it */ - g->ops.mm.vm_alloc_share = gk20a_vm_alloc_share; mm->remove_support = gk20a_remove_mm_support; mm->remove_ce_support = gk20a_remove_mm_ce_support; @@ -2451,65 +2449,6 @@ enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size) return gmmu_page_size_small; } -/* address space interfaces for the gk20a module */ -int gk20a_vm_alloc_share(struct gk20a_as_share *as_share, u32 big_page_size, - u32 flags) -{ - struct gk20a_as *as = as_share->as; - struct gk20a *g = gk20a_from_as(as); - struct mm_gk20a *mm = &g->mm; - struct vm_gk20a *vm; - char name[32]; - int err; - const bool userspace_managed = - (flags & NVGPU_GPU_IOCTL_ALLOC_AS_FLAGS_USERSPACE_MANAGED) != 0; - - gk20a_dbg_fn(""); - - if (big_page_size == 0) { - big_page_size = - gk20a_get_platform(g->dev)->default_big_page_size; - } else { - if (!is_power_of_2(big_page_size)) - return -EINVAL; - - if (!(big_page_size & g->gpu_characteristics.available_big_page_sizes)) - return -EINVAL; - } - - vm = nvgpu_kzalloc(g, sizeof(*vm)); - if (!vm) - return -ENOMEM; - - as_share->vm = vm; - vm->as_share = as_share; - vm->enable_ctag = true; - - snprintf(name, sizeof(name), "as_%d", as_share->id); - - err = nvgpu_init_vm(mm, vm, big_page_size, - big_page_size << 10, - mm->channel.kernel_size, - mm->channel.user_size + mm->channel.kernel_size, - !mm->disable_bigpage, userspace_managed, name); - - return err; -} - -int gk20a_vm_release_share(struct gk20a_as_share *as_share) -{ - struct vm_gk20a *vm = as_share->vm; - - gk20a_dbg_fn(""); - - vm->as_share = NULL; - as_share->vm = NULL; - - nvgpu_vm_put(vm); - - return 0; -} - int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch) { int err = 0; @@ -3130,7 +3069,6 @@ void gk20a_init_mm(struct gpu_ops *gops) { gops->mm.gmmu_map = gk20a_locked_gmmu_map; gops->mm.gmmu_unmap = gk20a_locked_gmmu_unmap; - gops->mm.vm_alloc_share = gk20a_vm_alloc_share; gops->mm.vm_bind_channel = gk20a_vm_bind_channel; gops->mm.fb_flush = gk20a_mm_fb_flush; gops->mm.l2_invalidate = gk20a_mm_l2_invalidate; diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.h b/drivers/gpu/nvgpu/gk20a/mm_gk20a.h index 94342818..16c35d34 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.h @@ -416,8 +416,6 @@ int nvgpu_vm_get_compbits_info(struct vm_gk20a *vm, /* vm-as interface */ struct nvgpu_as_alloc_space_args; struct nvgpu_as_free_space_args; -int gk20a_vm_alloc_share(struct gk20a_as_share *as_share, u32 big_page_size, - u32 flags); int gk20a_vm_release_share(struct gk20a_as_share *as_share); int gk20a_vm_bind_channel(struct gk20a_as_share *as_share, struct channel_gk20a *ch); diff --git a/drivers/gpu/nvgpu/gm20b/mm_gm20b.c b/drivers/gpu/nvgpu/gm20b/mm_gm20b.c index 78e083d0..0595fe2e 100644 --- a/drivers/gpu/nvgpu/gm20b/mm_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/mm_gm20b.c @@ -60,7 +60,6 @@ void gm20b_init_mm(struct gpu_ops *gops) gops->mm.support_sparse = gm20b_mm_support_sparse; gops->mm.gmmu_map = gk20a_locked_gmmu_map; gops->mm.gmmu_unmap = gk20a_locked_gmmu_unmap; - gops->mm.vm_alloc_share = gk20a_vm_alloc_share; gops->mm.vm_bind_channel = gk20a_vm_bind_channel; gops->mm.fb_flush = gk20a_mm_fb_flush; gops->mm.l2_invalidate = gk20a_mm_l2_invalidate; diff --git a/drivers/gpu/nvgpu/include/nvgpu/vgpu/vm.h b/drivers/gpu/nvgpu/include/nvgpu/vgpu/vm.h new file mode 100644 index 00000000..364baac6 --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/vgpu/vm.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NVGPU_VM_VGPU_H__ +#define __NVGPU_VM_VGPU_H__ + +#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION +int vgpu_vm_init(struct gk20a *g, struct vm_gk20a *vm); +void vgpu_vm_remove(struct vm_gk20a *vm); +#endif + +#endif diff --git a/drivers/gpu/nvgpu/include/nvgpu/vm.h b/drivers/gpu/nvgpu/include/nvgpu/vm.h index fed58f24..403f3b18 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/vm.h +++ b/drivers/gpu/nvgpu/include/nvgpu/vm.h @@ -225,12 +225,10 @@ int nvgpu_insert_mapped_buf(struct vm_gk20a *vm, void nvgpu_remove_mapped_buf(struct vm_gk20a *vm, struct nvgpu_mapped_buf *mapped_buffer); +void nvgpu_deinit_vm(struct vm_gk20a *vm); void __nvgpu_vm_remove(struct vm_gk20a *vm); void nvgpu_vm_remove(struct vm_gk20a *vm); void nvgpu_vm_remove_inst(struct vm_gk20a *vm, struct nvgpu_mem *inst_block); -#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION -void nvgpu_vm_remove_vgpu(struct vm_gk20a *vm); -#endif int nvgpu_init_vm(struct mm_gk20a *mm, struct vm_gk20a *vm, @@ -241,7 +239,6 @@ int nvgpu_init_vm(struct mm_gk20a *mm, bool big_pages, bool userspace_managed, char *name); -void nvgpu_deinit_vm(struct vm_gk20a *vm); /* * These are private to the VM code but are unfortunately used by the vgpu code. diff --git a/drivers/gpu/nvgpu/vgpu/mm_vgpu.c b/drivers/gpu/nvgpu/vgpu/mm_vgpu.c index 287567d6..b2bc6f0a 100644 --- a/drivers/gpu/nvgpu/vgpu/mm_vgpu.c +++ b/drivers/gpu/nvgpu/vgpu/mm_vgpu.c @@ -21,6 +21,8 @@ #include #include +#include + #include "vgpu/vgpu.h" #include "gk20a/mm_gk20a.h" @@ -201,7 +203,36 @@ static void vgpu_locked_gmmu_unmap(struct vm_gk20a *vm, /* TLB invalidate handled on server side */ } -void nvgpu_vm_remove_vgpu(struct vm_gk20a *vm) +/* + * This is called by the common VM init routine to handle vGPU specifics of + * intializing a VM on a vGPU. This alone is not enough to init a VM. See + * nvgpu_vm_init(). + */ +int vgpu_vm_init(struct gk20a *g, struct vm_gk20a *vm) +{ + struct tegra_vgpu_cmd_msg msg; + struct tegra_vgpu_as_share_params *p = &msg.params.as_share; + int err; + + msg.cmd = TEGRA_VGPU_CMD_AS_ALLOC_SHARE; + msg.handle = vgpu_get_handle(g); + p->size = vm->va_limit; + p->big_page_size = vm->big_page_size; + + err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); + if (err || msg.ret) + return -ENOMEM; + + vm->handle = p->handle; + + return 0; +} + +/* + * Similar to vgpu_vm_init() this is called as part of the cleanup path for + * VMs. This alone is not enough to remove a VM - see nvgpu_vm_remove(). + */ +void vgpu_vm_remove(struct vm_gk20a *vm) { struct gk20a *g = gk20a_from_vm(vm); struct tegra_vgpu_cmd_msg msg; @@ -238,169 +269,6 @@ u64 vgpu_bar1_map(struct gk20a *g, struct sg_table **sgt, u64 size) return addr; } -/* address space interfaces for the gk20a module */ -static int vgpu_vm_alloc_share(struct gk20a_as_share *as_share, - u32 big_page_size, u32 flags) -{ - struct gk20a_as *as = as_share->as; - struct gk20a *g = gk20a_from_as(as); - struct gk20a_platform *platform = gk20a_get_platform(g->dev); - struct tegra_vgpu_cmd_msg msg; - struct tegra_vgpu_as_share_params *p = &msg.params.as_share; - struct mm_gk20a *mm = &g->mm; - struct vm_gk20a *vm; - u64 user_vma_start, user_vma_limit, kernel_vma_start, kernel_vma_limit; - char name[32]; - int err, i; - const bool userspace_managed = - (flags & NVGPU_GPU_IOCTL_ALLOC_AS_FLAGS_USERSPACE_MANAGED) != 0; - - /* note: keep the page sizes sorted lowest to highest here */ - u32 gmmu_page_sizes[gmmu_nr_page_sizes] = { - SZ_4K, - big_page_size ? big_page_size : platform->default_big_page_size, - SZ_4K - }; - - gk20a_dbg_fn(""); - - if (userspace_managed) { - nvgpu_err(g, - "userspace-managed address spaces not yet supported"); - return -ENOSYS; - } - - big_page_size = gmmu_page_sizes[gmmu_page_size_big]; - - vm = nvgpu_kzalloc(g, sizeof(*vm)); - if (!vm) - return -ENOMEM; - - as_share->vm = vm; - - vm->mm = mm; - vm->as_share = as_share; - - /* Set up vma pointers. */ - vm->vma[0] = &vm->user; - vm->vma[1] = &vm->user; - vm->vma[2] = &vm->kernel; - - for (i = 0; i < gmmu_nr_page_sizes; i++) - vm->gmmu_page_sizes[i] = gmmu_page_sizes[i]; - - vm->big_pages = !mm->disable_bigpage; - vm->big_page_size = big_page_size; - - vm->va_start = big_page_size << 10; /* create a one pde hole */ - vm->va_limit = mm->channel.user_size + mm->channel.kernel_size; - - msg.cmd = TEGRA_VGPU_CMD_AS_ALLOC_SHARE; - msg.handle = vgpu_get_handle(g); - p->size = vm->va_limit; - p->big_page_size = vm->big_page_size; - err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); - if (err || msg.ret) { - err = -ENOMEM; - goto clean_up; - } - - vm->handle = p->handle; - - /* setup vma limits */ - user_vma_start = vm->va_start; - user_vma_limit = vm->va_limit - mm->channel.kernel_size; - - kernel_vma_start = vm->va_limit - mm->channel.kernel_size; - kernel_vma_limit = vm->va_limit; - - gk20a_dbg_info( - "user_vma=[0x%llx,0x%llx) kernel_vma=[0x%llx,0x%llx)\n", - user_vma_start, user_vma_limit, - kernel_vma_start, kernel_vma_limit); - - WARN_ON(user_vma_start > user_vma_limit); - WARN_ON(kernel_vma_start >= kernel_vma_limit); - - if (user_vma_start > user_vma_limit || - kernel_vma_start >= kernel_vma_limit) { - err = -EINVAL; - goto clean_up_share; - } - - if (user_vma_start < user_vma_limit) { - snprintf(name, sizeof(name), "gk20a_as_%d-%dKB", as_share->id, - gmmu_page_sizes[gmmu_page_size_small] >> 10); - if (!nvgpu_big_pages_possible(vm, user_vma_start, - user_vma_limit - user_vma_start)) - vm->big_pages = false; - - err = __nvgpu_buddy_allocator_init( - g, - vm->vma[gmmu_page_size_small], - vm, name, - user_vma_start, - user_vma_limit - user_vma_start, - SZ_4K, - GPU_BALLOC_MAX_ORDER, - GPU_ALLOC_GVA_SPACE); - if (err) - goto clean_up_share; - } else { - /* - * Make these allocator pointers point to the kernel allocator - * since we still use the legacy notion of page size to choose - * the allocator. - */ - vm->vma[0] = &vm->kernel; - vm->vma[1] = &vm->kernel; - } - - snprintf(name, sizeof(name), "gk20a_as_%dKB-sys", - gmmu_page_sizes[gmmu_page_size_kernel] >> 10); - if (!nvgpu_big_pages_possible(vm, kernel_vma_start, - kernel_vma_limit - kernel_vma_start)) - vm->big_pages = false; - - /* - * kernel reserved VMA is at the end of the aperture - */ - err = __nvgpu_buddy_allocator_init( - g, - vm->vma[gmmu_page_size_kernel], - vm, name, - kernel_vma_start, - kernel_vma_limit - kernel_vma_start, - SZ_4K, - GPU_BALLOC_MAX_ORDER, - GPU_ALLOC_GVA_SPACE); - if (err) - goto clean_up_user_allocator; - - vm->mapped_buffers = NULL; - - nvgpu_mutex_init(&vm->update_gmmu_lock); - kref_init(&vm->ref); - nvgpu_init_list_node(&vm->vm_area_list); - - vm->enable_ctag = true; - - return 0; - -clean_up_user_allocator: - if (user_vma_start < user_vma_limit) - nvgpu_alloc_destroy(&vm->user); -clean_up_share: - msg.cmd = TEGRA_VGPU_CMD_AS_FREE_SHARE; - msg.handle = vgpu_get_handle(g); - p->handle = vm->handle; - WARN_ON(vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)) || msg.ret); -clean_up: - nvgpu_kfree(g, vm); - as_share->vm = NULL; - return err; -} - static int vgpu_vm_bind_channel(struct gk20a_as_share *as_share, struct channel_gk20a *ch) { @@ -501,7 +369,6 @@ void vgpu_init_mm_ops(struct gpu_ops *gops) gops->fb.set_debug_mode = vgpu_mm_mmu_set_debug_mode; gops->mm.gmmu_map = vgpu_locked_gmmu_map; gops->mm.gmmu_unmap = vgpu_locked_gmmu_unmap; - gops->mm.vm_alloc_share = vgpu_vm_alloc_share; gops->mm.vm_bind_channel = vgpu_vm_bind_channel; gops->mm.fb_flush = vgpu_mm_fb_flush; gops->mm.l2_invalidate = vgpu_mm_l2_invalidate; -- cgit v1.2.2