Merge tag 'drm-misc-next-fixes-2021-09-09' of git://anongit.freedesktop.org/drm/drm...
[linux-2.6-microblaze.git] / drivers / gpu / host1x / hw / channel_hw.c
index d4c28fa..1999780 100644 (file)
@@ -47,39 +47,84 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
        }
 }
 
-static void submit_gathers(struct host1x_job *job)
+static void submit_wait(struct host1x_cdma *cdma, u32 id, u32 threshold,
+                       u32 next_class)
+{
+#if HOST1X_HW >= 2
+       host1x_cdma_push_wide(cdma,
+               host1x_opcode_setclass(
+                       HOST1X_CLASS_HOST1X,
+                       HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32,
+                       /* WAIT_SYNCPT_32 is at SYNCPT_PAYLOAD_32+2 */
+                       BIT(0) | BIT(2)
+               ),
+               threshold,
+               id,
+               host1x_opcode_setclass(next_class, 0, 0)
+       );
+#else
+       /* TODO add waitchk or use waitbases or other mitigation */
+       host1x_cdma_push(cdma,
+               host1x_opcode_setclass(
+                       HOST1X_CLASS_HOST1X,
+                       host1x_uclass_wait_syncpt_r(),
+                       BIT(0)
+               ),
+               host1x_class_host_wait_syncpt(id, threshold)
+       );
+       host1x_cdma_push(cdma,
+               host1x_opcode_setclass(next_class, 0, 0),
+               HOST1X_OPCODE_NOP
+       );
+#endif
+}
+
+static void submit_gathers(struct host1x_job *job, u32 job_syncpt_base)
 {
        struct host1x_cdma *cdma = &job->channel->cdma;
 #if HOST1X_HW < 6
        struct device *dev = job->channel->dev;
 #endif
        unsigned int i;
+       u32 threshold;
 
-       for (i = 0; i < job->num_gathers; i++) {
-               struct host1x_job_gather *g = &job->gathers[i];
-               dma_addr_t addr = g->base + g->offset;
-               u32 op2, op3;
+       for (i = 0; i < job->num_cmds; i++) {
+               struct host1x_job_cmd *cmd = &job->cmds[i];
 
-               op2 = lower_32_bits(addr);
-               op3 = upper_32_bits(addr);
+               if (cmd->is_wait) {
+                       if (cmd->wait.relative)
+                               threshold = job_syncpt_base + cmd->wait.threshold;
+                       else
+                               threshold = cmd->wait.threshold;
 
-               trace_write_gather(cdma, g->bo, g->offset, g->words);
+                       submit_wait(cdma, cmd->wait.id, threshold, cmd->wait.next_class);
+               } else {
+                       struct host1x_job_gather *g = &cmd->gather;
+
+                       dma_addr_t addr = g->base + g->offset;
+                       u32 op2, op3;
+
+                       op2 = lower_32_bits(addr);
+                       op3 = upper_32_bits(addr);
 
-               if (op3 != 0) {
+                       trace_write_gather(cdma, g->bo, g->offset, g->words);
+
+                       if (op3 != 0) {
 #if HOST1X_HW >= 6
-                       u32 op1 = host1x_opcode_gather_wide(g->words);
-                       u32 op4 = HOST1X_OPCODE_NOP;
+                               u32 op1 = host1x_opcode_gather_wide(g->words);
+                               u32 op4 = HOST1X_OPCODE_NOP;
 
-                       host1x_cdma_push_wide(cdma, op1, op2, op3, op4);
+                               host1x_cdma_push_wide(cdma, op1, op2, op3, op4);
 #else
-                       dev_err(dev, "invalid gather for push buffer %pad\n",
-                               &addr);
-                       continue;
+                               dev_err(dev, "invalid gather for push buffer %pad\n",
+                                       &addr);
+                               continue;
 #endif
-               } else {
-                       u32 op1 = host1x_opcode_gather(g->words);
+                       } else {
+                               u32 op1 = host1x_opcode_gather(g->words);
 
-                       host1x_cdma_push(cdma, op1, op2);
+                               host1x_cdma_push(cdma, op1, op2);
+                       }
                }
        }
 }
@@ -126,7 +171,7 @@ static int channel_submit(struct host1x_job *job)
        struct host1x *host = dev_get_drvdata(ch->dev->parent);
 
        trace_host1x_channel_submit(dev_name(ch->dev),
-                                   job->num_gathers, job->num_relocs,
+                                   job->num_cmds, job->num_relocs,
                                    job->syncpt->id, job->syncpt_incrs);
 
        /* before error checks, return current max */
@@ -181,7 +226,7 @@ static int channel_submit(struct host1x_job *job)
                                 host1x_opcode_setclass(job->class, 0, 0),
                                 HOST1X_OPCODE_NOP);
 
-       submit_gathers(job);
+       submit_gathers(job, syncval - user_syncpt_incrs);
 
        /* end CDMA submit & stash pinned hMems into sync queue */
        host1x_cdma_end(&ch->cdma, job);
@@ -191,7 +236,7 @@ static int channel_submit(struct host1x_job *job)
        /* schedule a submit complete interrupt */
        err = host1x_intr_add_action(host, sp, syncval,
                                     HOST1X_INTR_ACTION_SUBMIT_COMPLETE, ch,
-                                    completed_waiter, NULL);
+                                    completed_waiter, &job->waiter);
        completed_waiter = NULL;
        WARN(err, "Failed to set submit complete interrupt");