msm: kgsl: Keep the context alive until its fences signal
The context is currently kept alive until all its fences are released. This means that we do not destroy a context until all the fence fds associated with it are closed by userspace, which may be a long time. Instead, remove the timeline's refcount on its context when it is detached. This permits the context to be freed once all its fences signal. Change-Id: Ifc5dd55980358ddbb4d3f6220d8b5d9f725aed1b Signed-off-by: Lynus Vaz <lvaz@codeaurora.org> Signed-off-by: Hareesh Gundu <hareeshg@codeaurora.org>
This commit is contained in:
parent
bca4e894c5
commit
5eafefa5f1
@ -758,8 +758,7 @@ void kgsl_context_detach(struct kgsl_context *context)
|
||||
/* Remove the event group from the list */
|
||||
kgsl_del_event_group(device, &context->events);
|
||||
|
||||
kgsl_sync_timeline_put(context->ktimeline);
|
||||
|
||||
kgsl_sync_timeline_detach(context->ktimeline);
|
||||
kgsl_context_put(context);
|
||||
}
|
||||
|
||||
@ -778,6 +777,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) {
|
||||
|
||||
@ -801,7 +802,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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2019, 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,
|
||||
KGSL_TIMESTAMP_RETIRED, ×tamp_retired);
|
||||
spin_lock_irqsave(&ktimeline->lock, flags);
|
||||
ret = _kgsl_context_get(ktimeline->context);
|
||||
context = ret ? ktimeline->context : NULL;
|
||||
spin_unlock_irqrestore(&ktimeline->lock, flags);
|
||||
|
||||
kgsl_readtimestamp(ktimeline->device, ktimeline->context,
|
||||
KGSL_TIMESTAMP_QUEUED, ×tamp_queued);
|
||||
/* 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, ×tamp_retired);
|
||||
|
||||
kgsl_readtimestamp(ktimeline->device, context,
|
||||
KGSL_TIMESTAMP_QUEUED, ×tamp_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;
|
||||
|
||||
@ -320,6 +334,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;
|
||||
@ -352,27 +371,30 @@ 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)
|
||||
{
|
||||
kfree(context->ktimeline);
|
||||
unsigned long flags;
|
||||
struct kgsl_context *context = ktimeline->context;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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 = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2014,2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2014,2018-2019, 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,7 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user