From b25c4f30abff96848aed3ec4448cd7384c252a1f Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Fri, 6 Dec 2024 13:06:02 +0530 Subject: [PATCH] msm: kgsl: Use kthread instead of workqueue for event work Currently a workqueue is being used to process the event work. In certain scenarios like when most of CPU cores are busy, there can be a significant delay between the actual timestamp retire event and when the work is processed by the events workqueue as workqueues cannot have RT priority. Hence use kthread instead of workqueue for event work. Change-Id: Ib1ec7fa1ec3a133d03104c9a029dcc4c06180609 Signed-off-by: Puranam V G Tejaswi Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/kgsl.c | 26 +++++++++++--------------- drivers/gpu/msm/kgsl.h | 4 ++-- drivers/gpu/msm/kgsl_device.h | 4 ++-- drivers/gpu/msm/kgsl_events.c | 15 ++++++++------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 1b46bb3504a9..6242852b3880 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -609,11 +609,11 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, if (id == -ENOSPC) { /* * Before declaring that there are no contexts left try - * flushing the event workqueue just in case there are + * flushing the event worker just in case there are * detached contexts waiting to finish */ - flush_workqueue(device->events_wq); + kthread_flush_worker(device->events_worker); id = _kgsl_get_context_id(device); } @@ -5334,15 +5334,16 @@ int kgsl_device_platform_probe(struct kgsl_device *device) if (status) goto error; - device->events_wq = alloc_workqueue("kgsl-events", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0); + device->events_worker = kthread_create_worker(0, "kgsl-events"); - if (!device->events_wq) { - dev_err(device->dev, "Failed to allocate events workqueue\n"); - status = -ENOMEM; + if (IS_ERR(device->events_worker)) { + status = PTR_ERR(device->events_worker); + dev_err(device->dev, "Failed to create events worker ret=%d\n", status); goto error_pwrctrl_close; } + sched_set_fifo(device->events_worker->task); + if (!devm_request_mem_region(device->dev, device->reg_phys, device->reg_len, device->name)) { dev_err(device->dev, "request_mem_region failed\n"); @@ -5442,10 +5443,8 @@ int kgsl_device_platform_probe(struct kgsl_device *device) error_close_mmu: kgsl_mmu_close(device); error_pwrctrl_close: - if (device->events_wq) { - destroy_workqueue(device->events_wq); - device->events_wq = NULL; - } + if (!IS_ERR(device->events_worker)) + kthread_destroy_worker(device->events_worker); kgsl_pwrctrl_close(device); error: @@ -5457,10 +5456,7 @@ EXPORT_SYMBOL(kgsl_device_platform_probe); void kgsl_device_platform_remove(struct kgsl_device *device) { - if (device->events_wq) { - destroy_workqueue(device->events_wq); - device->events_wq = NULL; - } + kthread_destroy_worker(device->events_worker); kfree(device->dev->dma_parms); device->dev->dma_parms = NULL; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 0dc906aa3d9e..95703d31a659 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -316,7 +316,7 @@ typedef void (*kgsl_event_func)(struct kgsl_device *, struct kgsl_event_group *, * @priv: Private data passed to the callback function * @node: List node for the kgsl_event_group list * @created: Jiffies when the event was created - * @work: Work struct for dispatching the callback + * @work: kthread_work struct for dispatching the callback * @result: KGSL event result type to pass to the callback * group: The event group this event belongs to */ @@ -328,7 +328,7 @@ struct kgsl_event { void *priv; struct list_head node; unsigned int created; - struct work_struct work; + struct kthread_work work; int result; struct kgsl_event_group *group; }; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 55008e288e72..9137fc6138ed 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __KGSL_DEVICE_H #define __KGSL_DEVICE_H @@ -311,7 +311,7 @@ struct kgsl_device { struct kgsl_pwrscale pwrscale; int reset_counter; /* Track how many GPU core resets have occurred */ - struct workqueue_struct *events_wq; + struct kthread_worker *events_worker; struct device *busmondev; /* pseudo dev for GPU BW voting governor */ diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index b2c07c38e0d5..a6705d752299 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -21,17 +22,17 @@ static inline void signal_event(struct kgsl_device *device, { list_del(&event->node); event->result = result; - queue_work(device->events_wq, &event->work); + kthread_queue_work(device->events_worker, &event->work); } /** * _kgsl_event_worker() - Work handler for processing GPU event callbacks - * @work: Pointer to the work_struct for the event + * @work: Pointer to the kthread_work for the event * - * Each event callback has its own work struct and is run on a event specific - * workqeuue. This is the worker that queues up the event callback function. + * Each event callback has its own kthread_work struct and is run on a event specific + * worker thread. This is the worker that queues up the event callback function. */ -static void _kgsl_event_worker(struct work_struct *work) +static void _kgsl_event_worker(struct kthread_work *work) { struct kgsl_event *event = container_of(work, struct kgsl_event, work); int id = KGSL_CONTEXT_ID(event->context); @@ -273,7 +274,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, event->created = jiffies; event->group = group; - INIT_WORK(&event->work, _kgsl_event_worker); + kthread_init_work(&event->work, _kgsl_event_worker); trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func); @@ -288,7 +289,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, if (timestamp_cmp(retired, timestamp) >= 0) { event->result = KGSL_EVENT_RETIRED; - queue_work(device->events_wq, &event->work); + kthread_queue_work(device->events_worker, &event->work); spin_unlock(&group->lock); return 0; }