summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntti Hatala <ahatala@nvidia.com>2010-08-12 09:19:12 -0700
committerAntti Hatala <ahatala@nvidia.com>2010-08-16 02:12:41 -0700
commit522465251960937c589e79a25cdb3eb621a9280d (patch)
treefac5c081b1b08770575cf86e69b0581c408660e3
parentb16a29319c1f1d1ae54774f7f574dfc5622f6ab2 (diff)
nvhost: split hardware context state into refcounted object
Change-Id: I69bfed3522d7d2082530204d8f568458f2966638 Reviewed-on: http://git-master/r/5094 Reviewed-by: Andrew Howe <ahowe@nvidia.com> Reviewed-by: Antti Hatala <ahatala@nvidia.com> Tested-by: Antti Hatala <ahatala@nvidia.com>
-rw-r--r--drivers/video/tegra/host/nvhost_3dctx.c36
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c9
-rw-r--r--drivers/video/tegra/host/nvhost_dev.c44
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h10
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c1
5 files changed, 48 insertions, 52 deletions
diff --git a/drivers/video/tegra/host/nvhost_3dctx.c b/drivers/video/tegra/host/nvhost_3dctx.c
index c7c4c30ac9d3..57e39ce9d319 100644
--- a/drivers/video/tegra/host/nvhost_3dctx.c
+++ b/drivers/video/tegra/host/nvhost_3dctx.c
@@ -399,15 +399,21 @@ static void __init setup_save(
/*** ctx3d ***/
-static int ctx3d_init(struct nvhost_hwctx *ctx)
+static struct nvhost_hwctx *ctx3d_alloc(struct nvhost_channel *ch)
{
+ struct nvhost_hwctx *ctx;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
ctx->restore = nvmap_alloc(context_restore_size * 4, 32,
NVMEM_HANDLE_WRITE_COMBINE,
(void**)&ctx->save_cpu_data);
- if (IS_ERR_OR_NULL(ctx->restore))
- return PTR_ERR(ctx->restore);
-
+ if (IS_ERR_OR_NULL(ctx->restore)) {
+ kfree(ctx);
+ return NULL;
+ }
setup_restore(ctx->save_cpu_data, NVWAITBASE_3D);
+ ctx->channel = ch;
ctx->restore_phys = nvmap_pin_single(ctx->restore);
ctx->restore_size = context_restore_size;
ctx->save = context_save_buf;
@@ -416,12 +422,25 @@ static int ctx3d_init(struct nvhost_hwctx *ctx)
ctx->save_incrs = 3;
ctx->restore_incrs = 1;
ctx->valid = false;
- return 0;
+ kref_init(&ctx->ref);
+ return ctx;
}
-static void ctx3d_deinit(struct nvhost_hwctx *ctx)
+static void ctx3d_free(struct kref *ref)
{
+ struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
nvmap_free(ctx->restore, ctx->save_cpu_data);
+ kfree(ctx);
+}
+
+static void ctx3d_get(struct nvhost_hwctx *ctx)
+{
+ kref_get(&ctx->ref);
+}
+
+static void ctx3d_put(struct nvhost_hwctx *ctx)
+{
+ kref_put(&ctx->ref, ctx3d_free);
}
static void ctx3d_save_service(struct nvhost_hwctx *ctx)
@@ -477,8 +496,9 @@ int __init nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
context_save_phys = nvmap_pin_single(context_save_buf);
setup_save(context_save_ptr, NULL, NULL, NVSYNCPT_3D, NVWAITBASE_3D);
- h->init = ctx3d_init;
- h->deinit = ctx3d_deinit;
+ h->alloc = ctx3d_alloc;
+ h->get = ctx3d_get;
+ h->put = ctx3d_put;
h->save_service = ctx3d_save_service;
return 0;
}
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index 7215e597699b..f75ee292b57a 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -74,8 +74,8 @@ static const struct nvhost_channeldesc channelmap[] = {
/* channel 4 */
.name = "vi",
.syncpts = BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
- BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
- BIT(NVSYNCPT_VI_ISP_4) | BIT(NVSYNCPT_VI_ISP_5),
+ BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
+ BIT(NVSYNCPT_VI_ISP_4) | BIT(NVSYNCPT_VI_ISP_5),
.modulemutexes = BIT(NVMODMUTEX_VI),
.exclusive = true,
},
@@ -228,11 +228,10 @@ static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action)
save.op2 = ch->cur_ctx->save_phys;
ctxsw.intr_data = ch->cur_ctx;
ctxsw.syncpt_val = syncval - 1;
- nvhost_channel_submit(ch, &save, 1, &ctxsw, 1, NULL, 0, NVSYNCPT_3D, syncval);
- ch->cur_ctx->last_access_id = NVSYNCPT_3D;
- ch->cur_ctx->last_access_value = syncval;
ch->cur_ctx->valid = true;
+ ch->ctxhandler.get(ch->cur_ctx);
ch->cur_ctx = NULL;
+ nvhost_channel_submit(ch, &save, 1, &ctxsw, 1, NULL, 0, NVSYNCPT_3D, syncval);
nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncval,
NVHOST_INTR_ACTION_WAKEUP, &wq, NULL);
wait_event(wq, nvhost_syncpt_min_cmp(&ch->dev->syncpt, NVSYNCPT_3D, syncval));
diff --git a/drivers/video/tegra/host/nvhost_dev.c b/drivers/video/tegra/host/nvhost_dev.c
index 6a5dbcec58ea..b74e140d278e 100644
--- a/drivers/video/tegra/host/nvhost_dev.c
+++ b/drivers/video/tegra/host/nvhost_dev.c
@@ -53,7 +53,6 @@ struct nvhost_channel_userctx {
int pinarray_size;
struct nvmap_pinarray_elem pinarray[NVHOST_MAX_HANDLES];
struct nvmap_handle *unpinarray[NVHOST_MAX_HANDLES];
- /* hw context (if needed) */
};
struct nvhost_ctrl_userctx {
@@ -67,13 +66,8 @@ static int nvhost_channelrelease(struct inode *inode, struct file *filp)
filp->private_data = NULL;
nvhost_putchannel(priv->ch, priv->hwctx);
- if (priv->hwctx) {
- if (priv->hwctx->valid)
- nvhost_syncpt_wait(&priv->ch->dev->syncpt,
- priv->hwctx->last_access_id,
- priv->hwctx->last_access_value);
- priv->ch->ctxhandler.deinit(priv->hwctx);
- }
+ if (priv->hwctx)
+ priv->ch->ctxhandler.put(priv->hwctx);
if (priv->gather_mem)
nvmap_free(priv->gather_mem, priv->gathers);
if (priv->nvmapctx)
@@ -86,20 +80,13 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
{
struct nvhost_channel_userctx *priv;
struct nvhost_channel *ch;
- size_t hwctx_mem = 0;
- size_t alloc_size = 0;
ch = container_of(inode->i_cdev, struct nvhost_channel, cdev);
ch = nvhost_getchannel(ch);
if (IS_ERR(ch))
return PTR_ERR(ch);
- alloc_size += sizeof(*priv);
- if (ch->ctxhandler.init) {
- hwctx_mem = alloc_size;
- alloc_size += sizeof(struct nvhost_hwctx);
- }
- priv = kzalloc(alloc_size, GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
nvhost_putchannel(ch, NULL);
return -ENOMEM;
@@ -111,13 +98,10 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
NVMEM_HANDLE_CACHEABLE, (void**)&priv->gathers);
if (IS_ERR_OR_NULL(priv->gather_mem))
goto fail;
- if (ch->ctxhandler.init) {
- priv->hwctx = (struct nvhost_hwctx *)(((u8*)priv) + hwctx_mem);
- priv->hwctx->channel = ch;
- if (ch->ctxhandler.init(priv->hwctx) < 0) {
- priv->hwctx = NULL;
+ if (ch->ctxhandler.alloc) {
+ priv->hwctx = ch->ctxhandler.alloc(ch);
+ if (!priv->hwctx)
goto fail;
- }
}
return 0;
@@ -275,7 +259,10 @@ static int nvhost_ioctl_channel_flush(
num_intrs = 1;
ctxsw.syncpt_val = hw->save_incrs - 1;
ctxsw.intr_data = hw;
+ hw->valid = true;
+ ctx->ch->ctxhandler.get(hw);
}
+ ctx->ch->cur_ctx = ctx->hwctx;
}
/* add a setclass for modules that require it */
@@ -305,19 +292,6 @@ static int nvhost_ioctl_channel_flush(
nvhost_intr_add_action(&ctx->ch->dev->intr, ctx->syncpt_id, syncval,
NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ctx->ch, NULL);
- /* update current context */
- if (ctx->ch->cur_ctx != ctx->hwctx) {
- struct nvhost_hwctx *hw = ctx->ch->cur_ctx;
- if (hw) {
- hw->last_access_id = ctx->syncpt_id;
- hw->last_access_value = syncval;
- hw->valid = true;
- }
- hw = ctx->hwctx;
- hw->last_access_id = ctx->syncpt_id;
- hw->last_access_value = syncval;
- ctx->ch->cur_ctx = hw;
- }
mutex_unlock(&ctx->ch->submitlock);
args->value = syncval;
return 0;
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index d1a8930e0ecb..86ed9f5ed3e8 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -26,13 +26,14 @@
#include <linux/string.h>
#include <linux/nvhost.h>
#include <linux/nvmap.h>
+#include <linux/kref.h>
struct nvhost_channel;
struct nvhost_hwctx {
+ struct kref ref;
+
struct nvhost_channel *channel;
- u32 last_access_id;
- u32 last_access_value;
bool valid;
struct nvmap_handle *save;
@@ -48,8 +49,9 @@ struct nvhost_hwctx {
};
struct nvhost_hwctx_handler {
- int (*init) (struct nvhost_hwctx *ctx);
- void (*deinit) (struct nvhost_hwctx *ctx);
+ struct nvhost_hwctx * (*alloc) (struct nvhost_channel *ch);
+ void (*get) (struct nvhost_hwctx *ctx);
+ void (*put) (struct nvhost_hwctx *ctx);
void (*save_service) (struct nvhost_hwctx *ctx);
};
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 3d101b221b71..5b32b19c7a69 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -182,6 +182,7 @@ static void action_ctxsave(struct nvhost_waitlist *waiter)
struct nvhost_channel *channel = hwctx->channel;
channel->ctxhandler.save_service(hwctx);
+ channel->ctxhandler.put(hwctx);
}
static void action_wakeup(struct nvhost_waitlist *waiter)