Skip to content

Commit

Permalink
kgsl: convert some workqueues to use kthreads
Browse files Browse the repository at this point in the history
adreno_dispatch_work and _kgsl_event_worker are both low-latency
low-runtime functions that are in the critical path of GPU
rendering. Moving them out of workqueues and into a dedicated FIFO
kthread avoids significant jitter.

bug 30342017

Change-Id: I5feb4e829064d422b4b9af2acb449afd1f981899
[Francisco: adapted to Shamu from Marlin]
Signed-off-by: Francisco Franco <[email protected]>
  • Loading branch information
franciscofranco authored and holyangel committed Oct 1, 2018
1 parent dadf6b9 commit 8a80685
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 9 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/msm/adreno.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ struct adreno_dispatcher {
struct kgsl_cmdbatch *cmdqueue[ADRENO_DISPATCH_CMDQUEUE_SIZE];
unsigned int head;
unsigned int tail;
struct work_struct work;
struct kthread_work work;
struct kobject kobj;
struct completion idle_gate;
};
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/msm/adreno_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,7 +1412,7 @@ static void _print_recovery(struct kgsl_device *device,
*
* Process expired commands and send new ones.
*/
static void adreno_dispatcher_work(struct work_struct *work)
static void adreno_dispatcher_work(struct kthread_work *work)
{
struct adreno_dispatcher *dispatcher =
container_of(work, struct adreno_dispatcher, work);
Expand Down Expand Up @@ -1601,7 +1601,7 @@ void adreno_dispatcher_schedule(struct kgsl_device *device)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;

queue_work(device->work_queue, &dispatcher->work);
queue_kthread_work(&kgsl_driver.worker, &dispatcher->work);
}

/**
Expand Down Expand Up @@ -1881,7 +1881,7 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev)
setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
(unsigned long) adreno_dev);

INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
init_kthread_work(&dispatcher->work, adreno_dispatcher_work);

init_completion(&dispatcher->idle_gate);
complete_all(&dispatcher->idle_gate);
Expand Down
14 changes: 14 additions & 0 deletions drivers/gpu/msm/kgsl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4538,6 +4538,8 @@ static void kgsl_core_exit(void)
static int __init kgsl_core_init(void)
{
int result = 0;
struct sched_param param = { .sched_priority = 2 };

/* alloc major and minor device numbers */
result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX,
"kgsl");
Expand Down Expand Up @@ -4599,6 +4601,18 @@ static int __init kgsl_core_init(void)

kgsl_mmu_set_mmutype(ksgl_mmu_type);

init_kthread_worker(&kgsl_driver.worker);

kgsl_driver.worker_thread = kthread_run(kthread_worker_fn,
&kgsl_driver.worker, "kgsl_worker_thread");

if (IS_ERR(kgsl_driver.worker_thread)) {
pr_err("unable to start kgsl thread\n");
goto err;
}

sched_setscheduler(kgsl_driver.worker_thread, SCHED_FIFO, &param);

kgsl_events_init();

if (kgsl_memfree_hist_init())
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/msm/kgsl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/cdev.h>
#include <linux/regulator/consumer.h>
#include <linux/mm.h>
#include <linux/kthread.h>

/* The number of memstore arrays limits the number of contexts allowed.
* If more contexts are needed, update multiple for MEMSTORE_SIZE
Expand Down Expand Up @@ -107,6 +108,9 @@ struct kgsl_driver {
unsigned int histogram[16];
} stats;
unsigned int full_cache_threshold;

struct kthread_worker worker;
struct task_struct *worker_thread;
};

extern struct kgsl_driver kgsl_driver;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/msm/kgsl_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ struct kgsl_event {
void *priv;
struct list_head node;
unsigned int created;
struct work_struct work;
struct kthread_work work;
int result;
};

Expand Down
8 changes: 4 additions & 4 deletions drivers/gpu/msm/kgsl_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static inline void signal_event(struct kgsl_device *device,
{
list_del(&event->node);
event->result = result;
queue_work(device->events_wq, &event->work);
queue_kthread_work(&kgsl_driver.worker, &event->work);
}

/**
Expand All @@ -39,7 +39,7 @@ static inline void signal_event(struct kgsl_device *device,
* 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.
*/
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);
Expand Down Expand Up @@ -201,7 +201,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group,
event->func = func;
event->created = jiffies;

INIT_WORK(&event->work, _kgsl_event_worker);
init_kthread_work(&event->work, _kgsl_event_worker);

trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func);

Expand All @@ -215,7 +215,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);
queue_kthread_work(&kgsl_driver.worker, &event->work);
spin_unlock(&group->lock);
return 0;
}
Expand Down

0 comments on commit 8a80685

Please sign in to comment.