hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/gpu/drm/v3d/v3d_irq.c
....@@ -4,26 +4,34 @@
44 /**
55 * DOC: Interrupt management for the V3D engine
66 *
7
- * When we take a binning or rendering flush done interrupt, we need
8
- * to signal the fence for that job so that the scheduler can queue up
9
- * the next one and unblock any waiters.
7
+ * When we take a bin, render, TFU done, or CSD done interrupt, we
8
+ * need to signal the fence for that job so that the scheduler can
9
+ * queue up the next one and unblock any waiters.
1010 *
1111 * When we take the binner out of memory interrupt, we need to
1212 * allocate some new memory and pass it to the binner so that the
1313 * current job can make progress.
1414 */
1515
16
+#include <linux/platform_device.h>
17
+
1618 #include "v3d_drv.h"
1719 #include "v3d_regs.h"
20
+#include "v3d_trace.h"
1821
1922 #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
2023 V3D_INT_FLDONE | \
2124 V3D_INT_FRDONE | \
25
+ V3D_INT_CSDDONE | \
2226 V3D_INT_GMPV))
2327
2428 #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
2529 V3D_HUB_INT_MMU_PTI | \
26
- V3D_HUB_INT_MMU_CAP))
30
+ V3D_HUB_INT_MMU_CAP | \
31
+ V3D_HUB_INT_TFUC))
32
+
33
+static irqreturn_t
34
+v3d_hub_irq(int irq, void *arg);
2735
2836 static void
2937 v3d_overflow_mem_work(struct work_struct *work)
....@@ -32,12 +40,14 @@
3240 container_of(work, struct v3d_dev, overflow_mem_work);
3341 struct drm_device *dev = &v3d->drm;
3442 struct v3d_bo *bo = v3d_bo_create(dev, NULL /* XXX: GMP */, 256 * 1024);
43
+ struct drm_gem_object *obj;
3544 unsigned long irqflags;
3645
3746 if (IS_ERR(bo)) {
3847 DRM_ERROR("Couldn't allocate binner overflow mem\n");
3948 return;
4049 }
50
+ obj = &bo->base.base;
4151
4252 /* We lost a race, and our work task came in after the bin job
4353 * completed and exited. This can happen because the HW
....@@ -54,15 +64,15 @@
5464 goto out;
5565 }
5666
57
- drm_gem_object_get(&bo->base);
58
- list_add_tail(&bo->unref_head, &v3d->bin_job->unref_list);
67
+ drm_gem_object_get(obj);
68
+ list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list);
5969 spin_unlock_irqrestore(&v3d->job_lock, irqflags);
6070
6171 V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT);
62
- V3D_CORE_WRITE(0, V3D_PTB_BPOS, bo->base.size);
72
+ V3D_CORE_WRITE(0, V3D_PTB_BPOS, obj->size);
6373
6474 out:
65
- drm_gem_object_put_unlocked(&bo->base);
75
+ drm_gem_object_put(obj);
6676 }
6777
6878 static irqreturn_t
....@@ -80,19 +90,37 @@
8090 if (intsts & V3D_INT_OUTOMEM) {
8191 /* Note that the OOM status is edge signaled, so the
8292 * interrupt won't happen again until the we actually
83
- * add more memory.
93
+ * add more memory. Also, as of V3D 4.1, FLDONE won't
94
+ * be reported until any OOM state has been cleared.
8495 */
8596 schedule_work(&v3d->overflow_mem_work);
8697 status = IRQ_HANDLED;
8798 }
8899
89100 if (intsts & V3D_INT_FLDONE) {
90
- dma_fence_signal(v3d->bin_job->bin.done_fence);
101
+ struct v3d_fence *fence =
102
+ to_v3d_fence(v3d->bin_job->base.irq_fence);
103
+
104
+ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
105
+ dma_fence_signal(&fence->base);
91106 status = IRQ_HANDLED;
92107 }
93108
94109 if (intsts & V3D_INT_FRDONE) {
95
- dma_fence_signal(v3d->render_job->render.done_fence);
110
+ struct v3d_fence *fence =
111
+ to_v3d_fence(v3d->render_job->base.irq_fence);
112
+
113
+ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
114
+ dma_fence_signal(&fence->base);
115
+ status = IRQ_HANDLED;
116
+ }
117
+
118
+ if (intsts & V3D_INT_CSDDONE) {
119
+ struct v3d_fence *fence =
120
+ to_v3d_fence(v3d->csd_job->base.irq_fence);
121
+
122
+ trace_v3d_csd_irq(&v3d->drm, fence->seqno);
123
+ dma_fence_signal(&fence->base);
96124 status = IRQ_HANDLED;
97125 }
98126
....@@ -100,7 +128,13 @@
100128 * always-allowed mode.
101129 */
102130 if (intsts & V3D_INT_GMPV)
103
- dev_err(v3d->dev, "GMP violation\n");
131
+ dev_err(v3d->drm.dev, "GMP violation\n");
132
+
133
+ /* V3D 4.2 wires the hub and core IRQs together, so if we &
134
+ * didn't see the common one then check hub for MMU IRQs.
135
+ */
136
+ if (v3d->single_irq_line && status == IRQ_NONE)
137
+ return v3d_hub_irq(irq, arg);
104138
105139 return status;
106140 }
....@@ -117,14 +151,46 @@
117151 /* Acknowledge the interrupts we're handling here. */
118152 V3D_WRITE(V3D_HUB_INT_CLR, intsts);
119153
154
+ if (intsts & V3D_HUB_INT_TFUC) {
155
+ struct v3d_fence *fence =
156
+ to_v3d_fence(v3d->tfu_job->base.irq_fence);
157
+
158
+ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
159
+ dma_fence_signal(&fence->base);
160
+ status = IRQ_HANDLED;
161
+ }
162
+
120163 if (intsts & (V3D_HUB_INT_MMU_WRV |
121164 V3D_HUB_INT_MMU_PTI |
122165 V3D_HUB_INT_MMU_CAP)) {
123166 u32 axi_id = V3D_READ(V3D_MMU_VIO_ID);
124
- u64 vio_addr = (u64)V3D_READ(V3D_MMU_VIO_ADDR) << 8;
167
+ u64 vio_addr = ((u64)V3D_READ(V3D_MMU_VIO_ADDR) <<
168
+ (v3d->va_width - 32));
169
+ static const char *const v3d41_axi_ids[] = {
170
+ "L2T",
171
+ "PTB",
172
+ "PSE",
173
+ "TLB",
174
+ "CLE",
175
+ "TFU",
176
+ "MMU",
177
+ "GMP",
178
+ };
179
+ const char *client = "?";
125180
126
- dev_err(v3d->dev, "MMU error from client %d at 0x%08llx%s%s%s\n",
127
- axi_id, (long long)vio_addr,
181
+ V3D_WRITE(V3D_MMU_CTL,
182
+ V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED |
183
+ V3D_MMU_CTL_PT_INVALID |
184
+ V3D_MMU_CTL_WRITE_VIOLATION));
185
+
186
+ if (v3d->ver >= 41) {
187
+ axi_id = axi_id >> 5;
188
+ if (axi_id < ARRAY_SIZE(v3d41_axi_ids))
189
+ client = v3d41_axi_ids[axi_id];
190
+ }
191
+
192
+ dev_err(v3d->drm.dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
193
+ client, axi_id, (long long)vio_addr,
128194 ((intsts & V3D_HUB_INT_MMU_WRV) ?
129195 ", write violation" : ""),
130196 ((intsts & V3D_HUB_INT_MMU_PTI) ?
....@@ -140,7 +206,7 @@
140206 int
141207 v3d_irq_init(struct v3d_dev *v3d)
142208 {
143
- int ret, core;
209
+ int irq1, ret, core;
144210
145211 INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
146212
....@@ -151,24 +217,38 @@
151217 V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
152218 V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
153219
154
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
155
- v3d_hub_irq, IRQF_SHARED,
156
- "v3d_hub", v3d);
157
- if (ret)
158
- goto fail;
220
+ irq1 = platform_get_irq(v3d_to_pdev(v3d), 1);
221
+ if (irq1 == -EPROBE_DEFER)
222
+ return irq1;
223
+ if (irq1 > 0) {
224
+ ret = devm_request_irq(v3d->drm.dev, irq1,
225
+ v3d_irq, IRQF_SHARED,
226
+ "v3d_core0", v3d);
227
+ if (ret)
228
+ goto fail;
229
+ ret = devm_request_irq(v3d->drm.dev,
230
+ platform_get_irq(v3d_to_pdev(v3d), 0),
231
+ v3d_hub_irq, IRQF_SHARED,
232
+ "v3d_hub", v3d);
233
+ if (ret)
234
+ goto fail;
235
+ } else {
236
+ v3d->single_irq_line = true;
159237
160
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
161
- v3d_irq, IRQF_SHARED,
162
- "v3d_core0", v3d);
163
- if (ret)
164
- goto fail;
238
+ ret = devm_request_irq(v3d->drm.dev,
239
+ platform_get_irq(v3d_to_pdev(v3d), 0),
240
+ v3d_irq, IRQF_SHARED,
241
+ "v3d", v3d);
242
+ if (ret)
243
+ goto fail;
244
+ }
165245
166246 v3d_irq_enable(v3d);
167247 return 0;
168248
169249 fail:
170250 if (ret != -EPROBE_DEFER)
171
- dev_err(v3d->dev, "IRQ setup failed: %d\n", ret);
251
+ dev_err(v3d->drm.dev, "IRQ setup failed: %d\n", ret);
172252 return ret;
173253 }
174254