Commit 5f6c871f authored by Gerd Hoffmann's avatar Gerd Hoffmann
Browse files

drm/qxl: properly free qxl releases



Reorganize qxl_device_fini() a bit.
Add missing unpin() calls.

Count releases.  Add wait queue for releases.  That way
qxl_device_fini() can easily wait until everything is
ready for proper shutdown.

Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
Acked-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Link: http://patchwork.freedesktop.org/patch/msgid/20210204145712.1531203-9-kraxel@redhat.com
parent a7709b9b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ int qxl_garbage_collect(struct qxl_device *qdev)
		}
	}

	wake_up_all(&qdev->release_event);
	DRM_DEBUG_DRIVER("%d\n", i);

	return i;
+2 −0
Original line number Diff line number Diff line
@@ -214,6 +214,8 @@ struct qxl_device {
	spinlock_t	release_lock;
	struct idr	release_idr;
	uint32_t	release_seqno;
	atomic_t	release_count;
	wait_queue_head_t release_event;
	spinlock_t release_idr_lock;
	struct mutex	async_io_mutex;
	unsigned int last_sent_io_cmd;
+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ int qxl_irq_init(struct qxl_device *qdev)
	init_waitqueue_head(&qdev->display_event);
	init_waitqueue_head(&qdev->cursor_event);
	init_waitqueue_head(&qdev->io_cmd_event);
	init_waitqueue_head(&qdev->release_event);
	INIT_WORK(&qdev->client_monitors_config_work,
		  qxl_client_monitors_config_work_func);
	atomic_set(&qdev->irq_received, 0);
+23 −3
Original line number Diff line number Diff line
@@ -286,11 +286,31 @@ int qxl_device_init(struct qxl_device *qdev,

void qxl_device_fini(struct qxl_device *qdev)
{
	qxl_bo_unref(&qdev->current_release_bo[0]);
	qxl_bo_unref(&qdev->current_release_bo[1]);
	int cur_idx;

	for (cur_idx = 0; cur_idx < 3; cur_idx++) {
		if (!qdev->current_release_bo[cur_idx])
			continue;
		qxl_bo_unpin(qdev->current_release_bo[cur_idx]);
		qxl_bo_unref(&qdev->current_release_bo[cur_idx]);
		qdev->current_release_bo_offset[cur_idx] = 0;
		qdev->current_release_bo[cur_idx] = NULL;
	}

	/*
	 * Ask host to release resources (+fill release ring),
	 * then wait for the release actually happening.
	 */
	qxl_io_notify_oom(qdev);
	wait_event_timeout(qdev->release_event,
			   atomic_read(&qdev->release_count) == 0,
			   HZ);
	flush_work(&qdev->gc_work);
	qxl_surf_evict(qdev);
	qxl_vram_evict(qdev);

	qxl_gem_fini(qdev);
	qxl_bo_fini(qdev);
	flush_work(&qdev->gc_work);
	qxl_ring_free(qdev->command_ring);
	qxl_ring_free(qdev->cursor_ring);
	qxl_ring_free(qdev->release_ring);
+2 −0
Original line number Diff line number Diff line
@@ -196,6 +196,7 @@ qxl_release_free(struct qxl_device *qdev,
		qxl_release_free_list(release);
		kfree(release);
	}
	atomic_dec(&qdev->release_count);
}

static int qxl_release_bo_alloc(struct qxl_device *qdev,
@@ -344,6 +345,7 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
			*rbo = NULL;
		return idr_ret;
	}
	atomic_inc(&qdev->release_count);

	mutex_lock(&qdev->release_mutex);
	if (qdev->current_release_bo_offset[cur_idx] + 1 >= releases_per_bo[cur_idx]) {