diff options
author | Kerwin Wan <kerwinw@nvidia.com> | 2014-04-10 23:24:10 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:09:11 -0400 |
commit | 875d12c7a06bc6906bb072feb15227addec22276 (patch) | |
tree | 0c3755b00c06d24bd0549a28f8b6bd7cda44af06 /drivers/gpu/nvgpu/gk20a | |
parent | 0389835edbb9687fdd28bc25668f7cd23974b7c3 (diff) |
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 <kerwinw@nvidia.com>
Reviewed-on: http://git-master/r/395180
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 80 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 4 | ||||
-rw-r--r-- | 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) | |||
697 | { | 697 | { |
698 | struct channel_gk20a *ch = (struct channel_gk20a *)filp->private_data; | 698 | struct channel_gk20a *ch = (struct channel_gk20a *)filp->private_data; |
699 | struct gk20a *g = ch->g; | 699 | struct gk20a *g = ch->g; |
700 | int err; | ||
700 | 701 | ||
701 | trace_gk20a_channel_release(dev_name(&g->dev->dev)); | 702 | trace_gk20a_channel_release(dev_name(&g->dev->dev)); |
702 | 703 | ||
703 | gk20a_channel_busy(ch->g->dev); | 704 | err = gk20a_channel_busy(ch->g->dev); |
705 | if (err) { | ||
706 | gk20a_err(dev_from_gk20a(g), "failed to release channel %d", | ||
707 | ch->hw_chid); | ||
708 | return err; | ||
709 | } | ||
704 | gk20a_free_channel(ch, true); | 710 | gk20a_free_channel(ch, true); |
705 | gk20a_channel_idle(ch->g->dev); | 711 | gk20a_channel_idle(ch->g->dev); |
706 | 712 | ||
@@ -1422,7 +1428,7 @@ static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | |||
1422 | { | 1428 | { |
1423 | struct gk20a *g = c->g; | 1429 | struct gk20a *g = c->g; |
1424 | struct device *d = dev_from_gk20a(g); | 1430 | struct device *d = dev_from_gk20a(g); |
1425 | u32 err = 0; | 1431 | int err = 0; |
1426 | int i; | 1432 | int i; |
1427 | struct priv_cmd_entry *wait_cmd = NULL; | 1433 | struct priv_cmd_entry *wait_cmd = NULL; |
1428 | struct priv_cmd_entry *incr_cmd = NULL; | 1434 | struct priv_cmd_entry *incr_cmd = NULL; |
@@ -1453,7 +1459,11 @@ static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | |||
1453 | gk20a_dbg_info("channel %d", c->hw_chid); | 1459 | gk20a_dbg_info("channel %d", c->hw_chid); |
1454 | 1460 | ||
1455 | /* gk20a_channel_update releases this ref. */ | 1461 | /* gk20a_channel_update releases this ref. */ |
1456 | gk20a_channel_busy(g->dev); | 1462 | err = gk20a_channel_busy(g->dev); |
1463 | if (err) { | ||
1464 | gk20a_err(d, "failed to host gk20a to submit gpfifo"); | ||
1465 | return err; | ||
1466 | } | ||
1457 | 1467 | ||
1458 | trace_gk20a_channel_submit_gpfifo(c->g->dev->name, | 1468 | trace_gk20a_channel_submit_gpfifo(c->g->dev->name, |
1459 | c->hw_chid, | 1469 | c->hw_chid, |
@@ -2031,19 +2041,37 @@ long gk20a_channel_ioctl(struct file *filp, | |||
2031 | case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD: | 2041 | case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD: |
2032 | break; | 2042 | break; |
2033 | case NVHOST_IOCTL_CHANNEL_ALLOC_OBJ_CTX: | 2043 | case NVHOST_IOCTL_CHANNEL_ALLOC_OBJ_CTX: |
2034 | gk20a_channel_busy(dev); | 2044 | err = gk20a_channel_busy(dev); |
2045 | if (err) { | ||
2046 | dev_err(&dev->dev, | ||
2047 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2048 | __func__, cmd); | ||
2049 | return err; | ||
2050 | } | ||
2035 | err = gk20a_alloc_obj_ctx(ch, | 2051 | err = gk20a_alloc_obj_ctx(ch, |
2036 | (struct nvhost_alloc_obj_ctx_args *)buf); | 2052 | (struct nvhost_alloc_obj_ctx_args *)buf); |
2037 | gk20a_channel_idle(dev); | 2053 | gk20a_channel_idle(dev); |
2038 | break; | 2054 | break; |
2039 | case NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX: | 2055 | case NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX: |
2040 | gk20a_channel_busy(dev); | 2056 | err = gk20a_channel_busy(dev); |
2057 | if (err) { | ||
2058 | dev_err(&dev->dev, | ||
2059 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2060 | __func__, cmd); | ||
2061 | return err; | ||
2062 | } | ||
2041 | err = gk20a_free_obj_ctx(ch, | 2063 | err = gk20a_free_obj_ctx(ch, |
2042 | (struct nvhost_free_obj_ctx_args *)buf); | 2064 | (struct nvhost_free_obj_ctx_args *)buf); |
2043 | gk20a_channel_idle(dev); | 2065 | gk20a_channel_idle(dev); |
2044 | break; | 2066 | break; |
2045 | case NVHOST_IOCTL_CHANNEL_ALLOC_GPFIFO: | 2067 | case NVHOST_IOCTL_CHANNEL_ALLOC_GPFIFO: |
2046 | gk20a_channel_busy(dev); | 2068 | err = gk20a_channel_busy(dev); |
2069 | if (err) { | ||
2070 | dev_err(&dev->dev, | ||
2071 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2072 | __func__, cmd); | ||
2073 | return err; | ||
2074 | } | ||
2047 | err = gk20a_alloc_channel_gpfifo(ch, | 2075 | err = gk20a_alloc_channel_gpfifo(ch, |
2048 | (struct nvhost_alloc_gpfifo_args *)buf); | 2076 | (struct nvhost_alloc_gpfifo_args *)buf); |
2049 | gk20a_channel_idle(dev); | 2077 | gk20a_channel_idle(dev); |
@@ -2053,26 +2081,50 @@ long gk20a_channel_ioctl(struct file *filp, | |||
2053 | (struct nvhost_submit_gpfifo_args *)buf); | 2081 | (struct nvhost_submit_gpfifo_args *)buf); |
2054 | break; | 2082 | break; |
2055 | case NVHOST_IOCTL_CHANNEL_WAIT: | 2083 | case NVHOST_IOCTL_CHANNEL_WAIT: |
2056 | gk20a_channel_busy(dev); | 2084 | err = gk20a_channel_busy(dev); |
2085 | if (err) { | ||
2086 | dev_err(&dev->dev, | ||
2087 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2088 | __func__, cmd); | ||
2089 | return err; | ||
2090 | } | ||
2057 | err = gk20a_channel_wait(ch, | 2091 | err = gk20a_channel_wait(ch, |
2058 | (struct nvhost_wait_args *)buf); | 2092 | (struct nvhost_wait_args *)buf); |
2059 | gk20a_channel_idle(dev); | 2093 | gk20a_channel_idle(dev); |
2060 | break; | 2094 | break; |
2061 | case NVHOST_IOCTL_CHANNEL_ZCULL_BIND: | 2095 | case NVHOST_IOCTL_CHANNEL_ZCULL_BIND: |
2062 | gk20a_channel_busy(dev); | 2096 | err = gk20a_channel_busy(dev); |
2097 | if (err) { | ||
2098 | dev_err(&dev->dev, | ||
2099 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2100 | __func__, cmd); | ||
2101 | return err; | ||
2102 | } | ||
2063 | err = gk20a_channel_zcull_bind(ch, | 2103 | err = gk20a_channel_zcull_bind(ch, |
2064 | (struct nvhost_zcull_bind_args *)buf); | 2104 | (struct nvhost_zcull_bind_args *)buf); |
2065 | gk20a_channel_idle(dev); | 2105 | gk20a_channel_idle(dev); |
2066 | break; | 2106 | break; |
2067 | case NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER: | 2107 | case NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER: |
2068 | gk20a_channel_busy(dev); | 2108 | err = gk20a_channel_busy(dev); |
2109 | if (err) { | ||
2110 | dev_err(&dev->dev, | ||
2111 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2112 | __func__, cmd); | ||
2113 | return err; | ||
2114 | } | ||
2069 | err = gk20a_init_error_notifier(ch, | 2115 | err = gk20a_init_error_notifier(ch, |
2070 | (struct nvhost_set_error_notifier *)buf); | 2116 | (struct nvhost_set_error_notifier *)buf); |
2071 | gk20a_channel_idle(dev); | 2117 | gk20a_channel_idle(dev); |
2072 | break; | 2118 | break; |
2073 | #ifdef CONFIG_GK20A_CYCLE_STATS | 2119 | #ifdef CONFIG_GK20A_CYCLE_STATS |
2074 | case NVHOST_IOCTL_CHANNEL_CYCLE_STATS: | 2120 | case NVHOST_IOCTL_CHANNEL_CYCLE_STATS: |
2075 | gk20a_channel_busy(dev); | 2121 | err = gk20a_channel_busy(dev); |
2122 | if (err) { | ||
2123 | dev_err(&dev->dev, | ||
2124 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2125 | __func__, cmd); | ||
2126 | return err; | ||
2127 | } | ||
2076 | err = gk20a_channel_cycle_stats(ch, | 2128 | err = gk20a_channel_cycle_stats(ch, |
2077 | (struct nvhost_cycle_stats_args *)buf); | 2129 | (struct nvhost_cycle_stats_args *)buf); |
2078 | gk20a_channel_idle(dev); | 2130 | gk20a_channel_idle(dev); |
@@ -2105,7 +2157,13 @@ long gk20a_channel_ioctl(struct file *filp, | |||
2105 | ch->has_timedout; | 2157 | ch->has_timedout; |
2106 | break; | 2158 | break; |
2107 | case NVHOST_IOCTL_CHANNEL_SET_PRIORITY: | 2159 | case NVHOST_IOCTL_CHANNEL_SET_PRIORITY: |
2108 | gk20a_channel_busy(dev); | 2160 | err = gk20a_channel_busy(dev); |
2161 | if (err) { | ||
2162 | dev_err(&dev->dev, | ||
2163 | "%s: failed to host gk20a for ioctl cmd: 0x%x", | ||
2164 | __func__, cmd); | ||
2165 | return err; | ||
2166 | } | ||
2109 | gk20a_channel_set_priority(ch, | 2167 | gk20a_channel_set_priority(ch, |
2110 | ((struct nvhost_set_priority_args *)buf)->priority); | 2168 | ((struct nvhost_set_priority_args *)buf)->priority); |
2111 | gk20a_channel_idle(dev); | 2169 | 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, | |||
555 | 555 | ||
556 | gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "module busy"); | 556 | gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "module busy"); |
557 | gk20a_busy(g->dev); | 557 | gk20a_busy(g->dev); |
558 | gk20a_channel_busy(dbg_s->pdev); | 558 | err = gk20a_channel_busy(dbg_s->pdev); |
559 | if (err) | ||
560 | return -EPERM; | ||
559 | 561 | ||
560 | g->ops.clock_gating.slcg_gr_load_gating_prod(g, | 562 | g->ops.clock_gating.slcg_gr_load_gating_prod(g, |
561 | false); | 563 | 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, | |||
268 | struct platform_device *ndev = to_platform_device(device); | 268 | struct platform_device *ndev = to_platform_device(device); |
269 | struct gk20a *g = get_gk20a(ndev); | 269 | struct gk20a *g = get_gk20a(ndev); |
270 | unsigned long val = 0; | 270 | unsigned long val = 0; |
271 | int err; | ||
271 | 272 | ||
272 | if (kstrtoul(buf, 10, &val) < 0) | 273 | if (kstrtoul(buf, 10, &val) < 0) |
273 | return -EINVAL; | 274 | return -EINVAL; |
@@ -276,7 +277,10 @@ static ssize_t elpg_enable_store(struct device *device, | |||
276 | * Since elpg is refcounted, we should not unnecessarily call | 277 | * Since elpg is refcounted, we should not unnecessarily call |
277 | * enable/disable if it is already so. | 278 | * enable/disable if it is already so. |
278 | */ | 279 | */ |
279 | gk20a_channel_busy(g->dev); | 280 | err = gk20a_channel_busy(g->dev); |
281 | if (err) | ||
282 | return -EAGAIN; | ||
283 | |||
280 | if (val && !g->elpg_enabled) { | 284 | if (val && !g->elpg_enabled) { |
281 | g->elpg_enabled = true; | 285 | g->elpg_enabled = true; |
282 | gk20a_pmu_enable_elpg(g); | 286 | gk20a_pmu_enable_elpg(g); |