video: tegra: host: Refactor context handling logic
Terje Bergstrom [Tue, 21 Feb 2012 08:21:18 +0000 (10:21 +0200)]
Currently nvhost hard codes usage of context handler and sync point
id. Split the context handler and context structures into generic and
host1x specific parts, and move the allocation to happen via a
function pointer in nvhost_device.

Also updates gr3d and mpe to use sync point id and waitbase from
nvhost_device.

Bug 926690

Change-Id: I7f00b450cac99f3816baa27b37ee4e4cf68cfe24
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/84901
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

19 files changed:
drivers/video/tegra/host/dev.c
drivers/video/tegra/host/gr3d/gr3d.c
drivers/video/tegra/host/gr3d/gr3d.h
drivers/video/tegra/host/gr3d/gr3d_t20.c
drivers/video/tegra/host/gr3d/gr3d_t20.h
drivers/video/tegra/host/gr3d/gr3d_t30.c
drivers/video/tegra/host/gr3d/gr3d_t30.h
drivers/video/tegra/host/host1x/host1x_cdma.c
drivers/video/tegra/host/host1x/host1x_channel.c
drivers/video/tegra/host/host1x/host1x_hwctx.h [new file with mode: 0644]
drivers/video/tegra/host/mpe/mpe.c
drivers/video/tegra/host/mpe/mpe.h
drivers/video/tegra/host/nvhost_channel.c
drivers/video/tegra/host/nvhost_channel.h
drivers/video/tegra/host/nvhost_hwctx.h
drivers/video/tegra/host/nvhost_intr.c
drivers/video/tegra/host/t20/t20.c
drivers/video/tegra/host/t30/t30.c
include/linux/nvhost.h

index 38efa09..4ab0f1e 100644 (file)
@@ -125,7 +125,7 @@ static int nvhost_channelrelease(struct inode *inode, struct file *filp)
        nvhost_putchannel(priv->ch, priv->hwctx);
 
        if (priv->hwctx)
-               priv->ch->ctxhandler.put(priv->hwctx);
+               priv->ch->ctxhandler->put(priv->hwctx);
 
        if (priv->job)
                nvhost_job_put(priv->job);
@@ -155,8 +155,8 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
        priv->ch = ch;
        nvhost_module_add_client(ch->dev, priv);
 
-       if (ch->ctxhandler.alloc) {
-               priv->hwctx = ch->ctxhandler.alloc(ch);
+       if (ch->ctxhandler && ch->ctxhandler->alloc) {
+               priv->hwctx = ch->ctxhandler->alloc(ch->ctxhandler, ch);
                if (!priv->hwctx)
                        goto fail;
        }
index c26387f..6e7f87e 100644 (file)
 #include "dev.h"
 #include "gr3d.h"
 
-unsigned int nvhost_3dctx_restore_size;
-unsigned int nvhost_3dctx_restore_incrs;
-struct nvmap_handle_ref *nvhost_3dctx_save_buf;
-unsigned int nvhost_3dctx_save_incrs;
-unsigned int nvhost_3dctx_save_thresh;
-unsigned int nvhost_3dctx_save_slots;
-
-void nvhost_3dctx_restore_begin(u32 *ptr)
+void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *p, u32 *ptr)
 {
        /* set class to host */
        ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
        /* increment sync point base */
-       ptr[1] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
-                       nvhost_3dctx_restore_incrs);
+       ptr[1] = nvhost_class_host_incr_syncpt_base(p->waitbase,
+                       p->restore_incrs);
        /* set class to 3D */
        ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
        /* program PSEQ_QUAD_ID */
@@ -63,25 +56,25 @@ void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
        ptr[1] = nvhost_opcode_nonincr(data_reg, count);
 }
 
-void nvhost_3dctx_restore_end(u32 *ptr)
+void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
 {
        /* syncpt increment to track restore gather. */
        ptr[0] = nvhost_opcode_imm_incr_syncpt(
-                       NV_SYNCPT_OP_DONE, NVSYNCPT_3D);
+                       NV_SYNCPT_OP_DONE, p->syncpt);
 }
 
 /*** ctx3d ***/
 
-struct nvhost_hwctx *nvhost_3dctx_alloc_common(struct nvhost_channel *ch,
-                                       bool map_restore)
+struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
+               struct nvhost_channel *ch, bool map_restore)
 {
        struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
-       struct nvhost_hwctx *ctx;
+       struct host1x_hwctx *ctx;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return NULL;
-       ctx->restore = nvmap_alloc(nvmap, nvhost_3dctx_restore_size * 4, 32,
+       ctx->restore = nvmap_alloc(nvmap, p->restore_size * 4, 32,
                map_restore ? NVMAP_HANDLE_WRITE_COMBINE
                            : NVMAP_HANDLE_UNCACHEABLE);
        if (IS_ERR_OR_NULL(ctx->restore))
@@ -94,19 +87,19 @@ struct nvhost_hwctx *nvhost_3dctx_alloc_common(struct nvhost_channel *ch,
        } else
                ctx->restore_virt = NULL;
 
-       kref_init(&ctx->ref);
-       ctx->channel = ch;
-       ctx->valid = false;
-       ctx->save = nvhost_3dctx_save_buf;
-       ctx->save_incrs = nvhost_3dctx_save_incrs;
-       ctx->save_thresh = nvhost_3dctx_save_thresh;
-       ctx->save_slots = nvhost_3dctx_save_slots;
+       kref_init(&ctx->hwctx.ref);
+       ctx->hwctx.h = &p->h;
+       ctx->hwctx.channel = ch;
+       ctx->hwctx.valid = false;
+       ctx->save_incrs = p->save_incrs;
+       ctx->save_thresh = p->save_thresh;
+       ctx->save_slots = p->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;
+       ctx->restore_size = p->restore_size;
+       ctx->restore_incrs = p->restore_incrs;
        return ctx;
 
 fail:
@@ -127,8 +120,10 @@ void nvhost_3dctx_get(struct nvhost_hwctx *ctx)
 
 void nvhost_3dctx_free(struct kref *ref)
 {
-       struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
-       struct nvmap_client *nvmap = nvhost_get_host(ctx->channel->dev)->nvmap;
+       struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct nvmap_client *nvmap =
+               nvhost_get_host(nctx->channel->dev)->nvmap;
 
        if (ctx->restore_virt) {
                nvmap_munmap(ctx->restore, ctx->restore_virt);
index 00c25ea..3855b23 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef __NVHOST_GR3D_GR3D_H
 #define __NVHOST_GR3D_GR3D_H
 
+#include "host1x/host1x_hwctx.h"
 #include <linux/types.h>
 
 /* Registers of 3D unit */
 #define AR3D_GSHIM_READ_SELECT 0xb01
 #define AR3D_GLOBAL_MEMORY_OUTPUT_READS 0xe40
 
-/* Internal variables used by common 3D context switch functions */
-extern unsigned int nvhost_3dctx_restore_size;
-extern unsigned int nvhost_3dctx_restore_incrs;
-extern struct nvmap_handle_ref *nvhost_3dctx_save_buf;
-extern unsigned int nvhost_3dctx_save_incrs;
-extern unsigned int nvhost_3dctx_save_thresh;
-extern unsigned int nvhost_3dctx_save_slots;
-
 struct nvhost_hwctx;
 struct nvhost_channel;
 struct kref;
 
 /* Functions used commonly by all 3D context switch modules */
-void nvhost_3dctx_restore_begin(u32 *ptr);
+void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *h, u32 *ptr);
 void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count);
 void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg,
                u32 offset,     u32 data_reg, u32 count);
-void nvhost_3dctx_restore_end(u32 *ptr);
-struct nvhost_hwctx *nvhost_3dctx_alloc_common(
+void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *h, u32 *ptr);
+struct host1x_hwctx *nvhost_3dctx_alloc_common(
+               struct host1x_hwctx_handler *p,
                struct nvhost_channel *ch, bool map_restore);
 void nvhost_3dctx_get(struct nvhost_hwctx *ctx);
 void nvhost_3dctx_free(struct kref *ref);
index b067c3e..90892aa 100644 (file)
@@ -66,9 +66,6 @@ static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
 };
 
 /* the same context save command sequence is used for all contexts. */
