From 06fe28567d45c8fb1c2a04f0f007fa5d750b849d Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Thu, 23 Mar 2017 14:19:01 -0700 Subject: gpu: nvgpu: Move TSG IOCTL code to Linux module Move TSG IOCTL specific code to Linux module. This clears most Linux dependencies from tsg_gk20a.c. Move also remaining file_operations declarations from channel_gk20a.h to ioctl_channel.h. JIRA NVGPU-32 Change-Id: Idcc2a525ebe12b30db46c3893a2735509c41ff39 Signed-off-by: Terje Bergstrom Reviewed-on: http://git-master/r/1330805 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/Makefile.nvgpu | 1 + drivers/gpu/nvgpu/common/linux/ioctl.c | 10 +- drivers/gpu/nvgpu/common/linux/ioctl_channel.c | 1 + drivers/gpu/nvgpu/common/linux/ioctl_channel.h | 3 + drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 3 +- drivers/gpu/nvgpu/common/linux/ioctl_tsg.c | 470 +++++++++++++++++++++++++ drivers/gpu/nvgpu/common/linux/ioctl_tsg.h | 26 ++ drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 3 - drivers/gpu/nvgpu/gk20a/tsg_gk20a.c | 459 +----------------------- drivers/gpu/nvgpu/gk20a/tsg_gk20a.h | 11 +- 10 files changed, 523 insertions(+), 464 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/linux/ioctl_tsg.c create mode 100644 drivers/gpu/nvgpu/common/linux/ioctl_tsg.h (limited to 'drivers') diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu index 665076de..8a608ca4 100644 --- a/drivers/gpu/nvgpu/Makefile.nvgpu +++ b/drivers/gpu/nvgpu/Makefile.nvgpu @@ -29,6 +29,7 @@ nvgpu-y := \ common/linux/ioctl_ctrl.o \ common/linux/ioctl_as.o \ common/linux/ioctl_channel.o \ + common/linux/ioctl_tsg.o \ common/mm/nvgpu_allocator.o \ common/mm/bitmap_allocator.o \ common/mm/buddy_allocator.o \ diff --git a/drivers/gpu/nvgpu/common/linux/ioctl.c b/drivers/gpu/nvgpu/common/linux/ioctl.c index db252aeb..0e88e91e 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl.c @@ -23,10 +23,10 @@ #include "gk20a/gk20a.h" #include "gk20a/dbg_gpu_gk20a.h" #include "gk20a/ctxsw_trace_gk20a.h" -#include "gk20a/tsg_gk20a.h" #include "ioctl_channel.h" #include "ioctl_ctrl.h" #include "ioctl_as.h" +#include "ioctl_tsg.h" #define GK20A_NUM_CDEVS 7 @@ -89,12 +89,12 @@ static const struct file_operations gk20a_prof_ops = { static const struct file_operations gk20a_tsg_ops = { .owner = THIS_MODULE, - .release = gk20a_tsg_dev_release, - .open = gk20a_tsg_dev_open, + .release = nvgpu_ioctl_tsg_dev_release, + .open = nvgpu_ioctl_tsg_dev_open, #ifdef CONFIG_COMPAT - .compat_ioctl = gk20a_tsg_dev_ioctl, + .compat_ioctl = nvgpu_ioctl_tsg_dev_ioctl, #endif - .unlocked_ioctl = gk20a_tsg_dev_ioctl, + .unlocked_ioctl = nvgpu_ioctl_tsg_dev_ioctl, }; static const struct file_operations gk20a_ctxsw_ops = { diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c index 4a9531de..722dad20 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c @@ -31,6 +31,7 @@ #include "gk20a/ctxsw_trace_gk20a.h" #include "gk20a/dbg_gpu_gk20a.h" #include "gk20a/fence_gk20a.h" +#include "ioctl_channel.h" /* * Although channels do have pointers back to the gk20a struct that they were diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_channel.h b/drivers/gpu/nvgpu/common/linux/ioctl_channel.h index f57739e2..f488ceca 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_channel.h +++ b/drivers/gpu/nvgpu/common/linux/ioctl_channel.h @@ -18,4 +18,7 @@ int gk20a_channel_release(struct inode *inode, struct file *filp); long gk20a_channel_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +extern const struct file_operations gk20a_event_id_ops; +extern const struct file_operations gk20a_channel_ops; + #endif diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index 6aa376ea..cda9fb8d 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c @@ -24,6 +24,7 @@ #include #include "ioctl_ctrl.h" +#include "ioctl_tsg.h" #include "gk20a/gk20a.h" #include "gk20a/fence_gk20a.h" @@ -250,7 +251,7 @@ static int gk20a_ctrl_open_tsg(struct gk20a *g, goto clean_up; } - err = gk20a_tsg_open(g, file); + err = nvgpu_ioctl_tsg_open(g, file); if (err) goto clean_up_file; diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c new file mode 100644 index 00000000..75231c71 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2014-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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gk20a/gk20a.h" +#include "gk20a/tsg_gk20a.h" +#include "ioctl_channel.h" + +struct tsg_private { + struct gk20a *g; + struct tsg_gk20a *tsg; +}; + +static int gk20a_tsg_bind_channel_fd(struct tsg_gk20a *tsg, int ch_fd) +{ + struct channel_gk20a *ch; + int err; + + ch = gk20a_get_channel_from_file(ch_fd); + if (!ch) + return -EINVAL; + + err = ch->g->ops.fifo.tsg_bind_channel(tsg, ch); + return err; +} + +static int gk20a_tsg_get_event_data_from_id(struct tsg_gk20a *tsg, + unsigned int event_id, + struct gk20a_event_id_data **event_id_data) +{ + struct gk20a_event_id_data *local_event_id_data; + bool event_found = false; + + nvgpu_mutex_acquire(&tsg->event_id_list_lock); + list_for_each_entry(local_event_id_data, &tsg->event_id_list, + event_id_node) { + if (local_event_id_data->event_id == event_id) { + event_found = true; + break; + } + } + nvgpu_mutex_release(&tsg->event_id_list_lock); + + if (event_found) { + *event_id_data = local_event_id_data; + return 0; + } else { + return -1; + } +} + +void gk20a_tsg_event_id_post_event(struct tsg_gk20a *tsg, + int event_id) +{ + struct gk20a_event_id_data *event_id_data; + int err = 0; + + err = gk20a_tsg_get_event_data_from_id(tsg, event_id, + &event_id_data); + if (err) + return; + + nvgpu_mutex_acquire(&event_id_data->lock); + + gk20a_dbg_info( + "posting event for event_id=%d on tsg=%d\n", + event_id, tsg->tsgid); + event_id_data->event_posted = true; + + wake_up_interruptible_all(&event_id_data->event_id_wq); + + nvgpu_mutex_release(&event_id_data->lock); +} + +static int gk20a_tsg_event_id_enable(struct tsg_gk20a *tsg, + int event_id, + int *fd) +{ + int err = 0; + int local_fd; + struct file *file; + char name[64]; + struct gk20a_event_id_data *event_id_data; + struct gk20a *g; + + g = gk20a_get(tsg->g); + if (!g) + return -ENODEV; + + err = gk20a_tsg_get_event_data_from_id(tsg, + event_id, &event_id_data); + if (err == 0) { + /* We already have event enabled */ + err = -EINVAL; + goto free_ref; + } + + err = get_unused_fd_flags(O_RDWR); + if (err < 0) + goto free_ref; + local_fd = err; + + snprintf(name, sizeof(name), "nvgpu-event%d-fd%d", + event_id, local_fd); + + file = anon_inode_getfile(name, &gk20a_event_id_ops, + NULL, O_RDWR); + if (IS_ERR(file)) { + err = PTR_ERR(file); + goto clean_up; + } + + event_id_data = nvgpu_kzalloc(tsg->g, sizeof(*event_id_data)); + if (!event_id_data) { + err = -ENOMEM; + goto clean_up_file; + } + event_id_data->g = g; + event_id_data->id = tsg->tsgid; + event_id_data->is_tsg = true; + event_id_data->event_id = event_id; + + init_waitqueue_head(&event_id_data->event_id_wq); + err = nvgpu_mutex_init(&event_id_data->lock); + if (err) + goto clean_up_free; + + INIT_LIST_HEAD(&event_id_data->event_id_node); + + nvgpu_mutex_acquire(&tsg->event_id_list_lock); + list_add_tail(&event_id_data->event_id_node, &tsg->event_id_list); + nvgpu_mutex_release(&tsg->event_id_list_lock); + + fd_install(local_fd, file); + file->private_data = event_id_data; + + *fd = local_fd; + + return 0; + +clean_up_free: + kfree(event_id_data); +clean_up_file: + fput(file); +clean_up: + put_unused_fd(local_fd); +free_ref: + gk20a_put(g); + return err; +} + +static int gk20a_tsg_event_id_ctrl(struct gk20a *g, struct tsg_gk20a *tsg, + struct nvgpu_event_id_ctrl_args *args) +{ + int err = 0; + int fd = -1; + + if (args->event_id >= NVGPU_IOCTL_CHANNEL_EVENT_ID_MAX) + return -EINVAL; + + switch (args->cmd) { + case NVGPU_IOCTL_CHANNEL_EVENT_ID_CMD_ENABLE: + err = gk20a_tsg_event_id_enable(tsg, args->event_id, &fd); + if (!err) + args->event_fd = fd; + break; + + default: + gk20a_err(dev_from_gk20a(tsg->g), + "unrecognized tsg event id cmd: 0x%x", + args->cmd); + err = -EINVAL; + break; + } + + return err; +} + +int nvgpu_ioctl_tsg_open(struct gk20a *g, struct file *filp) +{ + struct tsg_private *priv; + struct tsg_gk20a *tsg; + struct device *dev; + int err; + + g = gk20a_get(g); + if (!g) + return -ENODEV; + + dev = dev_from_gk20a(g); + + gk20a_dbg(gpu_dbg_fn, "tsg: %s", dev_name(dev)); + + priv = nvgpu_kmalloc(g, sizeof(*priv)); + if (!priv) { + err = -ENOMEM; + goto free_ref; + } + + tsg = gk20a_tsg_open(g); + if (!tsg) { + nvgpu_kfree(g, priv); + err = -ENOMEM; + goto free_ref; + } + + priv->g = g; + priv->tsg = tsg; + filp->private_data = priv; + + return 0; + +free_ref: + gk20a_put(g); + return err; +} + +int nvgpu_ioctl_tsg_dev_open(struct inode *inode, struct file *filp) +{ + struct gk20a *g; + int ret; + + g = container_of(inode->i_cdev, + struct gk20a, tsg.cdev); + gk20a_dbg_fn(""); + ret = nvgpu_ioctl_tsg_open(g, filp); + gk20a_dbg_fn("done"); + return ret; +} + +int nvgpu_ioctl_tsg_dev_release(struct inode *inode, struct file *filp) +{ + struct tsg_private *priv = filp->private_data; + struct tsg_gk20a *tsg = priv->tsg; + + kref_put(&tsg->refcount, gk20a_tsg_release); + nvgpu_kfree(tsg->g, priv); + return 0; +} + +static int gk20a_tsg_ioctl_set_priority(struct gk20a *g, + struct tsg_gk20a *tsg, struct nvgpu_set_priority_args *arg) +{ + struct gk20a_sched_ctrl *sched = &g->sched_ctrl; + int err; + + nvgpu_mutex_acquire(&sched->control_lock); + if (sched->control_locked) { + err = -EPERM; + goto done; + } + + err = gk20a_busy(g); + if (err) { + gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); + goto done; + } + + err = gk20a_tsg_set_priority(g, tsg, arg->priority); + + gk20a_idle(g); +done: + nvgpu_mutex_release(&sched->control_lock); + return err; +} + +static int gk20a_tsg_ioctl_set_runlist_interleave(struct gk20a *g, + struct tsg_gk20a *tsg, struct nvgpu_runlist_interleave_args *arg) +{ + struct gk20a_sched_ctrl *sched = &g->sched_ctrl; + int err; + + gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid); + + nvgpu_mutex_acquire(&sched->control_lock); + if (sched->control_locked) { + err = -EPERM; + goto done; + } + err = gk20a_busy(g); + if (err) { + gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); + goto done; + } + + err = gk20a_tsg_set_runlist_interleave(tsg, arg->level); + + gk20a_idle(g); +done: + nvgpu_mutex_release(&sched->control_lock); + return err; +} + +static int gk20a_tsg_ioctl_set_timeslice(struct gk20a *g, + struct tsg_gk20a *tsg, struct nvgpu_timeslice_args *arg) +{ + struct gk20a_sched_ctrl *sched = &g->sched_ctrl; + int err; + + gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid); + + nvgpu_mutex_acquire(&sched->control_lock); + if (sched->control_locked) { + err = -EPERM; + goto done; + } + err = gk20a_busy(g); + if (err) { + gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); + goto done; + } + err = gk20a_tsg_set_timeslice(tsg, arg->timeslice_us); + gk20a_idle(g); +done: + nvgpu_mutex_release(&sched->control_lock); + return err; +} + + +long nvgpu_ioctl_tsg_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct tsg_private *priv = filp->private_data; + struct tsg_gk20a *tsg = priv->tsg; + struct gk20a *g = tsg->g; + u8 __maybe_unused buf[NVGPU_TSG_IOCTL_MAX_ARG_SIZE]; + int err = 0; + + gk20a_dbg(gpu_dbg_fn, ""); + + if ((_IOC_TYPE(cmd) != NVGPU_TSG_IOCTL_MAGIC) || + (_IOC_NR(cmd) == 0) || + (_IOC_NR(cmd) > NVGPU_TSG_IOCTL_LAST) || + (_IOC_SIZE(cmd) > NVGPU_TSG_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; + } + + if (!g->gr.sw_ready) { + err = gk20a_busy(g); + if (err) + return err; + + gk20a_idle(g); + } + + switch (cmd) { + case NVGPU_TSG_IOCTL_BIND_CHANNEL: + { + int ch_fd = *(int *)buf; + if (ch_fd < 0) { + err = -EINVAL; + break; + } + err = gk20a_tsg_bind_channel_fd(tsg, ch_fd); + break; + } + + case NVGPU_TSG_IOCTL_UNBIND_CHANNEL: + /* We do not support explicitly unbinding channel from TSG. + * Channel will be unbounded from TSG when it is closed. + */ + break; + + case NVGPU_IOCTL_TSG_ENABLE: + { + err = gk20a_busy(g); + if (err) { + gk20a_err(g->dev, + "failed to host gk20a for ioctl cmd: 0x%x", cmd); + return err; + } + gk20a_enable_tsg(tsg); + gk20a_idle(g); + break; + } + + case NVGPU_IOCTL_TSG_DISABLE: + { + err = gk20a_busy(g); + if (err) { + gk20a_err(g->dev, + "failed to host gk20a for ioctl cmd: 0x%x", cmd); + return err; + } + gk20a_disable_tsg(tsg); + gk20a_idle(g); + break; + } + + case NVGPU_IOCTL_TSG_PREEMPT: + { + err = gk20a_busy(g); + if (err) { + gk20a_err(g->dev, + "failed to host gk20a for ioctl cmd: 0x%x", cmd); + return err; + } + /* preempt TSG */ + err = g->ops.fifo.preempt_tsg(g, tsg->tsgid); + gk20a_idle(g); + break; + } + + case NVGPU_IOCTL_TSG_SET_PRIORITY: + { + err = gk20a_tsg_ioctl_set_priority(g, tsg, + (struct nvgpu_set_priority_args *)buf); + break; + } + + case NVGPU_IOCTL_TSG_EVENT_ID_CTRL: + { + err = gk20a_tsg_event_id_ctrl(g, tsg, + (struct nvgpu_event_id_ctrl_args *)buf); + break; + } + + case NVGPU_IOCTL_TSG_SET_RUNLIST_INTERLEAVE: + err = gk20a_tsg_ioctl_set_runlist_interleave(g, tsg, + (struct nvgpu_runlist_interleave_args *)buf); + break; + + case NVGPU_IOCTL_TSG_SET_TIMESLICE: + { + err = gk20a_tsg_ioctl_set_timeslice(g, tsg, + (struct nvgpu_timeslice_args *)buf); + break; + } + + default: + gk20a_err(dev_from_gk20a(g), + "unrecognized tsg gpu ioctl cmd: 0x%x", + cmd); + err = -ENOTTY; + break; + } + + if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ)) + err = copy_to_user((void __user *)arg, + buf, _IOC_SIZE(cmd)); + + return err; +} diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_tsg.h b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.h new file mode 100644 index 00000000..64d7a3da --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.h @@ -0,0 +1,26 @@ +/* + * 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. + */ +#ifndef NVGPU_IOCTL_TSG_H +#define NVGPU_IOCTL_TSG_H + +struct inode; +struct file; +struct gk20a; + +int nvgpu_ioctl_tsg_dev_release(struct inode *inode, struct file *filp); +int nvgpu_ioctl_tsg_dev_open(struct inode *inode, struct file *filp); +int nvgpu_ioctl_tsg_open(struct gk20a *g, struct file *filp); +long nvgpu_ioctl_tsg_dev_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); + +#endif diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index bcfdadec..d6356652 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h @@ -37,9 +37,6 @@ struct fifo_profile_gk20a; #include "gr_gk20a.h" #include "fence_gk20a.h" -extern const struct file_operations gk20a_event_id_ops; -extern const struct file_operations gk20a_channel_ops; - struct notification { struct { u32 nanoseconds[2]; diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c index cc3d94e4..70e40099 100644 --- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c @@ -14,24 +14,10 @@ * along with this program. If not, see . */ -#include -#include -#include -#include -#include -#include -#include - #include #include "gk20a.h" - -#include - -struct tsg_private { - struct gk20a *g; - struct tsg_gk20a *tsg; -}; +#include "tsg_gk20a.h" bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch) { @@ -81,19 +67,6 @@ static bool gk20a_is_channel_active(struct gk20a *g, struct channel_gk20a *ch) return false; } -static int gk20a_tsg_bind_channel_fd(struct tsg_gk20a *tsg, int ch_fd) -{ - struct channel_gk20a *ch; - int err; - - ch = gk20a_get_channel_from_file(ch_fd); - if (!ch) - return -EINVAL; - - err = ch->g->ops.fifo.tsg_bind_channel(tsg, ch); - return err; -} - /* * API to mark channel as part of TSG * @@ -181,7 +154,7 @@ int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid) return 0; } -static int gk20a_tsg_set_priority(struct gk20a *g, struct tsg_gk20a *tsg, +int gk20a_tsg_set_priority(struct gk20a *g, struct tsg_gk20a *tsg, u32 priority) { u32 timeslice_us; @@ -204,158 +177,6 @@ static int gk20a_tsg_set_priority(struct gk20a *g, struct tsg_gk20a *tsg, return gk20a_tsg_set_timeslice(tsg, timeslice_us); } -static int gk20a_tsg_get_event_data_from_id(struct tsg_gk20a *tsg, - unsigned int event_id, - struct gk20a_event_id_data **event_id_data) -{ - struct gk20a_event_id_data *local_event_id_data; - bool event_found = false; - - nvgpu_mutex_acquire(&tsg->event_id_list_lock); - list_for_each_entry(local_event_id_data, &tsg->event_id_list, - event_id_node) { - if (local_event_id_data->event_id == event_id) { - event_found = true; - break; - } - } - nvgpu_mutex_release(&tsg->event_id_list_lock); - - if (event_found) { - *event_id_data = local_event_id_data; - return 0; - } else { - return -1; - } -} - -void gk20a_tsg_event_id_post_event(struct tsg_gk20a *tsg, - int event_id) -{ - struct gk20a_event_id_data *event_id_data; - int err = 0; - - err = gk20a_tsg_get_event_data_from_id(tsg, event_id, - &event_id_data); - if (err) - return; - - nvgpu_mutex_acquire(&event_id_data->lock); - - gk20a_dbg_info( - "posting event for event_id=%d on tsg=%d\n", - event_id, tsg->tsgid); - event_id_data->event_posted = true; - - wake_up_interruptible_all(&event_id_data->event_id_wq); - - nvgpu_mutex_release(&event_id_data->lock); -} - -static int gk20a_tsg_event_id_enable(struct tsg_gk20a *tsg, - int event_id, - int *fd) -{ - int err = 0; - int local_fd; - struct file *file; - char name[64]; - struct gk20a_event_id_data *event_id_data; - struct gk20a *g; - - g = gk20a_get(tsg->g); - if (!g) - return -ENODEV; - - err = gk20a_tsg_get_event_data_from_id(tsg, - event_id, &event_id_data); - if (err == 0) { - /* We already have event enabled */ - err = -EINVAL; - goto free_ref; - } - - err = get_unused_fd_flags(O_RDWR); - if (err < 0) - goto free_ref; - local_fd = err; - - snprintf(name, sizeof(name), "nvgpu-event%d-fd%d", - event_id, local_fd); - - file = anon_inode_getfile(name, &gk20a_event_id_ops, - NULL, O_RDWR); - if (IS_ERR(file)) { - err = PTR_ERR(file); - goto clean_up; - } - - event_id_data = nvgpu_kzalloc(tsg->g, sizeof(*event_id_data)); - if (!event_id_data) { - err = -ENOMEM; - goto clean_up_file; - } - event_id_data->g = g; - event_id_data->id = tsg->tsgid; - event_id_data->is_tsg = true; - event_id_data->event_id = event_id; - - init_waitqueue_head(&event_id_data->event_id_wq); - err = nvgpu_mutex_init(&event_id_data->lock); - if (err) - goto clean_up_free; - - INIT_LIST_HEAD(&event_id_data->event_id_node); - - nvgpu_mutex_acquire(&tsg->event_id_list_lock); - list_add_tail(&event_id_data->event_id_node, &tsg->event_id_list); - nvgpu_mutex_release(&tsg->event_id_list_lock); - - fd_install(local_fd, file); - file->private_data = event_id_data; - - *fd = local_fd; - - return 0; - -clean_up_free: - kfree(event_id_data); -clean_up_file: - fput(file); -clean_up: - put_unused_fd(local_fd); -free_ref: - gk20a_put(g); - return err; -} - -static int gk20a_tsg_event_id_ctrl(struct gk20a *g, struct tsg_gk20a *tsg, - struct nvgpu_event_id_ctrl_args *args) -{ - int err = 0; - int fd = -1; - - if (args->event_id >= NVGPU_IOCTL_CHANNEL_EVENT_ID_MAX) - return -EINVAL; - - switch (args->cmd) { - case NVGPU_IOCTL_CHANNEL_EVENT_ID_CMD_ENABLE: - err = gk20a_tsg_event_id_enable(tsg, args->event_id, &fd); - if (!err) - args->event_fd = fd; - break; - - default: - gk20a_err(dev_from_gk20a(tsg->g), - "unrecognized tsg event id cmd: 0x%x", - args->cmd); - err = -EINVAL; - break; - } - - return err; -} - int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level) { struct gk20a *g = tsg->g; @@ -396,7 +217,7 @@ static void release_used_tsg(struct fifo_gk20a *f, struct tsg_gk20a *tsg) nvgpu_mutex_release(&f->tsg_inuse_mutex); } -static struct tsg_gk20a *acquire_unused_tsg(struct fifo_gk20a *f) +static struct tsg_gk20a *gk20a_tsg_acquire_unused_tsg(struct fifo_gk20a *f) { struct tsg_gk20a *tsg = NULL; unsigned int tsgid; @@ -414,33 +235,14 @@ static struct tsg_gk20a *acquire_unused_tsg(struct fifo_gk20a *f) return tsg; } -int gk20a_tsg_open(struct gk20a *g, struct file *filp) +struct tsg_gk20a *gk20a_tsg_open(struct gk20a *g) { - struct tsg_private *priv; struct tsg_gk20a *tsg; - struct device *dev; int err; - g = gk20a_get(g); - if (!g) - return -ENODEV; - - dev = dev_from_gk20a(g); - - gk20a_dbg(gpu_dbg_fn, "tsg: %s", g->name); - - priv = nvgpu_kmalloc(g, sizeof(*priv)); - if (!priv) { - err = -ENOMEM; - goto free_ref; - } - - tsg = acquire_unused_tsg(&g->fifo); - if (!tsg) { - nvgpu_kfree(g, priv); - err = -ENOMEM; - goto free_ref; - } + tsg = gk20a_tsg_acquire_unused_tsg(&g->fifo); + if (!tsg) + return NULL; tsg->g = g; tsg->num_active_channels = 0; @@ -455,15 +257,12 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp) tsg->runlist_id = ~0; tsg->tgid = current->tgid; - priv->g = g; - priv->tsg = tsg; - filp->private_data = priv; - if (g->ops.fifo.tsg_open) { err = g->ops.fifo.tsg_open(tsg); if (err) { - gk20a_err(dev, "tsg %d fifo open failed %d", - tsg->tsgid, err); + gk20a_err(dev_from_gk20a(g), + "tsg %d fifo open failed %d", + tsg->tsgid, err); goto clean_up; } } @@ -472,26 +271,11 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp) gk20a_sched_ctrl_tsg_added(g, tsg); - return 0; + return tsg; clean_up: kref_put(&tsg->refcount, gk20a_tsg_release); -free_ref: - gk20a_put(g); - return err; -} - -int gk20a_tsg_dev_open(struct inode *inode, struct file *filp) -{ - struct gk20a *g; - int ret; - - g = container_of(inode->i_cdev, - struct gk20a, tsg.cdev); - gk20a_dbg_fn(""); - ret = gk20a_tsg_open(g, filp); - gk20a_dbg_fn("done"); - return ret; + return NULL; } void gk20a_tsg_release(struct kref *ref) @@ -528,225 +312,6 @@ void gk20a_tsg_release(struct kref *ref) gk20a_put(g); } -int gk20a_tsg_dev_release(struct inode *inode, struct file *filp) -{ - struct tsg_private *priv = filp->private_data; - struct tsg_gk20a *tsg = priv->tsg; - - kref_put(&tsg->refcount, gk20a_tsg_release); - nvgpu_kfree(tsg->g, priv); - return 0; -} - -static int gk20a_tsg_ioctl_set_priority(struct gk20a *g, - struct tsg_gk20a *tsg, struct nvgpu_set_priority_args *arg) -{ - struct gk20a_sched_ctrl *sched = &g->sched_ctrl; - int err; - - nvgpu_mutex_acquire(&sched->control_lock); - if (sched->control_locked) { - err = -EPERM; - goto done; - } - - err = gk20a_busy(g); - if (err) { - gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); - goto done; - } - - err = gk20a_tsg_set_priority(g, tsg, arg->priority); - - gk20a_idle(g); -done: - nvgpu_mutex_release(&sched->control_lock); - return err; -} - -static int gk20a_tsg_ioctl_set_runlist_interleave(struct gk20a *g, - struct tsg_gk20a *tsg, struct nvgpu_runlist_interleave_args *arg) -{ - struct gk20a_sched_ctrl *sched = &g->sched_ctrl; - int err; - - gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid); - - nvgpu_mutex_acquire(&sched->control_lock); - if (sched->control_locked) { - err = -EPERM; - goto done; - } - err = gk20a_busy(g); - if (err) { - gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); - goto done; - } - - err = gk20a_tsg_set_runlist_interleave(tsg, arg->level); - - gk20a_idle(g); -done: - nvgpu_mutex_release(&sched->control_lock); - return err; -} - -static int gk20a_tsg_ioctl_set_timeslice(struct gk20a *g, - struct tsg_gk20a *tsg, struct nvgpu_timeslice_args *arg) -{ - struct gk20a_sched_ctrl *sched = &g->sched_ctrl; - int err; - - gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid); - - nvgpu_mutex_acquire(&sched->control_lock); - if (sched->control_locked) { - err = -EPERM; - goto done; - } - err = gk20a_busy(g); - if (err) { - gk20a_err(dev_from_gk20a(g), "failed to power on gpu"); - goto done; - } - err = gk20a_tsg_set_timeslice(tsg, arg->timeslice_us); - gk20a_idle(g); -done: - nvgpu_mutex_release(&sched->control_lock); - return err; -} - - -long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct tsg_private *priv = filp->private_data; - struct tsg_gk20a *tsg = priv->tsg; - struct gk20a *g = tsg->g; - u8 __maybe_unused buf[NVGPU_TSG_IOCTL_MAX_ARG_SIZE]; - int err = 0; - - gk20a_dbg(gpu_dbg_fn, ""); - - if ((_IOC_TYPE(cmd) != NVGPU_TSG_IOCTL_MAGIC) || - (_IOC_NR(cmd) == 0) || - (_IOC_NR(cmd) > NVGPU_TSG_IOCTL_LAST) || - (_IOC_SIZE(cmd) > NVGPU_TSG_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; - } - - if (!g->gr.sw_ready) { - err = gk20a_busy(g); - if (err) - return err; - - gk20a_idle(g); - } - - switch (cmd) { - case NVGPU_TSG_IOCTL_BIND_CHANNEL: - { - int ch_fd = *(int *)buf; - if (ch_fd < 0) { - err = -EINVAL; - break; - } - err = gk20a_tsg_bind_channel_fd(tsg, ch_fd); - break; - } - - case NVGPU_TSG_IOCTL_UNBIND_CHANNEL: - /* We do not support explicitly unbinding channel from TSG. - * Channel will be unbounded from TSG when it is closed. - */ - break; - - case NVGPU_IOCTL_TSG_ENABLE: - { - err = gk20a_busy(g); - if (err) { - gk20a_err(g->dev, - "failed to host gk20a for ioctl cmd: 0x%x", cmd); - return err; - } - gk20a_enable_tsg(tsg); - gk20a_idle(g); - break; - } - - case NVGPU_IOCTL_TSG_DISABLE: - { - err = gk20a_busy(g); - if (err) { - gk20a_err(g->dev, - "failed to host gk20a for ioctl cmd: 0x%x", cmd); - return err; - } - gk20a_disable_tsg(tsg); - gk20a_idle(g); - break; - } - - case NVGPU_IOCTL_TSG_PREEMPT: - { - err = gk20a_busy(g); - if (err) { - gk20a_err(g->dev, - "failed to host gk20a for ioctl cmd: 0x%x", cmd); - return err; - } - /* preempt TSG */ - err = g->ops.fifo.preempt_tsg(g, tsg->tsgid); - gk20a_idle(g); - break; - } - - case NVGPU_IOCTL_TSG_SET_PRIORITY: - { - err = gk20a_tsg_ioctl_set_priority(g, tsg, - (struct nvgpu_set_priority_args *)buf); - break; - } - - case NVGPU_IOCTL_TSG_EVENT_ID_CTRL: - { - err = gk20a_tsg_event_id_ctrl(g, tsg, - (struct nvgpu_event_id_ctrl_args *)buf); - break; - } - - case NVGPU_IOCTL_TSG_SET_RUNLIST_INTERLEAVE: - err = gk20a_tsg_ioctl_set_runlist_interleave(g, tsg, - (struct nvgpu_runlist_interleave_args *)buf); - break; - - case NVGPU_IOCTL_TSG_SET_TIMESLICE: - { - err = gk20a_tsg_ioctl_set_timeslice(g, tsg, - (struct nvgpu_timeslice_args *)buf); - break; - } - - default: - gk20a_err(dev_from_gk20a(g), - "unrecognized tsg gpu ioctl cmd: 0x%x", - cmd); - err = -ENOTTY; - break; - } - - if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ)) - err = copy_to_user((void __user *)arg, - buf, _IOC_SIZE(cmd)); - - return err; -} - void gk20a_init_tsg_ops(struct gpu_ops *gops) { gops->fifo.tsg_bind_channel = gk20a_tsg_bind_channel; diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h index b1f1640e..730a80b6 100644 --- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h @@ -22,17 +22,10 @@ struct channel_gk20a; struct gpu_ops; -struct file; bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch); - - -int gk20a_tsg_dev_release(struct inode *inode, struct file *filp); -int gk20a_tsg_dev_open(struct inode *inode, struct file *filp); +struct tsg_gk20a *gk20a_tsg_open(struct gk20a *g); void gk20a_tsg_release(struct kref *ref); -int gk20a_tsg_open(struct gk20a *g, struct file *filp); -long gk20a_tsg_dev_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid); void gk20a_init_tsg_ops(struct gpu_ops *gops); @@ -76,6 +69,8 @@ void gk20a_tsg_event_id_post_event(struct tsg_gk20a *tsg, int event_id); int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level); int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice); +int gk20a_tsg_set_priority(struct gk20a *g, struct tsg_gk20a *tsg, + u32 priority); #endif /* __TSG_GK20A_H_ */ -- cgit v1.2.2