From patchwork Tue Aug 24 05:17:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Pandruvada X-Patchwork-Id: 502052 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 48CC6C432BE for ; Tue, 24 Aug 2021 05:17:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 24D096135F for ; Tue, 24 Aug 2021 05:17:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229929AbhHXFST (ORCPT ); Tue, 24 Aug 2021 01:18:19 -0400 Received: from mga06.intel.com ([134.134.136.31]:55331 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229901AbhHXFST (ORCPT ); Tue, 24 Aug 2021 01:18:19 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10085"; a="278249110" X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="278249110" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Aug 2021 22:17:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="515282846" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga004.fm.intel.com with ESMTP; 23 Aug 2021 22:17:34 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, rjw@rjwysocki.net, lenb@kernel.org, amitk@kernel.org Cc: linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC PATCH 1/3] thermal/drivers/cpuidle_cooling: Reorganize cpuidle cooling driver Date: Mon, 23 Aug 2021 22:17:29 -0700 Message-Id: <20210824051731.2495462-2-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> References: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Reorganize cpuidle cooling driver, so that it can be reused for non DT/ARM implementations. No functional changes are expected. To reorganize: - Split cpuidle cooling driver into two parts, one common and on DT specific - The common part is moved to cpuidle_cooling_core.c - The DT specific part is left in cpuidle_cooling.c - cpuidle_cooling_device structure is moved to a header file - Created interface cpuidle_cooling_get_ops() to get cdev callbacks While here, fixed some checkpatch warnings. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 6 +- drivers/thermal/Makefile | 1 + drivers/thermal/cpuidle_cooling.c | 141 +---------------------- drivers/thermal/cpuidle_cooling_core.c | 148 +++++++++++++++++++++++++ drivers/thermal/cpuidle_cooling_core.h | 24 ++++ 5 files changed, 180 insertions(+), 140 deletions(-) create mode 100644 drivers/thermal/cpuidle_cooling_core.c create mode 100644 drivers/thermal/cpuidle_cooling_core.h diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index d7f44deab5b1..3d669a1774d3 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -167,6 +167,10 @@ config CPU_THERMAL cooling device available, this option allows to use the CPU as a cooling device. +config CPU_IDLE_THERMAL_CORE + bool + depends on IDLE_INJECT + if CPU_THERMAL config CPU_FREQ_THERMAL @@ -182,7 +186,7 @@ config CPU_FREQ_THERMAL config CPU_IDLE_THERMAL bool "CPU idle cooling device" - depends on IDLE_INJECT + select CPU_IDLE_THERMAL_CORE help This implements the CPU cooling mechanism through idle injection. This will throttle the CPU by injecting diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 82fc3e616e54..769d025beb11 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -23,6 +23,7 @@ thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += gov_power_allocator.o # cpufreq cooling thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o +thermal_sys-$(CONFIG_CPU_IDLE_THERMAL_CORE) += cpuidle_cooling_core.o thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o # devfreq cooling diff --git a/drivers/thermal/cpuidle_cooling.c b/drivers/thermal/cpuidle_cooling.c index 4f41102e8b16..863c811e0d26 100644 --- a/drivers/thermal/cpuidle_cooling.c +++ b/drivers/thermal/cpuidle_cooling.c @@ -9,150 +9,13 @@ #include #include -#include #include #include #include #include #include -/** - * struct cpuidle_cooling_device - data for the idle cooling device - * @ii_dev: an atomic to keep track of the last task exiting the idle cycle - * @state: a normalized integer giving the state of the cooling device - */ -struct cpuidle_cooling_device { - struct idle_inject_device *ii_dev; - unsigned long state; -}; - -/** - * cpuidle_cooling_runtime - Running time computation - * @idle_duration_us: CPU idle time to inject in microseconds - * @state: a percentile based number - * - * The running duration is computed from the idle injection duration - * which is fixed. If we reach 100% of idle injection ratio, that - * means the running duration is zero. If we have a 50% ratio - * injection, that means we have equal duration for idle and for - * running duration. - * - * The formula is deduced as follows: - * - * running = idle x ((100 / ratio) - 1) - * - * For precision purpose for integer math, we use the following: - * - * running = (idle x 100) / ratio - idle - * - * For example, if we have an injected duration of 50%, then we end up - * with 10ms of idle injection and 10ms of running duration. - * - * Return: An unsigned int for a usec based runtime duration. - */ -static unsigned int cpuidle_cooling_runtime(unsigned int idle_duration_us, - unsigned long state) -{ - if (!state) - return 0; - - return ((idle_duration_us * 100) / state) - idle_duration_us; -} - -/** - * cpuidle_cooling_get_max_state - Get the maximum state - * @cdev : the thermal cooling device - * @state : a pointer to the state variable to be filled - * - * The function always returns 100 as the injection ratio. It is - * percentile based for consistency accross different platforms. - * - * Return: The function can not fail, it is always zero - */ -static int cpuidle_cooling_get_max_state(struct thermal_cooling_device *cdev, - unsigned long *state) -{ - /* - * Depending on the configuration or the hardware, the running - * cycle and the idle cycle could be different. We want to - * unify that to an 0..100 interval, so the set state - * interface will be the same whatever the platform is. - * - * The state 100% will make the cluster 100% ... idle. A 0% - * injection ratio means no idle injection at all and 50% - * means for 10ms of idle injection, we have 10ms of running - * time. - */ - *state = 100; - - return 0; -} - -/** - * cpuidle_cooling_get_cur_state - Get the current cooling state - * @cdev: the thermal cooling device - * @state: a pointer to the state - * - * The function just copies the state value from the private thermal - * cooling device structure, the mapping is 1 <-> 1. - * - * Return: The function can not fail, it is always zero - */ -static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev, - unsigned long *state) -{ - struct cpuidle_cooling_device *idle_cdev = cdev->devdata; - - *state = idle_cdev->state; - - return 0; -} - -/** - * cpuidle_cooling_set_cur_state - Set the current cooling state - * @cdev: the thermal cooling device - * @state: the target state - * - * The function checks first if we are initiating the mitigation which - * in turn wakes up all the idle injection tasks belonging to the idle - * cooling device. In any case, it updates the internal state for the - * cooling device. - * - * Return: The function can not fail, it is always zero - */ -static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev, - unsigned long state) -{ - struct cpuidle_cooling_device *idle_cdev = cdev->devdata; - struct idle_inject_device *ii_dev = idle_cdev->ii_dev; - unsigned long current_state = idle_cdev->state; - unsigned int runtime_us, idle_duration_us; - - idle_cdev->state = state; - - idle_inject_get_duration(ii_dev, &runtime_us, &idle_duration_us); - - runtime_us = cpuidle_cooling_runtime(idle_duration_us, state); - - idle_inject_set_duration(ii_dev, runtime_us, idle_duration_us); - - if (current_state == 0 && state > 0) { - idle_inject_start(ii_dev); - } else if (current_state > 0 && !state) { - idle_inject_stop(ii_dev); - } - - return 0; -} - -/** - * cpuidle_cooling_ops - thermal cooling device ops - */ -static struct thermal_cooling_device_ops cpuidle_cooling_ops = { - .get_max_state = cpuidle_cooling_get_max_state, - .get_cur_state = cpuidle_cooling_get_cur_state, - .set_cur_state = cpuidle_cooling_set_cur_state, -}; +#include "cpuidle_cooling_core.h" /** * __cpuidle_cooling_register: register the cooling device @@ -207,7 +70,7 @@ static int __cpuidle_cooling_register(struct device_node *np, } cdev = thermal_of_cooling_device_register(np, name, idle_cdev, - &cpuidle_cooling_ops); + cpuidle_cooling_get_ops()); if (IS_ERR(cdev)) { ret = PTR_ERR(cdev); goto out_kfree_name; diff --git a/drivers/thermal/cpuidle_cooling_core.c b/drivers/thermal/cpuidle_cooling_core.c new file mode 100644 index 000000000000..20bf02b4e168 --- /dev/null +++ b/drivers/thermal/cpuidle_cooling_core.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Linaro Limited. + * + * Author: Daniel Lezcano + * + */ +#define pr_fmt(fmt) "cpuidle cooling: " fmt + +#include +#include +#include +#include + +#include "cpuidle_cooling_core.h" + +/** + * cpuidle_cooling_runtime - Running time computation + * @idle_duration_us: CPU idle time to inject in microseconds + * @state: a percentile based number + * + * The running duration is computed from the idle injection duration + * which is fixed. If we reach 100% of idle injection ratio, that + * means the running duration is zero. If we have a 50% ratio + * injection, that means we have equal duration for idle and for + * running duration. + * + * The formula is deduced as follows: + * + * running = idle x ((100 / ratio) - 1) + * + * For precision purpose for integer math, we use the following: + * + * running = (idle x 100) / ratio - idle + * + * For example, if we have an injected duration of 50%, then we end up + * with 10ms of idle injection and 10ms of running duration. + * + * Return: An unsigned int for a usec based runtime duration. + */ +static unsigned int cpuidle_cooling_runtime(unsigned int idle_duration_us, + unsigned long state) +{ + if (!state) + return 0; + + return ((idle_duration_us * 100) / state) - idle_duration_us; +} + +/** + * cpuidle_cooling_get_max_state - Get the maximum state + * @cdev : the thermal cooling device + * @state : a pointer to the state variable to be filled + * + * The function always returns 100 as the injection ratio. It is + * percentile based for consistency across different platforms. + * + * Return: The function can not fail, it is always zero + */ +static int cpuidle_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + /* + * Depending on the configuration or the hardware, the running + * cycle and the idle cycle could be different. We want to + * unify that to an 0..100 interval, so the set state + * interface will be the same whatever the platform is. + * + * The state 100% will make the cluster 100% ... idle. A 0% + * injection ratio means no idle injection at all and 50% + * means for 10ms of idle injection, we have 10ms of running + * time. + */ + *state = 100; + + return 0; +} + +/** + * cpuidle_cooling_get_cur_state - Get the current cooling state + * @cdev: the thermal cooling device + * @state: a pointer to the state + * + * The function just copies the state value from the private thermal + * cooling device structure, the mapping is 1 <-> 1. + * + * Return: The function can not fail, it is always zero + */ +static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct cpuidle_cooling_device *idle_cdev = cdev->devdata; + + *state = idle_cdev->state; + + return 0; +} + +/** + * cpuidle_cooling_set_cur_state - Set the current cooling state + * @cdev: the thermal cooling device + * @state: the target state + * + * The function checks first if we are initiating the mitigation which + * in turn wakes up all the idle injection tasks belonging to the idle + * cooling device. In any case, it updates the internal state for the + * cooling device. + * + * Return: The function can not fail, it is always zero + */ +static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct cpuidle_cooling_device *idle_cdev = cdev->devdata; + struct idle_inject_device *ii_dev = idle_cdev->ii_dev; + unsigned long current_state = idle_cdev->state; + unsigned int runtime_us, idle_duration_us; + + idle_cdev->state = state; + + idle_inject_get_duration(ii_dev, &runtime_us, &idle_duration_us); + + runtime_us = cpuidle_cooling_runtime(idle_duration_us, state); + + idle_inject_set_duration(ii_dev, runtime_us, idle_duration_us); + + if (current_state == 0 && state > 0) + idle_inject_start(ii_dev); + else if (current_state > 0 && !state) + idle_inject_stop(ii_dev); + + return 0; +} + +/** + * cpuidle_cooling_ops - thermal cooling device ops + */ +static struct thermal_cooling_device_ops cpuidle_cooling_ops = { + .get_max_state = cpuidle_cooling_get_max_state, + .get_cur_state = cpuidle_cooling_get_cur_state, + .set_cur_state = cpuidle_cooling_set_cur_state, +}; + +struct thermal_cooling_device_ops *cpuidle_cooling_get_ops(void) +{ + return &cpuidle_cooling_ops; +} +EXPORT_SYMBOL_GPL(cpuidle_cooling_get_ops); diff --git a/drivers/thermal/cpuidle_cooling_core.h b/drivers/thermal/cpuidle_cooling_core.h new file mode 100644 index 000000000000..9b9701334a8c --- /dev/null +++ b/drivers/thermal/cpuidle_cooling_core.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Linaro Limited. + * + * Author: Daniel Lezcano + * + */ + + #ifndef _CPUIDLE_COOLING_CORE_H + #define _CPUIDLE_COOLING_CORE_H + +/** + * struct cpuidle_cooling_device - data for the idle cooling device + * @ii_dev: an atomic to keep track of the last task exiting the idle cycle + * @state: a normalized integer giving the state of the cooling device + */ +struct cpuidle_cooling_device { + struct idle_inject_device *ii_dev; + unsigned long state; +}; + +struct thermal_cooling_device_ops *cpuidle_cooling_get_ops(void); + +#endif From patchwork Tue Aug 24 05:17:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Pandruvada X-Patchwork-Id: 502639 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A7A79C4320A for ; Tue, 24 Aug 2021 05:17:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8CDAC6113B for ; Tue, 24 Aug 2021 05:17:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229901AbhHXFSU (ORCPT ); Tue, 24 Aug 2021 01:18:20 -0400 Received: from mga06.intel.com ([134.134.136.31]:55331 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229646AbhHXFST (ORCPT ); Tue, 24 Aug 2021 01:18:19 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10085"; a="278249111" X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="278249111" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Aug 2021 22:17:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="515282852" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga004.fm.intel.com with ESMTP; 23 Aug 2021 22:17:35 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, rjw@rjwysocki.net, lenb@kernel.org, amitk@kernel.org Cc: linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC PATCH 2/3] powercap: idle_inject: Export symbols Date: Mon, 23 Aug 2021 22:17:30 -0700 Message-Id: <20210824051731.2495462-3-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> References: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Export symbols for interfaces used in other files. In this way the caller can be a module. Signed-off-by: Srinivas Pandruvada --- drivers/powercap/idle_inject.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/powercap/idle_inject.c b/drivers/powercap/idle_inject.c index 6e1a0043c411..204783dfc432 100644 --- a/drivers/powercap/idle_inject.c +++ b/drivers/powercap/idle_inject.c @@ -159,6 +159,7 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev, WRITE_ONCE(ii_dev->idle_duration_us, idle_duration_us); } } +EXPORT_SYMBOL_GPL(idle_inject_set_duration); /** * idle_inject_get_duration - idle and run duration retrieval helper @@ -182,6 +183,7 @@ void idle_inject_set_latency(struct idle_inject_device *ii_dev, { WRITE_ONCE(ii_dev->latency_us, latency_us); } +EXPORT_SYMBOL(idle_inject_set_latency); /** * idle_inject_start - start idle injections @@ -334,6 +336,7 @@ struct idle_inject_device *idle_inject_register(struct cpumask *cpumask) return NULL; } +EXPORT_SYMBOL_GPL(idle_inject_register); /** * idle_inject_unregister - unregister idle injection control device @@ -354,6 +357,7 @@ void idle_inject_unregister(struct idle_inject_device *ii_dev) kfree(ii_dev); } +EXPORT_SYMBOL_GPL(idle_inject_unregister); static struct smp_hotplug_thread idle_inject_threads = { .store = &idle_inject_thread.tsk, From patchwork Tue Aug 24 05:17:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Pandruvada X-Patchwork-Id: 502638 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 11112C4338F for ; Tue, 24 Aug 2021 05:17:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ED50B6113B for ; Tue, 24 Aug 2021 05:17:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229646AbhHXFSU (ORCPT ); Tue, 24 Aug 2021 01:18:20 -0400 Received: from mga06.intel.com ([134.134.136.31]:55331 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229955AbhHXFST (ORCPT ); Tue, 24 Aug 2021 01:18:19 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10085"; a="278249116" X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="278249116" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Aug 2021 22:17:36 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,346,1620716400"; d="scan'208";a="515282858" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga004.fm.intel.com with ESMTP; 23 Aug 2021 22:17:35 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, rjw@rjwysocki.net, lenb@kernel.org, amitk@kernel.org Cc: linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC PATCH 3/3] thermal/drivers/cpuidle_cooling: cpuidle cooling driver for non DT/ARM Date: Mon, 23 Aug 2021 22:17:31 -0700 Message-Id: <20210824051731.2495462-4-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> References: <20210824051731.2495462-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org This driver has same functionality as existing cpuidle_cooling driver. This uses idle injection to cool a CPU. This driver reuses all the code from the existing driver, except the DT specific function. Each CPU is registered as a cooling device, with type = idle-x, where x is the cpu number. It registers two module parameters: idle_duration_us : To change default idle duration idle_latency_us : To change default latency The meaning of these parameters is same as in the existing code. It is described in the header of file drivers/powercap/idle_inject.c. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 12 ++ drivers/thermal/Makefile | 2 + drivers/thermal/cpuidle_cooling_generic.c | 155 ++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 drivers/thermal/cpuidle_cooling_generic.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 3d669a1774d3..3efe3df75337 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -193,6 +193,18 @@ config CPU_IDLE_THERMAL idle cycle. endif +config CPU_IDLE_THERMAL_GENERIC + tristate "CPU idle cooling device" + depends on !CPU_THERMAL + select CPU_IDLE_THERMAL_CORE + help + This implements the CPU cooling mechanism through + idle injection. This will throttle the CPU by injecting + idle cycle. + + This driver can also be built as a module. If so, the module will + be called cpuidle_cooling_generic. + config DEVFREQ_THERMAL bool "Generic device cooling support" depends on PM_DEVFREQ diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 769d025beb11..c6dce523ab2b 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -26,6 +26,8 @@ thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o thermal_sys-$(CONFIG_CPU_IDLE_THERMAL_CORE) += cpuidle_cooling_core.o thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o +obj-$(CONFIG_CPU_IDLE_THERMAL_GENERIC) += cpuidle_cooling_generic.o + # devfreq cooling thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o diff --git a/drivers/thermal/cpuidle_cooling_generic.c b/drivers/thermal/cpuidle_cooling_generic.c new file mode 100644 index 000000000000..adb33dfba2e7 --- /dev/null +++ b/drivers/thermal/cpuidle_cooling_generic.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic cpu idle cooling driver + * Copyright (c) 2021, Intel Corporation. + * All rights reserved. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpuidle_cooling_core.h" + +#define IDLE_DURATION 10000 +#define IDLE_LATENCY 5000 + +static int idle_duration_us = IDLE_DURATION; +static int idle_latency_us = IDLE_LATENCY; + +module_param(idle_duration_us, int, 0644); +MODULE_PARM_DESC(idle_duration_us, + "Idle duration in us."); + +module_param(idle_latency_us, int, 0644); +MODULE_PARM_DESC(idle_latency_us, + "Idle latency in us."); + +struct cpuidle_cooling { + struct thermal_cooling_device *cdev; + struct idle_inject_device *ii_dev; + struct cpuidle_cooling_device *idle_cdev; +}; +static DEFINE_PER_CPU(struct cpuidle_cooling, cooling_devs); +static cpumask_t cpuidle_cpu_mask; + +static int cpuidle_cooling_register(int cpu) +{ + struct cpuidle_cooling *cooling_dev = &per_cpu(cooling_devs, cpu); + struct cpuidle_cooling_device *idle_cdev; + struct thermal_cooling_device *cdev; + struct idle_inject_device *ii_dev; + char *name; + int ret; + + if (cpumask_test_cpu(cpu, &cpuidle_cpu_mask)) + return 0; + + idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL); + if (!idle_cdev) { + ret = -ENOMEM; + goto out; + } + + ii_dev = idle_inject_register((struct cpumask *)cpumask_of(cpu)); + if (!ii_dev) { + pr_err("idle_inject_register failed for cpu:%d\n", cpu); + ret = -EINVAL; + goto out_kfree; + } + + idle_inject_set_duration(ii_dev, TICK_USEC, idle_duration_us); + idle_inject_set_latency(ii_dev, idle_latency_us); + + idle_cdev->ii_dev = ii_dev; + + name = kasprintf(GFP_KERNEL, "idle-%d", cpu); + if (!name) { + ret = -ENOMEM; + goto out_unregister; + } + + cdev = thermal_cooling_device_register(name, idle_cdev, + cpuidle_cooling_get_ops()); + if (IS_ERR(cdev)) { + ret = PTR_ERR(cdev); + goto out_kfree_name; + } + + pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n", + name, idle_duration_us, idle_latency_us); + + kfree(name); + + cooling_dev->cdev = cdev; + cooling_dev->ii_dev = ii_dev; + cooling_dev->idle_cdev = idle_cdev; + cpumask_set_cpu(cpu, &cpuidle_cpu_mask); + + return 0; + +out_kfree_name: + kfree(name); +out_unregister: + idle_inject_unregister(ii_dev); +out_kfree: + kfree(idle_cdev); +out: + return ret; +} + +static void cpuidle_cooling_unregister(int cpu) +{ + struct cpuidle_cooling *cooling_dev = &per_cpu(cooling_devs, cpu); + + thermal_cooling_device_unregister(cooling_dev->cdev); + idle_inject_unregister(cooling_dev->ii_dev); + kfree(cooling_dev->idle_cdev); +} + +static int cpuidle_cooling_cpu_online(unsigned int cpu) +{ + cpuidle_cooling_register(cpu); + + return 0; +} + +static enum cpuhp_state cpuidle_cooling_hp_state __read_mostly; + +static int __init cpuidle_cooling_init(void) +{ + int ret; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "thermal/cpuidle_cooling:online", + cpuidle_cooling_cpu_online, NULL); + if (ret < 0) + return ret; + + cpuidle_cooling_hp_state = ret; + + return 0; +} +module_init(cpuidle_cooling_init) + +static void __exit cpuidle_cooling_exit(void) +{ + int i; + + cpuhp_remove_state(cpuidle_cooling_hp_state); + + for_each_cpu(i, &cpuidle_cpu_mask) { + cpuidle_cooling_unregister(i); + } +} +module_exit(cpuidle_cooling_exit) + +MODULE_LICENSE("GPL v2");