Commit da4ce47e authored by Dave Airlie's avatar Dave Airlie
Browse files

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: default avatarDave Airlie <airlied@redhat.com>
From: Lucas Stach <l.stach@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/729a561b6cfed090457bcc856a9e14ed6209fe21.camel@pengutronix.de
parents 6880fa6c f2faea8b
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -397,8 +397,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
		if (switch_mmu_context) {
			struct etnaviv_iommu_context *old_context = gpu->mmu_context;

			etnaviv_iommu_context_get(mmu_context);
			gpu->mmu_context = mmu_context;
			gpu->mmu_context = etnaviv_iommu_context_get(mmu_context);
			etnaviv_iommu_context_put(old_context);
		}

+1 −2
Original line number Diff line number Diff line
@@ -294,8 +294,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
		list_del(&mapping->obj_node);
	}

	etnaviv_iommu_context_get(mmu_context);
	mapping->context = mmu_context;
	mapping->context = etnaviv_iommu_context_get(mmu_context);
	mapping->use = 1;

	ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,
+1 −2
Original line number Diff line number Diff line
@@ -532,8 +532,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
		goto err_submit_objects;

	submit->ctx = file->driver_priv;
	etnaviv_iommu_context_get(submit->ctx->mmu);
	submit->mmu_context = submit->ctx->mmu;
	submit->mmu_context = etnaviv_iommu_context_get(submit->ctx->mmu);
	submit->exec_state = args->exec_state;
	submit->flags = args->flags;

+25 −18
Original line number Diff line number Diff line
@@ -569,6 +569,12 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
	/* We rely on the GPU running, so program the clock */
	etnaviv_gpu_update_clock(gpu);

	gpu->fe_running = false;
	gpu->exec_state = -1;
	if (gpu->mmu_context)
		etnaviv_iommu_context_put(gpu->mmu_context);
	gpu->mmu_context = NULL;

	return 0;
}

@@ -637,19 +643,23 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
			  VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE |
			  VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch));
	}

	gpu->fe_running = true;
}

static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu)
static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu,
					  struct etnaviv_iommu_context *context)
{
	u32 address = etnaviv_cmdbuf_get_va(&gpu->buffer,
				&gpu->mmu_context->cmdbuf_mapping);
	u16 prefetch;
	u32 address;

	/* setup the MMU */
	etnaviv_iommu_restore(gpu, gpu->mmu_context);
	etnaviv_iommu_restore(gpu, context);

	/* Start command processor */
	prefetch = etnaviv_buffer_init(gpu);
	address = etnaviv_cmdbuf_get_va(&gpu->buffer,
					&gpu->mmu_context->cmdbuf_mapping);

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

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

	etnaviv_gpu_hw_init(gpu);
	gpu->exec_state = -1;
	gpu->mmu_context = NULL;

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

	if (!gpu->mmu_context) {
		etnaviv_iommu_context_get(submit->mmu_context);
		gpu->mmu_context = submit->mmu_context;
		etnaviv_gpu_start_fe_idleloop(gpu);
	} else {
		etnaviv_iommu_context_get(gpu->mmu_context);
		submit->prev_mmu_context = gpu->mmu_context;
	}
	if (!gpu->fe_running)
		etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context);

	if (submit->prev_mmu_context)
		etnaviv_iommu_context_put(submit->prev_mmu_context);
	submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context);

	if (submit->nr_pmrs) {
		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)

static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
{
	if (gpu->initialized && gpu->mmu_context) {
	if (gpu->initialized && gpu->fe_running) {
		/* Replace the last WAIT with END */
		mutex_lock(&gpu->lock);
		etnaviv_buffer_end(gpu);
@@ -1592,8 +1597,7 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
		 */
		etnaviv_gpu_wait_idle(gpu, 100);

		etnaviv_iommu_context_put(gpu->mmu_context);
		gpu->mmu_context = NULL;
		gpu->fe_running = false;
	}

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

	if (gpu->mmu_context)
		etnaviv_iommu_context_put(gpu->mmu_context);

	if (gpu->initialized) {
		etnaviv_cmdbuf_free(&gpu->buffer);
		etnaviv_iommu_global_fini(gpu);
+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ struct etnaviv_gpu {
	struct workqueue_struct *wq;
	struct drm_gpu_scheduler sched;
	bool initialized;
	bool fe_running;

	/* 'ring'-buffer: */
	struct etnaviv_cmdbuf buffer;
Loading