Skip to content

Commit da4ce47

Browse files
committed
Merge branch 'etnaviv/fixes' of https://git.pengutronix.de/git/lst/linux into drm-fixes
Fixes a very annoying issue where the driver view of the MMU state gets out of sync with the actual hardware state across a runtime PM cycle, so we end up restarting the GPU with the wrong (potentially already freed) MMU context. Hilarity ensues. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Lucas Stach <l.stach@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/729a561b6cfed090457bcc856a9e14ed6209fe21.camel@pengutronix.de
2 parents 6880fa6 + f2faea8 commit da4ce47

File tree

9 files changed

+45
-25
lines changed

9 files changed

+45
-25
lines changed

drivers/gpu/drm/etnaviv/etnaviv_buffer.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
397397
if (switch_mmu_context) {
398398
struct etnaviv_iommu_context *old_context = gpu->mmu_context;
399399

400-
etnaviv_iommu_context_get(mmu_context);
401-
gpu->mmu_context = mmu_context;
400+
gpu->mmu_context = etnaviv_iommu_context_get(mmu_context);
402401
etnaviv_iommu_context_put(old_context);
403402
}
404403

drivers/gpu/drm/etnaviv/etnaviv_gem.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
294294
list_del(&mapping->obj_node);
295295
}
296296

297-
etnaviv_iommu_context_get(mmu_context);
298-
mapping->context = mmu_context;
297+
mapping->context = etnaviv_iommu_context_get(mmu_context);
299298
mapping->use = 1;
300299

301300
ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,

drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
532532
goto err_submit_objects;
533533

534534
submit->ctx = file->driver_priv;
535-
etnaviv_iommu_context_get(submit->ctx->mmu);
536-
submit->mmu_context = submit->ctx->mmu;
535+
submit->mmu_context = etnaviv_iommu_context_get(submit->ctx->mmu);
537536
submit->exec_state = args->exec_state;
538537
submit->flags = args->flags;
539538

drivers/gpu/drm/etnaviv/etnaviv_gpu.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,12 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
569569
/* We rely on the GPU running, so program the clock */
570570
etnaviv_gpu_update_clock(gpu);
571571

572+
gpu->fe_running = false;
573+
gpu->exec_state = -1;
574+
if (gpu->mmu_context)
575+
etnaviv_iommu_context_put(gpu->mmu_context);
576+
gpu->mmu_context = NULL;
577+
572578
return 0;
573579
}
574580

@@ -637,19 +643,23 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
637643
VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE |
638644
VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch));
639645
}
646+
647+
gpu->fe_running = true;
640648
}
641649

642-
static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu)
650+
static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu,
651+
struct etnaviv_iommu_context *context)
643652
{
644-
u32 address = etnaviv_cmdbuf_get_va(&gpu->buffer,
645-
&gpu->mmu_context->cmdbuf_mapping);
646653
u16 prefetch;
654+
u32 address;
647655

648656
/* setup the MMU */
649-
etnaviv_iommu_restore(gpu, gpu->mmu_context);
657+
etnaviv_iommu_restore(gpu, context);
650658

651659
/* Start command processor */
652660
prefetch = etnaviv_buffer_init(gpu);
661+
address = etnaviv_cmdbuf_get_va(&gpu->buffer,
662+
&gpu->mmu_context->cmdbuf_mapping);
653663

654664
etnaviv_gpu_start_fe(gpu, address, prefetch);
655665
}
@@ -832,7 +842,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
832842
/* Now program the hardware */
833843
mutex_lock(&gpu->lock);
834844
etnaviv_gpu_hw_init(gpu);
835-
gpu->exec_state = -1;
836845
mutex_unlock(&gpu->lock);
837846

838847
pm_runtime_mark_last_busy(gpu->dev);
@@ -1057,8 +1066,6 @@ void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu)
10571066
spin_unlock(&gpu->event_spinlock);
10581067

10591068
etnaviv_gpu_hw_init(gpu);
1060-
gpu->exec_state = -1;
1061-
gpu->mmu_context = NULL;
10621069

10631070
mutex_unlock(&gpu->lock);
10641071
pm_runtime_mark_last_busy(gpu->dev);
@@ -1370,14 +1377,12 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit)
13701377
goto out_unlock;
13711378
}
13721379

1373-
if (!gpu->mmu_context) {
1374-
etnaviv_iommu_context_get(submit->mmu_context);
1375-
gpu->mmu_context = submit->mmu_context;
1376-
etnaviv_gpu_start_fe_idleloop(gpu);
1377-
} else {
1378-
etnaviv_iommu_context_get(gpu->mmu_context);
1379-
submit->prev_mmu_context = gpu->mmu_context;
1380-
}
1380+
if (!gpu->fe_running)
1381+
etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context);
1382+
1383+
if (submit->prev_mmu_context)
1384+
etnaviv_iommu_context_put(submit->prev_mmu_context);
1385+
submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context);
13811386