-static phys_addr_t save_phys;
-static unsigned int save_size;
-
 #define SAVE_BEGIN_V0_SIZE 5
 #define SAVE_DIRECT_V0_SIZE 3
 #define SAVE_INDIRECT_V0_SIZE 5
@@ -117,46 +114,48 @@ static u32 *setup_restore_regs_v0(u32 *ptr,
        return ptr;
 }
 
-static void setup_restore_v0(u32 *ptr)
+static void setup_restore_v0(struct host1x_hwctx_handler *h, u32 *ptr)
 {
-       nvhost_3dctx_restore_begin(ptr);
+       nvhost_3dctx_restore_begin(h, ptr);
        ptr += RESTORE_BEGIN_SIZE;
 
        ptr = setup_restore_regs_v0(ptr,
                        ctxsave_regs_3d_global,
                        ARRAY_SIZE(ctxsave_regs_3d_global));
 
-       nvhost_3dctx_restore_end(ptr);
+       nvhost_3dctx_restore_end(h, ptr);
 
        wmb();
 }
 
 /*** v0 saver ***/
 
-static void save_push_v0(struct nvhost_cdma *cdma,
-                       struct nvhost_hwctx *ctx)
+static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
 {
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
+
        nvhost_cdma_push_gather(cdma,
                        (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
                        (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
-                       nvhost_opcode_gather(save_size),
-                       save_phys);
+                       nvhost_opcode_gather(p->save_size),
+                       p->save_phys);
 }
 
-static void __init save_begin_v0(u32 *ptr)
+static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* 3d: when done, increment syncpt to base+1 */
        ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
        ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
-                       NVSYNCPT_3D); /*  incr 1 */
+                       h->syncpt); /*  incr 1 */
        /* host: wait for syncpt base+1 */
        ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
-       ptr[3] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                                               NVWAITBASE_3D, 1);
+       ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt,
+                                               h->waitbase, 1);
        /* host: signal context read thread to start reading */
        ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
-                       NVSYNCPT_3D); /* incr 2 */
+                       h->syncpt); /* incr 2 */
 }
 
 static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
@@ -180,16 +179,16 @@ static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
        ptr[4] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
 }
 
-static void __init save_end_v0(u32 *ptr)
+static void __init save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* Wait for context read service to finish (cpu incr 3) */
        ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
-       ptr[1] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                       NVWAITBASE_3D, nvhost_3dctx_save_incrs);
+       ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt,
+                       h->waitbase, h->save_incrs);
        /* Advance syncpoint base */
        ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
        ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
-                       nvhost_3dctx_save_incrs);
+                       h->save_incrs);
        /* set class back to the unit */
        ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
 }
@@ -281,7 +280,7 @@ static void __init setup_save_regs(struct save_info *info,
        info->restore_count = restore_count;
 }
 
-static void __init setup_save(u32 *ptr)
+static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        struct save_info info = {
                ptr,
@@ -292,7 +291,7 @@ static void __init setup_save(u32 *ptr)
        };
 
        if (info.ptr) {
-               save_begin_v0(info.ptr);
+               save_begin_v0(h, info.ptr);
                info.ptr += SAVE_BEGIN_V0_SIZE;
        }
 
@@ -302,83 +301,95 @@ static void __init setup_save(u32 *ptr)
                        ARRAY_SIZE(ctxsave_regs_3d_global));
 
        if (info.ptr) {
-               save_end_v0(info.ptr);
+               save_end_v0(h, info.ptr);
                info.ptr += SAVE_END_V0_SIZE;
        }
 
        wmb();
 
-       save_size = info.save_count + SAVE_END_V0_SIZE;
-       nvhost_3dctx_restore_size = info.restore_count + RESTORE_END_SIZE;
-       nvhost_3dctx_save_incrs = info.save_incrs;
-       nvhost_3dctx_save_thresh =
-                       nvhost_3dctx_save_incrs - SAVE_THRESH_OFFSET;
-       nvhost_3dctx_restore_incrs = info.restore_incrs;
+       h->save_size = info.save_count + SAVE_END_V0_SIZE;
+       h->restore_size = info.restore_count + RESTORE_END_SIZE;
+       h->save_incrs = info.save_incrs;
+       h->save_thresh = h->save_incrs - SAVE_THRESH_OFFSET;
+       h->restore_incrs = info.restore_incrs;
 }
 
 
 
 /*** ctx3d ***/
 
-static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_channel *ch)
+static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_hwctx_handler *h,
+               struct nvhost_channel *ch)
 {
-       struct nvhost_hwctx *ctx = nvhost_3dctx_alloc_common(ch, true);
-       if (ctx)
-               setup_restore_v0(ctx->restore_virt);
-       return ctx;
+       struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
+       struct host1x_hwctx *ctx =
+               nvhost_3dctx_alloc_common(p, ch, true);
+       if (ctx) {
+               setup_restore_v0(p, ctx->restore_virt);
+               return &ctx->hwctx;
+       } else
+               return NULL;
 }
 
-static void ctx3d_save_service(struct nvhost_hwctx *ctx)
+static void ctx3d_save_service(struct nvhost_hwctx *nctx)
 {
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+
        u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
        unsigned int pending = 0;
 
-       ptr = save_regs_v0(ptr, &pending, ctx->channel->aperture,
+       ptr = save_regs_v0(ptr, &pending, nctx->channel->aperture,
                        ctxsave_regs_3d_global,
                        ARRAY_SIZE(ctxsave_regs_3d_global));
 
        wmb();
-       nvhost_syncpt_cpu_incr(&nvhost_get_host(ctx->channel->dev)->syncpt,
-                       NVSYNCPT_3D);
+       nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
+                       host1x_hwctx_handler(ctx)->syncpt);
 }
 
