From b48e8f4f52338c5097588a16b21e979eb0d77e4c Mon Sep 17 00:00:00 2001 From: Andrew Evans Date: Thu, 9 Nov 2023 14:57:57 -0800 Subject: Merge KGSL fixes for January 2024 EMR into android13-msm-pixelwatch-5.15 msm: kgsl: Simplify timelineobj cleanup msm: kgsl: Defer drawobj_sync_timeline_fence_work() to a workqueue Bug: 307604078 Signed-off-by: Andrew Evans (cherry picked from https://partner-android-review.googlesource.com/q/commit:5f0124adcdfe68e348874b5d5b12db3bcae3c104) Merged-In: I82919a18ee097083ca50727ababa5cd69827880c Change-Id: I82919a18ee097083ca50727ababa5cd69827880c --- adreno_dispatch.c | 5 +-- adreno_hwsched.c | 4 +-- kgsl_drawobj.c | 101 +++++++++++++++++++++++++++++++----------------------- kgsl_drawobj.h | 14 ++------ 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/adreno_dispatch.c b/adreno_dispatch.c index bdf5598..7b68256 100644 --- a/adreno_dispatch.c +++ b/adreno_dispatch.c @@ -364,11 +364,8 @@ static int dispatch_retire_syncobj(struct kgsl_drawobj *drawobj, static int drawqueue_retire_timelineobj(struct kgsl_drawobj *drawobj, struct adreno_context *drawctxt) { - struct kgsl_drawobj_timeline *timelineobj = TIMELINEOBJ(drawobj); - _pop_drawobj(drawctxt); - kgsl_drawobj_timelineobj_retire(timelineobj); - + kgsl_drawobj_destroy(drawobj); return 0; } diff --git a/adreno_hwsched.c b/adreno_hwsched.c index cae6a3c..7d35d15 100644 --- a/adreno_hwsched.c +++ b/adreno_hwsched.c @@ -197,10 +197,8 @@ static int _retire_markerobj(struct adreno_device *adreno_dev, struct kgsl_drawo static int _retire_timelineobj(struct kgsl_drawobj *drawobj, struct adreno_context *drawctxt) { - struct kgsl_drawobj_timeline *timelineobj = TIMELINEOBJ(drawobj); - _pop_drawobj(drawctxt); - kgsl_drawobj_timelineobj_retire(timelineobj); + kgsl_drawobj_destroy(drawobj); return 0; } diff --git a/kgsl_drawobj.c b/kgsl_drawobj.c index 19d6a60..f1fdc7b 100644 --- a/kgsl_drawobj.c +++ b/kgsl_drawobj.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ /* @@ -280,7 +280,7 @@ static void drawobj_sync_func(struct kgsl_device *device, kgsl_drawobj_put(&event->syncobj->base); } -static void drawobj_sync_timeline_fence_work(struct irq_work *work) +static void drawobj_sync_timeline_fence_work(struct work_struct *work) { struct kgsl_drawobj_sync_event *event = container_of(work, struct kgsl_drawobj_sync_event, work); @@ -333,7 +333,7 @@ static void drawobj_sync_timeline_fence_callback(struct dma_fence *f, * removing the fence */ if (drawobj_sync_expire(event->device, event)) - irq_work_queue(&event->work); + queue_work(kgsl_driver.lockless_workqueue, &event->work); } static void syncobj_destroy(struct kgsl_drawobj *drawobj) @@ -393,12 +393,16 @@ static void syncobj_destroy(struct kgsl_drawobj *drawobj) } -static void timelineobj_destroy(struct kgsl_drawobj *drawobj) +static void _drawobj_timelineobj_retire(struct kref *kref) { - struct kgsl_drawobj_timeline *timelineobj = TIMELINEOBJ(drawobj); int i; + struct kgsl_drawobj_timeline *timelineobj = container_of(kref, + struct kgsl_drawobj_timeline, sig_refcount); for (i = 0; i < timelineobj->count; i++) { + kgsl_timeline_signal(timelineobj->timelines[i].timeline, + timelineobj->timelines[i].seqno); + kgsl_timeline_put(timelineobj->timelines[i].timeline); kgsl_context_put(timelineobj->timelines[i].context); } @@ -408,6 +412,32 @@ static void timelineobj_destroy(struct kgsl_drawobj *drawobj) timelineobj->count = 0; } +static void kgsl_timelineobj_signal(struct kgsl_drawobj_timeline *timelineobj) +{ + kref_put(&timelineobj->sig_refcount, _drawobj_timelineobj_retire); +} + +static void timelineobj_destroy(struct kgsl_drawobj *drawobj) +{ + struct kgsl_drawobj_timeline *timelineobj = TIMELINEOBJ(drawobj); + int i; + + /* + * At this point any syncobjs blocking this timelinobj have been + * signaled. The timelineobj now only needs all preceding timestamps to + * retire before signaling the timelines. Notify timelines to keep them + * in sync with the timestamps as they retire. + */ + for (i = 0; i < timelineobj->count; i++) + kgsl_timeline_add_signal(&timelineobj->timelines[i]); + + /* + * The scheduler is done with the timelineobj. Put the initial + * sig_refcount to continue with the signaling process. + */ + kgsl_timelineobj_signal(timelineobj); +} + static void bindobj_destroy(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_bind *bindobj = BINDOBJ(drawobj); @@ -547,7 +577,7 @@ static int drawobj_add_sync_timeline(struct kgsl_device *device, event->device = device; event->context = NULL; event->fence = fence; - init_irq_work(&event->work, drawobj_sync_timeline_fence_work); + INIT_WORK(&event->work, drawobj_sync_timeline_fence_work); INIT_LIST_HEAD(&event->cb.node); @@ -938,7 +968,8 @@ kgsl_drawobj_timeline_create(struct kgsl_device *device, * Initialize the sig_refcount that triggers the timeline signal. * This refcount goes to 0 when: * 1) This timelineobj is popped off the context queue. This implies - * any syncobj blocking this timelineobj was already signaled. + * any syncobj blocking this timelineobj was already signaled, or + * the context queue is cleaned up at detach time. * 2) The cmdobjs queued on this context before this timeline object * are retired. */ @@ -950,43 +981,17 @@ kgsl_drawobj_timeline_create(struct kgsl_device *device, return timelineobj; } -static void _drawobj_timelineobj_retire(struct kref *kref) -{ - struct kgsl_drawobj_timeline *timelineobj = container_of(kref, - struct kgsl_drawobj_timeline, sig_refcount); - struct kgsl_drawobj *drawobj = DRAWOBJ(timelineobj); - int i; - - for (i = 0; i < timelineobj->count; i++) - kgsl_timeline_signal(timelineobj->timelines[i].timeline, - timelineobj->timelines[i].seqno); - - /* Now that timelines are signaled destroy the drawobj */ - kgsl_drawobj_destroy(drawobj); -} - static void _timeline_signaled(struct kgsl_device *device, struct kgsl_event_group *group, void *priv, int ret) { struct kgsl_drawobj_timeline *timelineobj = priv; + struct kgsl_drawobj *drawobj = DRAWOBJ(timelineobj); - kref_put(&timelineobj->sig_refcount, _drawobj_timelineobj_retire); -} - -void kgsl_drawobj_timelineobj_retire(struct kgsl_drawobj_timeline *timelineobj) -{ - int i; + /* Put the sig_refcount we took when registering this event */ + kgsl_timelineobj_signal(timelineobj); - /* - * At this point any syncobjs blocking this timelinobj have been - * signaled. The timelineobj now only needs all preceding timestamps to - * retire before signaling the timelines. Notify timelines to keep them - * in sync with the timestamps as they retire. - */ - for (i = 0; i < timelineobj->count; i++) - kgsl_timeline_add_signal(&timelineobj->timelines[i]); - - kref_put(&timelineobj->sig_refcount, _drawobj_timelineobj_retire); + /* Put the drawobj refcount we took when registering this event */ + kgsl_drawobj_put(drawobj); } int kgsl_drawobj_add_timeline(struct kgsl_device_private *dev_priv, @@ -1063,18 +1068,30 @@ int kgsl_drawobj_add_timeline(struct kgsl_device_private *dev_priv, timelineobj->count = cmd.count; /* - * Take a refcount that we put when the last queued timestamp on this - * context is retired. Use a kgsl_event to notify us when this - * timestamp retires. + * Register a kgsl_event to notify us when the last queued timestamp + * retires. Take a refcount on the drawobj to keep it valid for the + * callback, and take the sig_refcount to synchronize with the + * timelineobj retire. Both these refcounts are put in the callback. */ + kref_get(&drawobj->refcount); kref_get(&timelineobj->sig_refcount); ret = kgsl_add_event(device, &context->events, queued, _timeline_signaled, timelineobj); if (ret) - goto err; + goto event_err; return 0; + +event_err: + /* + * If there was an error, put back sig_refcount and drawobj refcounts. + * The caller still holds initial refcounts on both and puts them in + * kgsl_drawobj_destroy(). Clean up the timelinelines array since we + * do not want to signal anything now. + */ + kgsl_timelineobj_signal(timelineobj); + kgsl_drawobj_put(drawobj); err: for (i = 0; i < cmd.count; i++) { kgsl_timeline_put(timelineobj->timelines[i].timeline); diff --git a/kgsl_drawobj.h b/kgsl_drawobj.h index 5f55461..138df54 100644 --- a/kgsl_drawobj.h +++ b/kgsl_drawobj.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __KGSL_DRAWOBJ_H @@ -203,8 +203,8 @@ struct kgsl_drawobj_sync_event { struct dma_fence *fence; /** @cb: Callback struct for KGSL_CMD_SYNCPOINT_TYPE_TIMELINE */ struct dma_fence_cb cb; - /** @work : irq worker for KGSL_CMD_SYNCPOINT_TYPE_TIMELINE */ - struct irq_work work; + /** @work : work_struct for KGSL_CMD_SYNCPOINT_TYPE_TIMELINE */ + struct work_struct work; }; #define KGSL_DRAWOBJ_FLAGS \ @@ -345,12 +345,4 @@ int kgsl_drawobj_add_timeline(struct kgsl_device_private *dev_priv, struct kgsl_drawobj_timeline *timelineobj, void __user *src, u64 cmdsize); -/** - * kgsl_drawobj_timelineobj_retire - Retire the timeline drawobj - * @timelineobj: Pointer to a timeline drawobject - * - * Retire the timelineobj when it is popped off the context queue. - */ -void kgsl_drawobj_timelineobj_retire(struct kgsl_drawobj_timeline *timelineobj); - #endif /* __KGSL_DRAWOBJ_H */ -- cgit v1.2.3