Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 713f0247 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Keep the context alive until its fences signal"

parents cbd97cb4 db3cf7f3
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -698,8 +698,7 @@ void kgsl_context_detach(struct kgsl_context *context)
	/* Remove the event group from the list */
	kgsl_del_event_group(&context->events);

	kgsl_sync_timeline_put(context->ktimeline);

	kgsl_sync_timeline_detach(context->ktimeline);
	kgsl_context_put(context);
}

@@ -718,6 +717,8 @@ kgsl_context_destroy(struct kref *kref)
	 */
	BUG_ON(!kgsl_context_detached(context));

	kgsl_sync_timeline_put(context->ktimeline);

	write_lock(&device->context_lock);
	if (context->id != KGSL_CONTEXT_INVALID) {

@@ -741,7 +742,6 @@ kgsl_context_destroy(struct kref *kref)
		context->id = KGSL_CONTEXT_INVALID;
	}
	write_unlock(&device->context_lock);
	kgsl_sync_timeline_destroy(context);
	kgsl_process_private_put(context->proc_priv);

	device->ftbl->drawctxt_destroy(context);
+43 −23
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/file.h>
@@ -249,27 +249,41 @@ static void kgsl_sync_timeline_value_str(struct dma_fence *fence,
{
	struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
	struct kgsl_sync_timeline *ktimeline = kfence->parent;
	struct kgsl_context *context = NULL;
	unsigned long flags;
	int ret = 0;

	unsigned int timestamp_retired = 0;
	unsigned int timestamp_queued = 0;
	unsigned int timestamp_retired;
	unsigned int timestamp_queued;

	if (!kref_get_unless_zero(&ktimeline->kref))
		return;
	if (!ktimeline->device)
		goto put_timeline;

	/*
	 * ktimeline->device might be NULL here but kgsl_readtimestamp()
	 * will handle that correctly
	 */
	kgsl_readtimestamp(ktimeline->device, ktimeline->context,
	spin_lock_irqsave(&ktimeline->lock, flags);
	ret = _kgsl_context_get(ktimeline->context);
	context = ret ? ktimeline->context : NULL;
	spin_unlock_irqrestore(&ktimeline->lock, flags);

	/* Get the last signaled timestamp if the context is not valid */
	timestamp_queued = ktimeline->last_timestamp;
	timestamp_retired = timestamp_queued;
	if (context) {
		kgsl_readtimestamp(ktimeline->device, context,
			KGSL_TIMESTAMP_RETIRED, &timestamp_retired);

	kgsl_readtimestamp(ktimeline->device, ktimeline->context,
		kgsl_readtimestamp(ktimeline->device, context,
			KGSL_TIMESTAMP_QUEUED, &timestamp_queued);

		kgsl_context_put(context);
	}

	snprintf(str, size, "%u queued:%u retired:%u",
		ktimeline->last_timestamp,
		timestamp_queued, timestamp_retired);

put_timeline:
	kgsl_sync_timeline_put(ktimeline);
}

@@ -298,7 +312,7 @@ int kgsl_sync_timeline_create(struct kgsl_context *context)
{
	struct kgsl_sync_timeline *ktimeline;

	/* Put context when timeline is released */
	/* Put context at detach time */
	if (!_kgsl_context_get(context))
		return -ENOENT;

@@ -319,6 +333,11 @@ int kgsl_sync_timeline_create(struct kgsl_context *context)
	INIT_LIST_HEAD(&ktimeline->child_list_head);
	spin_lock_init(&ktimeline->lock);
	ktimeline->device = context->device;

	/*
	 * The context pointer is valid till detach time, where we put the
	 * refcount on the context
	 */
	ktimeline->context = context;

	context->ktimeline = ktimeline;
@@ -351,30 +370,31 @@ static void kgsl_sync_timeline_signal(struct kgsl_sync_timeline *ktimeline,
	kgsl_sync_timeline_put(ktimeline);
}

void kgsl_sync_timeline_destroy(struct kgsl_context *context)
void kgsl_sync_timeline_detach(struct kgsl_sync_timeline *ktimeline)
{
	struct kgsl_sync_timeline *ktimeline = context->ktimeline;
	unsigned long flags;
	struct kgsl_context *context = ktimeline->context;

	kfree(ktimeline->name);
	kfree(ktimeline);
	/* Set context pointer to NULL and drop our refcount on the context */
	spin_lock_irqsave(&ktimeline->lock, flags);
	ktimeline->context = NULL;
	spin_unlock_irqrestore(&ktimeline->lock, flags);
	kgsl_context_put(context);
}

static void kgsl_sync_timeline_release(struct kref *kref)
static void kgsl_sync_timeline_destroy(struct kref *kref)
{
	struct kgsl_sync_timeline *ktimeline =
		container_of(kref, struct kgsl_sync_timeline, kref);

	/*
	 * Only put the context refcount here. The context destroy function
	 * will call kgsl_sync_timeline_destroy() to kfree it
	 */
	kgsl_context_put(ktimeline->context);
	kfree(ktimeline->name);
	kfree(ktimeline);
}

void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline)
{
	if (ktimeline)
		kref_put(&ktimeline->kref, kgsl_sync_timeline_release);
		kref_put(&ktimeline->kref, kgsl_sync_timeline_destroy);
}

static const struct dma_fence_ops kgsl_sync_fence_ops = {
+6 −4
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2014,2018-2020 The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2014,2018-2021 The Linux Foundation. All rights reserved.
 */
#ifndef __KGSL_SYNC_H
#define __KGSL_SYNC_H
@@ -9,7 +9,8 @@

/**
 * struct kgsl_sync_timeline - A sync timeline associated with a kgsl context
 * @kref: Refcount to keep the struct alive until all its fences are released
 * @kref: Refcount to keep the struct alive until all its fences are signaled,
	  and as long as the context exists
 * @name: String to describe this timeline
 * @fence_context: Used by the fence driver to identify fences belonging to
 *		   this context
@@ -80,7 +81,7 @@ int kgsl_add_fence_event(struct kgsl_device *device,

int kgsl_sync_timeline_create(struct kgsl_context *context);

void kgsl_sync_timeline_destroy(struct kgsl_context *context);
void kgsl_sync_timeline_detach(struct kgsl_sync_timeline *ktimeline);

void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline);

@@ -118,7 +119,8 @@ static inline int kgsl_sync_timeline_create(struct kgsl_context *context)
	return 0;
}

static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
static inline void kgsl_sync_timeline_detach(
					struct kgsl_sync_timeline *ktimeline)
{
}