-int __init nvhost_gr3d_t20_ctxhandler_init(struct nvhost_hwctx_handler *h)
+struct nvhost_hwctx_handler * __init nvhost_gr3d_t20_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch)
 {
-       struct nvhost_channel *ch;
        struct nvmap_client *nvmap;
        u32 *save_ptr;
+       struct host1x_hwctx_handler *p;
 
-       ch = container_of(h, struct nvhost_channel, ctxhandler);
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
        nvmap = nvhost_get_host(ch->dev)->nvmap;
 
-       setup_save(NULL);
+       p->syncpt = syncpt;
+       p->waitbase = waitbase;
+
+       setup_save(p, NULL);
 
-       nvhost_3dctx_save_buf = nvmap_alloc(nvmap, save_size * sizeof(u32), 32,
+       p->save_buf = nvmap_alloc(nvmap, p->save_size * sizeof(u32), 32,
                                NVMAP_HANDLE_WRITE_COMBINE);
-       if (IS_ERR(nvhost_3dctx_save_buf)) {
-               int err = PTR_ERR(nvhost_3dctx_save_buf);
-               nvhost_3dctx_save_buf = NULL;
-               return err;
+       if (IS_ERR(p->save_buf)) {
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       nvhost_3dctx_save_slots = 1;
+       p->save_slots = 1;
 
-       save_ptr = nvmap_mmap(nvhost_3dctx_save_buf);
+       save_ptr = nvmap_mmap(p->save_buf);
        if (!save_ptr) {
-               nvmap_free(nvmap, nvhost_3dctx_save_buf);
-               nvhost_3dctx_save_buf = NULL;
-               return -ENOMEM;
+               nvmap_free(nvmap, p->save_buf);
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       save_phys = nvmap_pin(nvmap, nvhost_3dctx_save_buf);
+       p->save_phys = nvmap_pin(nvmap, p->save_buf);
 
-       setup_save(save_ptr);
+       setup_save(p, save_ptr);
 
-       h->alloc = ctx3d_alloc_v0;
-       h->save_push = save_push_v0;
-       h->save_service = ctx3d_save_service;
-       h->get = nvhost_3dctx_get;
-       h->put = nvhost_3dctx_put;
+       p->h.alloc = ctx3d_alloc_v0;
+       p->h.save_push = save_push_v0;
+       p->h.save_service = ctx3d_save_service;
+       p->h.get = nvhost_3dctx_get;
+       p->h.put = nvhost_3dctx_put;
 
-       return 0;
+       return &p->h;
 }
index 6141084..5fe6d50 100644 (file)
@@ -23,6 +23,8 @@
 
 struct nvhost_hwctx_handler;
 
-int nvhost_gr3d_t20_ctxhandler_init(struct nvhost_hwctx_handler *h);
+struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch);
 
 #endif
index 05a009e..6a7c147 100644 (file)
@@ -84,10 +84,6 @@ static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
 
 static unsigned int restore_set1_offset;
 
-/* the same context save command sequence is used for all contexts. */
-static phys_addr_t save_phys;
-static unsigned int save_size;
-
 #define SAVE_BEGIN_V1_SIZE (1 + RESTORE_BEGIN_SIZE)
 #define SAVE_DIRECT_V1_SIZE (4 + RESTORE_DIRECT_SIZE)
 #define SAVE_INDIRECT_V1_SIZE (6 + RESTORE_INDIRECT_SIZE)
@@ -109,19 +105,21 @@ struct save_info {
 
 /*** v1 saver ***/
 
-static void save_push_v1(struct nvhost_cdma *cdma,
-                       struct nvhost_hwctx *ctx)
+static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
 {
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
+
        /* wait for 3d idle */
        nvhost_cdma_push(cdma,
                        nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
                        nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
-                                       NVSYNCPT_3D));
+                                       p->syncpt));
        nvhost_cdma_push(cdma,
                        nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
-                       nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                                                       NVWAITBASE_3D, 1));
+                       nvhost_class_host_wait_syncpt_base(p->syncpt,
+                                                       p->waitbase, 1));
        /* back to 3d */
        nvhost_cdma_push(cdma,
                        nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
@@ -147,15 +145,15 @@ static void save_push_v1(struct nvhost_cdma *cdma,
        nvhost_cdma_push_gather(cdma,
                        (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
                        (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
-                       nvhost_opcode_gather(save_size),
-                       save_phys);
+                       nvhost_opcode_gather(p->save_size),
+                       p->save_phys);
 }
 
-static void __init save_begin_v1(u32 *ptr)
+static void __init save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
 {
        ptr[0] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
                        RESTORE_BEGIN_SIZE);
-       nvhost_3dctx_restore_begin(ptr + 1);
+       nvhost_3dctx_restore_begin(p, ptr + 1);
        ptr += RESTORE_BEGIN_SIZE;
 }
 
@@ -190,34 +188,34 @@ static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
        ptr[5] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
 }
 
-static void __init save_end_v1(u32 *ptr)
+static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
 {
        /* write end of restore buffer */
        ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
                        AR3D_DW_MEMORY_OUTPUT_DATA, 1);
-       nvhost_3dctx_restore_end(ptr + 1);
+       nvhost_3dctx_restore_end(p, ptr + 1);
        ptr += RESTORE_END_SIZE;
        /* reset to dual reg if necessary */
        ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
                        (1 << register_sets) - 1);
        /* op_done syncpt incr to flush FDC */
-       ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, NVSYNCPT_3D);
+       ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, p->syncpt);
        /* host wait for that syncpt incr, and advance the wait base */
        ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                        NV_CLASS_HOST_WAIT_SYNCPT_BASE,
                        nvhost_mask2(
                                        NV_CLASS_HOST_WAIT_SYNCPT_BASE,
                                        NV_CLASS_HOST_INCR_SYNCPT_BASE));
-       ptr[4] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                               NVWAITBASE_3D, nvhost_3dctx_save_incrs - 1);
-       ptr[5] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
-                       nvhost_3dctx_save_incrs);
+       ptr[4] = nvhost_class_host_wait_syncpt_base(p->syncpt,
+                               p->waitbase, p->save_incrs - 1);
+       ptr[5] = nvhost_class_host_incr_syncpt_base(p->waitbase,
+                       p->save_incrs);
        /* set class back to 3d */
        ptr[6] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
        /* send reg reads back to host */
        ptr[7] = nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 0);
        /* final syncpt increment to release waiters */
-       ptr[8] = nvhost_opcode_imm(0, NVSYNCPT_3D);
+       ptr[8] = nvhost_opcode_imm(0, p->syncpt);
 }
 
 /*** save ***/
@@ -303,7 +301,7 @@ static void __init switch_gpu(struct save_info *info,
        info->restore_count += 1;
 }
 
-static void __init setup_save(u32 *ptr)
+static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
 {
        struct save_info info = {
                ptr,
@@ -317,7 +315,7 @@ static void __init setup_save(u32 *ptr)
        BUG_ON(register_sets > 2);
 
        if (info.ptr) {
-               save_begin_v1(info.ptr);
+               save_begin_v1(p, info.ptr);
                info.ptr += SAVE_BEGIN_V1_SIZE;
        }
 
@@ -355,70 +353,83 @@ static void __init setup_save(u32 *ptr)
                switch_gpu(&info, 0, 2, 3);
 
        if (info.ptr) {
-               save_end_v1(info.ptr);
+               save_end_v1(p, info.ptr);
                info.ptr += SAVE_END_V1_SIZE;
        }
 
        wmb();
 
-       save_size = info.save_count + save_end_size;
-       nvhost_3dctx_restore_size = info.restore_count + RESTORE_END_SIZE;
-       nvhost_3dctx_save_incrs = info.save_incrs;
-       nvhost_3dctx_save_thresh = nvhost_3dctx_save_incrs
-                       - SAVE_THRESH_OFFSET;
-       nvhost_3dctx_restore_incrs = info.restore_incrs;
+       p->save_size = info.save_count + save_end_size;
+       p->restore_size = info.restore_count + RESTORE_END_SIZE;
+       p->save_incrs = info.save_incrs;
+       p->save_thresh = p->save_incrs - SAVE_THRESH_OFFSET;
+       p->restore_incrs = info.restore_incrs;
 }
 
 
 /*** ctx3d ***/
 
-static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_channel *ch)
+static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_hwctx_handler *h,
+               struct nvhost_channel *ch)
 {
-       return nvhost_3dctx_alloc_common(ch, false);
+       struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
+       struct host1x_hwctx *ctx = nvhost_3dctx_alloc_common(p, ch, false);
+
+       if (ctx)
+               return &ctx->hwctx;
+       else
+               return NULL;
 }
 
