From 947f489dac381b825847df3e6fd3bf6f6c09682b Mon Sep 17 00:00:00 2001 From: Ishan Shah Date: Wed, 23 Nov 2022 21:01:48 +0000 Subject: [PATCH] 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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2814926 Reviewed-by: Laxman Dewangan GVS: Gerrit_Virtual_Submit --- dkms.conf | 4 ++ drivers/Makefile | 1 + drivers/cpuidle/Makefile | 3 + drivers/cpuidle/cpuidle-debugfs.c | 116 ++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 drivers/cpuidle/cpuidle-debugfs.c diff --git a/dkms.conf b/dkms.conf index 60137eb6..7f4089a2 100644 --- a/dkms.conf +++ b/dkms.conf @@ -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" diff --git a/drivers/Makefile b/drivers/Makefile index d3ce459d..34afe59a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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/ diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 1e2cf72e..0c3f0a0a 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -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 diff --git a/drivers/cpuidle/cpuidle-debugfs.c b/drivers/cpuidle/cpuidle-debugfs.c new file mode 100644 index 00000000..31c8edf9 --- /dev/null +++ b/drivers/cpuidle/cpuidle-debugfs.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("cpuidle debugfs driver"); +MODULE_LICENSE("GPL");