[PATCH v2 3/8] gpu: host1x: Program context stream ID on submission

Mikko Perttunen
2021-09-16T14:36:16Z

Add code to do stream ID switching at the beginning of a job. The
stream ID is switched to the stream ID specified by the context
passed in the job structure.

Before switching the stream ID, an OP_DONE wait is done on the
channel's engine to ensure that there is no residual ongoing
work that might do DMA using the new stream ID.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
drivers/gpu/host1x/hw/channel_hw.c | 52 +++++++++++++++++++++--
drivers/gpu/host1x/hw/host1x06_hardware.h | 10 +++++
drivers/gpu/host1x/hw/host1x07_hardware.h | 10 +++++
include/linux/host1x.h | 4 ++
4 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c
index 1999780a7203..d451f8437f62 100644
--- a/drivers/gpu/host1x/hw/channel_hw.c
+++ b/drivers/gpu/host1x/hw/channel_hw.c
@@ -159,6 +159,45 @@ static void host1x_channel_set_streamid(struct host1x_channel *channel)
#endif
}

+static void host1x_channel_program_engine_streamid(struct host1x_job *job)
+{
+#if HOST1X_HW >= 6
+ u32 fence;
+
+ if (!job->context)
+ return;
+
+ fence = host1x_syncpt_incr_max(job->syncpt, 1);
+
+ /* First, increment a syncpoint on OP_DONE condition.. */
+
+ host1x_cdma_push(&job->channel->cdma,
+ host1x_opcode_nonincr(HOST1X_UCLASS_INCR_SYNCPT, 1),
+ HOST1X_UCLASS_INCR_SYNCPT_INDX_F(job->syncpt->id) |
+ HOST1X_UCLASS_INCR_SYNCPT_COND_F(1));
+
+ /* Wait for syncpoint to increment */
+
+ host1x_cdma_push(&job->channel->cdma,
+ host1x_opcode_setclass(HOST1X_CLASS_HOST1X,
+ host1x_uclass_wait_syncpt_r(), 1),
+ host1x_class_host_wait_syncpt(job->syncpt->id, fence));
+
+ /*
+ * Now that we know the engine is idle, return to class and
+ * change stream ID.
+ */
+
+ host1x_cdma_push(&job->channel->cdma,
+ host1x_opcode_setclass(job->class, 0, 0),
+ HOST1X_OPCODE_NOP);
+
+ host1x_cdma_push(&job->channel->cdma,
+ host1x_opcode_setpayload(job->context->stream_id),
+ host1x_opcode_setstreamid(job->engine_streamid_offset / 4));
+#endif
+}
+
static int channel_submit(struct host1x_job *job)
{
struct host1x_channel *ch = job->channel;
@@ -214,18 +253,23 @@ static int channel_submit(struct host1x_job *job)
if (sp->base)
synchronize_syncpt_base(job);

- syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
-
host1x_hw_syncpt_assign_to_channel(host, sp, ch);

- job->syncpt_end = syncval;
-
/* add a setclass for modules that require it */
if (job->class)
host1x_cdma_push(&ch->cdma,
host1x_opcode_setclass(job->class, 0, 0),
HOST1X_OPCODE_NOP);

+ /*
+ * Ensure engine DMA is idle and set new stream ID. May increment
+ * syncpt max.
+ */
+ host1x_channel_program_engine_streamid(job);
+
+ syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
+ job->syncpt_end = syncval;
+
submit_gathers(job, syncval - user_syncpt_incrs);

/* end CDMA submit & stash pinned hMems into sync queue */
diff --git a/drivers/gpu/host1x/hw/host1x06_hardware.h b/drivers/gpu/host1x/hw/host1x06_hardware.h
index 01a142a09800..5d515745eee7 100644
--- a/drivers/gpu/host1x/hw/host1x06_hardware.h
+++ b/drivers/gpu/host1x/hw/host1x06_hardware.h
@@ -127,6 +127,16 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
}

+static inline u32 host1x_opcode_setstreamid(unsigned streamid)
+{
+ return (7 << 28) | streamid;
+}
+
+static inline u32 host1x_opcode_setpayload(unsigned payload)
+{
+ return (9 << 28) | payload;
+}
+
static inline u32 host1x_opcode_gather_wide(unsigned count)
{
return (12 << 28) | count;
diff --git a/drivers/gpu/host1x/hw/host1x07_hardware.h b/drivers/gpu/host1x/hw/host1x07_hardware.h
index e6582172ebfd..82c0cc9bb0b5 100644
--- a/drivers/gpu/host1x/hw/host1x07_hardware.h
+++ b/drivers/gpu/host1x/hw/host1x07_hardware.h
@@ -127,6 +127,16 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
}

+static inline u32 host1x_opcode_setstreamid(unsigned streamid)
+{
+ return (7 << 28) | streamid;
+}
+
+static inline u32 host1x_opcode_setpayload(unsigned payload)
+{
+ return (9 << 28) | payload;
+}
+
static inline u32 host1x_opcode_gather_wide(unsigned count)
{
return (12 << 28) | count;
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index f3073738564a..eb0ca304ca92 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -277,6 +277,10 @@ struct host1x_job {

/* Whether host1x-side firewall should be ran for this job or not */
bool enable_firewall;
+
+ /* Options for configuring engine data stream ID */
+ struct host1x_context *context;
+ u32 engine_streamid_offset;
};

struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,