-int __init nvhost_gr3d_t30_ctxhandler_init(struct nvhost_hwctx_handler *h)
+struct nvhost_hwctx_handler *__init nvhost_gr3d_t30_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch)
 {
-       struct nvhost_channel *ch;
        struct nvmap_client *nvmap;
        u32 *save_ptr;
+       struct host1x_hwctx_handler *p;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
 
-       ch = container_of(h, struct nvhost_channel, ctxhandler);
        nvmap = nvhost_get_host(ch->dev)->nvmap;
 
        register_sets = tegra_gpu_register_sets();
        BUG_ON(register_sets == 0 || register_sets > 2);
 
-       setup_save(NULL);
+       p->syncpt = syncpt;
+       p->waitbase = waitbase;
+
+       setup_save(p, NULL);
 
-       nvhost_3dctx_save_buf = nvmap_alloc(nvmap, save_size * 4, 32,
+       p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
                                NVMAP_HANDLE_WRITE_COMBINE);
-       if (IS_ERR(nvhost_3dctx_save_buf)) {
-               int err = PTR_ERR(nvhost_3dctx_save_buf);
-               nvhost_3dctx_save_buf = NULL;
-               return err;
+       if (IS_ERR(p->save_buf)) {
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       nvhost_3dctx_save_slots = 6;
+       p->save_slots = 6;
        if (register_sets == 2)
-               nvhost_3dctx_save_slots += 2;
+               p->save_slots += 2;
 
-       save_ptr = nvmap_mmap(nvhost_3dctx_save_buf);
+       save_ptr = nvmap_mmap(p->save_buf);
        if (!save_ptr) {
-               nvmap_free(nvmap, nvhost_3dctx_save_buf);
-               nvhost_3dctx_save_buf = NULL;
-               return -ENOMEM;
+               nvmap_free(nvmap, p->save_buf);
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       save_phys = nvmap_pin(nvmap, nvhost_3dctx_save_buf);
+       p->save_phys = nvmap_pin(nvmap, p->save_buf);
 
-       setup_save(save_ptr);
+       setup_save(p, save_ptr);
 
-       h->alloc = ctx3d_alloc_v1;
-       h->save_push = save_push_v1;
-       h->save_service = NULL;
-       h->get = nvhost_3dctx_get;
-       h->put = nvhost_3dctx_put;
+       p->h.alloc = ctx3d_alloc_v1;
+       p->h.save_push = save_push_v1;
+       p->h.save_service = NULL;
+       p->h.get = nvhost_3dctx_get;
+       p->h.put = nvhost_3dctx_put;
 
-       return 0;
+       return &p->h;
 }
index 409f1af..d1b787e 100644 (file)
@@ -23,6 +23,8 @@
 
 struct nvhost_hwctx_handler;
 
-int nvhost_gr3d_t30_ctxhandler_init(struct nvhost_hwctx_handler *h);
+struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch);
 
 #endif
index c670e08..0955275 100644 (file)
@@ -26,6 +26,7 @@
 #include "host1x_hardware.h"
 #include "host1x_syncpt.h"
 #include "host1x_cdma.h"
+#include "host1x_hwctx.h"
 
 static inline u32 host1x_channel_dmactrl(int stop, int get_rst, int init_get)
 {
@@ -336,7 +337,7 @@ static void cdma_timeout_pb_incr(struct nvhost_cdma *cdma, u32 getptr,
        struct nvhost_master *dev = cdma_to_dev(cdma);
        struct syncpt_buffer *sb = &cdma->syncpt_buffer;
        struct push_buffer *pb = &cdma->push_buffer;
-       struct nvhost_hwctx *hwctx = cdma->timeout.ctx;
+       struct host1x_hwctx *hwctx = to_host1x_hwctx(cdma->timeout.ctx);
        u32 getidx, *p;
 
        /* should have enough slots to incr to desired count */
index 7142cea..34ae887 100644 (file)
@@ -27,6 +27,7 @@
 #include "host1x_syncpt.h"
 #include "host1x_channel.h"
 #include "host1x_hardware.h"
+#include "host1x_hwctx.h"
 #include "nvhost_intr.h"
 
 #define NV_FIFO_READ_TIMEOUT 200000
@@ -48,7 +49,7 @@ static void sync_waitbases(struct nvhost_channel *ch, u32 syncpt_val)
 
 int host1x_channel_submit(struct nvhost_job *job)
 {
-       struct nvhost_hwctx *hwctx_to_save = NULL;
+       struct host1x_hwctx *hwctx_to_save = NULL;
        struct nvhost_channel *channel = job->ch;
        struct nvhost_syncpt *sp = &nvhost_get_host(job->ch->dev)->syncpt;
        u32 user_syncpt_incrs = job->syncpt_incrs;
@@ -125,9 +126,10 @@ int host1x_channel_submit(struct nvhost_job *job)
        if (channel->cur_ctx != job->hwctx) {
                trace_nvhost_channel_context_switch(channel->dev->name,
                  channel->cur_ctx, job->hwctx);
-               hwctx_to_save = channel->cur_ctx;
+               hwctx_to_save = channel->cur_ctx ?
+                       to_host1x_hwctx(channel->cur_ctx) : NULL;
                if (hwctx_to_save &&
-                       hwctx_to_save->has_timedout) {
+                       hwctx_to_save->hwctx.has_timedout) {
                        hwctx_to_save = NULL;
                        dev_dbg(&channel->dev->dev,
                                "%s: skip save of timed out context (0x%p)\n",
@@ -135,12 +137,13 @@ int host1x_channel_submit(struct nvhost_job *job)
                }
                if (hwctx_to_save) {
                        job->syncpt_incrs += hwctx_to_save->save_incrs;
-                       hwctx_to_save->valid = true;
-                       channel->ctxhandler.get(hwctx_to_save);
+                       hwctx_to_save->hwctx.valid = true;
+                       channel->ctxhandler->get(&hwctx_to_save->hwctx);
                }
                channel->cur_ctx = job->hwctx;
                if (need_restore)
-                       job->syncpt_incrs += channel->cur_ctx->restore_incrs;
+                       job->syncpt_incrs +=
+                               to_host1x_hwctx(job->hwctx)->restore_incrs;
        }
 
        /* get absolute sync value */
@@ -155,16 +158,19 @@ int host1x_channel_submit(struct nvhost_job *job)
 
        /* push save buffer (pre-gather setup depends on unit) */
        if (hwctx_to_save)
-               channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
+               channel->ctxhandler->save_push(&hwctx_to_save->hwctx,
+                               &channel->cdma);
 
        /* gather restore buffer */
        if (need_restore) {
+               struct host1x_hwctx *cur_ctx =
+                       to_host1x_hwctx(channel->cur_ctx);
                nvhost_cdma_push_gather(&channel->cdma,
                        nvhost_get_host(channel->dev)->nvmap,
-                       nvmap_ref_to_handle(channel->cur_ctx->restore),
-                       nvhost_opcode_gather(channel->cur_ctx->restore_size),
-                       channel->cur_ctx->restore_phys);
-               channel->ctxhandler.get(channel->cur_ctx);
+                       nvmap_ref_to_handle(cur_ctx->restore),
+                       nvhost_opcode_gather(cur_ctx->restore_size),
+                       cur_ctx->restore_phys);
+               channel->ctxhandler->get(channel->cur_ctx);
        }
 
        /* add a setclass for modules that require it (unless ctxsw added it) */
@@ -225,7 +231,7 @@ int host1x_channel_submit(struct nvhost_job *job)
                        job->syncpt_id,
                        syncval - job->syncpt_incrs
                                + hwctx_to_save->save_thresh,
-                       NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
+                       NVHOST_INTR_ACTION_CTXSAVE, &hwctx_to_save->hwctx,
                        ctxsave_waiter,
                        NULL);
                ctxsave_waiter = NULL;
@@ -269,7 +275,9 @@ int host1x_channel_read_3d_reg(
        u32 offset,
        u32 *value)
 {
-       struct nvhost_hwctx *hwctx_to_save = NULL;
+       struct host1x_hwctx *hwctx_to_save = NULL;
+       struct nvhost_hwctx_handler *h = hwctx->h;
+       struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
        bool need_restore = false;
        u32 syncpt_incrs = 4;
        unsigned int pending = 0;
@@ -311,23 +319,25 @@ int host1x_channel_read_3d_reg(
 
        /* context switch */
        if (channel->cur_ctx != hwctx) {
-               hwctx_to_save = channel->cur_ctx;
+               hwctx_to_save = channel->cur_ctx ?
+                       to_host1x_hwctx(channel->cur_ctx) : NULL;
                if (hwctx_to_save) {
                        syncpt_incrs += hwctx_to_save->save_incrs;
-                       hwctx_to_save->valid = true;
-                       channel->ctxhandler.get(hwctx_to_save);
+                       hwctx_to_save->hwctx.valid = true;
+                       channel->ctxhandler->get(&hwctx_to_save->hwctx);
                }
                channel->cur_ctx = hwctx;
                if (channel->cur_ctx && channel->cur_ctx->valid) {
                        need_restore = true;
-                       syncpt_incrs += channel->cur_ctx->restore_incrs;
+                       syncpt_incrs += to_host1x_hwctx(channel->cur_ctx)
+                               ->restore_incrs;
                }
        }
 
        syncval = nvhost_syncpt_incr_max(&nvhost_get_host(channel->dev)->syncpt,
-               NVSYNCPT_3D, syncpt_incrs);
+               p->syncpt, syncpt_incrs);
 
-       job->syncpt_id = NVSYNCPT_3D;
+       job->syncpt_id = p->syncpt;
        job->syncpt_incrs = syncpt_incrs;
        job->syncpt_end = syncval;
 
@@ -336,23 +346,25 @@ int host1x_channel_read_3d_reg(
 
        /* push save buffer (pre-gather setup depends on unit) */
        if (hwctx_to_save)
-               channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
+               h->save_push(&hwctx_to_save->hwctx, &channel->cdma);
 
        /* gather restore buffer */
        if (need_restore)
                nvhost_cdma_push(&channel->cdma,
-                       nvhost_opcode_gather(channel->cur_ctx->restore_size),
-                       channel->cur_ctx->restore_phys);
+                       nvhost_opcode_gather(to_host1x_hwctx(channel->cur_ctx)
+                               ->restore_size),
+                       to_host1x_hwctx(channel->cur_ctx)->restore_phys);
 
        /* Switch to 3D - wait for it to complete what it was doing */
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
-               nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, NVSYNCPT_3D));
+               nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+                       p->syncpt));
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                        NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
-               nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                       NVWAITBASE_3D, 1));
+               nvhost_class_host_wait_syncpt_base(p->syncpt,
+                       p->waitbase, 1));
        /*  Tell 3D to send register value to FIFO */
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1),
@@ -364,21 +376,21 @@ int host1x_channel_read_3d_reg(
        /*  Increment syncpt to indicate that FIFO can be read */
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
-                       NVSYNCPT_3D),
+                       p->syncpt),
                NVHOST_OPCODE_NOOP);
        /*  Wait for value to be read from FIFO */
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
-               nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
-                       NVWAITBASE_3D, 3));
+               nvhost_class_host_wait_syncpt_base(p->syncpt,
+                       p->waitbase, 3));
        /*  Indicate submit complete */
        nvhost_cdma_push(&channel->cdma,
                nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1),
