From 875d12c7a06bc6906bb072feb15227addec22276 Mon Sep 17 00:00:00 2001 From: Kerwin Wan Date: Fri, 11 Apr 2014 11:24:10 +0800 Subject: gpu: nvgpu: gk20a: check the return value of gk20a_channel_busy gk20a_channel_busy is called to host gpu so that gk20a can be accessed. But it may return error like if gpu fails to be powered on. Always check the return value of gk20a_channel_busy to avoid illegal access to gk20a. Bug 1488409 Change-Id: Ie22da9e436ee5ea711003530419f546a73791b73 Signed-off-by: Kerwin Wan Reviewed-on: http://git-master/r/395180 Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 80 ++++++++++++++++++++++++++++----- drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 4 +- drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | 6 ++- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 1cc0f154..90b7489c 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -697,10 +697,16 @@ int gk20a_channel_release(struct inode *inode, struct file *filp) { struct channel_gk20a *ch = (struct channel_gk20a *)filp->private_data; struct gk20a *g = ch->g; + int err; trace_gk20a_channel_release(dev_name(&g->dev->dev)); - gk20a_channel_busy(ch->g->dev); + err = gk20a_channel_busy(ch->g->dev); + if (err) { + gk20a_err(dev_from_gk20a(g), "failed to release channel %d", + ch->hw_chid); + return err; + } gk20a_free_channel(ch, true); gk20a_channel_idle(ch->g->dev); @@ -1422,7 +1428,7 @@ static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, { struct gk20a *g = c->g; struct device *d = dev_from_gk20a(g); - u32 err = 0; + int err = 0; int i; struct priv_cmd_entry *wait_cmd = NULL; struct priv_cmd_entry *incr_cmd = NULL; @@ -1453,7 +1459,11 @@ static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, gk20a_dbg_info("channel %d", c->hw_chid); /* gk20a_channel_update releases this ref. */ - gk20a_channel_busy(g->dev); + err = gk20a_channel_busy(g->dev); + if (err) { + gk20a_err(d, "failed to host gk20a to submit gpfifo"); + return err; + } trace_gk20a_channel_submit_gpfifo(c->g->dev->name, c->hw_chid, @@ -2031,19 +2041,37 @@ long gk20a_channel_ioctl(struct file *filp, case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD: break; case NVHOST_IOCTL_CHANNEL_ALLOC_OBJ_CTX: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_alloc_obj_ctx(ch, (struct nvhost_alloc_obj_ctx_args *)buf); gk20a_channel_idle(dev); break; case NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_free_obj_ctx(ch, (struct nvhost_free_obj_ctx_args *)buf); gk20a_channel_idle(dev); break; case NVHOST_IOCTL_CHANNEL_ALLOC_GPFIFO: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_alloc_channel_gpfifo(ch, (struct nvhost_alloc_gpfifo_args *)buf); gk20a_channel_idle(dev); @@ -2053,26 +2081,50 @@ long gk20a_channel_ioctl(struct file *filp, (struct nvhost_submit_gpfifo_args *)buf); break; case NVHOST_IOCTL_CHANNEL_WAIT: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_channel_wait(ch, (struct nvhost_wait_args *)buf); gk20a_channel_idle(dev); break; case NVHOST_IOCTL_CHANNEL_ZCULL_BIND: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_channel_zcull_bind(ch, (struct nvhost_zcull_bind_args *)buf); gk20a_channel_idle(dev); break; case NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_init_error_notifier(ch, (struct nvhost_set_error_notifier *)buf); gk20a_channel_idle(dev); break; #ifdef CONFIG_GK20A_CYCLE_STATS case NVHOST_IOCTL_CHANNEL_CYCLE_STATS: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } err = gk20a_channel_cycle_stats(ch, (struct nvhost_cycle_stats_args *)buf); gk20a_channel_idle(dev); @@ -2105,7 +2157,13 @@ long gk20a_channel_ioctl(struct file *filp, ch->has_timedout; break; case NVHOST_IOCTL_CHANNEL_SET_PRIORITY: - gk20a_channel_busy(dev); + err = gk20a_channel_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } gk20a_channel_set_priority(ch, ((struct nvhost_set_priority_args *)buf)->priority); gk20a_channel_idle(dev); diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c index da7d733e..bc5dc4c1 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c @@ -555,7 +555,9 @@ static int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "module busy"); gk20a_busy(g->dev); - gk20a_channel_busy(dbg_s->pdev); + err = gk20a_channel_busy(dbg_s->pdev); + if (err) + return -EPERM; g->ops.clock_gating.slcg_gr_load_gating_prod(g, false); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c index f6b43f50..14629fbe 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c @@ -268,6 +268,7 @@ static ssize_t elpg_enable_store(struct device *device, struct platform_device *ndev = to_platform_device(device); struct gk20a *g = get_gk20a(ndev); unsigned long val = 0; + int err; if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; @@ -276,7 +277,10 @@ static ssize_t elpg_enable_store(struct device *device, * Since elpg is refcounted, we should not unnecessarily call * enable/disable if it is already so. */ - gk20a_channel_busy(g->dev); + err = gk20a_channel_busy(g->dev); + if (err) + return -EAGAIN; + if (val && !g->elpg_enabled) { g->elpg_enabled = true; gk20a_pmu_enable_elpg(g); -- cgit v1.2.2