New paste Repaste Download
// SPDX-License-Identifier: GPL-2.0
/*
* KernelSpace Profiles
*
* This Linux kernel module provides a framework for managing and switching between system profiles or modes
* at the kernel level. Each profile represents a specific configuration of kernel features and settings
* optimized for different use cases such as battery life, balanced performance, or maximum performance.
*
* The module supports various subsystems, including MSM DRM, MI DRM, and framebuffer (FB). It integrates
* with these subsystems to receive notifications about screen state changes and adjust the active profile
* accordingly.
*
* The module offers functions for setting the profile mode, overriding the mode temporarily, and retrieving
* the active profile mode. Profiles can be dynamically switched based on system events, user requests, or
* time-based rules.
*
* For more information and usage examples, refer to the README file at:
* https://github.com/beakthoven/Kprofiles/blob/main/README.md
*
* Copyright (C) 2021-2025 Dakkshesh <dakkshesh5@gmail.com>
* Version: 6.0.0
* License: GPL-2.0
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
#include <linux/compiler.h>
#include "version.h"
static BLOCKING_NOTIFIER_HEAD(kp_mode_notifier);
unsigned int KP_MODE_CHANGE = 0x80000000;
EXPORT_SYMBOL_GPL(KP_MODE_CHANGE);
static unsigned int kp_override_mode;
static bool kp_override;
static bool auto_kp __read_mostly = 0;
module_param(auto_kp, bool, 0664);
MODULE_PARM_DESC(auto_kp, "Enable/disable automatic kernel profile management");
static unsigned int kp_mode = CONFIG_KP_DEFAULT_MODE;
static struct kobject *kp_kobj;
DEFINE_MUTEX(kp_set_mode_rb_lock);
#ifdef CONFIG_KP_VERBOSE_DEBUG
#define kp_dbg(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
#else
#define kp_dbg(fmt, ...)
#endif
#define kp_err(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
#define kp_info(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
/*
* Mapping:
* - 0 -> 2 (kprofiles "disabled" behaves like mode 2 to in-kernel users)
* - 1..3 unchanged
*/
static __always_inline unsigned int kp_effective_mode(unsigned int stored)
{
if (stored == 0)
return 2;
return stored;
}
static void kp_trigger_mode_change_event(void);
static __always_inline int __kp_set_mode(unsigned int level)
{
if (unlikely(level > 3))
return -EINVAL;
WRITE_ONCE(kp_mode, level);
return 0;
}
/**
* kp_set_mode_rollback - Change profile to a given mode for a specific duration
* @level: The profile mode level to set (0-3)
* @duration_ms: The duration to keep the profile mode in milliseconds
*
* This function changes the profile to the specified mode for a specific
* duration during any in-kernel event, and then returns to the previously
* active mode.
*
* Usage example: kp_set_mode_rollback(3, 55);
*/
void kp_set_mode_rollback(unsigned int level, unsigned int duration_ms)
{
if (unlikely(level > 3)) {
kp_err("Invalid mode requested, skipping mode change.\n");
return;
}
mutex_lock(&kp_set_mode_rb_lock);
WRITE_ONCE(kp_override_mode, level);
WRITE_ONCE(kp_override, true);
kp_trigger_mode_change_event();
msleep(duration_ms);
WRITE_ONCE(kp_override, false);
kp_trigger_mode_change_event();
mutex_unlock(&kp_set_mode_rb_lock);
}
EXPORT_SYMBOL_GPL(kp_set_mode_rollback);
/**
* kp_set_mode - Change profile to a given mode
* @level: The profile mode level to set (0-3)
*
* This function changes the profile to the specified mode during any
* in-kernel event.
*
* Usage example: kp_set_mode(3);
*/
void kp_set_mode(unsigned int level)
{
int ret = 0;
mutex_lock(&kp_set_mode_rb_lock);
ret = __kp_set_mode(level);
if (ret) {
kp_err("Invalid mode requested, skipping mode change.\n");
mutex_unlock(&kp_set_mode_rb_lock);
return;
}
kp_trigger_mode_change_event();
mutex_unlock(&kp_set_mode_rb_lock);
}
EXPORT_SYMBOL_GPL(kp_set_mode);
/**
* kp_active_mode - Get the currently active profile mode
*
* This function returns a number from 0 to 3 depending on the active profile mode.
* The returned value can be used in conditions to disable/enable or tune kernel
* features according to the profile mode.
*
* Return:
* The currently active profile mode (0-3)
*
* Usage example:
*
* switch (kp_active_mode()) {
* case 1:
*     // Things to be done when battery profile is active
*     break;
* case 2:
*     // Things to be done when balanced profile is active
*     break;
* case 3:
*     // Things to be done when performance profile is active
*     break;
* default:
*     // Things to be done when kprofiles is disabled (forced to balanced in kernel)
*     break;
* }
*/
int kp_active_mode(void)
{
unsigned int mode;
if (READ_ONCE(kp_override)) {
mode = READ_ONCE(kp_override_mode);
if (unlikely(mode > 3))
mode = 0;
return kp_effective_mode(mode);
}
mode = READ_ONCE(kp_mode);
if (unlikely(mode > 3)) {
WRITE_ONCE(kp_mode, 0);
kp_err("Invalid value passed, falling back to level 0\n");
mode = 0;
}
return kp_effective_mode(mode);
}
EXPORT_SYMBOL_GPL(kp_active_mode);
/**
* kp_trigger_mode_change_event - Trigger a mode change event
*
* This function triggers a mode change event by calling the blocking notifier
* chain for kp_mode_notifier. It informs all registered listeners about the
* change in the profile mode.
*/
static __always_inline void kp_trigger_mode_change_event(void)
{
unsigned int current_mode = kp_active_mode();
blocking_notifier_call_chain(&kp_mode_notifier, KP_MODE_CHANGE,
     (void *)(uintptr_t)current_mode);
}
/**
* kp_notifier_register_client - Register a notifier client for profile mode changes
* @nb: The notifier block to register
*
* This function registers a notifier client to receive notifications about profile mode changes.
*
* Return:
* 0 on success, or an error code on failure.
*/
int kp_notifier_register_client(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&kp_mode_notifier, nb);
}
EXPORT_SYMBOL_GPL(kp_notifier_register_client);
/**
* kp_notifier_unregister_client - Unregister a notifier client for profile mode changes
* @nb: The notifier block to unregister
*
* This function unregisters a previously registered notifier client for profile mode changes.
*
* Return:
* 0 on success, or an error code on failure.
*/
int kp_notifier_unregister_client(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&kp_mode_notifier, nb);
}
EXPORT_SYMBOL_GPL(kp_notifier_unregister_client);
static inline ssize_t kp_mode_show(struct kobject *kobj,
   struct kobj_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%u\n", READ_ONCE(kp_mode));
}
static inline ssize_t kp_mode_store(struct kobject *kobj,
    struct kobj_attribute *attr,
    const char *buf, size_t count)
{
unsigned int new_mode;
int ret;
ret = kstrtouint(buf, 10, &new_mode);
if (ret)
return ret;
mutex_lock(&kp_set_mode_rb_lock);
ret = __kp_set_mode(new_mode);
if (ret) {
kp_err("User changed mode is invalid, skipping mode change.\n");
mutex_unlock(&kp_set_mode_rb_lock);
return ret;
}
kp_trigger_mode_change_event();
mutex_unlock(&kp_set_mode_rb_lock);
return count;
}
static struct kobj_attribute kp_mode_attribute =
__ATTR(kp_mode, 0664, kp_mode_show, kp_mode_store);
static struct attribute *kp_attrs[] = {
&kp_mode_attribute.attr,
NULL,
};
static struct attribute_group kp_attr_group = {
.attrs = kp_attrs,
};
static int __init kp_init(void)
{
int ret = 0;
kp_kobj = kobject_create_and_add("kprofiles", kernel_kobj);
if (!kp_kobj) {
kp_err("Failed to create Kprofiles kobject\n");
return -ENOMEM;
}
ret = sysfs_create_group(kp_kobj, &kp_attr_group);
if (ret) {
kp_err("Failed to create sysfs attributes for Kprofiles\n");
kobject_put(kp_kobj);
return ret;
}
kp_info("Kprofiles " KPROFILES_VERSION
" loaded successfully. For further details, visit https://github.com/beakthoven/Kprofiles/blob/main/README.md\n");
kp_info("Copyright (C) 2021-2025 Dakkshesh <dakkshesh5@gmail.com>.\n");
return ret;
}
module_init(kp_init);
static void __exit kp_exit(void)
{
sysfs_remove_group(kp_kobj, &kp_attr_group);
kobject_put(kp_kobj);
}
module_exit(kp_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KernelSpace Profiles");
MODULE_AUTHOR("Dakkshesh <dakkshesh5@gmail.com>");
MODULE_VERSION(KPROFILES_VERSION);
Filename: stdin. Size: 8kb. View raw, , hex, or download this file.

This paste expires on 2026-07-16 15:49:02.678421+00:00. Pasted through v1-api.