-               nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D, 4));
+               nvhost_class_host_incr_syncpt_base(p->waitbase, 4));
        nvhost_cdma_push(&channel->cdma,
                NVHOST_OPCODE_NOOP,
                nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
-                       NVSYNCPT_3D));
+                       p->syncpt));
 
        /* end CDMA submit  */
        nvhost_cdma_end(&channel->cdma, job);
@@ -392,8 +404,10 @@ int host1x_channel_read_3d_reg(
        if (hwctx_to_save) {
                err = nvhost_intr_add_action(
                        &nvhost_get_host(channel->dev)->intr,
-                       NVSYNCPT_3D,
-                       syncval - syncpt_incrs + hwctx_to_save->save_incrs - 1,
+                       p->syncpt,
+                       syncval - syncpt_incrs
+                               + hwctx_to_save->save_incrs
+                               - 1,
                        NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
                        ctx_waiter,
                        NULL);
@@ -403,7 +417,7 @@ int host1x_channel_read_3d_reg(
 
        /* Wait for FIFO to be ready */
        err = nvhost_intr_add_action(&nvhost_get_host(channel->dev)->intr,
-                       NVSYNCPT_3D, syncval - 2,
+                       p->syncpt, syncval - 2,
                        NVHOST_INTR_ACTION_WAKEUP, &wq,
                        read_waiter,
                        &ref);
@@ -411,7 +425,7 @@ int host1x_channel_read_3d_reg(
        WARN(err, "Failed to set wakeup interrupt");
        wait_event(wq,
                nvhost_syncpt_min_cmp(&nvhost_get_host(channel->dev)->syncpt,
-                               NVSYNCPT_3D, syncval - 2));
+                               p->syncpt, syncval - 2));
        nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref);
 
        /* Read the register value from FIFO */
@@ -420,11 +434,11 @@ int host1x_channel_read_3d_reg(
 
        /* Indicate we've read the value */
        nvhost_syncpt_cpu_incr(&nvhost_get_host(channel->dev)->syncpt,
-                       NVSYNCPT_3D);
+                       p->syncpt);
 
        /* Schedule a submit complete interrupt */
        err = nvhost_intr_add_action(&nvhost_get_host(channel->dev)->intr,
-                       NVSYNCPT_3D, syncval,
+                       p->syncpt, syncval,
                        NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel,
                        completed_waiter, NULL);
        completed_waiter = NULL;
@@ -520,10 +534,10 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
        }
 
        hwctx_to_save->valid = true;
-       ch->ctxhandler.get(hwctx_to_save);
+       ch->ctxhandler->get(hwctx_to_save);
        ch->cur_ctx = NULL;
 
