diff options
author | Antti Hatala <ahatala@nvidia.com> | 2010-08-12 09:19:12 -0700 |
---|---|---|
committer | Antti Hatala <ahatala@nvidia.com> | 2010-08-16 02:12:41 -0700 |
commit | 522465251960937c589e79a25cdb3eb621a9280d (patch) | |
tree | fac5c081b1b08770575cf86e69b0581c408660e3 /drivers | |
parent | b16a29319c1f1d1ae54774f7f574dfc5622f6ab2 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/host/nvhost_3dctx.c | 36 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_channel.c | 9 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_dev.c | 44 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_hwctx.h | 10 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_intr.c | 1 |
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) |