Files
balgxmr b1fa147c36 [SQUASH]: treewide: Remove perf critical api affining
Revert "kgsl: move worker thread to hp mask"

This reverts commit 9ede9a602a214b9d11b30efb7119fa29176a39a0.

Revert "kernel: irq: manage: use a different way of affining perf IRQs"

This reverts commit 7b6ed81bb5.

Revert "kernel: irq: properly disallow userspace from changing IRQs affinity"

This reverts commit 6192075134.

Revert "kernel: Add a mixed big and prime cluster mode to the perf-critical API."

This reverts commit e8b11fd3fa.

Revert "kernel: Split PF_PERF_CRITICAL into 6 standalone flags"

This reverts commit 514e32786f.

Revert "drm: Affine IRQ to the prime CPU cluster"

This reverts commit a2e2127328b5fae0e306ba43a9509d4efdd25166.

Revert "simple_lmk: Run reclaim kthread on big CPU cluster"

This reverts commit 5cc18c8f61.

Revert "msm_thermal_simple: update for prime affining"

This reverts commit f6250a3c23.

Revert "devfreq_boost: Run boost kthreads on big CPU cluster"

This reverts commit 4476a2602b.

Revert "rcu: Run nocb kthreads on little CPUs"

This reverts commit f1dfdd3bff.

Revert "kernel: Warn when an IRQ's affinity notifier gets overwritten"

This reverts commit e48923d05f.

Revert "kernel: Don't allow IRQ affinity masks to have more than one CPU"

This reverts commit c6074310eb.

Revert "kernel: Extend the perf-critical API to little CPUs"

This reverts commit 57fb9de6b1b3efd9d809cd3b000841cbacd4a82a.

Revert "kernel: Add tri-cluster API to affine IRQs and kthreads to fast CPUs"

This reverts commit f8e46638b4b2752ce15dad1e8f18b90f58d476a1.

Revert "cpumask: Add cpu_hp_mask which contains both the big and prime clusters."

This reverts commit cd8a444526.

Revert "cpumask: Add cpu_hp_mask which contains both the big and prime clusters."

This reverts commit 486f73aa6a34cb24f2844cc377595c77d13bf285.

Revert "[ADAPTED] cpumask: Add cpumasks for first and second Big CPUs on Big cluster"

This reverts commit 216a7226495b68061bafb49a9aad762f5848e7f5.

Revert "input: fingerprint: goodix_ta: Affine IRQ to the big CPU cluster"

This reverts commit 1004d2079b.

treewide: Remove affine

Revert "msm: kgsl: Affine kgsl_3d0_irq and worker kthread to the big CPU cluster"

This reverts commit e8a2c62980.
2023-10-23 14:55:14 -05:00