-       syncpt_incrs = hwctx_to_save->save_incrs;
+       syncpt_incrs = to_host1x_hwctx(hwctx_to_save)->save_incrs;
        syncpt_val = nvhost_syncpt_incr_max(&nvhost_get_host(ch->dev)->syncpt,
                                        syncpt_id, syncpt_incrs);
 
@@ -537,13 +551,14 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
                goto done;
        }
 
-       ch->ctxhandler.save_push(&ch->cdma, hwctx_to_save);
+       ch->ctxhandler->save_push(hwctx_to_save, &ch->cdma);
        nvhost_cdma_end(&ch->cdma, job);
        nvhost_job_put(job);
        job = NULL;
 
        err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr, syncpt_id,
-                       syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh,
+                       syncpt_val - syncpt_incrs +
+                               to_host1x_hwctx(hwctx_to_save)->save_thresh,
                        NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
                        ctx_waiter,
                        NULL);
diff --git a/drivers/video/tegra/host/host1x/host1x_hwctx.h b/drivers/video/tegra/host/host1x/host1x_hwctx.h
new file mode 100644 (file)
index 0000000..7587642
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * drivers/video/tegra/host/host1x/host1x_hwctx.h
+ *
+ * Tegra Graphics Host HOST1X Hardware Context Interface
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __NVHOST_HOST1X_HWCTX_H
+#define __NVHOST_HOST1X_HWCTX_H
+
+#include <linux/kref.h>
+
+struct nvhost_hwctx_handler;
+struct nvhost_channel;
+
+#define to_host1x_hwctx_handler(handler) \
+       container_of((handler), struct host1x_hwctx_handler, h)
+#define to_host1x_hwctx(h) container_of((h), struct host1x_hwctx, hwctx)
+#define host1x_hwctx_handler(_hwctx) to_host1x_hwctx_handler((_hwctx)->hwctx.h)
+
+struct host1x_hwctx {
+       struct nvhost_hwctx hwctx;
+
+       u32 save_incrs;
+       u32 save_thresh;
+       u32 save_slots;
+
+       struct nvmap_handle_ref *restore;
+       u32 *restore_virt;
+       phys_addr_t restore_phys;
+       u32 restore_size;
+       u32 restore_incrs;
+};
+
+struct host1x_hwctx_handler {
+       struct nvhost_hwctx_handler h;
+
+       u32 syncpt;
+       u32 waitbase;
+       u32 restore_size;
+       u32 restore_incrs;
+       struct nvmap_handle_ref *save_buf;
+       u32 save_incrs;
+       u32 save_thresh;
+       u32 save_slots;
+       phys_addr_t save_phys;
+       u32 save_size;
+};
+
+#endif
index 0f39500..a5459e8 100644 (file)
@@ -23,6 +23,7 @@
 #include "host1x/host1x_hardware.h"
 #include "host1x/host1x_channel.h"
 #include "host1x/host1x_syncpt.h"
+#include "host1x/host1x_hwctx.h"
 #include "t20/t20.h"
 #include <linux/slab.h>
 
@@ -130,13 +131,13 @@ struct mpe_save_info {
 
 static unsigned int restore_size;
 
-static void restore_begin(u32 *ptr)
+static void restore_begin(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* set class to host */
        ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
        /* increment sync point base */
-       ptr[1] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_MPE, 1);
+       ptr[1] = nvhost_class_host_incr_syncpt_base(h->waitbase, 1);
        /* set class to MPE */
        ptr[2] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
 }
@@ -150,11 +151,11 @@ static void restore_ram(u32 *ptr, unsigned words,
 }
 #define RESTORE_RAM_SIZE 2
 
-static void restore_end(u32 *ptr)
+static void restore_end(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* syncpt increment to track restore gather. */
        ptr[0] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
-                       NVSYNCPT_MPE);
+                       h->syncpt);
 }
 #define RESTORE_END_SIZE 1
 
@@ -180,9 +181,9 @@ static u32 *setup_restore_ram(u32 *ptr, unsigned words,
        return ptr + (RESTORE_RAM_SIZE + words);
 }
 
-static void setup_restore(u32 *ptr)
+static void setup_restore(struct host1x_hwctx_handler *h, u32 *ptr)
 {
-       restore_begin(ptr);
+       restore_begin(h, ptr);
        ptr += RESTORE_BEGIN_SIZE;
 
        ptr = setup_restore_regs(ptr, ctxsave_regs_mpe,
@@ -194,39 +195,30 @@ static void setup_restore(u32 *ptr)
        ptr = setup_restore_ram(ptr, IRFR_RAM_SIZE,
                        IRFR_RAM_LOAD_CMD, IRFR_RAM_LOAD_DATA);
 
-       restore_end(ptr);
+       restore_end(h, ptr);
 
        wmb();
 }
 
 
 /*** save ***/
-
-/* the same context save command sequence is used for all contexts. */
-static struct nvmap_handle_ref *save_buf;
-static phys_addr_t save_phys;
-static unsigned int save_size;
-
 struct save_info {
        u32 *ptr;
        unsigned int save_count;
        unsigned int restore_count;
 };
 
-static void __init save_begin(u32 *ptr)
+static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* MPE: when done, increment syncpt to base+1 */
        ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
-       ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
-                       NVSYNCPT_MPE);
+       ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, h->syncpt);
        /* host: wait for syncpt base+1 */
        ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
-       ptr[3] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_MPE,
-                                               NVWAITBASE_MPE, 1);
+       ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 1);
        /* host: signal context read thread to start reading */
-       ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
-                       NVSYNCPT_MPE);
+       ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE, h->syncpt);
 }
 #define SAVE_BEGIN_SIZE 5
 
@@ -262,16 +254,15 @@ static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
 }
 #define SAVE_READ_RAM_DATA_NASTY_SIZE 5
 
-static void __init save_end(u32 *ptr)
+static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        /* Wait for context read service to finish (cpu incr 3) */
        ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
                                        NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
-       ptr[1] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_MPE,
-                                               NVWAITBASE_MPE, 3);
+       ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 3);
        /* Advance syncpoint base */
        ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
-       ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_MPE, 3);
+       ptr[3] = nvhost_class_host_incr_syncpt_base(h->waitbase, 3);
        /* set class back to the unit */
        ptr[4] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
 }
@@ -332,7 +323,7 @@ static void __init setup_save_ram_nasty(struct save_info *info,     unsigned words,
        info->restore_count = restore_count;
 }
 
-static void __init setup_save(u32 *ptr)
+static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
 {
        struct save_info info = {
                ptr,
@@ -341,7 +332,7 @@ static void __init setup_save(u32 *ptr)
        };
 
        if (info.ptr) {
-               save_begin(info.ptr);
+               save_begin(h, info.ptr);
                info.ptr += SAVE_BEGIN_SIZE;
        }
 
@@ -355,13 +346,13 @@ static void __init setup_save(u32 *ptr)
                        IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
 
        if (info.ptr) {
-               save_end(info.ptr);
+               save_end(h, info.ptr);
                info.ptr += SAVE_END_SIZE;
        }
 
        wmb();
 
-       save_size = info.save_count + SAVE_END_SIZE;
+       h->save_size = info.save_count + SAVE_END_SIZE;
        restore_size = info.restore_count + RESTORE_END_SIZE;
 }
 
