From 8bdce5337ee5f4d1e1f6d4c7b2dc0abe4a532893 Mon Sep 17 00:00:00 2001 From: Konsta Holtta Date: Mon, 6 Nov 2017 14:25:47 +0200 Subject: gpu: nvgpu: support tuning per-ch deterministic opts Add a new ioctl NVGPU_GPU_IOCTL_SET_DETERMINISTIC_OPTS to adjust deterministic options on a per-channel basis. Currently, the only supported option is to relax the no-railgating requirement on open deterministic channels. This also disallows submits on such channels, until the railgate option is reset. Bug 200327089 Change-Id: If4f0f51fd1d40ad7407d13638150d7402479aff0 Signed-off-by: Konsta Holtta Reviewed-on: https://git-master.nvidia.com/r/1554563 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/linux/channel.c | 11 +++ drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 115 ++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) (limited to 'drivers/gpu/nvgpu/common/linux') diff --git a/drivers/gpu/nvgpu/common/linux/channel.c b/drivers/gpu/nvgpu/common/linux/channel.c index 716c5820..c295336f 100644 --- a/drivers/gpu/nvgpu/common/linux/channel.c +++ b/drivers/gpu/nvgpu/common/linux/channel.c @@ -537,6 +537,17 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, if (c->deterministic) nvgpu_rwsem_down_read(&g->deterministic_busy); + if (c->deterministic && c->deterministic_railgate_allowed) { + /* + * Nope - this channel has dropped its own power ref. As + * deterministic submits don't hold power on per each submitted + * job like normal ones do, the GPU might railgate any time now + * and thus submit is disallowed. + */ + err = -EINVAL; + goto clean_up; + } + trace_gk20a_channel_submit_gpfifo(g->name, c->chid, num_entries, diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index 73911717..08a831b9 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c @@ -161,6 +161,8 @@ static struct nvgpu_flags_mapping flags_mapping[] = { NVGPU_SUPPORT_DETERMINISTIC_SUBMIT_NO_JOBTRACKING}, {NVGPU_GPU_FLAGS_SUPPORT_DETERMINISTIC_SUBMIT_FULL, NVGPU_SUPPORT_DETERMINISTIC_SUBMIT_FULL}, + {NVGPU_GPU_FLAGS_SUPPORT_DETERMINISTIC_OPTS, + NVGPU_SUPPORT_DETERMINISTIC_OPTS}, {NVGPU_GPU_FLAGS_SUPPORT_IO_COHERENCE, NVGPU_SUPPORT_IO_COHERENCE}, {NVGPU_GPU_FLAGS_SUPPORT_RESCHEDULE_RUNLIST, @@ -1319,6 +1321,114 @@ static int nvgpu_gpu_set_therm_alert_limit(struct gk20a *g, return err; } +static int nvgpu_gpu_set_deterministic_ch_railgate(struct channel_gk20a *ch, + u32 flags) +{ + int err = 0; + bool allow; + bool disallow; + + allow = flags & + NVGPU_GPU_SET_DETERMINISTIC_OPTS_FLAGS_ALLOW_RAILGATING; + + disallow = flags & + NVGPU_GPU_SET_DETERMINISTIC_OPTS_FLAGS_DISALLOW_RAILGATING; + + /* Can't be both at the same time */ + if (allow && disallow) + return -EINVAL; + + /* Nothing to do */ + if (!allow && !disallow) + return 0; + + /* + * Moving into explicit idle or back from it? A call that doesn't + * change the status is a no-op. + */ + if (!ch->deterministic_railgate_allowed && + allow) { + gk20a_idle(ch->g); + } else if (ch->deterministic_railgate_allowed && + !allow) { + err = gk20a_busy(ch->g); + if (err) { + nvgpu_warn(ch->g, + "cannot busy to restore deterministic ch"); + return err; + } + } + ch->deterministic_railgate_allowed = allow; + + return err; +} + +static int nvgpu_gpu_set_deterministic_ch(struct channel_gk20a *ch, u32 flags) +{ + if (!ch->deterministic) + return -EINVAL; + + return nvgpu_gpu_set_deterministic_ch_railgate(ch, flags); +} + +static int nvgpu_gpu_set_deterministic_opts(struct gk20a *g, + struct nvgpu_gpu_set_deterministic_opts_args *args) +{ + int __user *user_channels; + u32 i = 0; + int err = 0; + + gk20a_dbg_fn(""); + + user_channels = (int __user *)(uintptr_t)args->channels; + + /* Upper limit; prevent holding deterministic_busy for long */ + if (args->num_channels > g->fifo.num_channels) { + err = -EINVAL; + goto out; + } + + /* Trivial sanity check first */ + if (!access_ok(VERIFY_READ, user_channels, + args->num_channels * sizeof(int))) { + err = -EFAULT; + goto out; + } + + nvgpu_rwsem_down_read(&g->deterministic_busy); + + /* note: we exit at the first failure */ + for (; i < args->num_channels; i++) { + int ch_fd = 0; + struct channel_gk20a *ch; + + if (copy_from_user(&ch_fd, &user_channels[i], sizeof(int))) { + /* User raced with above access_ok */ + err = -EFAULT; + break; + } + + ch = gk20a_get_channel_from_file(ch_fd); + if (!ch) { + err = -EINVAL; + break; + } + + err = nvgpu_gpu_set_deterministic_ch(ch, args->flags); + + gk20a_channel_put(ch); + + if (err) + break; + } + + nvgpu_rwsem_up_read(&g->deterministic_busy); + +out: + args->num_channels = i; + return err; +} + long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct gk20a_ctrl_priv *priv = filp->private_data; @@ -1633,6 +1743,11 @@ long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg (struct nvgpu_gpu_set_therm_alert_limit_args *)buf); break; + case NVGPU_GPU_IOCTL_SET_DETERMINISTIC_OPTS: + err = nvgpu_gpu_set_deterministic_opts(g, + (struct nvgpu_gpu_set_deterministic_opts_args *)buf); + break; + default: gk20a_dbg_info("unrecognized gpu ioctl cmd: 0x%x", cmd); err = -ENOTTY; -- cgit v1.2.2