From patchwork Thu Apr 1 18:36:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179377 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 78546C433B4 for ; Thu, 1 Apr 2021 19:24:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 52C7B610CC for ; Thu, 1 Apr 2021 19:24:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235119AbhDATYm (ORCPT ); Thu, 1 Apr 2021 15:24:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52024 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234463AbhDATYY (ORCPT ); Thu, 1 Apr 2021 15:24:24 -0400 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 556C1C0319D2 for ; Thu, 1 Apr 2021 11:37:10 -0700 (PDT) Received: by mail-wm1-x32b.google.com with SMTP id u5-20020a7bcb050000b029010e9316b9d5so1362809wmj.2 for ; Thu, 01 Apr 2021 11:37:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=Sv35hqDzF6q3d0fFvqaS34YxJ0dsD6UI4ML9lDyS//s=; b=p8EMbAG3ehQlxpSTNU/e9v3Gl+PipToEEbxY8lZqWmGSGn5BMHTlGzDHwMlv+H9vtc 5ZASRSco2SsB3xXvPuIjcnIAfRtL+VsxEjrHObfgbc9JgZn6QQmW4UOfrPFRHPpEmO2j GluO7xHNu2MUohn8dJn4h91bAOXedpmRLS8AmMsjW6ce26VrPqQED5t/dZkskFhXXzRL zaU4JlEX+H+fUdWnyIV2I3130neknjBI235mHMEJQGO2KlOoESSD6q7bB+ESJBHVCUFY 3eVV2j2CqYcaBiFj7OgZrS08TYO1UgboWveZzMIkMJNKTcLvW01zhx2qxA1UBzKLB+Ir TTsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=Sv35hqDzF6q3d0fFvqaS34YxJ0dsD6UI4ML9lDyS//s=; b=EjvGCHpQFnRk66fzh9H624332cXA+QcMiTTxsv0aBoDwtZ1Q4UKM7f6dMB2nwOfLAc ovI1CKlYEHYvkN6iYbM76WXS+r2uu8dhiNagS6ziXbn9Iw3WqD1ZS3SCpwOMDzb8HWOl GrEX6idj0eauwEFxP/r+TieJ6Frq82XsG3xL+QbY42Mb/KLivkGogc7kltoXyWZ0CWt3 0XRonE417/w5DJaz4AwsFnFu9GAaAsBoYIggxhMvkltwAJxOPzvW5YmNadAzmwGdHaIA phMJaQmxe5FHOGwu6+HH+IMnZ4PKZmPmwr3TjruzuFCRBbh7hBItVyCu5GW1WM044/LN JW3A== X-Gm-Message-State: AOAM5320dU8HvwvwBwySJZHcWxsErpdhznF6IiLJiBstQxXl0sb4JXjg y4N+EwMj0jzVyP/kH/OIeOtdPw== X-Google-Smtp-Source: ABdhPJwiiNG6U4d2dS7K0uWPP2zPZbjZOSxQsT8sVhGq09ZfB3AGtalmYMs6gCl99zd+c/tU+MpPFA== X-Received: by 2002:a1c:4e12:: with SMTP id g18mr9093538wmh.56.1617302228633; Thu, 01 Apr 2021 11:37:08 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:08 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 1/7] powercap/drivers/dtpm: Encapsulate even more the code Date: Thu, 1 Apr 2021 20:36:48 +0200 Message-Id: <20210401183654.27214-1-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org In order to increase the self-encapsulation of the dtpm generic code, the following changes are adding a power update ops to the dtpm ops. That allows the generic code to call directly the dtpm backend function to update the power values. The power update function does compute the power characteristics when the function is invoked. In the case of the CPUs, the power consumption depends on the number of online CPUs. The online CPUs mask is not up to date at CPUHP_AP_ONLINE_DYN state in the tear down callback. That is the reason why the online / offline are at separate state. As there is already an existing state for DTPM, this one is only moved to the DEAD state, so there is no addition of new state with these changes. The dtpm node is not removed when the cpu is unplugged. That simplifies the code for the next changes and results in a more self-encapsulated code. Signed-off-by: Daniel Lezcano Reviewed-by: Lukasz Luba --- V4: - Replaced s/sprintf/snprintf/ for the dtpm node name V2: - Updated the changelog with the CPU node not being removed - Commented the cpu hotplug callbacks to explain why there are two callbacks - Changed 'upt_power_uw' to 'update_power_uw' - Removed unused cpumask variable --- drivers/powercap/dtpm.c | 54 ++++++------- drivers/powercap/dtpm_cpu.c | 148 ++++++++++++++++-------------------- include/linux/cpuhotplug.h | 2 +- include/linux/dtpm.h | 3 +- 4 files changed, 97 insertions(+), 110 deletions(-) diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c index c2185ec5f887..58433b8ef9a1 100644 --- a/drivers/powercap/dtpm.c +++ b/drivers/powercap/dtpm.c @@ -116,8 +116,6 @@ static void __dtpm_sub_power(struct dtpm *dtpm) parent->power_limit -= dtpm->power_limit; parent = parent->parent; } - - __dtpm_rebalance_weight(root); } static void __dtpm_add_power(struct dtpm *dtpm) @@ -130,45 +128,45 @@ static void __dtpm_add_power(struct dtpm *dtpm) parent->power_limit += dtpm->power_limit; parent = parent->parent; } +} + +static int __dtpm_update_power(struct dtpm *dtpm) +{ + int ret; + + __dtpm_sub_power(dtpm); - __dtpm_rebalance_weight(root); + ret = dtpm->ops->update_power_uw(dtpm); + if (ret) + pr_err("Failed to update power for '%s': %d\n", + dtpm->zone.name, ret); + + if (!test_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags)) + dtpm->power_limit = dtpm->power_max; + + __dtpm_add_power(dtpm); + + if (root) + __dtpm_rebalance_weight(root); + + return ret; } /** * dtpm_update_power - Update the power on the dtpm * @dtpm: a pointer to a dtpm structure to update - * @power_min: a u64 representing the new power_min value - * @power_max: a u64 representing the new power_max value * * Function to update the power values of the dtpm node specified in * parameter. These new values will be propagated to the tree. * * Return: zero on success, -EINVAL if the values are inconsistent */ -int dtpm_update_power(struct dtpm *dtpm, u64 power_min, u64 power_max) +int dtpm_update_power(struct dtpm *dtpm) { - int ret = 0; + int ret; mutex_lock(&dtpm_lock); - - if (power_min == dtpm->power_min && power_max == dtpm->power_max) - goto unlock; - - if (power_max < power_min) { - ret = -EINVAL; - goto unlock; - } - - __dtpm_sub_power(dtpm); - - dtpm->power_min = power_min; - dtpm->power_max = power_max; - if (!test_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags)) - dtpm->power_limit = power_max; - - __dtpm_add_power(dtpm); - -unlock: + ret = __dtpm_update_power(dtpm); mutex_unlock(&dtpm_lock); return ret; @@ -436,6 +434,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) if (dtpm->ops && !(dtpm->ops->set_power_uw && dtpm->ops->get_power_uw && + dtpm->ops->update_power_uw && dtpm->ops->release)) return -EINVAL; @@ -455,7 +454,8 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) root = dtpm; } - __dtpm_add_power(dtpm); + if (dtpm->ops && !dtpm->ops->update_power_uw(dtpm)) + __dtpm_add_power(dtpm); pr_info("Registered dtpm node '%s' / %llu-%llu uW, \n", dtpm->zone.name, dtpm->power_min, dtpm->power_max); diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index 51c366938acd..f6076de39540 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -14,6 +14,8 @@ * The CPU hotplug is supported and the power numbers will be updated * if a CPU is hot plugged / unplugged. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -23,8 +25,6 @@ #include #include -static struct dtpm *__parent; - static DEFINE_PER_CPU(struct dtpm *, dtpm_per_cpu); struct dtpm_cpu { @@ -32,57 +32,16 @@ struct dtpm_cpu { int cpu; }; -/* - * When a new CPU is inserted at hotplug or boot time, add the power - * contribution and update the dtpm tree. - */ -static int power_add(struct dtpm *dtpm, struct em_perf_domain *em) -{ - u64 power_min, power_max; - - power_min = em->table[0].power; - power_min *= MICROWATT_PER_MILLIWATT; - power_min += dtpm->power_min; - - power_max = em->table[em->nr_perf_states - 1].power; - power_max *= MICROWATT_PER_MILLIWATT; - power_max += dtpm->power_max; - - return dtpm_update_power(dtpm, power_min, power_max); -} - -/* - * When a CPU is unplugged, remove its power contribution from the - * dtpm tree. - */ -static int power_sub(struct dtpm *dtpm, struct em_perf_domain *em) -{ - u64 power_min, power_max; - - power_min = em->table[0].power; - power_min *= MICROWATT_PER_MILLIWATT; - power_min = dtpm->power_min - power_min; - - power_max = em->table[em->nr_perf_states - 1].power; - power_max *= MICROWATT_PER_MILLIWATT; - power_max = dtpm->power_max - power_max; - - return dtpm_update_power(dtpm, power_min, power_max); -} - static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) { struct dtpm_cpu *dtpm_cpu = dtpm->private; - struct em_perf_domain *pd; + struct em_perf_domain *pd = em_cpu_get(dtpm_cpu->cpu); struct cpumask cpus; unsigned long freq; u64 power; int i, nr_cpus; - pd = em_cpu_get(dtpm_cpu->cpu); - cpumask_and(&cpus, cpu_online_mask, to_cpumask(pd->cpus)); - nr_cpus = cpumask_weight(&cpus); for (i = 0; i < pd->nr_perf_states; i++) { @@ -113,6 +72,7 @@ static u64 get_pd_power_uw(struct dtpm *dtpm) pd = em_cpu_get(dtpm_cpu->cpu); freq = cpufreq_quick_get(dtpm_cpu->cpu); + cpumask_and(&cpus, cpu_online_mask, to_cpumask(pd->cpus)); nr_cpus = cpumask_weight(&cpus); @@ -128,6 +88,27 @@ static u64 get_pd_power_uw(struct dtpm *dtpm) return 0; } +static int update_pd_power_uw(struct dtpm *dtpm) +{ + struct dtpm_cpu *dtpm_cpu = dtpm->private; + struct em_perf_domain *em = em_cpu_get(dtpm_cpu->cpu); + struct cpumask cpus; + int nr_cpus; + + cpumask_and(&cpus, cpu_online_mask, to_cpumask(em->cpus)); + nr_cpus = cpumask_weight(&cpus); + + dtpm->power_min = em->table[0].power; + dtpm->power_min *= MICROWATT_PER_MILLIWATT; + dtpm->power_min *= nr_cpus; + + dtpm->power_max = em->table[em->nr_perf_states - 1].power; + dtpm->power_max *= MICROWATT_PER_MILLIWATT; + dtpm->power_max *= nr_cpus; + + return 0; +} + static void pd_release(struct dtpm *dtpm) { struct dtpm_cpu *dtpm_cpu = dtpm->private; @@ -139,39 +120,24 @@ static void pd_release(struct dtpm *dtpm) } static struct dtpm_ops dtpm_ops = { - .set_power_uw = set_pd_power_limit, - .get_power_uw = get_pd_power_uw, - .release = pd_release, + .set_power_uw = set_pd_power_limit, + .get_power_uw = get_pd_power_uw, + .update_power_uw = update_pd_power_uw, + .release = pd_release, }; static int cpuhp_dtpm_cpu_offline(unsigned int cpu) { - struct cpufreq_policy *policy; struct em_perf_domain *pd; struct dtpm *dtpm; - policy = cpufreq_cpu_get(cpu); - - if (!policy) - return 0; - pd = em_cpu_get(cpu); if (!pd) return -EINVAL; dtpm = per_cpu(dtpm_per_cpu, cpu); - power_sub(dtpm, pd); - - if (cpumask_weight(policy->cpus) != 1) - return 0; - - for_each_cpu(cpu, policy->related_cpus) - per_cpu(dtpm_per_cpu, cpu) = NULL; - - dtpm_unregister(dtpm); - - return 0; + return dtpm_update_power(dtpm); } static int cpuhp_dtpm_cpu_online(unsigned int cpu) @@ -184,7 +150,6 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) int ret = -ENOMEM; policy = cpufreq_cpu_get(cpu); - if (!policy) return 0; @@ -194,7 +159,7 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) dtpm = per_cpu(dtpm_per_cpu, cpu); if (dtpm) - return power_add(dtpm, pd); + return dtpm_update_power(dtpm); dtpm = dtpm_alloc(&dtpm_ops); if (!dtpm) @@ -210,27 +175,20 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) for_each_cpu(cpu, policy->related_cpus) per_cpu(dtpm_per_cpu, cpu) = dtpm; - sprintf(name, "cpu%d", dtpm_cpu->cpu); + snprintf(name, sizeof(name), "cpu%d-cpufreq", dtpm_cpu->cpu); - ret = dtpm_register(name, dtpm, __parent); + ret = dtpm_register(name, dtpm, NULL); if (ret) goto out_kfree_dtpm_cpu; - ret = power_add(dtpm, pd); - if (ret) - goto out_dtpm_unregister; - ret = freq_qos_add_request(&policy->constraints, &dtpm_cpu->qos_req, FREQ_QOS_MAX, pd->table[pd->nr_perf_states - 1].frequency); if (ret) - goto out_power_sub; + goto out_dtpm_unregister; return 0; -out_power_sub: - power_sub(dtpm, pd); - out_dtpm_unregister: dtpm_unregister(dtpm); dtpm_cpu = NULL; @@ -248,10 +206,38 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) int dtpm_register_cpu(struct dtpm *parent) { - __parent = parent; + int ret; + + /* + * The callbacks at CPU hotplug time are calling + * dtpm_update_power() which in turns calls update_pd_power(). + * + * The function update_pd_power() uses the online mask to + * figure out the power consumption limits. + * + * At CPUHP_AP_ONLINE_DYN, the CPU is present in the CPU + * online mask when the cpuhp_dtpm_cpu_online function is + * called, but the CPU is still in the online mask for the + * tear down callback. So the power can not be updated when + * the CPU is unplugged. + * + * At CPUHP_AP_DTPM_CPU_DEAD, the situation is the opposite as + * above. The CPU online mask is not up to date when the CPU + * is plugged in. + * + * For this reason, we need to call the online and offline + * callbacks at different moments when the CPU online mask is + * consistent with the power numbers we want to update. + */ + ret = cpuhp_setup_state(CPUHP_AP_DTPM_CPU_DEAD, "dtpm_cpu:offline", + NULL, cpuhp_dtpm_cpu_offline); + if (ret < 0) + return ret; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dtpm_cpu:online", + cpuhp_dtpm_cpu_online, NULL); + if (ret < 0) + return ret; - return cpuhp_setup_state(CPUHP_AP_DTPM_CPU_ONLINE, - "dtpm_cpu:online", - cpuhp_dtpm_cpu_online, - cpuhp_dtpm_cpu_offline); + return 0; } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index f14adb882338..b9c50c1b5948 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -61,6 +61,7 @@ enum cpuhp_state { CPUHP_LUSTRE_CFS_DEAD, CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, CPUHP_WORKQUEUE_PREP, CPUHP_POWER_NUMA_PREPARE, CPUHP_HRTIMERS_PREPARE, @@ -195,7 +196,6 @@ enum cpuhp_state { CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30, CPUHP_AP_X86_HPET_ONLINE, CPUHP_AP_X86_KVM_CLK_ONLINE, - CPUHP_AP_DTPM_CPU_ONLINE, CPUHP_AP_ACTIVE, CPUHP_ONLINE, }; diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h index e80a332e3d8a..acf8d3638988 100644 --- a/include/linux/dtpm.h +++ b/include/linux/dtpm.h @@ -29,6 +29,7 @@ struct dtpm { struct dtpm_ops { u64 (*set_power_uw)(struct dtpm *, u64); u64 (*get_power_uw)(struct dtpm *); + int (*update_power_uw)(struct dtpm *); void (*release)(struct dtpm *); }; @@ -62,7 +63,7 @@ static inline struct dtpm *to_dtpm(struct powercap_zone *zone) return container_of(zone, struct dtpm, zone); } -int dtpm_update_power(struct dtpm *dtpm, u64 power_min, u64 power_max); +int dtpm_update_power(struct dtpm *dtpm); int dtpm_release_zone(struct powercap_zone *pcz); From patchwork Thu Apr 1 18:36:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179379 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 B361EC43460 for ; Thu, 1 Apr 2021 19:24:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 867D2610CB for ; Thu, 1 Apr 2021 19:24:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234463AbhDATYm (ORCPT ); Thu, 1 Apr 2021 15:24:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52490 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234733AbhDATYY (ORCPT ); Thu, 1 Apr 2021 15:24:24 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 585D8C0319D4 for ; Thu, 1 Apr 2021 11:37:11 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id j20-20020a05600c1914b029010f31e15a7fso3322049wmq.1 for ; Thu, 01 Apr 2021 11:37:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=rmrwFawScZd+dgSKIdw3HeIwPz5cHCEkBuBk6dorpvc=; b=MCTWNqrDBe5vVSfL76zgApZjRoexIMl3kZz7aYRH1Aukw/7T9gw5sXxuanQLUUQYRr WxShjx7t3ymh0gaQCsJ+f5Hmhzq6Ecgij/sVAtYNCtB5cqaADGWVWlYeG7z2Dduz6xDs eJs+4EqtyFhdB8ruh343ChpbGCpdrP+euOLlMUEtbgNkHqC36GoJkcQASc/hKV/XCZ3g mCEGTIewFkrSusVvTYNyoW1LT/sh9D+6RSr1v1apopMuw3tABle62rsNTtxoGiufHp8E pOo+VD+f+Qek/qf6PN3RfjUddn9GFU0fgRW/qn+xOKgG7ANTdK99KpU1ozIgiPD/Xa3Q j4OQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=rmrwFawScZd+dgSKIdw3HeIwPz5cHCEkBuBk6dorpvc=; b=sIZ0LFVBO7Ktc1zvdP+VAtVAW2r3D34PFU4dKIaL7hllZQ8P2A5CrBn24ZKDutCDNg xEkp/shupilMblvvAfbx+8gHR8sYCenjNevjo0nX0u8vPbTUOp951B5/mnm+AoU2i/0W S4XUrMZz/J0cLVUMznYapHukPQBlM+4AY238I8UdwfvfXZSyuzjpGn82mzLlF/qJPAGs 617JdGMP3RHGf/8+EXmhr9QnSWKuO8FonHQ5ng3mSycE62aituJJ9PdbSGd2XmGlNZfm piLTK/dtycXSX+YTewfFaRFjjRGEpLQW0SBWKhBwP6sXXSLRigiLVnUZMkos6rhCmdC8 ZRsQ== X-Gm-Message-State: AOAM532tBR/yeZOCLhavopRGzVd0szsl9HXI5CGJSXmyyqPJlnsqOH3+ SfjHbv9pgEGQU1Ux5FjnyHAogX+QxGndNA== X-Google-Smtp-Source: ABdhPJzI1YBLni6HsfWQ92lf9dwBGOdmx76Hgg/M/EA/CDJpov3WQ6fcFvGuVAEhfm3rmi0MmoD60g== X-Received: by 2002:a1c:a74b:: with SMTP id q72mr9255532wme.158.1617302229849; Thu, 01 Apr 2021 11:37:09 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:09 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 2/7] powercap/drivers/dtpm: Create a registering system Date: Thu, 1 Apr 2021 20:36:49 +0200 Message-Id: <20210401183654.27214-2-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org A SoC can be differently structured depending on the platform and the kernel can not be aware of all the combinations, as well as the specific tweaks for a particular board. The creation of the hierarchy must be delegated to userspace. These changes provide a registering mechanism where the different subsystems will initialize their dtpm backends and register with a name the dtpm node in a list. The next changes will provide an userspace interface to create hierarchically the different nodes. Those will be created by name and found via the list filled by the different subsystem. If a specified name is not found in the list, it is assumed to be a virtual node which will have children and the default is to allocate such node. Cc: Greg KH Signed-off-by: Daniel Lezcano Reviewed-by: Lukasz Luba --- V6: - Added the EXPORT_SYMBOL_GPL V5: - Decrease log level from 'info' to 'debug' - Remove the refcount, it is pointless, lifetime cycle is already handled by the device refcounting. The dtpm node allocator is in charge of freeing it. - Rename the functions to 'dtpm_add, dtpm_del, dtpm_lookup' - Fix missing kfrees when deleting the node from the list V4: - Fixed typo in the commit log V2: - Fixed error code path by dropping lock --- drivers/powercap/dtpm.c | 124 ++++++++++++++++++++++++++++++++++-- drivers/powercap/dtpm_cpu.c | 8 +-- include/linux/dtpm.h | 6 ++ 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c index 58433b8ef9a1..a707cc2965a1 100644 --- a/drivers/powercap/dtpm.c +++ b/drivers/powercap/dtpm.c @@ -34,6 +34,14 @@ static DEFINE_MUTEX(dtpm_lock); static struct powercap_control_type *pct; static struct dtpm *root; +struct dtpm_node { + const char *name; + struct dtpm *dtpm; + struct list_head node; +}; + +static LIST_HEAD(dtpm_list); + static int get_time_window_us(struct powercap_zone *pcz, int cid, u64 *window) { return -ENOSYS; @@ -152,6 +160,116 @@ static int __dtpm_update_power(struct dtpm *dtpm) return ret; } +static struct dtpm *__dtpm_lookup(const char *name) +{ + struct dtpm_node *node; + + list_for_each_entry(node, &dtpm_list, node) { + if (!strcmp(name, node->name)) + return node->dtpm; + } + + return NULL; +} + +/** + * dtpm_lookup - Lookup for a registered dtpm node given its name + * @name: the name of the dtpm device + * + * The function looks up in the list of the registered dtpm + * devices. This function must be called to create a dtpm node in the + * powercap hierarchy. + * + * Return: a pointer to a dtpm structure, NULL if not found. + */ +struct dtpm *dtpm_lookup(const char *name) +{ + struct dtpm *dtpm; + + mutex_lock(&dtpm_lock); + dtpm = __dtpm_lookup(name); + mutex_unlock(&dtpm_lock); + + return dtpm; +} +EXPORT_SYMBOL_GPL(dtpm_lookup); + +/** + * dtpm_add - Add the dtpm in the dtpm list + * @name: a name used as an identifier + * @dtpm: the dtpm node to be registered + * + * Stores the dtpm device in a list. The list contains all the devices + * which are power capable in terms of limitation and power + * consumption measurements. Even if conceptually, a power capable + * device won't register itself twice, the function will check if it + * was already registered in order to prevent a misuse of the API. + * + * Return: 0 on success, -EEXIST if the device name is already present + * in the list, -ENOMEM in case of memory allocation failure. + */ +int dtpm_add(const char *name, struct dtpm *dtpm) +{ + struct dtpm_node *node; + int ret; + + mutex_lock(&dtpm_lock); + + ret = -EEXIST; + if (__dtpm_lookup(name)) + goto out_unlock; + + ret = -ENOMEM; + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + goto out_unlock; + + node->name = kstrdup(name, GFP_KERNEL); + if (!node->name) { + kfree(node); + goto out_unlock; + } + + node->dtpm = dtpm; + + list_add(&node->node, &dtpm_list); + + ret = 0; +out_unlock: + mutex_unlock(&dtpm_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dtpm_add); + +/** + * dtpm_del - Remove the dtpm device from the list + * @name: the dtpm device name to be removed + * + * Remove the dtpm device from the list of the registered devices. + */ +void dtpm_del(const char *name) +{ + struct dtpm_node *node; + + mutex_lock(&dtpm_lock); + + list_for_each_entry(node, &dtpm_list, node) { + + if (strcmp(name, node->name)) + continue; + + list_del(&node->node); + kfree(node->name); + kfree(node); + + break; + } + + mutex_unlock(&dtpm_lock); +} +EXPORT_SYMBOL_GPL(dtpm_del); + /** * dtpm_update_power - Update the power on the dtpm * @dtpm: a pointer to a dtpm structure to update @@ -208,8 +326,6 @@ int dtpm_release_zone(struct powercap_zone *pcz) if (root == dtpm) root = NULL; - kfree(dtpm); - return 0; } @@ -388,7 +504,7 @@ void dtpm_unregister(struct dtpm *dtpm) { powercap_unregister_zone(pct, &dtpm->zone); - pr_info("Unregistered dtpm node '%s'\n", dtpm->zone.name); + pr_debug("Unregistered dtpm node '%s'\n", dtpm->zone.name); } /** @@ -457,7 +573,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) if (dtpm->ops && !dtpm->ops->update_power_uw(dtpm)) __dtpm_add_power(dtpm); - pr_info("Registered dtpm node '%s' / %llu-%llu uW, \n", + pr_debug("Created dtpm node '%s' / %llu-%llu uW, \n", dtpm->zone.name, dtpm->power_min, dtpm->power_max); mutex_unlock(&dtpm_lock); diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index f6076de39540..9deafd16a197 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -177,7 +177,7 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) snprintf(name, sizeof(name), "cpu%d-cpufreq", dtpm_cpu->cpu); - ret = dtpm_register(name, dtpm, NULL); + ret = dtpm_add(name, dtpm); if (ret) goto out_kfree_dtpm_cpu; @@ -185,12 +185,12 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) &dtpm_cpu->qos_req, FREQ_QOS_MAX, pd->table[pd->nr_perf_states - 1].frequency); if (ret) - goto out_dtpm_unregister; + goto out_dtpm_del; return 0; -out_dtpm_unregister: - dtpm_unregister(dtpm); +out_dtpm_del: + dtpm_del(name); dtpm_cpu = NULL; dtpm = NULL; diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h index acf8d3638988..577c71d4e098 100644 --- a/include/linux/dtpm.h +++ b/include/linux/dtpm.h @@ -75,4 +75,10 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent); int dtpm_register_cpu(struct dtpm *parent); +struct dtpm *dtpm_lookup(const char *name); + +int dtpm_add(const char *name, struct dtpm *dtpm); + +void dtpm_del(const char *name); + #endif From patchwork Thu Apr 1 18:36:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179381 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 672D5C433B4 for ; Thu, 1 Apr 2021 19:24:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 451FA61001 for ; Thu, 1 Apr 2021 19:24:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235163AbhDATYq (ORCPT ); Thu, 1 Apr 2021 15:24:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52274 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234491AbhDATY0 (ORCPT ); Thu, 1 Apr 2021 15:24:26 -0400 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 568E6C0319D9 for ; Thu, 1 Apr 2021 11:37:12 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id j20-20020a05600c1914b029010f31e15a7fso3322062wmq.1 for ; Thu, 01 Apr 2021 11:37:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jKIZkbItowaPQxULRKcIdraIpHfRIarThuC7TM+kRe0=; b=QM22qBLSYYovgxkVDG/SwqB17lGS8Jfn07QAw5CWk7M32iFHuCRkFSNPf6e6d2ZlOC 1mc4y6MUENMBXNNExNJH0GVwMvmm/h02g5zoVsTwSts10DDyaCU2t+/Ol16UbsAmZfzh VC/0g3YEnYNRuJohrnogKsazsL8FNSYacBgv31vF6A36gYM2DsG0Hc3+sP5qQIgMCSx6 +fjDPMD2zTdEN2D5QzEoWaCDCU/2RJaeLO4Xh/DmTgPzGjWozLm6vi7QC7W1br1C+u6E xp6F64GNSuenaThmCXoJ7pmP9BN9j35JTL/SS9j5Y90fPUoewcuIrxFTLPTouddOrJvJ GVHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jKIZkbItowaPQxULRKcIdraIpHfRIarThuC7TM+kRe0=; b=LG1c/CAKKng+umyg1diIANw9NzaeZzfIqSaYZPa1LbxJItNcIEn9ecTg/QzAL3+Otv T04C4aMHCprnNXz8NQ7vTou5zx5Xdd3TM3PKivuP95EuvZ3cGkhGF8MUw7sA7gBdNegN t4S/dRR0JCw5imrHja8AFJgfwFzgowxgoZN+h5+QzKDmLORa6RrK46XicB5HIKTpGHe8 YDz++GLgFGmCMXy0nQqdDazypEfxtPXepHeDZJmZwWrZsOXuP1awX2VLXz+P1HMzClLN D7Ui4+it8R8C1+zUPH/ZXG/9SqgP+779nV/lgpHnbEolK1LlnGmp5iVn503u92tbSz9h c19w== X-Gm-Message-State: AOAM532ZKjS3c15X1zrp/YdYTIljsObhLQ/K2lh/DPoXsfwqqXcUKMAb LJsUuKg0ByqlGmgz63pBlOW0ZGEGIAlLrQ== X-Google-Smtp-Source: ABdhPJzNG3HEPqAipzK217TBu+/uLXZ8OJWI8IgFiMJR9EBdbV3HA9SFm9T7SZHqNX3uxwJs8F5XtQ== X-Received: by 2002:a1c:94:: with SMTP id 142mr9612353wma.0.1617302231005; Thu, 01 Apr 2021 11:37:11 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:10 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 3/7] powercap/drivers/dtpm: Simplify the dtpm table Date: Thu, 1 Apr 2021 20:36:50 +0200 Message-Id: <20210401183654.27214-3-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The dtpm table is an array of pointers, that forces the user of the table to define initdata along with the declaration of the table entry. It is more efficient to create an array of dtpm structure, so the declaration of the table entry can be done by initializing the different fields. Signed-off-by: Daniel Lezcano Reviewed-by: Lukasz Luba --- drivers/powercap/dtpm.c | 4 ++-- drivers/powercap/dtpm_cpu.c | 4 +++- include/linux/dtpm.h | 20 +++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c index a707cc2965a1..d9aac107c927 100644 --- a/drivers/powercap/dtpm.c +++ b/drivers/powercap/dtpm.c @@ -583,7 +583,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) static int __init dtpm_init(void) { - struct dtpm_descr **dtpm_descr; + struct dtpm_descr *dtpm_descr; pct = powercap_register_control_type(NULL, "dtpm", NULL); if (IS_ERR(pct)) { @@ -592,7 +592,7 @@ static int __init dtpm_init(void) } for_each_dtpm_table(dtpm_descr) - (*dtpm_descr)->init(*dtpm_descr); + dtpm_descr->init(); return 0; } diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index 9deafd16a197..74b39a1082e5 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -204,7 +204,7 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) return ret; } -int dtpm_register_cpu(struct dtpm *parent) +static int __init dtpm_cpu_init(void) { int ret; @@ -241,3 +241,5 @@ int dtpm_register_cpu(struct dtpm *parent) return 0; } + +DTPM_DECLARE(dtpm_cpu, dtpm_cpu_init); diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h index 577c71d4e098..2ec2821111d1 100644 --- a/include/linux/dtpm.h +++ b/include/linux/dtpm.h @@ -33,25 +33,23 @@ struct dtpm_ops { void (*release)(struct dtpm *); }; -struct dtpm_descr; - -typedef int (*dtpm_init_t)(struct dtpm_descr *); +typedef int (*dtpm_init_t)(void); struct dtpm_descr { - struct dtpm *parent; - const char *name; dtpm_init_t init; }; /* Init section thermal table */ -extern struct dtpm_descr *__dtpm_table[]; -extern struct dtpm_descr *__dtpm_table_end[]; +extern struct dtpm_descr __dtpm_table[]; +extern struct dtpm_descr __dtpm_table_end[]; -#define DTPM_TABLE_ENTRY(name) \ - static typeof(name) *__dtpm_table_entry_##name \ - __used __section("__dtpm_table") = &name +#define DTPM_TABLE_ENTRY(name, __init) \ + static struct dtpm_descr __dtpm_table_entry_##name \ + __used __section("__dtpm_table") = { \ + .init = __init, \ + } -#define DTPM_DECLARE(name) DTPM_TABLE_ENTRY(name) +#define DTPM_DECLARE(name, init) DTPM_TABLE_ENTRY(name, init) #define for_each_dtpm_table(__dtpm) \ for (__dtpm = __dtpm_table; \ From patchwork Thu Apr 1 18:36:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179383 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable 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 0FEBDC43460 for ; Thu, 1 Apr 2021 19:25:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D917D610CB for ; Thu, 1 Apr 2021 19:25:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235313AbhDATY6 (ORCPT ); Thu, 1 Apr 2021 15:24:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52126 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235040AbhDATYj (ORCPT ); Thu, 1 Apr 2021 15:24:39 -0400 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9C330C0319DC for ; Thu, 1 Apr 2021 11:37:13 -0700 (PDT) Received: by mail-wm1-x336.google.com with SMTP id a132-20020a1c668a0000b029010f141fe7c2so3349642wmc.0 for ; Thu, 01 Apr 2021 11:37:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=uwNzOty3eBxNeuagxO2LQDxnjzwQ2p6EJivjUhMa5vU=; b=lPOgDaPFIBlbRUC8Pzy/T/tkdThYFu5XRLs1q3chxemhB/rfthPnUv9UmDYT0xdf1n mltTvAMZnXRboOBvqrBdSEmiGdiRNzAgklPVZ9EL64qQu7g0a/80DNKNGy4uXdmG4j0V k2paKJ7rS6qfRx2JlJjyyGJoSXjGP2aC0FmNum5qGAqOYiUFEbUe2ZGiSXVVoc3l3IhY pt3SFvdIiH0eh1Jdu7ho5lFzcsjlKrXz4cZvJdp7igU/rPzpEqFFQsKQWVK4FAlIoBbd a50alfMUtlv+ogWZEnbk0kQh4x3j7btuIik+ulN5xjYEDVnP6emu/Q9wJDVr8q/bL7iX YFkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uwNzOty3eBxNeuagxO2LQDxnjzwQ2p6EJivjUhMa5vU=; b=MTAh5dafBFfjYEJx5SlMWQmg3lGnc+QWwjKgzhqn3yt7p64lk4mLBnF8acyGLGTYIs kpZGPAKSgdrCfNqtzAnSMjO20tMB+d8ATotoSSGSUEVc6BbTelIhr1Wap+Q5aPJl8bRd 3tFSA8mDL9JwEdusjhK5Lq2j9+5uodU5vl70YRON8HDVg/N6JIkyF9GcRG3IXuGCkOBU fKnPueRekwLSM/6SjMbV6McroeQuY5H17B+mcmOUjLLTMFF7hVudHzbnjNcT6L47fKGh 0Zx6aOtxgr9Jo/cntTrdo+0/A7BChU4TxIGRf/MvMuCrKYibumhT2Oz+tBC43ZCGP3N0 4ObA== X-Gm-Message-State: AOAM532prCHb/h2jTU/aZ1AJWnw+RILfAgBft10uCP5nRxcP4NSkpNys Gjc6OPPjM8CKoyHfy7zk+wi0RmOh8liTWw== X-Google-Smtp-Source: ABdhPJxVvLukiZV/7iFXb2qX+I4ksysrdREJyjsnn08BzMZDdpBC2wNWVdGc5DkYeQW4BnErfXNOEA== X-Received: by 2002:a05:600c:4f89:: with SMTP id n9mr9506151wmq.133.1617302232194; Thu, 01 Apr 2021 11:37:12 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:11 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 4/7] powercap/drivers/dtpm: Use container_of instead of a private data field Date: Thu, 1 Apr 2021 20:36:51 +0200 Message-Id: <20210401183654.27214-4-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The dtpm framework provides an API to allocate a dtpm node. However when a backend dtpm driver needs to allocate a dtpm node it must define its own structure and store the pointer of this structure in the private field of the dtpm structure. It is more elegant to use the container_of macro and add the dtpm structure inside the dtpm backend specific structure. The code will be able to deal properly with the dtpm structure as a generic entity, making all this even more self-encapsulated. The dtpm_alloc() function does no longer make sense as the dtpm structure will be allocated when allocating the device specific dtpm structure. The dtpm_init() is provided instead. Signed-off-by: Daniel Lezcano Reviewed-by: Lukasz Luba --- drivers/powercap/dtpm.c | 18 +++++---------- drivers/powercap/dtpm_cpu.c | 46 ++++++++++++++++++------------------- include/linux/dtpm.h | 3 +-- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c index d9aac107c927..b389bc397cdf 100644 --- a/drivers/powercap/dtpm.c +++ b/drivers/powercap/dtpm.c @@ -473,24 +473,18 @@ static struct powercap_zone_ops zone_ops = { }; /** - * dtpm_alloc - Allocate and initialize a dtpm struct - * @name: a string specifying the name of the node - * - * Return: a struct dtpm pointer, NULL in case of error + * dtpm_init - Allocate and initialize a dtpm struct + * @dtpm: The dtpm struct pointer to be initialized + * @ops: The dtpm device specific ops, NULL for a virtual node */ -struct dtpm *dtpm_alloc(struct dtpm_ops *ops) +void dtpm_init(struct dtpm *dtpm, struct dtpm_ops *ops) { - struct dtpm *dtpm; - - dtpm = kzalloc(sizeof(*dtpm), GFP_KERNEL); if (dtpm) { INIT_LIST_HEAD(&dtpm->children); INIT_LIST_HEAD(&dtpm->sibling); dtpm->weight = 1024; dtpm->ops = ops; } - - return dtpm; } /** @@ -581,7 +575,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) return 0; } -static int __init dtpm_init(void) +static int __init init_dtpm(void) { struct dtpm_descr *dtpm_descr; @@ -596,4 +590,4 @@ static int __init dtpm_init(void) return 0; } -late_initcall(dtpm_init); +late_initcall(init_dtpm); diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index 74b39a1082e5..f4092d1b01d7 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -25,16 +25,22 @@ #include #include -static DEFINE_PER_CPU(struct dtpm *, dtpm_per_cpu); - struct dtpm_cpu { + struct dtpm dtpm; struct freq_qos_request qos_req; int cpu; }; +static DEFINE_PER_CPU(struct dtpm_cpu *, dtpm_per_cpu); + +static struct dtpm_cpu *to_dtpm_cpu(struct dtpm *dtpm) +{ + return container_of(dtpm, struct dtpm_cpu, dtpm); +} + static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) { - struct dtpm_cpu *dtpm_cpu = dtpm->private; + struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm); struct em_perf_domain *pd = em_cpu_get(dtpm_cpu->cpu); struct cpumask cpus; unsigned long freq; @@ -64,7 +70,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) static u64 get_pd_power_uw(struct dtpm *dtpm) { - struct dtpm_cpu *dtpm_cpu = dtpm->private; + struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm); struct em_perf_domain *pd; struct cpumask cpus; unsigned long freq; @@ -90,7 +96,7 @@ static u64 get_pd_power_uw(struct dtpm *dtpm) static int update_pd_power_uw(struct dtpm *dtpm) { - struct dtpm_cpu *dtpm_cpu = dtpm->private; + struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm); struct em_perf_domain *em = em_cpu_get(dtpm_cpu->cpu); struct cpumask cpus; int nr_cpus; @@ -111,7 +117,7 @@ static int update_pd_power_uw(struct dtpm *dtpm) static void pd_release(struct dtpm *dtpm) { - struct dtpm_cpu *dtpm_cpu = dtpm->private; + struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm); if (freq_qos_request_active(&dtpm_cpu->qos_req)) freq_qos_remove_request(&dtpm_cpu->qos_req); @@ -129,20 +135,19 @@ static struct dtpm_ops dtpm_ops = { static int cpuhp_dtpm_cpu_offline(unsigned int cpu) { struct em_perf_domain *pd; - struct dtpm *dtpm; + struct dtpm_cpu *dtpm_cpu; pd = em_cpu_get(cpu); if (!pd) return -EINVAL; - dtpm = per_cpu(dtpm_per_cpu, cpu); + dtpm_cpu = per_cpu(dtpm_per_cpu, cpu); - return dtpm_update_power(dtpm); + return dtpm_update_power(&dtpm_cpu->dtpm); } static int cpuhp_dtpm_cpu_online(unsigned int cpu) { - struct dtpm *dtpm; struct dtpm_cpu *dtpm_cpu; struct cpufreq_policy *policy; struct em_perf_domain *pd; @@ -157,27 +162,23 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) if (!pd) return -EINVAL; - dtpm = per_cpu(dtpm_per_cpu, cpu); - if (dtpm) - return dtpm_update_power(dtpm); - - dtpm = dtpm_alloc(&dtpm_ops); - if (!dtpm) - return -EINVAL; + dtpm_cpu = per_cpu(dtpm_per_cpu, cpu); + if (dtpm_cpu) + return dtpm_update_power(&dtpm_cpu->dtpm); dtpm_cpu = kzalloc(sizeof(*dtpm_cpu), GFP_KERNEL); if (!dtpm_cpu) - goto out_kfree_dtpm; + return -ENOMEM; - dtpm->private = dtpm_cpu; + dtpm_init(&dtpm_cpu->dtpm, &dtpm_ops); dtpm_cpu->cpu = cpu; for_each_cpu(cpu, policy->related_cpus) - per_cpu(dtpm_per_cpu, cpu) = dtpm; + per_cpu(dtpm_per_cpu, cpu) = dtpm_cpu; snprintf(name, sizeof(name), "cpu%d-cpufreq", dtpm_cpu->cpu); - ret = dtpm_add(name, dtpm); + ret = dtpm_add(name, &dtpm_cpu->dtpm); if (ret) goto out_kfree_dtpm_cpu; @@ -192,15 +193,12 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu) out_dtpm_del: dtpm_del(name); dtpm_cpu = NULL; - dtpm = NULL; out_kfree_dtpm_cpu: for_each_cpu(cpu, policy->related_cpus) per_cpu(dtpm_per_cpu, cpu) = NULL; kfree(dtpm_cpu); -out_kfree_dtpm: - kfree(dtpm); return ret; } diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h index 2ec2821111d1..e47bd5bbf56e 100644 --- a/include/linux/dtpm.h +++ b/include/linux/dtpm.h @@ -23,7 +23,6 @@ struct dtpm { u64 power_max; u64 power_min; int weight; - void *private; }; struct dtpm_ops { @@ -65,7 +64,7 @@ int dtpm_update_power(struct dtpm *dtpm); int dtpm_release_zone(struct powercap_zone *pcz); -struct dtpm *dtpm_alloc(struct dtpm_ops *ops); +void dtpm_init(struct dtpm *dtpm, struct dtpm_ops *ops); void dtpm_unregister(struct dtpm *dtpm); From patchwork Thu Apr 1 18:36:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179385 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 E2C2DC433B4 for ; Thu, 1 Apr 2021 19:25:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BFFB1610CB for ; Thu, 1 Apr 2021 19:25:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235338AbhDATY7 (ORCPT ); Thu, 1 Apr 2021 15:24:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234666AbhDATYj (ORCPT ); Thu, 1 Apr 2021 15:24:39 -0400 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 04814C0319E0 for ; Thu, 1 Apr 2021 11:37:14 -0700 (PDT) Received: by mail-wr1-x42f.google.com with SMTP id z2so2751390wrl.5 for ; Thu, 01 Apr 2021 11:37:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=IN1SjCUiJXttEzEwKJpOwO8v8lxJB5yWOIgxTzXkjf4=; b=ju8n3USnaxhhInT8bHoK0O8Q+jNnDM93vNa6glwrdRfdcG5o9CssZIqPXKiV8fcOSF 397FBdWnyUZ/h3yC8/rKIteR2jIX3Ai8ZE55e7knAGIo81u0NeEhBsx1g8ar7ufyybGa SZXxUMbLcwreoYamhiaoPigO6FtXfCY56EGu1q65o2+Iftn3noZLlqyO7ataBz7z0hPj v48uD5iHJFcJZY/wH6cGz+nC3xIa4cwFjToK+SlzE/w71aj+QbfyMHtXgL+GZZNJPkC4 e2Ys1dD4BXutq1xIhF2u3AVpf6Ni/H/pWevx590KAkxM7dB6RgMbldEOltQlbaXTeipm zbDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IN1SjCUiJXttEzEwKJpOwO8v8lxJB5yWOIgxTzXkjf4=; b=FGrtkB/khu8ZNOCQQHlCUIWKiKnC5rL84cd1/EBjty3nQbhbznLTOIJtFMpSljh335 N82QsXpKO6DXMmIPT/t9ssHtbQSafzDLymFO++xptx+deWHM3ficlWLKFi8boFoOroj1 Qmii9e+ThpJ+N186MalR9NHFlaj/EYcpKl4epHHMREmO7FN/xyaVldHTtYPmTqfb/mUD hGjT76wYe8fdvvKnOUhFPNw0WQN9f1iNgHtyT64THYlPbj7c9cBM6to8xgGD/BOqQiPC Lm8oKMCPQNDIXlbVzcyh3Xcd7aY0HnsdOKT9hQoMKIGePQUN5NbuhzjggZTPm99AZECc AVLA== X-Gm-Message-State: AOAM533waTyHU/Cb1a0o4saVvpHz/BI97Bd7usmRnzO8i/uIdojUqxuR +CfVYWW65xNhlcDmcYr6JvlFFw== X-Google-Smtp-Source: ABdhPJy3mVd8OhSj7jurZo2He6O+lQ5XAsdkC1gSFOVBuoYTB6OH80mJpBmbSvdUDk1o0xLclTCtaA== X-Received: by 2002:a5d:548c:: with SMTP id h12mr11363871wrv.46.1617302233482; Thu, 01 Apr 2021 11:37:13 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:12 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 5/7] powercap/drivers/dtpm: Scale the power with the load Date: Thu, 1 Apr 2021 20:36:52 +0200 Message-Id: <20210401183654.27214-5-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Currently the power consumption is based on the current OPP power assuming the entire performance domain is fully loaded. That gives very gross power estimation and we can do much better by using the load to scale the power consumption. Use the utilization to normalize and scale the power usage over the max possible power. Tested on a rock960 with 2 big CPUS, the power consumption estimation conforms with the expected one. Before this change: ~$ ~/dhrystone -t 1 -l 10000& ~$ cat /sys/devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:1/constraint_0_max_power_uw 2260000 After this change: ~$ ~/dhrystone -t 1 -l 10000& ~$ cat /sys/devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:1/constraint_0_max_power_uw 1130000 ~$ ~/dhrystone -t 2 -l 10000& ~$ cat /sys/devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:1/constraint_0_max_power_uw 2260000 Signed-off-by: Daniel Lezcano Reviewed-by: Lukasz Luba --- V3: - Fixed uninitialized 'cpu' in scaled_power_uw() V2: - Replaced cpumask by em_span_cpus - Changed 'util' metrics variable types - Optimized utilization scaling power computation - Renamed parameter name for scale_pd_power_uw() --- drivers/powercap/dtpm_cpu.c | 46 +++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index f4092d1b01d7..eae35ae3c42e 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -68,27 +68,59 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) return power_limit; } +static u64 scale_pd_power_uw(struct cpumask *pd_mask, u64 power) +{ + unsigned long max = 0, sum_util = 0; + int cpu; + + for_each_cpu_and(cpu, pd_mask, cpu_online_mask) { + + /* + * The capacity is the same for all CPUs belonging to + * the same perf domain, so a single call to + * arch_scale_cpu_capacity() is enough. However, we + * need the CPU parameter to be initialized by the + * loop, so the call ends up in this block. + * + * We can initialize 'max' with a cpumask_first() call + * before the loop but the bits computation is not + * worth given the arch_scale_cpu_capacity() just + * returns a value where the resulting assembly code + * will be optimized by the compiler. + */ + max = arch_scale_cpu_capacity(cpu); + sum_util += sched_cpu_util(cpu, max); + } + + /* + * In the improbable case where all the CPUs of the perf + * domain are offline, 'max' will be zero and will lead to an + * illegal operation with a zero division. + */ + return max ? (power * ((sum_util << 10) / max)) >> 10 : 0; +} + static u64 get_pd_power_uw(struct dtpm *dtpm) { struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm); struct em_perf_domain *pd; - struct cpumask cpus; + struct cpumask *pd_mask; unsigned long freq; - int i, nr_cpus; + int i; pd = em_cpu_get(dtpm_cpu->cpu); - freq = cpufreq_quick_get(dtpm_cpu->cpu); - cpumask_and(&cpus, cpu_online_mask, to_cpumask(pd->cpus)); - nr_cpus = cpumask_weight(&cpus); + pd_mask = em_span_cpus(pd); + + freq = cpufreq_quick_get(dtpm_cpu->cpu); for (i = 0; i < pd->nr_perf_states; i++) { if (pd->table[i].frequency < freq) continue; - return pd->table[i].power * - MICROWATT_PER_MILLIWATT * nr_cpus; + return scale_pd_power_uw(pd_mask, pd->table[i].power * + MICROWATT_PER_MILLIWATT); } return 0; From patchwork Thu Apr 1 18:36:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179387 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 CF69DC43462 for ; Thu, 1 Apr 2021 19:25:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A3979610CC for ; Thu, 1 Apr 2021 19:25:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235351AbhDATZC (ORCPT ); Thu, 1 Apr 2021 15:25:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234646AbhDATYk (ORCPT ); Thu, 1 Apr 2021 15:24:40 -0400 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C820C0319E3 for ; Thu, 1 Apr 2021 11:37:16 -0700 (PDT) Received: by mail-wr1-x42e.google.com with SMTP id x13so2737878wrs.9 for ; Thu, 01 Apr 2021 11:37:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mWp87AvriRPuSbwzklCYB4OLn1zwKcfSlyq/Ns8RiTU=; b=qXsmmaslDu7+q9I+6oxHqAzPye7Ygo83eFdoYV6MpA8awK+MWTJkISpji/Zceg8hf9 XfuXrlJf9Qk2NMbj7SQYi7XnPg/6mZ4RNqGc138v0Ax/12WAFwxD8YQKXCF7jnZpcz/M FNpF38UDo9p1bQNV5yvJsGoDbJnPMFYnxMSj2NMC5Jm5r7EsrWqiap1sswpQOvAqhjJ9 D3fJk5hu1b/tNajDtx5BWi7FsrZMTxkKaFmip7WlAxXoC9VMvwYlSLBjowG8CvQpS5TV 2IWKuvrzxnXJ+Ac1/8tDQ6A2lrn6mVbGPs+3JVvr9Ak+y+YaVSQyiu3PlQRS8kH02HUq dBCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mWp87AvriRPuSbwzklCYB4OLn1zwKcfSlyq/Ns8RiTU=; b=d9WBSWEfK2Z6FzoM8K/m5IgPHb5mqGUjw5w2EJqYGf3qmZ+/d+KmvdyvU9OMjk3o7s 8jFEZ2rP02d1bY6o60xvsaM74BukIFkSZ7VWDGeFER6OINSn16ZQkLF2CNImFmpvsTPd 7GyjdMXTBQeXg9USrtVCYUF25PS0sGNQGk5Z2o4ZnGjar34GTdAaYTTxpczwSJiGERqr f95pqYIpox1I2dg3IJxcaBO92QbjMgX4F6JOUqPnfNhGcdfcy/duPNwexn73NrTF3Ykb jQb4j1aFPxBRmGvOIjMLGgTS9e+S/loFHXE+cj9GqmdMXYipOEONXF/iC1Jg4ssgX8Du h1QQ== X-Gm-Message-State: AOAM532KkajpSWqdFwTkFy4Mw4Q+skBD/ePT5qmNWIvmj8gQ5yTXxvPt WNrqNfO4DvGRuaFmINI/zlhebg== X-Google-Smtp-Source: ABdhPJwattzDw5AfClw4cKUx5DETB7Tk72Dsv8S0ms+4/8KuYiJlAZT6WFQedDiojl0bh7428+2JdA== X-Received: by 2002:a5d:6242:: with SMTP id m2mr11160995wrv.384.1617302235113; Thu, 01 Apr 2021 11:37:15 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:14 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 6/7] powercap/drivers/dtpm: Export the symbols for the modules Date: Thu, 1 Apr 2021 20:36:53 +0200 Message-Id: <20210401183654.27214-6-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The DTPM framework provides a generic API to register devices which power capable. The devices may be compiled as modules while the framework is not. Export the necessary API to let the drivers register themselves. Signed-off-by: Daniel Lezcano --- drivers/powercap/dtpm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c index b389bc397cdf..733567bbe0be 100644 --- a/drivers/powercap/dtpm.c +++ b/drivers/powercap/dtpm.c @@ -289,6 +289,7 @@ int dtpm_update_power(struct dtpm *dtpm) return ret; } +EXPORT_SYMBOL_GPL(dtpm_update_power); /** * dtpm_release_zone - Cleanup when the node is released @@ -486,6 +487,7 @@ void dtpm_init(struct dtpm *dtpm, struct dtpm_ops *ops) dtpm->ops = ops; } } +EXPORT_SYMBOL_GPL(dtpm_init); /** * dtpm_unregister - Unregister a dtpm node from the hierarchy tree @@ -500,6 +502,7 @@ void dtpm_unregister(struct dtpm *dtpm) pr_debug("Unregistered dtpm node '%s'\n", dtpm->zone.name); } +EXPORT_SYMBOL_GPL(dtpm_unregister); /** * dtpm_register - Register a dtpm node in the hierarchy tree @@ -574,6 +577,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) return 0; } +EXPORT_SYMBOL_GPL(dtpm_register); static int __init init_dtpm(void) { From patchwork Thu Apr 1 18:36:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 12179389 X-Patchwork-Delegate: daniel.lezcano@linaro.org 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=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 2E56FC433ED for ; Thu, 1 Apr 2021 19:25:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 09D9B610CB for ; Thu, 1 Apr 2021 19:25:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235132AbhDATZF (ORCPT ); Thu, 1 Apr 2021 15:25:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52458 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235135AbhDATYm (ORCPT ); Thu, 1 Apr 2021 15:24:42 -0400 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CBEDCC0319E4 for ; Thu, 1 Apr 2021 11:37:17 -0700 (PDT) Received: by mail-wm1-x32b.google.com with SMTP id y124-20020a1c32820000b029010c93864955so3299964wmy.5 for ; Thu, 01 Apr 2021 11:37:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=KQ6hPo95a3wvVRy/jZ2q06aWXfh952Y7a16CltLTSbI=; b=VI8VSv/bTrFExp50I79hMr6vhgekzzKfzYdLibJwWBezGhMCDqN2QFxiXnd+lgjZ1A BnXlgoc7rYgXvb5aD1aFR4OBKK2pWrRapDlWgZVxgzlACICALWIPyk9Ma87eGt03bH8P 0yYDD5/PICXXWL492yxktYIIRlxvupnpAtcqWj4C6TgpNQyz+QlwK18thZ8Xn0zjKYOX CiijXMvAvtIMSZ8v4vZVTfAgnirPGxoEEhmV8F462Rjr4BzAPpq/8NT4zEShCXMST0p8 mS+p3Y6VR7dgJCgRBzvbsKes8cB078Z+IPA+gJOzNR+F7Gy1tT+uctVCbTqScF4oFCUv jMdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=KQ6hPo95a3wvVRy/jZ2q06aWXfh952Y7a16CltLTSbI=; b=KShbZF2VXH83dcIUvZz8wlwAN6SYhVIr9ZL7TJK4ZLujp719ielcTmBQpz7zdXMLyu yXNQ5u4XFgx4yv6Xsn5XR7UV3A2Dpy26b8GYjqmS7+THpTspVBJXTs/GXbv5elTTswJk NDkEozkhjP1Wwl1mH1FZdKB/8vZjyThCtT+qx7cZknIKw81lVnVr7uhB0ZBnxFQ1k3C5 d/r+AqHH1swBgDaUc4h0g6FY10El5gwKQ4kn0+8w0QDck806PgveK5LuAJ7yzVDrAZFx UI7n2+AtuiPhyg/5SaDawS8cEdvV+wV9eb38m0fpMcy8PL9AiVVObTLJvfhQxIgMn3Id 2eGQ== X-Gm-Message-State: AOAM533agUfD05LVWyJTzJH45WzaU3eM5kSF6dHK/l/v6byAJWnx59yV dLyNFgfP28q+6CmWOMsRv+MUBA== X-Google-Smtp-Source: ABdhPJyA3cKfSTYjh1/2fVaH/IqrtBKol3oPQL0aC7WIlbRLzGMukvCEzJaf2vt67ZPsG3+SG/9Inw== X-Received: by 2002:a1c:20ce:: with SMTP id g197mr9192700wmg.129.1617302236346; Thu, 01 Apr 2021 11:37:16 -0700 (PDT) Received: from localhost.localdomain ([82.142.26.252]) by smtp.gmail.com with ESMTPSA id b131sm9111490wmb.34.2021.04.01.11.37.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Apr 2021 11:37:15 -0700 (PDT) From: Daniel Lezcano To: daniel.lezcano@linaro.org Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, lukasz.luba@arm.com, rafael@kernel.org, gregkh@linuxfoundation.org Subject: [PATCH v6 7/7] powercap/drivers/dtpm: Allow dtpm node device creation through configfs Date: Thu, 1 Apr 2021 20:36:54 +0200 Message-Id: <20210401183654.27214-7-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210401183654.27214-1-daniel.lezcano@linaro.org> References: <20210401183654.27214-1-daniel.lezcano@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The DTPM framework is built on top of the powercap framework as a new controller to act on the power of the devices. The approach is to provide an unified API to do power limitation on devices which are capable of that with different techniques. In addition, the DTPM framework allows to create a hierarchical representation of the devices in order to reflect the dependencies of the power constraints we want to apply to a group of devices. The hierarchy can be different for the same platform as it will depend on the form factor (tablet, notebook, phone, ...), on other components and/or a policy, and application scenario. The kernel can not have such knowledge and only the SoC vendor can setup its platform to fulfill the objectives of its hardware. This patch adds the ability to create a DTPM hierarchy via configfs. All DTPM capable devices are registered in a list, and the creation of a configfs directory with the name of one of this device will create a DTPM node in the DTPM powercap sysfs. If the name is not in the list, a virtual node will be created instead. This virtual node in the DTPM semantic is to aggregate the power characteristics of the children. In order to do the connection between the configfs and sysfs easily, a 'device' file contains the path to the corresponding DTPM powercap node in sysfs (cross filesystems symlink is not supported by configfs). In order to not block any new features in the future, the hierarchical constraints are stored under a top folder 'constraints', so sibling can be created for other purposes if needed. When the configfs was populated, the module can not be unloaded until all the elements in the tree have been removed. 1) Resulting creation via mkdir: root@rock960:/sys/kernel/config# tree dtpm/ dtpm/ └── constraints └── platform ├── device └── soc ├── device └── pkg ├── device ├── cpu0-cpufreq │   └── device ├── cpu4-cpufreq │   └── device └── panfrost-devfreq └── device 2) The content of the 'device' file above root@rock960:/sys/kernel/config# find dtpm/constraints -name "device" -exec cat {} \; /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0/dtpm:0:0:1 /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:2 /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:1 /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:0 /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0/dtpm:0:0:0 /devices/virtual/powercap/dtpm/dtpm:0/dtpm:0:0 /devices/virtual/powercap/dtpm/dtpm:0 3) The dtpm device creation node is reflected in sysfs: root@rock960:/sys/devices/virtual/powercap/dtpm# find . -type d | grep dtpm ./dtpm:0 ./dtpm:0/power ./dtpm:0/dtpm:0:0 ./dtpm:0/dtpm:0:0/power ./dtpm:0/dtpm:0:0/dtpm:0:0:0 ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:1 ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:1/power ./dtpm:0/dtpm:0:0/dtpm:0:0:0/power ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:2 ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:2/power ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:0 ./dtpm:0/dtpm:0:0/dtpm:0:0:0/dtpm:0:0:0:0/power ./dtpm:0/dtpm:0:0/dtpm:0:0:1 ./dtpm:0/dtpm:0:0/dtpm:0:0:1/power Signed-off-by: Daniel Lezcano --- drivers/powercap/Kconfig | 8 ++ drivers/powercap/Makefile | 1 + drivers/powercap/dtpm_configfs.c | 202 +++++++++++++++++++++++++++++++ include/linux/dtpm.h | 2 + 4 files changed, 213 insertions(+) create mode 100644 drivers/powercap/dtpm_configfs.c diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig index 8242e8c5ed77..599b41e4e0a7 100644 --- a/drivers/powercap/Kconfig +++ b/drivers/powercap/Kconfig @@ -50,6 +50,14 @@ config DTPM This enables support for the power capping for the dynamic thermal power management userspace engine. +config DTPM_CONFIGFS + tristate "Dynamic Thermal Power Management configuration via configfs" + depends on DTPM && CONFIGFS_FS + help + This enables support for creating the DTPM device hierarchy + via configfs giving the userspace full control of the + thermal constraint representation. + config DTPM_CPU bool "Add CPU power capping based on the energy model" depends on DTPM && ENERGY_MODEL diff --git a/drivers/powercap/Makefile b/drivers/powercap/Makefile index fabcf388a8d3..519cabc624c3 100644 --- a/drivers/powercap/Makefile +++ b/drivers/powercap/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_DTPM) += dtpm.o +obj-$(CONFIG_DTPM_CONFIGFS) += dtpm_configfs.o obj-$(CONFIG_DTPM_CPU) += dtpm_cpu.o obj-$(CONFIG_POWERCAP) += powercap_sys.o obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o diff --git a/drivers/powercap/dtpm_configfs.c b/drivers/powercap/dtpm_configfs.c new file mode 100644 index 000000000000..b8de71e94fc3 --- /dev/null +++ b/drivers/powercap/dtpm_configfs.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2021 Linaro Limited + * + * Author: Daniel Lezcano + * + * The DTPM framework defines a set of devices which are power capable. + * + * The configfs allows to create a hierarchy of devices in order + * to reflect the constraints we want to apply to them. + * + * Each dtpm node is created via a mkdir operation in the configfs + * directory. It will create the corresponding dtpm device in the + * sysfs and the 'device' will contain the absolute path to the dtpm + * node in the sysfs, thus allowing to do the connection between the + * created dtpm node in the configfs hierarchy and the dtpm node in + * the powercap framework. + * + * The dtpm nodes can be real or virtual. The former is a real device + * where acting on its power is possible and is registered in a dtpm + * framework's list with an unique name. A creation with mkdir with + * one of the registered name will instanciate the dtpm device. If the + * name is not in the registered list, it will create a virtual node + * where its purpose is to aggregate the power characteristics of its + * children which can virtual or real. + * + * It is not allowed to create a node if another one in the hierarchy + * has the same name. That ensures the consistency and prevents + * multiple instanciation of the same dtpm device. + */ +#include +#include +#include +#include +#include +#include + +static struct config_group *cstrn_group; + +static struct config_item_type dtpm_cstrn_type; + +static const struct config_item_type dtpm_root_group_type = { + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem dtpm_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "dtpm", + .ci_type = &dtpm_root_group_type, + }, + }, + .su_mutex = __MUTEX_INITIALIZER(dtpm_subsys.su_mutex), +}; + +static bool dtpm_configfs_exists(struct config_group *grp, const char *name) +{ + struct list_head *entry; + + list_for_each(entry, &grp->cg_children) { + struct config_item *item = + container_of(entry, struct config_item, ci_entry); + + if (config_item_name(item) && + !strcmp(config_item_name(item), name)) + return true; + + if (dtpm_configfs_exists(to_config_group(item), name)) + return true; + } + + return false; +} + +static struct config_group *dtpm_cstrn_make_group(struct config_group *grp, const char *name) +{ + struct dtpm *d, *p; + int ret; + + if (dtpm_configfs_exists(cstrn_group, name)) + return ERR_PTR(-EEXIST); + + d = dtpm_lookup(name); + if (!d) { + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) + return ERR_PTR(-ENOMEM); + dtpm_init(d, NULL); + } + + config_group_init_type_name(&d->cfg, name, &dtpm_cstrn_type); + + /* + * Retrieve the dtpm parent node. The first dtpm node in the + * hierarchy constraint is the root node, thus it does not + * have a parent. + */ + p = (grp == cstrn_group) ? NULL : + container_of(grp, struct dtpm, cfg); + + ret = dtpm_register(name, d, p); + if (ret) + goto dtpm_free; + + if (!try_module_get(THIS_MODULE)) { + ret = -ENODEV; + goto dtpm_unregister; + } + + return &d->cfg; + +dtpm_unregister: + dtpm_unregister(d); +dtpm_free: + if (!d->ops) + kfree(d); + + return ERR_PTR(ret); +} + +static void dtpm_cstrn_drop_group(struct config_group *grp, + struct config_item *cfg) +{ + struct config_group *cg = to_config_group(cfg); + struct dtpm *d = container_of(cg, struct dtpm, cfg); + + dtpm_unregister(d); + if (!d->ops) + kfree(d); + module_put(THIS_MODULE); + config_item_put(cfg); +} + +static struct configfs_group_operations dtpm_cstrn_group_ops = { + .make_group = dtpm_cstrn_make_group, + .drop_item = dtpm_cstrn_drop_group, +}; + +static ssize_t dtpm_cstrn_device_show(struct config_item *cfg, char *str) +{ + struct config_group *cg = to_config_group(cfg); + struct dtpm *d = container_of(cg, struct dtpm, cfg); + struct kobject *kobj = &d->zone.dev.kobj; + char *string = kobject_get_path(kobj, GFP_KERNEL); + ssize_t len; + + if (!string) + return -EINVAL; + + len = sprintf(str, "%s\n", string); + + kfree(string); + + return len; +} + +CONFIGFS_ATTR_RO(dtpm_cstrn_, device); + +static struct configfs_attribute *dtpm_cstrn_attrs[] = { + &dtpm_cstrn_attr_device, + NULL +}; + +static struct config_item_type dtpm_cstrn_type = { + .ct_owner = THIS_MODULE, + .ct_group_ops = &dtpm_cstrn_group_ops, +}; + +static int __init dtpm_configfs_init(void) +{ + int ret; + + config_group_init(&dtpm_subsys.su_group); + + ret = configfs_register_subsystem(&dtpm_subsys); + if (ret) + return ret; + + cstrn_group = configfs_register_default_group(&dtpm_subsys.su_group, + "constraints", + &dtpm_cstrn_type); + + /* + * The default group does not contain attributes but the other + * group will + */ + dtpm_cstrn_type.ct_attrs = dtpm_cstrn_attrs; + + return PTR_ERR_OR_ZERO(cstrn_group); +} +module_init(dtpm_configfs_init); + +static void __exit dtpm_configfs_exit(void) +{ + configfs_unregister_default_group(cstrn_group); + configfs_unregister_subsystem(&dtpm_subsys); +} +module_exit(dtpm_configfs_exit); + +MODULE_DESCRIPTION("DTPM configuration driver"); +MODULE_AUTHOR("Daniel Lezcano"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h index e47bd5bbf56e..d7bbb9fd97eb 100644 --- a/include/linux/dtpm.h +++ b/include/linux/dtpm.h @@ -8,11 +8,13 @@ #define ___DTPM_H__ #include +#include #define MAX_DTPM_DESCR 8 #define MAX_DTPM_CONSTRAINTS 1 struct dtpm { + struct config_group cfg; struct powercap_zone zone; struct dtpm *parent; struct list_head sibling;