mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-23 01:50:07 +03:00
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 <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1330805 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
a07e10f494
commit
06fe28567d
@@ -29,6 +29,7 @@ nvgpu-y := \
|
|||||||
common/linux/ioctl_ctrl.o \
|
common/linux/ioctl_ctrl.o \
|
||||||
common/linux/ioctl_as.o \
|
common/linux/ioctl_as.o \
|
||||||
common/linux/ioctl_channel.o \
|
common/linux/ioctl_channel.o \
|
||||||
|
common/linux/ioctl_tsg.o \
|
||||||
common/mm/nvgpu_allocator.o \
|
common/mm/nvgpu_allocator.o \
|
||||||
common/mm/bitmap_allocator.o \
|
common/mm/bitmap_allocator.o \
|
||||||
common/mm/buddy_allocator.o \
|
common/mm/buddy_allocator.o \
|
||||||
|
|||||||
@@ -23,10 +23,10 @@
|
|||||||
#include "gk20a/gk20a.h"
|
#include "gk20a/gk20a.h"
|
||||||
#include "gk20a/dbg_gpu_gk20a.h"
|
#include "gk20a/dbg_gpu_gk20a.h"
|
||||||
#include "gk20a/ctxsw_trace_gk20a.h"
|
#include "gk20a/ctxsw_trace_gk20a.h"
|
||||||
#include "gk20a/tsg_gk20a.h"
|
|
||||||
#include "ioctl_channel.h"
|
#include "ioctl_channel.h"
|
||||||
#include "ioctl_ctrl.h"
|
#include "ioctl_ctrl.h"
|
||||||
#include "ioctl_as.h"
|
#include "ioctl_as.h"
|
||||||
|
#include "ioctl_tsg.h"
|
||||||
|
|
||||||
#define GK20A_NUM_CDEVS 7
|
#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 = {
|
static const struct file_operations gk20a_tsg_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.release = gk20a_tsg_dev_release,
|
.release = nvgpu_ioctl_tsg_dev_release,
|
||||||
.open = gk20a_tsg_dev_open,
|
.open = nvgpu_ioctl_tsg_dev_open,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = gk20a_tsg_dev_ioctl,
|
.compat_ioctl = nvgpu_ioctl_tsg_dev_ioctl,
|
||||||
#endif
|
#endif
|
||||||
.unlocked_ioctl = gk20a_tsg_dev_ioctl,
|
.unlocked_ioctl = nvgpu_ioctl_tsg_dev_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations gk20a_ctxsw_ops = {
|
static const struct file_operations gk20a_ctxsw_ops = {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "gk20a/ctxsw_trace_gk20a.h"
|
#include "gk20a/ctxsw_trace_gk20a.h"
|
||||||
#include "gk20a/dbg_gpu_gk20a.h"
|
#include "gk20a/dbg_gpu_gk20a.h"
|
||||||
#include "gk20a/fence_gk20a.h"
|
#include "gk20a/fence_gk20a.h"
|
||||||
|
#include "ioctl_channel.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Although channels do have pointers back to the gk20a struct that they were
|
* Although channels do have pointers back to the gk20a struct that they were
|
||||||
|
|||||||
@@ -18,4 +18,7 @@ int gk20a_channel_release(struct inode *inode, struct file *filp);
|
|||||||
long gk20a_channel_ioctl(struct file *filp,
|
long gk20a_channel_ioctl(struct file *filp,
|
||||||
unsigned int cmd, unsigned long arg);
|
unsigned int cmd, unsigned long arg);
|
||||||
|
|
||||||
|
extern const struct file_operations gk20a_event_id_ops;
|
||||||
|
extern const struct file_operations gk20a_channel_ops;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <nvgpu/kmem.h>
|
#include <nvgpu/kmem.h>
|
||||||
|
|
||||||
#include "ioctl_ctrl.h"
|
#include "ioctl_ctrl.h"
|
||||||
|
#include "ioctl_tsg.h"
|
||||||
#include "gk20a/gk20a.h"
|
#include "gk20a/gk20a.h"
|
||||||
#include "gk20a/fence_gk20a.h"
|
#include "gk20a/fence_gk20a.h"
|
||||||
|
|
||||||
@@ -250,7 +251,7 @@ static int gk20a_ctrl_open_tsg(struct gk20a *g,
|
|||||||
goto clean_up;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gk20a_tsg_open(g, file);
|
err = nvgpu_ioctl_tsg_open(g, file);
|
||||||
if (err)
|
if (err)
|
||||||
goto clean_up_file;
|
goto clean_up_file;
|
||||||
|
|
||||||
|
|||||||
470
drivers/gpu/nvgpu/common/linux/ioctl_tsg.c
Normal file
470
drivers/gpu/nvgpu/common/linux/ioctl_tsg.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/nvhost.h>
|
||||||
|
#include <uapi/linux/nvgpu.h>
|
||||||
|
#include <linux/anon_inodes.h>
|
||||||
|
|
||||||
|
#include <nvgpu/kmem.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
26
drivers/gpu/nvgpu/common/linux/ioctl_tsg.h
Normal file
26
drivers/gpu/nvgpu/common/linux/ioctl_tsg.h
Normal file
@@ -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
|
||||||
@@ -37,9 +37,6 @@ struct fifo_profile_gk20a;
|
|||||||
#include "gr_gk20a.h"
|
#include "gr_gk20a.h"
|
||||||
#include "fence_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 notification {
|
||||||
struct {
|
struct {
|
||||||
u32 nanoseconds[2];
|
u32 nanoseconds[2];
|
||||||
|
|||||||
@@ -14,24 +14,10 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/cdev.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/nvhost.h>
|
|
||||||
#include <uapi/linux/nvgpu.h>
|
|
||||||
#include <linux/anon_inodes.h>
|
|
||||||
|
|
||||||
#include <nvgpu/kmem.h>
|
#include <nvgpu/kmem.h>
|
||||||
|
|
||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
|
#include "tsg_gk20a.h"
|
||||||
#include <nvgpu/hw/gk20a/hw_ccsr_gk20a.h>
|
|
||||||
|
|
||||||
struct tsg_private {
|
|
||||||
struct gk20a *g;
|
|
||||||
struct tsg_gk20a *tsg;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch)
|
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;
|
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
|
* API to mark channel as part of TSG
|
||||||
*
|
*
|
||||||
@@ -181,7 +154,7 @@ int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid)
|
|||||||
return 0;
|
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 priority)
|
||||||
{
|
{
|
||||||
u32 timeslice_us;
|
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);
|
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)
|
int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level)
|
||||||
{
|
{
|
||||||
struct gk20a *g = tsg->g;
|
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);
|
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;
|
struct tsg_gk20a *tsg = NULL;
|
||||||
unsigned int tsgid;
|
unsigned int tsgid;
|
||||||
@@ -414,33 +235,14 @@ static struct tsg_gk20a *acquire_unused_tsg(struct fifo_gk20a *f)
|
|||||||
return tsg;
|
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 tsg_gk20a *tsg;
|
||||||
struct device *dev;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
g = gk20a_get(g);
|
tsg = gk20a_tsg_acquire_unused_tsg(&g->fifo);
|
||||||
if (!g)
|
if (!tsg)
|
||||||
return -ENODEV;
|
return NULL;
|
||||||
|
|
||||||
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->g = g;
|
tsg->g = g;
|
||||||
tsg->num_active_channels = 0;
|
tsg->num_active_channels = 0;
|
||||||
@@ -455,15 +257,12 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp)
|
|||||||
tsg->runlist_id = ~0;
|
tsg->runlist_id = ~0;
|
||||||
tsg->tgid = current->tgid;
|
tsg->tgid = current->tgid;
|
||||||
|
|
||||||
priv->g = g;
|
|
||||||
priv->tsg = tsg;
|
|
||||||
filp->private_data = priv;
|
|
||||||
|
|
||||||
if (g->ops.fifo.tsg_open) {
|
if (g->ops.fifo.tsg_open) {
|
||||||
err = g->ops.fifo.tsg_open(tsg);
|
err = g->ops.fifo.tsg_open(tsg);
|
||||||
if (err) {
|
if (err) {
|
||||||
gk20a_err(dev, "tsg %d fifo open failed %d",
|
gk20a_err(dev_from_gk20a(g),
|
||||||
tsg->tsgid, err);
|
"tsg %d fifo open failed %d",
|
||||||
|
tsg->tsgid, err);
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,26 +271,11 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp)
|
|||||||
|
|
||||||
gk20a_sched_ctrl_tsg_added(g, tsg);
|
gk20a_sched_ctrl_tsg_added(g, tsg);
|
||||||
|
|
||||||
return 0;
|
return tsg;
|
||||||
|
|
||||||
clean_up:
|
clean_up:
|
||||||
kref_put(&tsg->refcount, gk20a_tsg_release);
|
kref_put(&tsg->refcount, gk20a_tsg_release);
|
||||||
free_ref:
|
return NULL;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gk20a_tsg_release(struct kref *ref)
|
void gk20a_tsg_release(struct kref *ref)
|
||||||
@@ -528,225 +312,6 @@ void gk20a_tsg_release(struct kref *ref)
|
|||||||
gk20a_put(g);
|
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)
|
void gk20a_init_tsg_ops(struct gpu_ops *gops)
|
||||||
{
|
{
|
||||||
gops->fifo.tsg_bind_channel = gk20a_tsg_bind_channel;
|
gops->fifo.tsg_bind_channel = gk20a_tsg_bind_channel;
|
||||||
|
|||||||
@@ -22,17 +22,10 @@
|
|||||||
|
|
||||||
struct channel_gk20a;
|
struct channel_gk20a;
|
||||||
struct gpu_ops;
|
struct gpu_ops;
|
||||||
struct file;
|
|
||||||
|
|
||||||
bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch);
|
bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch);
|
||||||
|
struct tsg_gk20a *gk20a_tsg_open(struct gk20a *g);
|
||||||
|
|
||||||
int gk20a_tsg_dev_release(struct inode *inode, struct file *filp);
|
|
||||||
int gk20a_tsg_dev_open(struct inode *inode, struct file *filp);
|
|
||||||
void gk20a_tsg_release(struct kref *ref);
|
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);
|
int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid);
|
||||||
void gk20a_init_tsg_ops(struct gpu_ops *gops);
|
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 event_id);
|
||||||
int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level);
|
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_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_ */
|
#endif /* __TSG_GK20A_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user