From 1e355ca52e2b3ac5f4e433e1bb115f6fd8499954 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Thu, 23 Mar 2017 12:49:58 -0700 Subject: gpu: nvgpu: Split as code to as IOCTL and common Split as_gk20a.c into two parts: common/linux/ioctl_as.c deals with as related devnodes and ioctls. This file contains all the Linux specific parts of as_gk20a.c. common/as.c deals with general as_gk20a maintenance and is Linux independent. JIRA NVGPU-16 Change-Id: I2d8541e0bd6ce159dc6e4de8e819dfcff0fa8f80 Signed-off-by: Terje Bergstrom Reviewed-on: http://git-master/r/1330803 Reviewed-by: svccoveritychecker GVS: Gerrit_Virtual_Submit --- drivers/gpu/nvgpu/Makefile.nvgpu | 3 +- drivers/gpu/nvgpu/common/as.c | 99 ++++++ drivers/gpu/nvgpu/common/linux/ioctl.c | 10 +- drivers/gpu/nvgpu/common/linux/ioctl_as.c | 377 +++++++++++++++++++++++ drivers/gpu/nvgpu/common/linux/ioctl_as.h | 26 ++ drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 4 +- drivers/gpu/nvgpu/gk20a/as_gk20a.c | 461 ---------------------------- drivers/gpu/nvgpu/gk20a/as_gk20a.h | 49 --- drivers/gpu/nvgpu/gk20a/gk20a.h | 8 +- drivers/gpu/nvgpu/include/nvgpu/as.h | 36 +++ 10 files changed, 554 insertions(+), 519 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/as.c create mode 100644 drivers/gpu/nvgpu/common/linux/ioctl_as.c create mode 100644 drivers/gpu/nvgpu/common/linux/ioctl_as.h delete mode 100644 drivers/gpu/nvgpu/gk20a/as_gk20a.c delete mode 100644 drivers/gpu/nvgpu/gk20a/as_gk20a.h create mode 100644 drivers/gpu/nvgpu/include/nvgpu/as.h (limited to 'drivers/gpu') diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu index 9186bcc7..e9e7581a 100644 --- a/drivers/gpu/nvgpu/Makefile.nvgpu +++ b/drivers/gpu/nvgpu/Makefile.nvgpu @@ -27,6 +27,7 @@ nvgpu-y := \ common/linux/timers.o \ common/linux/ioctl.o \ common/linux/ioctl_ctrl.o \ + common/linux/ioctl_as.o \ common/mm/nvgpu_allocator.o \ common/mm/bitmap_allocator.o \ common/mm/buddy_allocator.o \ @@ -35,12 +36,12 @@ nvgpu-y := \ common/pramin.o \ common/nvgpu_common.o \ common/semaphore.o \ + common/as.o \ common/vbios/bios.o \ gk20a/gk20a.o \ gk20a/bus_gk20a.o \ gk20a/pramin_gk20a.o \ gk20a/sched_gk20a.o \ - gk20a/as_gk20a.o \ gk20a/ce2_gk20a.o \ gk20a/fifo_gk20a.o \ gk20a/channel_gk20a.o \ diff --git a/drivers/gpu/nvgpu/common/as.c b/drivers/gpu/nvgpu/common/as.c new file mode 100644 index 00000000..3182642a --- /dev/null +++ b/drivers/gpu/nvgpu/common/as.c @@ -0,0 +1,99 @@ +/* + * GK20A Address Spaces + * + * Copyright (c) 2011-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. + */ + +#include + +#include + +#include "gk20a/gk20a.h" + +/* dumb allocator... */ +static int generate_as_share_id(struct gk20a_as *as) +{ + gk20a_dbg_fn(""); + return ++as->last_share_id; +} +/* still dumb */ +static void release_as_share_id(struct gk20a_as *as, int id) +{ + gk20a_dbg_fn(""); + return; +} + +int gk20a_as_alloc_share(struct gk20a *g, + u32 big_page_size, u32 flags, + struct gk20a_as_share **out) +{ + struct gk20a_as_share *as_share; + int err = 0; + + gk20a_dbg_fn(""); + g = gk20a_get(g); + if (!g) + return -ENODEV; + + *out = NULL; + as_share = nvgpu_kzalloc(g, sizeof(*as_share)); + if (!as_share) + return -ENOMEM; + + as_share->as = &g->as; + as_share->id = generate_as_share_id(as_share->as); + + /* this will set as_share->vm. */ + err = gk20a_busy(g); + if (err) + goto failed; + err = g->ops.mm.vm_alloc_share(as_share, big_page_size, flags); + gk20a_idle(g); + + if (err) + goto failed; + + *out = as_share; + return 0; + +failed: + nvgpu_kfree(g, as_share); + return err; +} + +/* + * channels and the device nodes call this to release. + * once the ref_cnt hits zero the share is deleted. + */ +int gk20a_as_release_share(struct gk20a_as_share *as_share) +{ + struct gk20a *g = as_share->vm->mm->g; + int err; + + gk20a_dbg_fn(""); + + err = gk20a_busy(g); + + if (err) + goto release_fail; + + err = gk20a_vm_release_share(as_share); + + gk20a_idle(g); + +release_fail: + release_as_share_id(as_share->as, as_share->id); + gk20a_put(g); + nvgpu_kfree(g, as_share); + + return err; +} diff --git a/drivers/gpu/nvgpu/common/linux/ioctl.c b/drivers/gpu/nvgpu/common/linux/ioctl.c index 202ea0ef..53b9476e 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl.c @@ -24,9 +24,9 @@ #include "gk20a/dbg_gpu_gk20a.h" #include "gk20a/ctxsw_trace_gk20a.h" #include "gk20a/channel_gk20a.h" -#include "gk20a/as_gk20a.h" #include "gk20a/tsg_gk20a.h" #include "ioctl_ctrl.h" +#include "ioctl_as.h" #define GK20A_NUM_CDEVS 7 @@ -167,9 +167,9 @@ void gk20a_user_deinit(struct device *dev, struct class *class) cdev_del(&g->channel.cdev); } - if (g->as.node) { - device_destroy(class, g->as.cdev.dev); - cdev_del(&g->as.cdev); + if (g->as_dev.node) { + device_destroy(class, g->as_dev.cdev.dev); + cdev_del(&g->as_dev.cdev); } if (g->ctrl.node) { @@ -228,7 +228,7 @@ int gk20a_user_init(struct device *dev, const char *interface_name, goto fail; err = gk20a_create_device(dev, devno++, interface_name, "-as", - &g->as.cdev, &g->as.node, + &g->as_dev.cdev, &g->as_dev.node, &gk20a_as_ops, class); if (err) diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_as.c b/drivers/gpu/nvgpu/common/linux/ioctl_as.c new file mode 100644 index 00000000..ff9787db --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/ioctl_as.c @@ -0,0 +1,377 @@ +/* + * GK20A Address Spaces + * + * Copyright (c) 2011-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. + */ + +#include +#include + +#include + +#include + +#include "gk20a/gk20a.h" + +static int gk20a_as_ioctl_bind_channel( + struct gk20a_as_share *as_share, + struct nvgpu_as_bind_channel_args *args) +{ + int err = 0; + struct channel_gk20a *ch; + + gk20a_dbg_fn(""); + + ch = gk20a_get_channel_from_file(args->channel_fd); + if (!ch || gk20a_channel_as_bound(ch)) + return -EINVAL; + + /* this will set channel_gk20a->vm */ + err = ch->g->ops.mm.vm_bind_channel(as_share, ch); + if (err) + return err; + + return err; +} + +static int gk20a_as_ioctl_alloc_space( + struct gk20a_as_share *as_share, + struct nvgpu_as_alloc_space_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_alloc_space(as_share, args); +} + +static int gk20a_as_ioctl_free_space( + struct gk20a_as_share *as_share, + struct nvgpu_as_free_space_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_free_space(as_share, args); +} + +static int gk20a_as_ioctl_map_buffer_ex( + struct gk20a_as_share *as_share, + struct nvgpu_as_map_buffer_ex_args *args) +{ + gk20a_dbg_fn(""); + + return gk20a_vm_map_buffer(as_share->vm, args->dmabuf_fd, + &args->offset, args->flags, + args->kind, + args->buffer_offset, + args->mapping_size, + NULL); +} + +static int gk20a_as_ioctl_map_buffer( + struct gk20a_as_share *as_share, + struct nvgpu_as_map_buffer_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_map_buffer(as_share->vm, args->dmabuf_fd, + &args->o_a.offset, + args->flags, NV_KIND_DEFAULT, + 0, 0, NULL); + /* args->o_a.offset will be set if !err */ +} + +static int gk20a_as_ioctl_unmap_buffer( + struct gk20a_as_share *as_share, + struct nvgpu_as_unmap_buffer_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_unmap_buffer(as_share->vm, args->offset, NULL); +} + +static int gk20a_as_ioctl_map_buffer_batch( + struct gk20a_as_share *as_share, + struct nvgpu_as_map_buffer_batch_args *args) +{ + struct gk20a *g = as_share->vm->mm->g; + u32 i; + int err = 0; + + struct nvgpu_as_unmap_buffer_args __user *user_unmap_args = + (struct nvgpu_as_unmap_buffer_args __user *)(uintptr_t) + args->unmaps; + struct nvgpu_as_map_buffer_ex_args __user *user_map_args = + (struct nvgpu_as_map_buffer_ex_args __user *)(uintptr_t) + args->maps; + + struct vm_gk20a_mapping_batch batch; + + gk20a_dbg_fn(""); + + if (args->num_unmaps > g->gpu_characteristics.map_buffer_batch_limit || + args->num_maps > g->gpu_characteristics.map_buffer_batch_limit) + return -EINVAL; + + gk20a_vm_mapping_batch_start(&batch); + + for (i = 0; i < args->num_unmaps; ++i) { + struct nvgpu_as_unmap_buffer_args unmap_args; + + if (copy_from_user(&unmap_args, &user_unmap_args[i], + sizeof(unmap_args))) { + err = -EFAULT; + break; + } + + err = gk20a_vm_unmap_buffer(as_share->vm, unmap_args.offset, + &batch); + if (err) + break; + } + + if (err) { + gk20a_vm_mapping_batch_finish(as_share->vm, &batch); + + args->num_unmaps = i; + args->num_maps = 0; + return err; + } + + for (i = 0; i < args->num_maps; ++i) { + struct nvgpu_as_map_buffer_ex_args map_args; + memset(&map_args, 0, sizeof(map_args)); + + if (copy_from_user(&map_args, &user_map_args[i], + sizeof(map_args))) { + err = -EFAULT; + break; + } + + err = gk20a_vm_map_buffer( + as_share->vm, map_args.dmabuf_fd, + &map_args.offset, map_args.flags, + map_args.kind, + map_args.buffer_offset, + map_args.mapping_size, + &batch); + if (err) + break; + } + + gk20a_vm_mapping_batch_finish(as_share->vm, &batch); + + if (err) + args->num_maps = i; + /* note: args->num_unmaps will be unmodified, which is ok + * since all unmaps are done */ + + return err; +} + +static int gk20a_as_ioctl_get_va_regions( + struct gk20a_as_share *as_share, + struct nvgpu_as_get_va_regions_args *args) +{ + unsigned int i; + unsigned int write_entries; + struct nvgpu_as_va_region __user *user_region_ptr; + struct vm_gk20a *vm = as_share->vm; + unsigned int page_sizes = gmmu_page_size_kernel; + + gk20a_dbg_fn(""); + + if (!vm->big_pages) + page_sizes--; + + write_entries = args->buf_size / sizeof(struct nvgpu_as_va_region); + if (write_entries > page_sizes) + write_entries = page_sizes; + + user_region_ptr = + (struct nvgpu_as_va_region __user *)(uintptr_t)args->buf_addr; + + for (i = 0; i < write_entries; ++i) { + struct nvgpu_as_va_region region; + struct nvgpu_allocator *vma = vm->vma[i]; + + memset(®ion, 0, sizeof(struct nvgpu_as_va_region)); + + region.page_size = vm->gmmu_page_sizes[i]; + region.offset = nvgpu_alloc_base(vma); + /* No __aeabi_uldivmod() on some platforms... */ + region.pages = (nvgpu_alloc_end(vma) - + nvgpu_alloc_base(vma)) >> ilog2(region.page_size); + + if (copy_to_user(user_region_ptr + i, ®ion, sizeof(region))) + return -EFAULT; + } + + args->buf_size = + page_sizes * sizeof(struct nvgpu_as_va_region); + + return 0; +} + +static int gk20a_as_ioctl_get_buffer_compbits_info( + struct gk20a_as_share *as_share, + struct nvgpu_as_get_buffer_compbits_info_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_get_compbits_info(as_share->vm, + args->mapping_gva, + &args->compbits_win_size, + &args->compbits_win_ctagline, + &args->mapping_ctagline, + &args->flags); +} + +static int gk20a_as_ioctl_map_buffer_compbits( + struct gk20a_as_share *as_share, + struct nvgpu_as_map_buffer_compbits_args *args) +{ + gk20a_dbg_fn(""); + return gk20a_vm_map_compbits(as_share->vm, + args->mapping_gva, + &args->compbits_win_gva, + &args->mapping_iova, + args->flags); +} + +int gk20a_as_dev_open(struct inode *inode, struct file *filp) +{ + struct gk20a_as_share *as_share; + struct gk20a *g; + int err; + + gk20a_dbg_fn(""); + + g = container_of(inode->i_cdev, struct gk20a, as_dev.cdev); + + err = gk20a_as_alloc_share(g, 0, 0, &as_share); + if (err) { + gk20a_dbg_fn("failed to alloc share"); + return err; + } + + filp->private_data = as_share; + return 0; +} + +int gk20a_as_dev_release(struct inode *inode, struct file *filp) +{ + struct gk20a_as_share *as_share = filp->private_data; + + gk20a_dbg_fn(""); + + if (!as_share) + return 0; + + return gk20a_as_release_share(as_share); +} + +long gk20a_as_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct gk20a_as_share *as_share = filp->private_data; + struct gk20a *g = gk20a_from_as(as_share->as); + + u8 buf[NVGPU_AS_IOCTL_MAX_ARG_SIZE]; + + if ((_IOC_TYPE(cmd) != NVGPU_AS_IOCTL_MAGIC) || + (_IOC_NR(cmd) == 0) || + (_IOC_NR(cmd) > NVGPU_AS_IOCTL_LAST) || + (_IOC_SIZE(cmd) > NVGPU_AS_IOCTL_MAX_ARG_SIZE)) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + if (_IOC_DIR(cmd) & _IOC_WRITE) { + if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + } + + err = gk20a_busy(g); + if (err) + return err; + + switch (cmd) { + case NVGPU_AS_IOCTL_BIND_CHANNEL: + trace_gk20a_as_ioctl_bind_channel(g->name); + err = gk20a_as_ioctl_bind_channel(as_share, + (struct nvgpu_as_bind_channel_args *)buf); + + break; + case NVGPU32_AS_IOCTL_ALLOC_SPACE: + { + struct nvgpu32_as_alloc_space_args *args32 = + (struct nvgpu32_as_alloc_space_args *)buf; + struct nvgpu_as_alloc_space_args args; + + args.pages = args32->pages; + args.page_size = args32->page_size; + args.flags = args32->flags; + args.o_a.offset = args32->o_a.offset; + trace_gk20a_as_ioctl_alloc_space(g->name); + err = gk20a_as_ioctl_alloc_space(as_share, &args); + args32->o_a.offset = args.o_a.offset; + break; + } + case NVGPU_AS_IOCTL_ALLOC_SPACE: + trace_gk20a_as_ioctl_alloc_space(g->name); + err = gk20a_as_ioctl_alloc_space(as_share, + (struct nvgpu_as_alloc_space_args *)buf); + break; + case NVGPU_AS_IOCTL_FREE_SPACE: + trace_gk20a_as_ioctl_free_space(g->name); + err = gk20a_as_ioctl_free_space(as_share, + (struct nvgpu_as_free_space_args *)buf); + break; + case NVGPU_AS_IOCTL_MAP_BUFFER: + trace_gk20a_as_ioctl_map_buffer(g->name); + err = gk20a_as_ioctl_map_buffer(as_share, + (struct nvgpu_as_map_buffer_args *)buf); + break; + case NVGPU_AS_IOCTL_MAP_BUFFER_EX: + trace_gk20a_as_ioctl_map_buffer(g->name); + err = gk20a_as_ioctl_map_buffer_ex(as_share, + (struct nvgpu_as_map_buffer_ex_args *)buf); + break; + case NVGPU_AS_IOCTL_UNMAP_BUFFER: + trace_gk20a_as_ioctl_unmap_buffer(g->name); + err = gk20a_as_ioctl_unmap_buffer(as_share, + (struct nvgpu_as_unmap_buffer_args *)buf); + break; + case NVGPU_AS_IOCTL_GET_VA_REGIONS: + trace_gk20a_as_ioctl_get_va_regions(g->name); + err = gk20a_as_ioctl_get_va_regions(as_share, + (struct nvgpu_as_get_va_regions_args *)buf); + break; + case NVGPU_AS_IOCTL_GET_BUFFER_COMPBITS_INFO: + err = gk20a_as_ioctl_get_buffer_compbits_info(as_share, + (struct nvgpu_as_get_buffer_compbits_info_args *)buf); + break; + case NVGPU_AS_IOCTL_MAP_BUFFER_COMPBITS: + err = gk20a_as_ioctl_map_buffer_compbits(as_share, + (struct nvgpu_as_map_buffer_compbits_args *)buf); + break; + case NVGPU_AS_IOCTL_MAP_BUFFER_BATCH: + err = gk20a_as_ioctl_map_buffer_batch(as_share, + (struct nvgpu_as_map_buffer_batch_args *)buf); + break; + default: + dev_dbg(dev_from_gk20a(g), "unrecognized as ioctl: 0x%x", cmd); + err = -ENOTTY; + break; + } + + gk20a_idle(g); + + if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ)) + if (copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd))) + err = -EFAULT; + + return err; +} diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_as.h b/drivers/gpu/nvgpu/common/linux/ioctl_as.h new file mode 100644 index 00000000..ae6690a1 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/ioctl_as.h @@ -0,0 +1,26 @@ +/* + * GK20A Address Spaces + * + * Copyright (c) 2011-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. + */ +#ifndef __NVGPU_COMMON_LINUX_AS_H__ +#define __NVGPU_COMMON_LINUX_AS_H__ + +struct inode; +struct file; + +/* struct file_operations driver interface */ +int gk20a_as_dev_open(struct inode *inode, struct file *filp); +int gk20a_as_dev_release(struct inode *inode, struct file *filp); +long gk20a_as_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#endif diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index fa05deb9..6aa376ea 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c @@ -205,13 +205,13 @@ static int gk20a_ctrl_alloc_as( snprintf(name, sizeof(name), "nvhost-%s-fd%d", g->name, fd); - file = anon_inode_getfile(name, g->as.cdev.ops, NULL, O_RDWR); + file = anon_inode_getfile(name, g->as_dev.cdev.ops, NULL, O_RDWR); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; } - err = gk20a_as_alloc_share(&g->as, args->big_page_size, args->flags, + err = gk20a_as_alloc_share(g, args->big_page_size, args->flags, &as_share); if (err) goto clean_up_file; diff --git a/drivers/gpu/nvgpu/gk20a/as_gk20a.c b/drivers/gpu/nvgpu/gk20a/as_gk20a.c deleted file mode 100644 index 5acc626b..00000000 --- a/drivers/gpu/nvgpu/gk20a/as_gk20a.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * GK20A Address Spaces - * - * Copyright (c) 2011-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. - */ - -#include -#include -#include -#include - -#include - -#include - -#include - -#include "gk20a.h" - -/* dumb allocator... */ -static int generate_as_share_id(struct gk20a_as *as) -{ - gk20a_dbg_fn(""); - return ++as->last_share_id; -} -/* still dumb */ -static void release_as_share_id(struct gk20a_as *as, int id) -{ - gk20a_dbg_fn(""); - return; -} - -int gk20a_as_alloc_share(struct gk20a_as *as, - u32 big_page_size, u32 flags, - struct gk20a_as_share **out) -{ - struct gk20a *g = gk20a_from_as(as); - struct gk20a_as_share *as_share; - int err = 0; - - gk20a_dbg_fn(""); - g = gk20a_get(g); - if (!g) - return -ENODEV; - - *out = NULL; - as_share = nvgpu_kzalloc(g, sizeof(*as_share)); - if (!as_share) - return -ENOMEM; - - as_share->as = as; - as_share->id = generate_as_share_id(as_share->as); - - /* this will set as_share->vm. */ - err = gk20a_busy(g); - if (err) - goto failed; - err = g->ops.mm.vm_alloc_share(as_share, big_page_size, flags); - gk20a_idle(g); - - if (err) - goto failed; - - *out = as_share; - return 0; - -failed: - nvgpu_kfree(g, as_share); - return err; -} - -/* - * channels and the device nodes call this to release. - * once the ref_cnt hits zero the share is deleted. - */ -int gk20a_as_release_share(struct gk20a_as_share *as_share) -{ - struct gk20a *g = as_share->vm->mm->g; - int err; - - gk20a_dbg_fn(""); - - err = gk20a_busy(g); - - if (err) - goto release_fail; - - err = gk20a_vm_release_share(as_share); - - gk20a_idle(g); - -release_fail: - release_as_share_id(as_share->as, as_share->id); - nvgpu_kfree(g, as_share); - gk20a_put(g); - - return err; -} - -static int gk20a_as_ioctl_bind_channel( - struct gk20a_as_share *as_share, - struct nvgpu_as_bind_channel_args *args) -{ - int err = 0; - struct channel_gk20a *ch; - - gk20a_dbg_fn(""); - - ch = gk20a_get_channel_from_file(args->channel_fd); - if (!ch || gk20a_channel_as_bound(ch)) - return -EINVAL; - - /* this will set channel_gk20a->vm */ - err = ch->g->ops.mm.vm_bind_channel(as_share, ch); - if (err) - return err; - - return err; -} - -static int gk20a_as_ioctl_alloc_space( - struct gk20a_as_share *as_share, - struct nvgpu_as_alloc_space_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_alloc_space(as_share, args); -} - -static int gk20a_as_ioctl_free_space( - struct gk20a_as_share *as_share, - struct nvgpu_as_free_space_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_free_space(as_share, args); -} - -static int gk20a_as_ioctl_map_buffer_ex( - struct gk20a_as_share *as_share, - struct nvgpu_as_map_buffer_ex_args *args) -{ - gk20a_dbg_fn(""); - - return gk20a_vm_map_buffer(as_share->vm, args->dmabuf_fd, - &args->offset, args->flags, - args->kind, - args->buffer_offset, - args->mapping_size, - NULL); -} - -static int gk20a_as_ioctl_map_buffer( - struct gk20a_as_share *as_share, - struct nvgpu_as_map_buffer_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_map_buffer(as_share->vm, args->dmabuf_fd, - &args->o_a.offset, - args->flags, NV_KIND_DEFAULT, - 0, 0, NULL); - /* args->o_a.offset will be set if !err */ -} - -static int gk20a_as_ioctl_unmap_buffer( - struct gk20a_as_share *as_share, - struct nvgpu_as_unmap_buffer_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_unmap_buffer(as_share->vm, args->offset, NULL); -} - -static int gk20a_as_ioctl_map_buffer_batch( - struct gk20a_as_share *as_share, - struct nvgpu_as_map_buffer_batch_args *args) -{ - struct gk20a *g = as_share->vm->mm->g; - u32 i; - int err = 0; - - struct nvgpu_as_unmap_buffer_args __user *user_unmap_args = - (struct nvgpu_as_unmap_buffer_args __user *)(uintptr_t) - args->unmaps; - struct nvgpu_as_map_buffer_ex_args __user *user_map_args = - (struct nvgpu_as_map_buffer_ex_args __user *)(uintptr_t) - args->maps; - - struct vm_gk20a_mapping_batch batch; - - gk20a_dbg_fn(""); - - if (args->num_unmaps > g->gpu_characteristics.map_buffer_batch_limit || - args->num_maps > g->gpu_characteristics.map_buffer_batch_limit) - return -EINVAL; - - gk20a_vm_mapping_batch_start(&batch); - - for (i = 0; i < args->num_unmaps; ++i) { - struct nvgpu_as_unmap_buffer_args unmap_args; - - if (copy_from_user(&unmap_args, &user_unmap_args[i], - sizeof(unmap_args))) { - err = -EFAULT; - break; - } - - err = gk20a_vm_unmap_buffer(as_share->vm, unmap_args.offset, - &batch); - if (err) - break; - } - - if (err) { - gk20a_vm_mapping_batch_finish(as_share->vm, &batch); - - args->num_unmaps = i; - args->num_maps = 0; - return err; - } - - for (i = 0; i < args->num_maps; ++i) { - struct nvgpu_as_map_buffer_ex_args map_args; - memset(&map_args, 0, sizeof(map_args)); - - if (copy_from_user(&map_args, &user_map_args[i], - sizeof(map_args))) { - err = -EFAULT; - break; - } - - err = gk20a_vm_map_buffer( - as_share->vm, map_args.dmabuf_fd, - &map_args.offset, map_args.flags, - map_args.kind, - map_args.buffer_offset, - map_args.mapping_size, - &batch); - if (err) - break; - } - - gk20a_vm_mapping_batch_finish(as_share->vm, &batch); - - if (err) - args->num_maps = i; - /* note: args->num_unmaps will be unmodified, which is ok - * since all unmaps are done */ - - return err; -} - -static int gk20a_as_ioctl_get_va_regions( - struct gk20a_as_share *as_share, - struct nvgpu_as_get_va_regions_args *args) -{ - unsigned int i; - unsigned int write_entries; - struct nvgpu_as_va_region __user *user_region_ptr; - struct vm_gk20a *vm = as_share->vm; - unsigned int page_sizes = gmmu_page_size_kernel; - - gk20a_dbg_fn(""); - - if (!vm->big_pages) - page_sizes--; - - write_entries = args->buf_size / sizeof(struct nvgpu_as_va_region); - if (write_entries > page_sizes) - write_entries = page_sizes; - - user_region_ptr = - (struct nvgpu_as_va_region __user *)(uintptr_t)args->buf_addr; - - for (i = 0; i < write_entries; ++i) { - struct nvgpu_as_va_region region; - struct nvgpu_allocator *vma = vm->vma[i]; - - memset(®ion, 0, sizeof(struct nvgpu_as_va_region)); - - region.page_size = vm->gmmu_page_sizes[i]; - region.offset = nvgpu_alloc_base(vma); - /* No __aeabi_uldivmod() on some platforms... */ - region.pages = (nvgpu_alloc_end(vma) - - nvgpu_alloc_base(vma)) >> ilog2(region.page_size); - - if (copy_to_user(user_region_ptr + i, ®ion, sizeof(region))) - return -EFAULT; - } - - args->buf_size = - page_sizes * sizeof(struct nvgpu_as_va_region); - - return 0; -} - -static int gk20a_as_ioctl_get_buffer_compbits_info( - struct gk20a_as_share *as_share, - struct nvgpu_as_get_buffer_compbits_info_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_get_compbits_info(as_share->vm, - args->mapping_gva, - &args->compbits_win_size, - &args->compbits_win_ctagline, - &args->mapping_ctagline, - &args->flags); -} - -static int gk20a_as_ioctl_map_buffer_compbits( - struct gk20a_as_share *as_share, - struct nvgpu_as_map_buffer_compbits_args *args) -{ - gk20a_dbg_fn(""); - return gk20a_vm_map_compbits(as_share->vm, - args->mapping_gva, - &args->compbits_win_gva, - &args->mapping_iova, - args->flags); -} - -int gk20a_as_dev_open(struct inode *inode, struct file *filp) -{ - struct gk20a_as_share *as_share; - struct gk20a *g; - int err; - - gk20a_dbg_fn(""); - - g = container_of(inode->i_cdev, struct gk20a, as.cdev); - - err = gk20a_as_alloc_share(&g->as, 0, 0, &as_share); - if (err) { - gk20a_dbg_fn("failed to alloc share"); - return err; - } - - filp->private_data = as_share; - return 0; -} - -int gk20a_as_dev_release(struct inode *inode, struct file *filp) -{ - struct gk20a_as_share *as_share = filp->private_data; - - gk20a_dbg_fn(""); - - if (!as_share) - return 0; - - return gk20a_as_release_share(as_share); -} - -long gk20a_as_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int err = 0; - struct gk20a_as_share *as_share = filp->private_data; - struct gk20a *g = gk20a_from_as(as_share->as); - - u8 buf[NVGPU_AS_IOCTL_MAX_ARG_SIZE]; - - if ((_IOC_TYPE(cmd) != NVGPU_AS_IOCTL_MAGIC) || - (_IOC_NR(cmd) == 0) || - (_IOC_NR(cmd) > NVGPU_AS_IOCTL_LAST) || - (_IOC_SIZE(cmd) > NVGPU_AS_IOCTL_MAX_ARG_SIZE)) - return -EINVAL; - - memset(buf, 0, sizeof(buf)); - if (_IOC_DIR(cmd) & _IOC_WRITE) { - if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd))) - return -EFAULT; - } - - err = gk20a_busy(g); - if (err) - return err; - - switch (cmd) { - case NVGPU_AS_IOCTL_BIND_CHANNEL: - trace_gk20a_as_ioctl_bind_channel(g->name); - err = gk20a_as_ioctl_bind_channel(as_share, - (struct nvgpu_as_bind_channel_args *)buf); - - break; - case NVGPU32_AS_IOCTL_ALLOC_SPACE: - { - struct nvgpu32_as_alloc_space_args *args32 = - (struct nvgpu32_as_alloc_space_args *)buf; - struct nvgpu_as_alloc_space_args args; - - args.pages = args32->pages; - args.page_size = args32->page_size; - args.flags = args32->flags; - args.o_a.offset = args32->o_a.offset; - trace_gk20a_as_ioctl_alloc_space(g->name); - err = gk20a_as_ioctl_alloc_space(as_share, &args); - args32->o_a.offset = args.o_a.offset; - break; - } - case NVGPU_AS_IOCTL_ALLOC_SPACE: - trace_gk20a_as_ioctl_alloc_space(g->name); - err = gk20a_as_ioctl_alloc_space(as_share, - (struct nvgpu_as_alloc_space_args *)buf); - break; - case NVGPU_AS_IOCTL_FREE_SPACE: - trace_gk20a_as_ioctl_free_space(g->name); - err = gk20a_as_ioctl_free_space(as_share, - (struct nvgpu_as_free_space_args *)buf); - break; - case NVGPU_AS_IOCTL_MAP_BUFFER: - trace_gk20a_as_ioctl_map_buffer(g->name); - err = gk20a_as_ioctl_map_buffer(as_share, - (struct nvgpu_as_map_buffer_args *)buf); - break; - case NVGPU_AS_IOCTL_MAP_BUFFER_EX: - trace_gk20a_as_ioctl_map_buffer(g->name); - err = gk20a_as_ioctl_map_buffer_ex(as_share, - (struct nvgpu_as_map_buffer_ex_args *)buf); - break; - case NVGPU_AS_IOCTL_UNMAP_BUFFER: - trace_gk20a_as_ioctl_unmap_buffer(g->name); - err = gk20a_as_ioctl_unmap_buffer(as_share, - (struct nvgpu_as_unmap_buffer_args *)buf); - break; - case NVGPU_AS_IOCTL_GET_VA_REGIONS: - trace_gk20a_as_ioctl_get_va_regions(g->name); - err = gk20a_as_ioctl_get_va_regions(as_share, - (struct nvgpu_as_get_va_regions_args *)buf); - break; - case NVGPU_AS_IOCTL_GET_BUFFER_COMPBITS_INFO: - err = gk20a_as_ioctl_get_buffer_compbits_info(as_share, - (struct nvgpu_as_get_buffer_compbits_info_args *)buf); - break; - case NVGPU_AS_IOCTL_MAP_BUFFER_COMPBITS: - err = gk20a_as_ioctl_map_buffer_compbits(as_share, - (struct nvgpu_as_map_buffer_compbits_args *)buf); - break; - case NVGPU_AS_IOCTL_MAP_BUFFER_BATCH: - err = gk20a_as_ioctl_map_buffer_batch(as_share, - (struct nvgpu_as_map_buffer_batch_args *)buf); - break; - default: - dev_dbg(dev_from_gk20a(g), "unrecognized as ioctl: 0x%x", cmd); - err = -ENOTTY; - break; - } - - gk20a_idle(g); - - if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ)) - if (copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd))) - err = -EFAULT; - - return err; -} diff --git a/drivers/gpu/nvgpu/gk20a/as_gk20a.h b/drivers/gpu/nvgpu/gk20a/as_gk20a.h deleted file mode 100644 index 9b0c6e14..00000000 --- a/drivers/gpu/nvgpu/gk20a/as_gk20a.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * GK20A Address Spaces - * - * Copyright (c) 2011-2015, 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. - */ -#ifndef AS_GK20A_H -#define AS_GK20A_H - -#include -#include -#include - -struct gk20a_as; -struct gk20a_as_share; -struct vm_gk20a; - -struct gk20a_as_share { - struct gk20a_as *as; - int id; - struct vm_gk20a *vm; -}; - -struct gk20a_as { - int last_share_id; /* dummy allocator for now */ - struct cdev cdev; - struct device *node; -}; - -int gk20a_as_release_share(struct gk20a_as_share *as_share); - -/* struct file_operations driver interface */ -int gk20a_as_dev_open(struct inode *inode, struct file *filp); -int gk20a_as_dev_release(struct inode *inode, struct file *filp); -long gk20a_as_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); - -/* if big_page_size == 0, the default big page size is used */ -int gk20a_as_alloc_share(struct gk20a_as *as, u32 big_page_size, - u32 flags, struct gk20a_as_share **out); - -#endif diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 451e32ca..1158add1 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -37,13 +37,14 @@ struct dbg_profiler_object_data; #include #include #include +#include #include "../../../arch/arm/mach-tegra/iomap.h" #include #include +#include -#include "as_gk20a.h" #include "clk_gk20a.h" #include "ce2_gk20a.h" #include "fifo_gk20a.h" @@ -1041,6 +1042,11 @@ struct gk20a { struct device *node; } ctrl; + struct { + struct cdev cdev; + struct device *node; + } as_dev; + struct { struct cdev cdev; struct device *node; diff --git a/drivers/gpu/nvgpu/include/nvgpu/as.h b/drivers/gpu/nvgpu/include/nvgpu/as.h new file mode 100644 index 00000000..0e784396 --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/as.h @@ -0,0 +1,36 @@ +/* + * GK20A Address Spaces + * + * Copyright (c) 2011-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. + */ +#ifndef __NVGPU_AS_H__ +#define __NVGPU_AS_H__ + +struct vm_gk20a; + +struct gk20a_as_share { + struct gk20a_as *as; + int id; + struct vm_gk20a *vm; +}; + +struct gk20a_as { + int last_share_id; /* dummy allocator for now */ +}; + +int gk20a_as_release_share(struct gk20a_as_share *as_share); + +/* if big_page_size == 0, the default big page size is used */ +int gk20a_as_alloc_share(struct gk20a *g, u32 big_page_size, + u32 flags, struct gk20a_as_share **out); + +#endif -- cgit v1.2.2