@@ -435,10 +426,12 @@ static u32 *save_ram(u32 *ptr, unsigned int *pending,
 
 /*** ctxmpe ***/
 
-static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_channel *ch)
+static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
+               struct nvhost_channel *ch)
 {
        struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
-       struct nvhost_hwctx *ctx;
+       struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
+       struct host1x_hwctx *ctx;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -457,19 +450,19 @@ static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_channel *ch)
                return NULL;
        }
 
-       kref_init(&ctx->ref);
-       ctx->channel = ch;
-       ctx->valid = false;
-       ctx->save = save_buf;
+       kref_init(&ctx->hwctx.ref);
+       ctx->hwctx.h = &p->h;
+       ctx->hwctx.channel = ch;
+       ctx->hwctx.valid = false;
        ctx->save_incrs = 3;
        ctx->save_thresh = 2;
        ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
        ctx->restore_size = restore_size;
        ctx->restore_incrs = 1;
 
-       setup_restore(ctx->restore_virt);
+       setup_restore(p, ctx->restore_virt);
 
-       return ctx;
+       return &ctx->hwctx;
 }
 
 static void ctxmpe_get(struct nvhost_hwctx *ctx)
@@ -479,8 +472,10 @@ static void ctxmpe_get(struct nvhost_hwctx *ctx)
 
 static void ctxmpe_free(struct kref *ref)
 {
-       struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
-       struct nvmap_client *nvmap = nvhost_get_host(ctx->channel->dev)->nvmap;
+       struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct nvmap_client *nvmap =
+               nvhost_get_host(nctx->channel->dev)->nvmap;
 
        if (ctx->restore_virt)
                nvmap_munmap(ctx->restore, ctx->restore_virt);
@@ -494,15 +489,21 @@ static void ctxmpe_put(struct nvhost_hwctx *ctx)
        kref_put(&ctx->ref, ctxmpe_free);
 }
 
-static void ctxmpe_save_push(struct nvhost_cdma *cdma, struct nvhost_hwctx *ctx)
+static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
+               struct nvhost_cdma *cdma)
 {
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
        nvhost_cdma_push(cdma,
-                       nvhost_opcode_gather(save_size),
-                       save_phys);
+                       nvhost_opcode_gather(h->save_size),
+                       h->save_phys);
 }
 