13821387
if (submit->nr_pmrs) {
13831388
gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre;
@@ -1579,7 +1584,7 @@ int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms)
15791584

15801585
static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
15811586
{
1582-
if (gpu->initialized && gpu->mmu_context) {
1587+
if (gpu->initialized && gpu->fe_running) {
15831588
/* Replace the last WAIT with END */
15841589
mutex_lock(&gpu->lock);
15851590
etnaviv_buffer_end(gpu);
@@ -1592,8 +1597,7 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
15921597
*/
15931598
etnaviv_gpu_wait_idle(gpu, 100);
15941599

1595-
etnaviv_iommu_context_put(gpu->mmu_context);
1596-
gpu->mmu_context = NULL;
1600+
gpu->fe_running = false;
15971601
}
15981602

15991603
gpu->exec_state = -1;
@@ -1741,6 +1745,9 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
17411745
etnaviv_gpu_hw_suspend(gpu);
17421746
#endif
17431747

1748+
if (gpu->mmu_context)
1749+
etnaviv_iommu_context_put(gpu->mmu_context);
1750+
17441751
if (gpu->initialized) {
17451752
etnaviv_cmdbuf_free(&gpu->buffer);
17461753
etnaviv_iommu_global_fini(gpu);

drivers/gpu/drm/etnaviv/etnaviv_gpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ struct etnaviv_gpu {
101101
struct workqueue_struct *wq;
102102
struct drm_gpu_scheduler sched;
103103
bool initialized;
104+
bool fe_running;
104105

105106
/* 'ring'-buffer: */
106107
struct etnaviv_cmdbuf buffer;

drivers/gpu/drm/etnaviv/etnaviv_iommu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ static void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu,
9292
struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);
9393
u32 pgtable;
9494

95+
if (gpu->mmu_context)
96+
etnaviv_iommu_context_put(gpu->mmu_context);
97+
gpu->mmu_context = etnaviv_iommu_context_get(context);
98+
9599
/* set base addresses */
96100
gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, context->global->memory_base);
97101
gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, context->global->memory_base);

drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu,
172172
if (gpu_read(gpu, VIVS_MMUv2_CONTROL) & VIVS_MMUv2_CONTROL_ENABLE)
173173
return;
174174

175+
if (gpu->mmu_context)
176+
etnaviv_iommu_context_put(gpu->mmu_context);
177+
gpu->mmu_context = etnaviv_iommu_context_get(context);
178+
175179
prefetch = etnaviv_buffer_config_mmuv2(gpu,
176180
(u32)v2_context->mtlb_dma,
177181
(u32)context->global->bad_page_dma);
@@ -192,6 +196,10 @@ static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu,
192196
if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) & VIVS_MMUv2_SEC_CONTROL_ENABLE)
193197
return;
194198

199+
if (gpu->mmu_context)
200+
etnaviv_iommu_context_put(gpu->mmu_context);
201+
gpu->mmu_context = etnaviv_iommu_context_get(context);
202+
195203
gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_LOW,
196204
lower_32_bits(context->global->v2.pta_dma));
197205
gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_HIGH,

drivers/gpu/drm/etnaviv/etnaviv_mmu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context,
199199
*/
200200
list_for_each_entry_safe(m, n, &list, scan_node) {
201201
etnaviv_iommu_remove_mapping(context, m);
202+
etnaviv_iommu_context_put(m->context);
202203
m->context = NULL;
203204
list_del_init(&m->mmu_node);
204205
list_del_init(&m->scan_node);

drivers/gpu/drm/etnaviv/etnaviv_mmu.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,11 @@ void etnaviv_iommu_dump(struct etnaviv_iommu_context *ctx, void *buf);
105105
struct etnaviv_iommu_context *
106106
etnaviv_iommu_context_init(struct etnaviv_iommu_global *global,
107107
struct etnaviv_cmdbuf_suballoc *suballoc);
108-
static inline void etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx)
108+
static inline struct etnaviv_iommu_context *
109+
etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx)
109110
{
110111
kref_get(&ctx->refcount);
112+
return ctx;
111113
}
112114
void etnaviv_iommu_context_put(struct etnaviv_iommu_context *ctx);
113115
void etnaviv_iommu_restore(struct etnaviv_gpu *gpu,

0 commit comments

Comments
 (0)