342 lines
8.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018-2021 Sultan Alsawaf <sultan@kerneltoast.com>.
*/
#define pr_fmt(fmt) "devfreq_boost: " fmt
#include <linux/devfreq_boost.h>
#include <linux/input.h>
#include <linux/kthread.h>
#include <linux/msm_drm_notify.h>
#include <linux/slab.h>
#include <uapi/linux/sched/types.h>
enum {
SCREEN_OFF,
INPUT_BOOST,
MAX_BOOST
};
struct boost_dev {
struct devfreq *df;
struct delayed_work input_unboost;
struct delayed_work max_unboost;
wait_queue_head_t boost_waitq;
atomic_long_t max_boost_expires;
unsigned long boost_freq;
unsigned long state;
};
struct df_boost_drv {
struct boost_dev devices[DEVFREQ_MAX];
struct notifier_block msm_drm_notif;
};
static void devfreq_input_unboost(struct work_struct *work);
static void devfreq_max_unboost(struct work_struct *work);
#define BOOST_DEV_INIT(b, dev, freq) .devices[dev] = { \
.input_unboost = \
__DELAYED_WORK_INITIALIZER((b).devices[dev].input_unboost, \
devfreq_input_unboost, 0), \
.max_unboost = \
__DELAYED_WORK_INITIALIZER((b).devices[dev].max_unboost, \
devfreq_max_unboost, 0), \
.boost_waitq = \
__WAIT_QUEUE_HEAD_INITIALIZER((b).devices[dev].boost_waitq), \
.boost_freq = freq \
}
static struct df_boost_drv df_boost_drv_g __read_mostly = {
BOOST_DEV_INIT(df_boost_drv_g, DEVFREQ_CPU_LLCC_DDR_BW,
CONFIG_DEVFREQ_CPU_LLCC_DDR_BW_BOOST_FREQ)
};
static void __devfreq_boost_kick(struct boost_dev *b)
{
if (!READ_ONCE(b->df) || test_bit(SCREEN_OFF, &b->state))
return;
set_bit(INPUT_BOOST, &b->state);
if (!mod_delayed_work(system_unbound_wq, &b->input_unboost,
msecs_to_jiffies(CONFIG_DEVFREQ_INPUT_BOOST_DURATION_MS))) {
/* Set the bit again in case we raced with the unboost worker */
set_bit(INPUT_BOOST, &b->state);
wake_up(&b->boost_waitq);
}
}
void devfreq_boost_kick(enum df_device device)
{
struct df_boost_drv *d = &df_boost_drv_g;
__devfreq_boost_kick(&d->devices[device]);
}
static void __devfreq_boost_kick_max(struct boost_dev *b,
unsigned int duration_ms)
{
unsigned long boost_jiffies, curr_expires, new_expires;
if (!READ_ONCE(b->df) || test_bit(SCREEN_OFF, &b->state))
return;
boost_jiffies = msecs_to_jiffies(duration_ms);
do {
curr_expires = atomic_long_read(&b->max_boost_expires);
new_expires = jiffies + boost_jiffies;
/* Skip this boost if there's a longer boost in effect */
if (time_after(curr_expires, new_expires))
return;
} while (atomic_long_cmpxchg(&b->max_boost_expires, curr_expires,
new_expires) != curr_expires);
set_bit(MAX_BOOST, &b->state);
if (!mod_delayed_work(system_unbound_wq, &b->max_unboost,
boost_jiffies)) {
/* Set the bit again in case we raced with the unboost worker */
set_bit(MAX_BOOST, &b->state);
wake_up(&b->boost_waitq);
}
}
void devfreq_boost_kick_max(enum df_device device, unsigned int duration_ms)
{
struct df_boost_drv *d = &df_boost_drv_g;
__devfreq_boost_kick_max(&d->devices[device], duration_ms);
}
void devfreq_register_boost_device(enum df_device device, struct devfreq *df)
{
struct df_boost_drv *d = &df_boost_drv_g;
struct boost_dev *b;
df->is_boost_device = true;
b = &d->devices[device];
WRITE_ONCE(b->df, df);
}
static void devfreq_input_unboost(struct work_struct *work)
{
struct boost_dev *b = container_of(to_delayed_work(work), typeof(*b),
input_unboost);
clear_bit(INPUT_BOOST, &b->state);
wake_up(&b->boost_waitq);
}
static void devfreq_max_unboost(struct work_struct *work)
{
struct boost_dev *b = container_of(to_delayed_work(work), typeof(*b),
max_unboost);
clear_bit(MAX_BOOST, &b->state);
wake_up(&b->boost_waitq);
}
static void devfreq_update_boosts(struct boost_dev *b, unsigned long state)
{
struct devfreq *df = b->df;
mutex_lock(&df->lock);
if (state & BIT(SCREEN_OFF)) {
df->min_freq = df->profile->freq_table[0];
df->max_boost = false;
} else {
df->min_freq = state & BIT(INPUT_BOOST) ?
min(b->boost_freq, df->max_freq) :
df->profile->freq_table[0];
df->max_boost = state & BIT(MAX_BOOST);
}
update_devfreq(df);
mutex_unlock(&df->lock);
}
static int devfreq_boost_thread(void *data)
{
static const struct sched_param sched_max_rt_prio = {
.sched_priority = MAX_RT_PRIO - 1
};
struct boost_dev *b = data;
unsigned long old_state = 0;
sched_setscheduler_nocheck(current, SCHED_FIFO, &sched_max_rt_prio);
while (1) {
bool should_stop = false;
unsigned long curr_state;
wait_event_interruptible(b->boost_waitq,
(curr_state = READ_ONCE(b->state)) != old_state ||
(should_stop = kthread_should_stop()));
if (should_stop)
break;
if (old_state != curr_state) {
devfreq_update_boosts(b, curr_state);
old_state = curr_state;
}
}
return 0;
}
static int msm_drm_notifier_cb(struct notifier_block *nb,
unsigned long action, void *data)
{
struct df_boost_drv *d = container_of(nb, typeof(*d), msm_drm_notif);
int i, *blank = ((struct msm_drm_notifier *)data)->data;
/* Parse DRM blank events as soon as they occur */
if (action != MSM_DRM_EARLY_EVENT_BLANK)
return NOTIFY_OK;
/* Boost when the screen turns on and unboost when it turns off */
for (i = 0; i < DEVFREQ_MAX; i++) {
struct boost_dev *b = &d->devices[i];
if (*blank == MSM_DRM_BLANK_UNBLANK) {
clear_bit(SCREEN_OFF, &b->state);
__devfreq_boost_kick_max(b,
CONFIG_DEVFREQ_WAKE_BOOST_DURATION_MS);
} else {
set_bit(SCREEN_OFF, &b->state);
wake_up(&b->boost_waitq);
}
}
return NOTIFY_OK;
}
static void devfreq_boost_input_event(struct input_handle *handle,
unsigned int type, unsigned int code,
int value)
{
struct df_boost_drv *d = handle->handler->private;
int i;
for (i = 0; i < DEVFREQ_MAX; i++)
__devfreq_boost_kick(&d->devices[i]);
}
static int devfreq_boost_input_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct input_handle *handle;
int ret;
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "devfreq_boost_handle";
ret = input_register_handle(handle);
if (ret)
goto free_handle;
ret = input_open_device(handle);
if (ret)
goto unregister_handle;
return 0;
unregister_handle:
input_unregister_handle(handle);
free_handle:
kfree(handle);
return ret;
}
static void devfreq_boost_input_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}
static const struct input_device_id devfreq_boost_ids[] = {
/* Multi-touch touchscreen */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_ABS) },
.absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
BIT_MASK(ABS_MT_POSITION_X) |
BIT_MASK(ABS_MT_POSITION_Y) }
},
/* Touchpad */
{
.flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
.absbit = { [BIT_WORD(ABS_X)] =
BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }
},
/* Keypad */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_KEY) }
},
{ }
};
static struct input_handler devfreq_boost_input_handler = {
.event = devfreq_boost_input_event,
.connect = devfreq_boost_input_connect,
.disconnect = devfreq_boost_input_disconnect,
.name = "devfreq_boost_handler",
.id_table = devfreq_boost_ids
};
static int __init devfreq_boost_init(void)
{
struct df_boost_drv *d = &df_boost_drv_g;
struct task_struct *thread[DEVFREQ_MAX];
int i, ret;
for (i = 0; i < DEVFREQ_MAX; i++) {
struct boost_dev *b = &d->devices[i];
thread[i] = kthread_run(devfreq_boost_thread, b,
"devfreq_boostd/%d", i);
if (IS_ERR(thread[i])) {
ret = PTR_ERR(thread[i]);
pr_err("Failed to create kthread, err: %d\n", ret);
goto stop_kthreads;
}
}
devfreq_boost_input_handler.private = d;
ret = input_register_handler(&devfreq_boost_input_handler);
if (ret) {
pr_err("Failed to register input handler, err: %d\n", ret);
goto stop_kthreads;
}
d->msm_drm_notif.notifier_call = msm_drm_notifier_cb;
d->msm_drm_notif.priority = INT_MAX;
ret = msm_drm_register_client(&d->msm_drm_notif);
if (ret) {
pr_err("Failed to register msm_drm notifier, err: %d\n", ret);
goto unregister_handler;
}
return 0;
unregister_handler:
input_unregister_handler(&devfreq_boost_input_handler);
stop_kthreads:
while (i--)
kthread_stop(thread[i]);
return ret;
}
late_initcall(devfreq_boost_init);