video: tegra: host: New submit interface
Terje Bergstrom [Thu, 8 Nov 2012 13:21:07 +0000 (15:21 +0200)]
Add new interface for submit. Now a single IOCTL will send the whole
job to kernel.

Also removes 32 sync point limit from the interface, and adds
possibility to have variable number of sync point ids and increments.

Because of these changes, nvhost_job has been refactored to remove
dependency to the submit header struct.

Change-Id: Id43b0c916e5ad5cdc7541726ea2d96bfc7497256
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/162888
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/gr3d/gr3d_t20.c
drivers/video/tegra/host/gr3d/gr3d_t30.c
drivers/video/tegra/host/host1x/host1x_channel.c
drivers/video/tegra/host/nvhost_job.c
drivers/video/tegra/host/nvhost_job.h
include/linux/nvhost_ioctl.h
include/trace/events/nvhost.h

index 4b0b81d..484c60f 100644 (file)
@@ -206,13 +206,17 @@ static int set_submit(struct nvhost_channel_userctx *ctx)
        }
        ctx->job = nvhost_job_alloc(ctx->ch,
                        ctx->hwctx,
-                       &ctx->hdr,
-                       ctx->memmgr,
-                       ctx->priority,
-                       ctx->clientid);
+                       ctx->hdr.num_cmdbufs,
+                       ctx->hdr.num_relocs,
+                       ctx->hdr.num_waitchks,
+                       ctx->memmgr);
        if (!ctx->job)
                return -ENOMEM;
        ctx->job->timeout = ctx->timeout;
+       ctx->job->syncpt_id = ctx->hdr.syncpt_id;
+       ctx->job->syncpt_incrs = ctx->hdr.syncpt_incrs;
+       ctx->job->priority = ctx->priority;
+       ctx->job->clientid = ctx->clientid;
 
        if (ctx->hdr.submit_version >= NVHOST_SUBMIT_VERSION_V2)
                ctx->num_relocshifts = ctx->hdr.num_relocs;
@@ -317,8 +321,7 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
                                break;
                        }
                        trace_nvhost_channel_write_waitchks(
-                         chname, numwaitchks,
-                         hdr->waitchk_mask);
+                         chname, numwaitchks);
                        job->num_waitchk += numwaitchks;
                        hdr->num_waitchks -= numwaitchks;
                } else if (priv->num_relocshifts) {
@@ -401,6 +404,101 @@ fail:
        return err;
 }
 