-static void ctxmpe_save_service(struct nvhost_hwctx *ctx)
+static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
 {
+       struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
+       struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
+
        u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
        unsigned int pending = 0;
        struct mpe_save_info msi;
@@ -510,57 +511,64 @@ static void ctxmpe_save_service(struct nvhost_hwctx *ctx)
        msi.in_pos = 0;
        msi.out_pos = 0;
 
-       ptr = save_regs(ptr, &pending, ctx->channel,
+       ptr = save_regs(ptr, &pending, nctx->channel,
                        ctxsave_regs_mpe, ARRAY_SIZE(ctxsave_regs_mpe), &msi);
 
-       ptr = save_ram(ptr, &pending, ctx->channel,
+       ptr = save_ram(ptr, &pending, nctx->channel,
                RC_RAM_SIZE, RC_RAM_READ_CMD, RC_RAM_READ_DATA);
 
-       ptr = save_ram(ptr, &pending, ctx->channel,
+       ptr = save_ram(ptr, &pending, nctx->channel,
                IRFR_RAM_SIZE, IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
 
        wmb();
-       nvhost_syncpt_cpu_incr(&nvhost_get_host(ctx->channel->dev)->syncpt,
-                       NVSYNCPT_MPE);
+       nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
+                       h->syncpt);
 }
 
-int __init nvhost_mpe_ctxhandler_init(struct nvhost_hwctx_handler *h)
+struct nvhost_hwctx_handler * __init nvhost_mpe_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch)
 {
-       struct nvhost_channel *ch;
        struct nvmap_client *nvmap;
        u32 *save_ptr;
+       struct host1x_hwctx_handler *p;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
 
-       ch = container_of(h, struct nvhost_channel, ctxhandler);
        nvmap = nvhost_get_host(ch->dev)->nvmap;
 
-       setup_save(NULL);
+       p->syncpt = syncpt;
+       p->waitbase = waitbase;
+
+       setup_save(p, NULL);
 
-       save_buf = nvmap_alloc(nvmap, save_size * 4, 32,
+       p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
                                NVMAP_HANDLE_WRITE_COMBINE);
-       if (IS_ERR(save_buf)) {
-               int err = PTR_ERR(save_buf);
-               save_buf = NULL;
-               return err;
+       if (IS_ERR(p->save_buf)) {
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       save_ptr = nvmap_mmap(save_buf);
+       save_ptr = nvmap_mmap(p->save_buf);
        if (!save_ptr) {
-               nvmap_free(nvmap, save_buf);
-               save_buf = NULL;
-               return -ENOMEM;
+               nvmap_free(nvmap, p->save_buf);
+               p->save_buf = NULL;
+               return NULL;
        }
 
-       save_phys = nvmap_pin(nvmap, save_buf);
+       p->save_phys = nvmap_pin(nvmap, p->save_buf);
 
-       setup_save(save_ptr);
+       setup_save(p, save_ptr);
 
-       h->alloc = ctxmpe_alloc;
-       h->save_push = ctxmpe_save_push;
-       h->save_service = ctxmpe_save_service;
-       h->get = ctxmpe_get;
-       h->put = ctxmpe_put;
+       p->h.alloc = ctxmpe_alloc;
+       p->h.save_push = ctxmpe_save_push;
+       p->h.save_service = ctxmpe_save_service;
+       p->h.get = ctxmpe_get;
+       p->h.put = ctxmpe_put;
 
-       return 0;
+       return &p->h;
 }
 
 int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
index 8ec7f7b..1bc2a8a 100644 (file)
@@ -24,7 +24,9 @@
 struct nvhost_hwctx_handler;
 struct nvhost_device;
 
-int nvhost_mpe_ctxhandler_init(struct nvhost_hwctx_handler *h);
+struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
+               u32 syncpt, u32 waitbase,
+               struct nvhost_channel *ch);
 int nvhost_mpe_prepare_power_off(struct nvhost_device *dev);
 
 #endif
index c4834b5..a7c0330 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "nvhost_channel.h"
 #include "dev.h"
-#include "nvhost_hwctx.h"
 #include "nvhost_job.h"
 #include <trace/events/nvhost.h>
 #include <linux/nvhost_ioctl.h>
index 260ae82..7b946c8 100644 (file)
@@ -56,7 +56,7 @@ struct nvhost_channel {
        struct device *node;
        struct nvhost_device *dev;
        struct cdev cdev;
-       struct nvhost_hwctx_handler ctxhandler;
+       struct nvhost_hwctx_handler *ctxhandler;
        struct nvhost_cdma cdma;
 };
 
index a2fef66..02a3976 100644 (file)
@@ -32,30 +32,21 @@ struct nvhost_cdma;
 
 struct nvhost_hwctx {
        struct kref ref;
-
+       struct nvhost_hwctx_handler *h;
        struct nvhost_channel *channel;
        bool valid;
-
-       struct nvmap_handle_ref *save;
-       u32 save_incrs;
-       u32 save_thresh;
-       u32 save_slots;
-
-       struct nvmap_handle_ref *restore;
-       u32 *restore_virt;
-       phys_addr_t restore_phys;
-       u32 restore_size;
-       u32 restore_incrs;
-
        bool has_timedout;
 };
 
 struct nvhost_hwctx_handler {
-       struct nvhost_hwctx * (*alloc) (struct nvhost_channel *ch);
+       struct nvhost_hwctx * (*alloc) (struct nvhost_hwctx_handler *h,
+                       struct nvhost_channel *ch);
        void (*get) (struct nvhost_hwctx *ctx);
        void (*put) (struct nvhost_hwctx *ctx);
-       void (*save_push) (struct nvhost_cdma *cdma, struct nvhost_hwctx *ctx);
+       void (*save_push) (struct nvhost_hwctx *ctx,
+                       struct nvhost_cdma *cdma);
        void (*save_service) (struct nvhost_hwctx *ctx);
+       void *priv;
 };
 
 
index fe3948d..0fc6652 100644 (file)
@@ -142,9 +142,9 @@ static void action_ctxsave(struct nvhost_waitlist *waiter)
        struct nvhost_hwctx *hwctx = waiter->data;
        struct nvhost_channel *channel = hwctx->channel;
 
-       if (channel->ctxhandler.save_service)
-               channel->ctxhandler.save_service(hwctx);
-       channel->ctxhandler.put(hwctx);
+       if (channel->ctxhandler->save_service)
+               channel->ctxhandler->save_service(hwctx);
+       channel->ctxhandler->put(hwctx);
 }
 
 static void action_ctxrestore(struct nvhost_waitlist *waiter)
@@ -152,7 +152,7 @@ static void action_ctxrestore(struct nvhost_waitlist *waiter)
        struct nvhost_hwctx *hwctx = waiter->data;
        struct nvhost_channel *channel = hwctx->channel;
 
-       channel->ctxhandler.put(hwctx);
+       channel->ctxhandler->put(hwctx);
 }
 
 static void action_wakeup(struct nvhost_waitlist *waiter)
index cbc6f71..227e2b7 100644 (file)
@@ -29,6 +29,7 @@
 #include "gr3d/gr3d.h"
 #include "gr3d/gr3d_t20.h"
 #include "mpe/mpe.h"
+#include "nvhost_hwctx.h"
 
 #define NVMODMUTEX_2D_FULL   (1)
 #define NVMODMUTEX_2D_SIMPLE (2)
@@ -65,6 +66,7 @@ struct nvhost_device devices[] = {
        .modulemutexes = BIT(NVMODMUTEX_3D),
        .class         = NV_GRAPHICS_3D_CLASS_ID,
        .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+       .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
        .clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
        .powergate_ids = {TEGRA_POWERGATE_3D, -1},
        NVHOST_DEFAULT_CLOCKGATE_DELAY,
@@ -119,6 +121,7 @@ struct nvhost_device devices[] = {
        .waitbasesync  = true,
        .keepalive     = true,
        .prepare_poweroff = nvhost_mpe_prepare_power_off,
+       .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
        .clocks = {{"mpe", UINT_MAX}, {"emc", UINT_MAX}, {} },
        .powergate_ids = {TEGRA_POWERGATE_MPE, -1},
        NVHOST_DEFAULT_CLOCKGATE_DELAY,
@@ -142,15 +145,22 @@ static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
        return p;
 }
 
-static inline int t20_nvhost_hwctx_handler_init(
-       struct nvhost_hwctx_handler *h,
-       const char *module)
+static inline int t20_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
 {
-       if (strcmp(module, "gr3d") == 0)
-               return nvhost_gr3d_t20_ctxhandler_init(h);
-       else if (strcmp(module, "mpe") == 0)
-               return nvhost_mpe_ctxhandler_init(h);
-       return 0;
+       int err = 0;
+       unsigned long syncpts = ch->dev->syncpts;
+       unsigned long waitbases = ch->dev->waitbases;
+       u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
+       u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+
+       if (ch->dev->alloc_hwctx_handler) {
+               ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+                               waitbase, ch);
+               if (!ch->ctxhandler)
+                       err = -ENOMEM;
+       }
+
+       return err;
 }
 
 static int t20_channel_init(struct nvhost_channel *ch,
@@ -164,7 +174,7 @@ static int t20_channel_init(struct nvhost_channel *ch,
        nvhost_device_register(ch->dev);
        ch->aperture = t20_channel_aperture(dev->aperture, index);
 
-       return t20_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->dev->name);
+       return t20_nvhost_hwctx_handler_init(ch);
 }
 
 int nvhost_init_t20_channel_support(struct nvhost_master *host)
index 88a44ab..484f077 100644 (file)
@@ -75,6 +75,7 @@ static struct nvhost_device devices[] = {
        .init = nvhost_scale3d_init,
        .deinit = nvhost_scale3d_deinit,
        .suspend = nvhost_scale3d_suspend,
+       .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
        .clocks = {{"gr3d", UINT_MAX},
                        {"gr3d2", UINT_MAX},
                        {"emc", UINT_MAX} },
@@ -134,6 +135,7 @@ static struct nvhost_device devices[] = {
        .waitbasesync  = true,
        .keepalive     = true,
        .prepare_poweroff = nvhost_mpe_prepare_power_off,
+       .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
        .clocks = {{"mpe", UINT_MAX}, {"emc", UINT_MAX}, {} },
        .powergate_ids  = {TEGRA_POWERGATE_MPE, -1},
        NVHOST_DEFAULT_CLOCKGATE_DELAY,
@@ -154,16 +156,22 @@ static struct nvhost_device devices[] = {
 
 #define NVHOST_CHANNEL_BASE 0
 
-static inline int t30_nvhost_hwctx_handler_init(
-       struct nvhost_hwctx_handler *h,
-       const char *module)
+static inline int t30_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
 {
-       if (strcmp(module, "gr3d") == 0)
-               return nvhost_gr3d_t30_ctxhandler_init(h);
-       else if (strcmp(module, "mpe") == 0)
-               return nvhost_mpe_ctxhandler_init(h);
-
-       return 0;
+       int err = 0;
+       unsigned long syncpts = ch->dev->syncpts;
+       unsigned long waitbases = ch->dev->waitbases;
+       u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
+       u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+
+       if (ch->dev->alloc_hwctx_handler) {
+               ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+                               waitbase, ch);
+               if (!ch->ctxhandler)
+                       err = -ENOMEM;
+       }
+
+       return err;
 }
 
 static inline void __iomem *t30_channel_aperture(void __iomem *p, int ndx)
@@ -185,7 +193,7 @@ static int t30_channel_init(struct nvhost_channel *ch,
        nvhost_device_register(ch->dev);
        ch->aperture = t30_channel_aperture(dev->aperture, index);
 
-       return t30_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->dev->name);
+       return t30_nvhost_hwctx_handler_init(ch);
 }
 
 int nvhost_init_t30_channel_support(struct nvhost_master *host)
index 80f257a..bc1d9d7 100644 (file)
@@ -81,6 +81,9 @@ struct nvhost_device {
 
        struct nvhost_channel *channel; /* Channel assigned for the module */
 
+       /* Allocates a context handler for the device */
+       struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+                       u32 waitbase, struct nvhost_channel *ch);
        /* Preparing for power off. Used for context save. */
        int (*prepare_poweroff)(struct nvhost_device *dev);
        /* Finalize power on. Can be used for context restore. */