mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
nvidia-oot: cpuidle: Add idle debugfs nodes
Adding debugfs support to force cpus into idle states. Building as module instead of driver. Generic to support any standard cpuidle implementation. Bug 3583597 Change-Id: I5dd9e8635b844f465bc4c9da7e1d45ee17dd669f Signed-off-by: Ishan Shah <ishah@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2814926 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
db2721e896
commit
947f489dac
@@ -115,4 +115,8 @@ BUILT_MODULE_NAME[27]="generic-pwm-tachometer"
|
||||
BUILT_MODULE_LOCATION[27]="drivers/hwmon"
|
||||
DEST_MODULE_LOCATION[27]="/extra"
|
||||
|
||||
BUILT_MODULE_NAME[28]="cpuidle-debugfs"
|
||||
BUILT_MODULE_LOCATION[28]="drivers/cpuidle"
|
||||
DEST_MODULE_LOCATION[28]="/extra"
|
||||
|
||||
AUTO_INSTALL="yes"
|
||||
|
||||
@@ -7,6 +7,7 @@ obj-m += block/tegra_virt_storage/
|
||||
obj-m += block/tegra_oops_virt_storage/
|
||||
obj-m += c2c/
|
||||
obj-m += clink/
|
||||
obj-m += cpuidle/
|
||||
obj-m += crypto/
|
||||
obj-m += debug/
|
||||
obj-m += devfreq/
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
obj-m += cpuidle-tegra-auto.o
|
||||
obj-m += cpuidle-debugfs.o
|
||||
|
||||
116
drivers/cpuidle/cpuidle-debugfs.c
Normal file
116
drivers/cpuidle/cpuidle-debugfs.c
Normal file
@@ -0,0 +1,116 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
*
|
||||
* Module to force cpuidle states through debugfs files.
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpuidle.h>
|
||||
|
||||
#define US_TO_NS(x) (1000 * x)
|
||||
|
||||
static struct cpuidle_driver *drv;
|
||||
|
||||
static bool is_timer_irq(struct irq_desc *desc)
|
||||
{
|
||||
return desc && desc->action && (desc->action->flags & IRQF_TIMER);
|
||||
}
|
||||
|
||||
static void suspend_all_device_irqs(void)
|
||||
{
|
||||
struct irq_data *data;
|
||||
struct irq_desc *desc;
|
||||
int irq;
|
||||
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
|
||||
irq++, data = irq_get_irq_data(irq)) {
|
||||
if (!data)
|
||||
continue;
|
||||
desc = irq_data_to_desc(data);
|
||||
if (!desc || is_timer_irq(desc))
|
||||
continue;
|
||||
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
|
||||
disable_irq_nosync(irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void resume_all_device_irqs(void)
|
||||
{
|
||||
struct irq_data *data;
|
||||
struct irq_desc *desc;
|
||||
int irq;
|
||||
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
|
||||
irq++, data = irq_get_irq_data(irq)) {
|
||||
if (!data)
|
||||
continue;
|
||||
desc = irq_data_to_desc(data);
|
||||
if (!desc || is_timer_irq(desc))
|
||||
continue;
|
||||
enable_irq(desc->irq_data.irq);
|
||||
irq_clear_status_flags(irq, IRQ_DISABLE_UNLAZY);
|
||||
}
|
||||
}
|
||||
|
||||
static int forced_idle_write(void *data, u64 val)
|
||||
{
|
||||
struct cpuidle_state *idle_state = (struct cpuidle_state *) data;
|
||||
int ret = 0;
|
||||
u64 duration_ns = US_TO_NS(val);
|
||||
|
||||
suspend_all_device_irqs();
|
||||
/* duration_ns, latency_ns */
|
||||
play_idle_precise(duration_ns, (u64) (idle_state->exit_latency_ns));
|
||||
resume_all_device_irqs();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(idle_state_fops, NULL, forced_idle_write, "%llu\n");
|
||||
|
||||
static struct dentry *cpuidle_debugfs_node;
|
||||
|
||||
static int init_debugfs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cpuidle_debugfs_node = debugfs_create_dir("cpuidle_debug", NULL);
|
||||
if (!cpuidle_debugfs_node)
|
||||
goto err_out;
|
||||
|
||||
for (i = 0; i < drv->state_count; i++) {
|
||||
debugfs_create_file(drv->states[i].name, 0200,
|
||||
cpuidle_debugfs_node, &(drv->states[i]), &idle_state_fops);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
pr_err("%s: Couldn't create debugfs node for cpuidle\n", __func__);
|
||||
debugfs_remove_recursive(cpuidle_debugfs_node);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int __init cpuidle_debugfs_probe(void)
|
||||
{
|
||||
drv = cpuidle_get_driver();
|
||||
init_debugfs();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cpuidle_debugfs_remove(void)
|
||||
{
|
||||
debugfs_remove_recursive(cpuidle_debugfs_node);
|
||||
}
|
||||
|
||||
module_init(cpuidle_debugfs_probe);
|
||||
module_exit(cpuidle_debugfs_remove);
|
||||
|
||||
MODULE_AUTHOR("Ishan Shah <ishah@nvidia.com>");
|
||||
MODULE_DESCRIPTION("cpuidle debugfs driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user