summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2011-09-22 15:37:17 +0300
committerVarun Colbert <vcolbert@nvidia.com>2011-10-13 18:10:52 -0700
commit8f0859aa3402ff10bf1c7cb3357d1b62994ade65 (patch)
tree0d6c138ef309edf3c02ea6366e9f7325ad684603 /drivers
parent5b05562dc0ad92d44f969da2f1a87ca009a8ba49 (diff)
video: tegra: host: Check for allocation failures
Adds checks for memory allocation failures, and proper propagation of error conditions. Adds clearing of pointers after free or unpin has been called to catch use after free. Bug 877551 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/54027 Reviewed-by: Antti Miettinen <amiettinen@nvidia.com> Reviewed-by: Hiroshi Doyu <hdoyu@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Krishna Reddy <vdumpa@nvidia.com> Tested-by: Gerrit_Virtual_Submit (cherry picked from commit bfbf2766d11a5f85781532ddce3a87b7ae762ba3) Change-Id: I04171ee5db6a42bb1689221d4f80d5f3d35e7399 Reviewed-on: http://git-master/r/57462
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/tegra/host/3dctx_common.c74
-rw-r--r--drivers/video/tegra/host/3dctx_common.h2
-rw-r--r--drivers/video/tegra/host/dev.c5
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c11
-rw-r--r--drivers/video/tegra/host/nvhost_acm.h2
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c7
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c16
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h7
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c11
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.c111
-rw-r--r--drivers/video/tegra/host/t30/acm_t30.c9
11 files changed, 194 insertions, 61 deletions
diff --git a/drivers/video/tegra/host/3dctx_common.c b/drivers/video/tegra/host/3dctx_common.c
index 05b4c1653b49..a194340dc88d 100644
--- a/drivers/video/tegra/host/3dctx_common.c
+++ b/drivers/video/tegra/host/3dctx_common.c
@@ -84,21 +84,15 @@ struct nvhost_hwctx *nvhost_3dctx_alloc_common(struct nvhost_channel *ch,
ctx->restore = nvmap_alloc(nvmap, nvhost_3dctx_restore_size * 4, 32,
map_restore ? NVMAP_HANDLE_WRITE_COMBINE
: NVMAP_HANDLE_UNCACHEABLE);
- if (IS_ERR_OR_NULL(ctx->restore)) {
- kfree(ctx);
- return NULL;
- }
+ if (IS_ERR_OR_NULL(ctx->restore))
+ goto fail;
if (map_restore) {
ctx->restore_virt = nvmap_mmap(ctx->restore);
- if (!ctx->restore_virt) {
- nvmap_free(nvmap, ctx->restore);
- kfree(ctx);
- return NULL;
- }
- } else {
+ if (!ctx->restore_virt)
+ goto fail;
+ } else
ctx->restore_virt = NULL;
- }
kref_init(&ctx->ref);
ctx->channel = ch;
@@ -108,9 +102,22 @@ struct nvhost_hwctx *nvhost_3dctx_alloc_common(struct nvhost_channel *ch,
ctx->save_thresh = nvhost_3dctx_save_thresh;
ctx->save_slots = nvhost_3dctx_save_slots;
ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
+ if (IS_ERR_VALUE(ctx->restore_phys))
+ goto fail;
+
ctx->restore_size = nvhost_3dctx_restore_size;
ctx->restore_incrs = nvhost_3dctx_restore_incrs;
return ctx;
+
+fail:
+ if (map_restore && ctx->restore_virt) {
+ nvmap_munmap(ctx->restore, ctx->restore_virt);
+ ctx->restore_virt = NULL;
+ }
+ nvmap_free(nvmap, ctx->restore);
+ ctx->restore = NULL;
+ kfree(ctx);
+ return NULL;
}
void nvhost_3dctx_get(struct nvhost_hwctx *ctx)
@@ -123,10 +130,14 @@ void nvhost_3dctx_free(struct kref *ref)
struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
struct nvmap_client *nvmap = ctx->channel->dev->nvmap;
- if (ctx->restore_virt)
+ if (ctx->restore_virt) {
nvmap_munmap(ctx->restore, ctx->restore_virt);
+ ctx->restore_virt = NULL;
+ }
nvmap_unpin(nvmap, ctx->restore);
+ ctx->restore_phys = 0;
nvmap_free(nvmap, ctx->restore);
+ ctx->restore = NULL;
kfree(ctx);
}
@@ -135,15 +146,23 @@ void nvhost_3dctx_put(struct nvhost_hwctx *ctx)
kref_put(&ctx->ref, nvhost_3dctx_free);
}
-void nvhost_3dctx_prepare_power_off(struct nvhost_module *mod)
+int nvhost_3dctx_prepare_power_off(struct nvhost_module *mod)
{
struct nvhost_channel *ch =
container_of(mod, struct nvhost_channel, mod);
struct nvhost_hwctx *hwctx_to_save;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
u32 syncpt_incrs, syncpt_val;
- int err;
+ int err = 0;
void *ref;
+ void *ctx_waiter = NULL, *wakeup_waiter = NULL;
+
+ ctx_waiter = nvhost_intr_alloc_waiter();
+ wakeup_waiter = nvhost_intr_alloc_waiter();
+ if (!ctx_waiter || !wakeup_waiter) {
+ err = -ENOMEM;
+ goto done;
+ }
if (mod->desc->busy)
mod->desc->busy(mod);
@@ -152,13 +171,13 @@ void nvhost_3dctx_prepare_power_off(struct nvhost_module *mod)
hwctx_to_save = ch->cur_ctx;
if (!hwctx_to_save) {
mutex_unlock(&ch->submitlock);
- return;
+ goto done;
}
err = nvhost_cdma_begin(&ch->cdma, hwctx_to_save->timeout);
if (err) {
mutex_unlock(&ch->submitlock);
- return;
+ goto done;
}
hwctx_to_save->valid = true;
@@ -173,12 +192,20 @@ void nvhost_3dctx_prepare_power_off(struct nvhost_module *mod)
nvhost_cdma_end(&ch->cdma, ch->dev->nvmap, NVSYNCPT_3D, syncpt_val,
NULL, 0, hwctx_to_save->timeout);
- nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D,
+ err = nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D,
syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh,
- NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
-
- nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val,
- NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
+ ctx_waiter,
+ NULL);
+ ctx_waiter = NULL;
+ WARN(err, "Failed to set context save interrupt");
+
+ err = nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val,
+ NVHOST_INTR_ACTION_WAKEUP, &wq,
+ wakeup_waiter,
+ &ref);
+ wakeup_waiter = NULL;
+ WARN(err, "Failed to set wakeup interrupt");
wait_event(wq,
nvhost_syncpt_min_cmp(&ch->dev->syncpt,
NVSYNCPT_3D, syncpt_val));
@@ -188,4 +215,9 @@ void nvhost_3dctx_prepare_power_off(struct nvhost_module *mod)
nvhost_cdma_update(&ch->cdma);
mutex_unlock(&ch->submitlock);
+
+done:
+ kfree(ctx_waiter);
+ kfree(wakeup_waiter);
+ return err;
}
diff --git a/drivers/video/tegra/host/3dctx_common.h b/drivers/video/tegra/host/3dctx_common.h
index 7df2af29cbe3..cece4f42a373 100644
--- a/drivers/video/tegra/host/3dctx_common.h
+++ b/drivers/video/tegra/host/3dctx_common.h
@@ -49,6 +49,6 @@ struct nvhost_hwctx *nvhost_3dctx_alloc_common(
void nvhost_3dctx_get(struct nvhost_hwctx *ctx);
void nvhost_3dctx_free(struct kref *ref);
void nvhost_3dctx_put(struct nvhost_hwctx *ctx);
-void nvhost_3dctx_prepare_power_off(struct nvhost_module *mod);
+int nvhost_3dctx_prepare_power_off(struct nvhost_module *mod);
#endif
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 020521904495..ce963c864503 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -132,6 +132,8 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
}
priv->gathers = nvmap_mmap(priv->gather_mem);
+ if (!priv->gathers)
+ goto fail;
return 0;
fail:
@@ -703,7 +705,7 @@ static void power_on_host(struct nvhost_module *mod)
nvhost_intr_start(&dev->intr, clk_get_rate(mod->clk[0]));
}
-static void power_off_host(struct nvhost_module *mod)
+static int power_off_host(struct nvhost_module *mod)
{
struct nvhost_master *dev =
container_of(mod, struct nvhost_master, mod);
@@ -713,6 +715,7 @@ static void power_off_host(struct nvhost_module *mod)
nvhost_channel_suspend(&dev->channels[i]);
nvhost_syncpt_save(&dev->syncpt);
nvhost_intr_stop(&dev->intr);
+ return 0;
}
static int __devinit nvhost_user_init(struct nvhost_master *host)
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 4af2cb2b9e5e..ed950a562be7 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -138,8 +138,15 @@ static void powerdown_handler(struct work_struct *work)
powerdown);
mutex_lock(&mod->lock);
if ((atomic_read(&mod->refcount) == 0) && mod->powered) {
- if (mod->desc->prepare_poweroff)
- mod->desc->prepare_poweroff(mod);
+ if (mod->desc->prepare_poweroff
+ && mod->desc->prepare_poweroff(mod)) {
+ /* If poweroff fails, retry */
+ mutex_unlock(&mod->lock);
+ schedule_delayed_work(&mod->powerdown,
+ msecs_to_jiffies(
+ mod->desc->powerdown_delay));
+ return;
+ }
clock_disable(mod);
powergate(mod);
mod->powered = false;
diff --git a/drivers/video/tegra/host/nvhost_acm.h b/drivers/video/tegra/host/nvhost_acm.h
index a31219eef97e..251e1bce6651 100644
--- a/drivers/video/tegra/host/nvhost_acm.h
+++ b/drivers/video/tegra/host/nvhost_acm.h
@@ -42,7 +42,7 @@ struct nvhost_moduledesc_clock {
#define NVHOST_DEFAULT_POWERDOWN_DELAY .powerdown_delay = 25
struct nvhost_moduledesc {
- void (*prepare_poweroff)(struct nvhost_module *mod);
+ int (*prepare_poweroff)(struct nvhost_module *mod);
void (*finalize_poweron)(struct nvhost_module *mod);
void (*busy)(struct nvhost_module *);
void (*idle)(struct nvhost_module *);
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index 5c04e5838d2a..769dba7c8b99 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -63,6 +63,9 @@
/* Number of words needed to store an entry containing one handle */
#define SYNC_QUEUE_MIN_ENTRY (SQ_IDX_HANDLES + (sizeof(void *)/4))
+/* Magic to use to fill freed handle slots */
+#define BAD_MAGIC 0xdeadbeef
+
/**
* Reset to empty queue.
*/
@@ -412,7 +415,9 @@ static void update_cdma(struct nvhost_cdma *cdma)
/* Unpin the memory */
nvmap_unpin_handles(nvmap, handles, nr_handles);
+ memset(handles, BAD_MAGIC, nr_handles * sizeof(*handles));
nvmap_client_put(nvmap);
+ sync[SQ_IDX_NVMAP_CTX] = 0;
/* Pop push buffer slots */
if (nr_slots) {
@@ -634,7 +639,7 @@ void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
BUG_ON(!cdma_pb_op(cdma).destroy);
BUG_ON(cdma->running);
kfree(cdma->sync_queue.buffer);
- cdma->sync_queue.buffer = 0;
+ cdma->sync_queue.buffer = NULL;
cdma_pb_op(cdma).destroy(pb);
cdma_op(cdma).timeout_destroy(cdma);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 7de6b48ec53d..4b6efca72884 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -266,20 +266,20 @@ static void free_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
enum nvhost_intr_action action, void *data,
+ void *_waiter,
void **ref)
{
- struct nvhost_waitlist *waiter;
+ struct nvhost_waitlist *waiter = _waiter;
struct nvhost_intr_syncpt *syncpt;
int queue_was_empty;
int err;
+ BUG_ON(waiter == NULL);
+
BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
intr_op(intr).enable_syncpt_intr));
- /* create and initialize a new waiter */
- waiter = kmalloc(sizeof(*waiter), GFP_KERNEL);
- if (!waiter)
- return -ENOMEM;
+ /* initialize a new waiter */
INIT_LIST_HEAD(&waiter->list);
kref_init(&waiter->refcount);
if (ref)
@@ -330,6 +330,12 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
return 0;
}
+void *nvhost_intr_alloc_waiter()
+{
+ return kzalloc(sizeof(struct nvhost_waitlist),
+ GFP_KERNEL|__GFP_REPEAT);
+}
+
void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref)
{
struct nvhost_waitlist *waiter = ref;
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index eac5716e6664..95fd94c522ad 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -92,15 +92,22 @@ struct nvhost_intr {
* @thresh the threshold
* @action the action to take
* @data a pointer to extra data depending on action, see above
+ * @waiter waiter allocated with nvhost_intr_alloc_waiter - assumes ownership
* @ref must be passed if cancellation is possible, else NULL
*
* This is a non-blocking api.
*/
int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
enum nvhost_intr_action action, void *data,
+ void *waiter,
void **ref);
/**
+ * Allocate a waiter.
+ */
+void *nvhost_intr_alloc_waiter(void);
+
+/**
* Unreference an action submitted to nvhost_intr_add_action().
* You must call this if you passed non-NULL as ref.
* @ref the ref returned from nvhost_intr_add_action()
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 3d2ec61e07a0..1c63b69fb294 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -111,6 +111,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
void *ref;
+ void *waiter;
int err = 0;
if (value)
@@ -150,8 +151,16 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
}
/* schedule a wakeup when the syncpoint value is reached */
+ waiter = nvhost_intr_alloc_waiter();
+ if (!waiter) {
+ err = -ENOMEM;
+ goto done;
+ }
+
err = nvhost_intr_add_action(&(syncpt_to_dev(sp)->intr), id, thresh,
- NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq, &ref);
+ NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq,
+ waiter,
+ &ref);
if (err)
goto done;
diff --git a/drivers/video/tegra/host/t20/channel_t20.c b/drivers/video/tegra/host/t20/channel_t20.c
index f1bd3dbbb390..4026274ddc77 100644
--- a/drivers/video/tegra/host/t20/channel_t20.c
+++ b/drivers/video/tegra/host/t20/channel_t20.c
@@ -25,6 +25,7 @@
#include "../nvhost_hwctx.h"
#include <trace/events/nvhost.h>
#include <mach/powergate.h>
+#include <linux/slab.h>
#include "hardware_t20.h"
#include "syncpt_t20.h"
@@ -192,6 +193,15 @@ static int t20_channel_submit(struct nvhost_channel *channel,
bool need_restore = false;
u32 syncval;
int err;
+ void *ctxrestore_waiter = NULL;
+ void *ctxsave_waiter, *completed_waiter;
+
+ ctxsave_waiter = nvhost_intr_alloc_waiter();
+ completed_waiter = nvhost_intr_alloc_waiter();
+ if (!ctxsave_waiter || !completed_waiter) {
+ err = -ENOMEM;
+ goto done;
+ }
/* keep module powered */
nvhost_module_busy(&channel->mod);
@@ -205,7 +215,19 @@ static int t20_channel_submit(struct nvhost_channel *channel,
err = mutex_lock_interruptible(&channel->submitlock);
if (err) {
nvhost_module_idle(&channel->mod);
- return err;
+ goto done;
+ }
+
+ /* If we are going to need a restore, allocate a waiter for it */
+ if (channel->cur_ctx != hwctx && hwctx && hwctx->valid) {
+ ctxrestore_waiter = nvhost_intr_alloc_waiter();
+ if (!ctxrestore_waiter) {
+ mutex_unlock(&channel->submitlock);
+ nvhost_module_idle(&channel->mod);
+ err = -ENOMEM;
+ goto done;
+ }
+ need_restore = true;
}
/* remove stale waits */
@@ -219,7 +241,7 @@ static int t20_channel_submit(struct nvhost_channel *channel,
"nvhost_syncpt_wait_check failed: %d\n", err);
mutex_unlock(&channel->submitlock);
nvhost_module_idle(&channel->mod);
- return err;
+ goto done;
}
}
@@ -228,7 +250,7 @@ static int t20_channel_submit(struct nvhost_channel *channel,
if (err) {
mutex_unlock(&channel->submitlock);
nvhost_module_idle(&channel->mod);
- return err;
+ goto done;
}
/* context switch */
@@ -249,10 +271,8 @@ static int t20_channel_submit(struct nvhost_channel *channel,
channel->ctxhandler.get(hwctx_to_save);
}
channel->cur_ctx = hwctx;
- if (channel->cur_ctx && channel->cur_ctx->valid) {
- need_restore = true;
+ if (need_restore)
syncpt_incrs += channel->cur_ctx->restore_incrs;
- }
}
/* get absolute sync value */
@@ -331,27 +351,44 @@ static int t20_channel_submit(struct nvhost_channel *channel,
* schedule a context save interrupt (to drain the host FIFO
* if necessary, and to release the restore buffer)
*/
- if (hwctx_to_save)
- nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
+ if (hwctx_to_save) {
+ err = nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
syncval - syncpt_incrs + hwctx_to_save->save_thresh,
- NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
+ ctxsave_waiter,
+ NULL);
+ ctxsave_waiter = NULL;
+ WARN(err, "Failed to set ctx save interrupt");
+ }
- if (need_restore)
- nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
+ if (need_restore) {
+ BUG_ON(!ctxrestore_waiter);
+ err = nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
syncval - user_syncpt_incrs,
- NVHOST_INTR_ACTION_CTXRESTORE, channel->cur_ctx, NULL);
+ NVHOST_INTR_ACTION_CTXRESTORE, channel->cur_ctx,
+ ctxrestore_waiter,
+ NULL);
+ ctxrestore_waiter = NULL;
+ WARN(err, "Failed to set ctx restore interrupt");
+ }
/* schedule a submit complete interrupt */
err = nvhost_intr_add_action(&channel->dev->intr, syncpt_id, syncval,
- NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
- /* if add_action failed, the submit has been already completed */
- if (err)
- trace_nvhost_channel_submit_complete(channel->desc->name, 1);
+ NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel,
+ completed_waiter,
+ NULL);
+ completed_waiter = NULL;
+ WARN(err, "Failed to set submit complete interrupt");
mutex_unlock(&channel->submitlock);
*syncpt_value = syncval;
- return 0;
+
+done:
+ kfree(ctxrestore_waiter);
+ kfree(ctxsave_waiter);
+ kfree(completed_waiter);
+ return err;
}
static int t20_channel_read_3d_reg(
@@ -367,9 +404,18 @@ static int t20_channel_read_3d_reg(
unsigned int pending = 0;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
void *ref;
+ void *ctx_waiter, *read_waiter, *completed_waiter;
u32 syncval;
int err;
+ ctx_waiter = nvhost_intr_alloc_waiter();
+ read_waiter = nvhost_intr_alloc_waiter();
+ completed_waiter = nvhost_intr_alloc_waiter();
+ if (!ctx_waiter || !read_waiter || !completed_waiter) {
+ err = -ENOMEM;
+ goto done;
+ }
+
/* keep module powered */
nvhost_module_busy(&channel->mod);
@@ -455,14 +501,24 @@ static int t20_channel_read_3d_reg(
* schedule a context save interrupt (to drain the host FIFO
* if necessary, and to release the restore buffer)
*/
- if (hwctx_to_save)
- nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D,
+ if (hwctx_to_save) {
+ err = nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D,
syncval - syncpt_incrs + hwctx_to_save->save_incrs - 1,
- NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
+ ctx_waiter,
+ NULL);
+ ctx_waiter = NULL;
+ WARN(err, "Failed to set context save interrupt");
+ }
/* Wait for FIFO to be ready */
- nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval - 2,
- NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
+ err = nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D,
+ syncval - 2,
+ NVHOST_INTR_ACTION_WAKEUP, &wq,
+ read_waiter,
+ &ref);
+ read_waiter = NULL;
+ WARN(err, "Failed to set wakeup interrupt");
wait_event(wq,
nvhost_syncpt_min_cmp(&channel->dev->syncpt,
NVSYNCPT_3D, syncval - 2));
@@ -476,11 +532,18 @@ static int t20_channel_read_3d_reg(
nvhost_syncpt_cpu_incr(&channel->dev->syncpt, NVSYNCPT_3D);
/* Schedule a submit complete interrupt */
- nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval,
- NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
+ err = nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval,
+ NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel,
+ completed_waiter, NULL);
+ completed_waiter = NULL;
+ WARN(err, "Failed to set submit complete interrupt");
mutex_unlock(&channel->submitlock);
+done:
+ kfree(ctx_waiter);
+ kfree(read_waiter);
+ kfree(completed_waiter);
return err;
}
diff --git a/drivers/video/tegra/host/t30/acm_t30.c b/drivers/video/tegra/host/t30/acm_t30.c
index 6c058be9c734..f209e6043fb4 100644
--- a/drivers/video/tegra/host/t30/acm_t30.c
+++ b/drivers/video/tegra/host/t30/acm_t30.c
@@ -123,10 +123,11 @@ void t30_acm_remove_client(struct nvhost_module *mod, void *priv)
break;
}
}
- m->priv = NULL;
- kfree(m);
- for (i = 0; i < mod->num_clks; i++)
- t30_acm_update_rate(mod, i);
+ if (m) {
+ kfree(m);
+ for (i = 0; i < mod->num_clks; i++)
+ t30_acm_update_rate(mod, i);
+ }
mutex_unlock(&client_list_lock);
}