From e97ce5ceb5f8f8f33a492e62936eb6eae52b09e6 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/adreno.c | 2 +- drivers/gpu/msm/kgsl.c | 26 +++++++++++--------------- drivers/gpu/msm/kgsl.h | 4 ++-- drivers/gpu/msm/kgsl_device.h | 3 ++- drivers/gpu/msm/kgsl_events.c | 15 ++++++++------- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index aa5589b7bf54..a37aa033ed98 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1746,7 +1746,7 @@ static int adreno_pm_suspend(struct device *dev) if (status) return status; - flush_workqueue(device->events_wq); + kthread_flush_worker(device->events_worker); flush_workqueue(kgsl_driver.mem_workqueue); return status; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 0699fdadade3..328ea61b46a8 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -686,11 +686,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); } @@ -4526,15 +4526,16 @@ int kgsl_device_platform_probe(struct kgsl_device *device) device->pwrctrl.interrupt_num = status; disable_irq(device->pwrctrl.interrupt_num); - 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); + /* This can return -EPROBE_DEFER */ status = kgsl_mmu_probe(device); if (status != 0) @@ -4559,10 +4560,8 @@ int kgsl_device_platform_probe(struct kgsl_device *device) return 0; 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: @@ -4572,10 +4571,7 @@ error: 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); kgsl_device_snapshot_close(device); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 4698aacf94cf..e86051f9aa57 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -295,7 +295,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 */ @@ -307,7 +307,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 3d3cfdab5128..0b4a6c01d1d0 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __KGSL_DEVICE_H #define __KGSL_DEVICE_H @@ -293,7 +294,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; /* Number of active contexts seen globally for this device */ int active_context_count; diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index 891c662ea339..674a3dc13e2c 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); @@ -268,7 +269,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); @@ -283,7 +284,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; }