+static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
+               struct nvhost_submit_args *args)
+{
+       struct nvhost_job *job;
+       int num_cmdbufs = args->num_cmdbufs;
+       int num_relocs = args->num_relocs;
+       int num_waitchks = args->num_waitchks;
+       struct nvhost_cmdbuf __user *cmdbufs = args->cmdbufs;
+       struct nvhost_reloc __user *relocs = args->relocs;
+       struct nvhost_reloc_shift __user *reloc_shifts = args->reloc_shifts;
+       struct nvhost_waitchk __user *waitchks = args->waitchks;
+       struct nvhost_syncpt_incr syncpt_incr;
+       int err;
+
+       /* We don't yet support other than one nvhost_syncpt_incrs per submit */
+       if (args->num_syncpt_incrs != 1)
+               return -EINVAL;
+
+       job = nvhost_job_alloc(ctx->ch,
+                       ctx->hwctx,
+                       args->num_cmdbufs,
+                       args->num_relocs,
+                       args->num_waitchks,
+                       ctx->memmgr);
+       if (!job)
+               return -ENOMEM;
+
+       job->num_relocs = args->num_relocs;
+       job->num_waitchk = args->num_waitchks;
+       job->priority = ctx->priority;
+       job->clientid = ctx->clientid;
+
+       while (num_cmdbufs) {
+               struct nvhost_cmdbuf cmdbuf;
+               err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
+               if (err)
+                       goto fail;
+               nvhost_job_add_gather(job,
+                               cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
+               num_cmdbufs--;
+               cmdbufs++;
+       }
+
+       err = copy_from_user(job->relocarray,
+                       relocs, sizeof(*relocs) * num_relocs);
+       if (err)
+               goto fail;
+
+       err = copy_from_user(job->relocshiftarray,
+                       reloc_shifts, sizeof(*reloc_shifts) * num_relocs);
+       if (err)
+               goto fail;
+
+       err = copy_from_user(job->waitchk,
+                       waitchks, sizeof(*waitchks) * num_waitchks);
+       if (err)
+               goto fail;
+
+       err = copy_from_user(&syncpt_incr,
+                       args->syncpt_incrs, sizeof(syncpt_incr));
+       if (err)
+               goto fail;
+       job->syncpt_id = syncpt_incr.syncpt_id;
+       job->syncpt_incrs = syncpt_incr.syncpt_incrs;
+
+       trace_nvhost_channel_submit(ctx->ch->dev->name,
+               job->num_gathers, job->num_relocs, job->num_waitchk,
+               job->syncpt_id, job->syncpt_incrs);
+
+       err = nvhost_job_pin(job, &nvhost_get_host(ctx->ch->dev)->syncpt);
+       if (err)
+               goto fail;
+
+       if (args->timeout)
+               job->timeout = min(ctx->timeout, args->timeout);
+       else
+               job->timeout = ctx->timeout;
+
+       err = nvhost_channel_submit(job);
+       if (err)
+               goto fail_submit;
+
+       args->fence = job->syncpt_end;
+
+       nvhost_job_put(job);
+
+       return 0;
+
+fail_submit:
+       nvhost_job_unpin(job);
+fail:
+       nvhost_job_put(job);
+       return err;
+}
+
 static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
        struct nvhost_read_3d_reg_args *args)
 {
@@ -640,6 +738,9 @@ static long nvhost_channelctl(struct file *filp,
        case NVHOST_IOCTL_CHANNEL_MODULE_REGRDWR:
                err = nvhost_ioctl_channel_module_regrdwr(priv, (void *)buf);
                break;
+       case NVHOST_IOCTL_CHANNEL_SUBMIT:
+               err = nvhost_ioctl_channel_submit(priv, (void *)buf);
+               break;
        default:
                err = -ENOTTY;
                break;
index a3218a6..78b12a5 100644 (file)
@@ -441,9 +441,8 @@ int nvhost_gr3d_t20_read_reg(struct platform_device *dev,
                goto done;
        }
 
-       job = nvhost_job_alloc(channel, hwctx,
-                       NULL,
-                       nvhost_get_host(dev)->memmgr, 0, 0);
+       job = nvhost_job_alloc(channel, hwctx, 0, 0, 0,
+                       nvhost_get_host(dev)->memmgr);
        if (!job) {
                err = -ENOMEM;
                goto done;
index bc290f6..df7ed6c 100644 (file)
@@ -509,9 +509,8 @@ int nvhost_gr3d_t30_read_reg(
                goto done;
        }
 
-       job = nvhost_job_alloc(channel, hwctx,
-                       NULL,
-                       nvhost_get_host(dev)->memmgr, 0, 0);
+       job = nvhost_job_alloc(channel, hwctx, 0, 0, 0,
+                       nvhost_get_host(dev)->memmgr);
        if (!job) {
                err = -ENOMEM;
                goto done;
index 0b6ce9a..3da0d67 100644 (file)
@@ -407,9 +407,8 @@ static int host1x_save_context(struct nvhost_channel *ch)
                goto done;
        }
 
-       job = nvhost_job_alloc(ch, hwctx_to_save,
-                       NULL,
-                       nvhost_get_host(ch->dev)->memmgr, 0, 0);
+       job = nvhost_job_alloc(ch, hwctx_to_save, 0, 0, 0,
+                       nvhost_get_host(ch->dev)->memmgr);
        if (IS_ERR_OR_NULL(job)) {
                err = PTR_ERR(job);
                mutex_unlock(&ch->submitlock);
index 14cd433..ab7d6bc 100644 (file)
 /* Magic to use to fill freed handle slots */
 #define BAD_MAGIC 0xdeadbeef
 
-static size_t job_size(struct nvhost_submit_hdr_ext *hdr)
+static size_t job_size(u32 num_cmdbufs, u32 num_relocs, u32 num_waitchks)
 {
-       s64 num_relocs = hdr ? (int)hdr->num_relocs : 0;
-       s64 num_waitchks = hdr ? (int)hdr->num_waitchks : 0;
-       s64 num_cmdbufs = hdr ? (int)hdr->num_cmdbufs : 0;
        s64 num_unpins = num_cmdbufs + num_relocs;
        s64 total;
 
@@ -59,19 +56,14 @@ static size_t job_size(struct nvhost_submit_hdr_ext *hdr)
        return (size_t)total;
 }
 
+
 static void init_fields(struct nvhost_job *job,
-               struct nvhost_submit_hdr_ext *hdr,
-               int priority, int clientid)
+               u32 num_cmdbufs, u32 num_relocs, u32 num_waitchks)
 {
-       int num_relocs = hdr ? hdr->num_relocs : 0;
-       int num_waitchks = hdr ? hdr->num_waitchks : 0;
-       int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
        int num_unpins = num_cmdbufs + num_relocs;
        void *mem = job;
 
        /* First init state to zero */
-       job->priority = priority;
-       job->clientid = clientid;
 
        /*
         * Redistribute memory to the structs.
@@ -93,25 +85,15 @@ static void init_fields(struct nvhost_job *job,
 
        job->reloc_addr_phys = job->addr_phys;
        job->gather_addr_phys = &job->addr_phys[num_relocs];
-
-
-       /* Copy information from header */
-       if (hdr) {
-               job->waitchk_mask = hdr->waitchk_mask;
-               job->syncpt_id = hdr->syncpt_id;
-               job->syncpt_incrs = hdr->syncpt_incrs;
-       }
 }
 
 struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
                struct nvhost_hwctx *hwctx,
-               struct nvhost_submit_hdr_ext *hdr,
-               struct mem_mgr *memmgr,
-               int priority,
-               int clientid)
+               int num_cmdbufs, int num_relocs, int num_waitchks,
+               struct mem_mgr *memmgr)
 {
        struct nvhost_job *job = NULL;
-       size_t size = job_size(hdr);
+       size_t size = job_size(num_cmdbufs, num_relocs, num_waitchks);
 
        if(!size)
                return NULL;
@@ -126,7 +108,7 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
                hwctx->h->get(hwctx);
        job->memmgr = memmgr ? mem_op().get_mgr(memmgr) : NULL;
 
-       init_fields(job, hdr, priority, clientid);
+       init_fields(job, num_cmdbufs, num_relocs, num_waitchks);
 
        return job;
 }
@@ -190,6 +172,10 @@ static int do_waitchks(struct nvhost_job *job, struct nvhost_syncpt *sp,
        for (i = 0; i < job->num_waitchk; i++) {
                struct nvhost_waitchk *wait = &job->waitchk[i];
 
+               /* validate syncpt id */
+               if (wait->syncpt_id > nvhost_syncpt_nb_pts(sp))
+                       continue;
+
                /* skip all other gathers */
                if (patch_mem != wait->mem)
                        continue;
@@ -341,11 +327,18 @@ static int do_relocs(struct nvhost_job *job,
 int nvhost_job_pin(struct nvhost_job *job, struct nvhost_syncpt *sp)
 {
        int err = 0, i = 0, j = 0;
-       unsigned long waitchk_mask = job->waitchk_mask;
+       unsigned long waitchk_mask[nvhost_syncpt_nb_pts(sp) / BITS_PER_LONG];
 
+       memset(&waitchk_mask[0], 0, sizeof(waitchk_mask));
+       for (i = 0; i < job->num_waitchk; i++) {
+               u32 syncpt_id = job->waitchk[i].syncpt_id;
+               if (syncpt_id < nvhost_syncpt_nb_pts(sp))
+                       waitchk_mask[BIT_WORD(syncpt_id)]
+                               |= BIT_MASK(syncpt_id);
+       }
 
        /* get current syncpt values for waitchk */
-       for_each_set_bit(i, &waitchk_mask, sizeof(job->waitchk_mask))
+       for_each_set_bit(i, &waitchk_mask[0], sizeof(waitchk_mask))
                nvhost_syncpt_update_min(sp, i);
 
        /* pin memory */
index 5a3c69c..b52a8b2 100644 (file)
@@ -66,7 +66,6 @@ struct nvhost_job {
        /* Wait checks to be processed at submit time */
        struct nvhost_waitchk *waitchk;
        int num_waitchk;
-       u32 waitchk_mask;
 
        /* Array of handles to be pinned & unpinned */
        struct nvhost_reloc *relocarray;
@@ -107,9 +106,8 @@ struct nvhost_job {
  */
 struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
                struct nvhost_hwctx *hwctx,
-               struct nvhost_submit_hdr_ext *hdr,
-               struct mem_mgr *memmgr,
-               int priority, int clientid);
+               int num_cmdbufs, int num_relocs, int num_waitchks,
+               struct mem_mgr *memmgr);
 
 /*
  * Add a gather to a job.
index 028de39..43498cd 100644 (file)
@@ -87,6 +87,11 @@ struct nvhost_waitchk {
        __u32 thresh;
 };
 
+struct nvhost_syncpt_incr {
+       __u32 syncpt_id;
+       __u32 syncpt_incrs;
+};
+
 struct nvhost_get_param_args {
        __u32 value;
 };
@@ -122,6 +127,23 @@ struct nvhost_ctrl_module_regrdwr_args {
        __u32 write;
 };
 
+struct nvhost_submit_args {
+       __u32 submit_version;
+       __u32 num_syncpt_incrs;
+       __u32 num_cmdbufs;
+       __u32 num_relocs;
+       __u32 num_waitchks;
+       __u32 timeout;
+       struct nvhost_syncpt_incr *syncpt_incrs;
+       struct nvhost_cmdbuf *cmdbufs;
+       struct nvhost_reloc *relocs;
+       struct nvhost_reloc_shift *reloc_shifts;
+       struct nvhost_waitchk *waitchks;
+
+       __u32 pad[5];           /* future expansion */
+       __u32 fence;            /* Return value */
+};
+
 #define NVHOST_IOCTL_CHANNEL_FLUSH             \
        _IOR(NVHOST_IOCTL_MAGIC, 1, struct nvhost_get_param_args)
 #define NVHOST_IOCTL_CHANNEL_GET_SYNCPOINTS    \
@@ -150,9 +172,11 @@ struct nvhost_ctrl_module_regrdwr_args {
        _IOW(NVHOST_IOCTL_MAGIC, 13, struct nvhost_set_priority_args)
 #define NVHOST_IOCTL_CHANNEL_MODULE_REGRDWR    \
        _IOWR(NVHOST_IOCTL_MAGIC, 14, struct nvhost_ctrl_module_regrdwr_args)
+#define NVHOST_IOCTL_CHANNEL_SUBMIT            \
+       _IOWR(NVHOST_IOCTL_MAGIC, 15, struct nvhost_submit_args)
 #define NVHOST_IOCTL_CHANNEL_LAST              \
-       _IOC_NR(NVHOST_IOCTL_CHANNEL_MODULE_REGRDWR)
-#define NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE sizeof(struct nvhost_submit_hdr_ext)
+       _IOC_NR(NVHOST_IOCTL_CHANNEL_SUBMIT)
+#define NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE sizeof(struct nvhost_submit_args)
 
 struct nvhost_ctrl_syncpt_read_args {
        __u32 id;
index 558a7d1..7827acf 100644 (file)
@@ -81,6 +81,36 @@ TRACE_EVENT(nvhost_channel_write_submit,
          __entry->syncpt_id, __entry->syncpt_incrs)
 );
 
+TRACE_EVENT(nvhost_channel_submit,
+       TP_PROTO(const char *name, u32 cmdbufs, u32 relocs, u32 waitchks,
+                       u32 syncpt_id, u32 syncpt_incrs),
+
+       TP_ARGS(name, cmdbufs, relocs, waitchks, syncpt_id, syncpt_incrs),
+
+       TP_STRUCT__entry(
+               __field(const char *, name)
+               __field(u32, cmdbufs)
+               __field(u32, relocs)
+               __field(u32, waitchks)
+               __field(u32, syncpt_id)
+               __field(u32, syncpt_incrs)
+       ),
+
+       TP_fast_assign(
+               __entry->name = name;
+               __entry->cmdbufs = cmdbufs;
+               __entry->relocs = relocs;
+               __entry->waitchks = waitchks;
+               __entry->syncpt_id = syncpt_id;
+               __entry->syncpt_incrs = syncpt_incrs;
+       ),
+
+       TP_printk("name=%s, cmdbufs=%u, relocs=%u, waitchks=%d,"
+               "syncpt_id=%u, syncpt_incrs=%u",
+         __entry->name, __entry->cmdbufs, __entry->relocs, __entry->waitchks,
+         __entry->syncpt_id, __entry->syncpt_incrs)
+);
+
 TRACE_EVENT(nvhost_ioctl_channel_submit,
        TP_PROTO(const char *name, u32 version, u32 cmdbufs, u32 relocs,
                 u32 waitchks, u32 syncpt_id, u32 syncpt_incrs),
@@ -267,24 +297,22 @@ TRACE_EVENT(nvhost_channel_write_reloc,
 );
 
 TRACE_EVENT(nvhost_channel_write_waitchks,
-       TP_PROTO(const char *name, u32 waitchks, u32 waitmask),
+       TP_PROTO(const char *name, u32 waitchks),
 
-       TP_ARGS(name, waitchks, waitmask),
+       TP_ARGS(name, waitchks),
 
        TP_STRUCT__entry(
                __field(const char *, name)
                __field(u32, waitchks)
-               __field(u32, waitmask)
        ),
 
        TP_fast_assign(
                __entry->name = name;
                __entry->waitchks = waitchks;
-               __entry->waitmask = waitmask;
        ),
 
-       TP_printk("name=%s, waitchks=%u, waitmask=%08x",
-         __entry->name, __entry->waitchks, __entry->waitmask)
+       TP_printk("name=%s, waitchks=%u",
+         __entry->name, __entry->waitchks)
 );
 
 TRACE_EVENT(nvhost_channel_context_save,