From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 975F9FF885D for ; Tue, 28 Apr 2026 09:10:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=KaisbcmdRgRyO49p4A8PJwYIry/4gJ55EoqFeLh8BtU=; b=Y8UZjzmZampjPnn/uKlYiQD6pn IrCioq6UGNRhXGO1Soku21ETxEAOnNUOCnQqpfe9bk7WabgDBPeSq937stztuje22di9ncsSdtvWk tjqrWvCw0OSLBLddqzRfyI0Kc6qnRJVTqXERXlsyqpJIG/66IBtrmMnnc+uBtd9BhmRTehodCp3mE L0xnibSP3P9RDybuRIX//TLRXPEKmpt+kh2M5uwVBYsSJ0yhRC/Z24qjteP30LJwKHGcy8hIZXPS9 Eca4sj4HJ9pfskSd3lA33fwIbXuf7XnoOyrUvuxXo5e5TZ12cg2Si/BB7809F3w97b0LZj10HU0WR Q5YU923A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1wHeSW-000000012MA-3vG8; Tue, 28 Apr 2026 09:10:24 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1wHeSB-0000000120z-3Un1 for linux-arm-kernel@lists.infradead.org; Tue, 28 Apr 2026 09:10:05 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CB10115A1; Tue, 28 Apr 2026 02:09:57 -0700 (PDT) Received: from donnerap.manchester.arm.com (donnerap.manchester.arm.com [10.33.8.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 029D93F62B; Tue, 28 Apr 2026 02:10:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1777367403; bh=pa5p7Hv08eM1D8fsxP+q41Tlroyicg+gua19J5Hsngg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lVvrdeyTv7FJT/QRbnv7UD8olakxNuttkpUhTP7Bwuw0oDhyoi8zMPUkZUPphFVXo E+WVkfnMrZIo9RTuiCWjSiA34Oao+uzJS0udNqbouqO8ng5159dCQ7fja4fhfIFwPP viwZnco5y33EATNO3TqtE2Lg+7nrZlysr2DZxwBE= From: Philip Radford To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org, linux-pm@vger.kernel.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, etienne.carriere@st.com, peng.fan@oss.nxp.com, michal.simek@amd.com, quic_sibis@quicinc.com, dan.carpenter@linaro.org, d-gole@ti.com, souvik.chakravarty@arm.com, Philip Radford Subject: [PATCH v5 10/12] powercap: arm_scmi: Create synthetic parent node for multi-instance Date: Tue, 28 Apr 2026 10:09:19 +0100 Message-ID: <20260428090922.346069-11-philip.radford@arm.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260428090922.346069-1-philip.radford@arm.com> References: <20260428090922.346069-1-philip.radford@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260428_021003_981085_7B750CBD X-CRM114-Status: GOOD ( 17.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org SCMI powercap domains are exposed as a flat list and may include multiple top-level domains without a parent. When registered with the powercap framework, these appear as independent root zones with no common hierarchy. The driver probes domains per SCMI instance, but when registering with the powercap framework, these would be combined into a single tree. This is particularly evident in multi-instance setups where zone IDs and parent zones can only coexist with other zones and parents from the same instance. Create a synthetic root zone to act as a common parent for all top-level domains. Creates a single hierarchy and unified entry point per-instance for userspace. Signed-off-by: Philip Radford --- --- drivers/powercap/arm_scmi_powercap.c | 67 ++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c index 7f2bb162f96c..d74869af1633 100644 --- a/drivers/powercap/arm_scmi_powercap.c +++ b/drivers/powercap/arm_scmi_powercap.c @@ -36,6 +36,7 @@ struct scmi_powercap_root { struct scmi_powercap_zone *spzones; struct list_head *registered_zones; struct list_head scmi_zones; + struct scmi_powercap_zone instance_root; }; static struct powercap_control_type *scmi_top_pcntrl; @@ -263,12 +264,47 @@ static const struct powercap_zone_constraint_ops constraint_ops = { .get_name = scmi_powercap_get_name, }; +/* Multi-instance constraints to meet driver requrements */ +static int instance_root_release(struct powercap_zone *pz) +{ + return 0; +} + +static int instance_root_get_power_uw(struct powercap_zone *pz, u64 *v) +{ + *v = 0; + return 0; +} + +static int instance_root_set_constraint(struct powercap_zone *pz, int cid, u64 v) +{ + return -EOPNOTSUPP; +} + +static int instance_root_get_constraint(struct powercap_zone *pz, int cid, u64 *v) +{ + return -EOPNOTSUPP; +} + +static const struct powercap_zone_ops instance_root_ops = { + .get_max_power_range_uw = scmi_powercap_get_max_power_range_uw, + .get_power_uw = instance_root_get_power_uw, + .release = instance_root_release, +}; + +static const struct powercap_zone_constraint_ops instance_root_const_ops = { + .set_power_limit_uw = instance_root_set_constraint, + .get_power_limit_uw = instance_root_get_constraint, + .set_time_window_us = instance_root_set_constraint, + .get_time_window_us = instance_root_get_constraint, +}; + static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr) { int i; /* Un-register children zones first starting from the leaves */ - for (i = pr->num_zones - 1; i >= 0; i--) { + for (i = pr->num_zones; i >= 0; i--) { if (!list_empty(&pr->registered_zones[i])) { struct scmi_powercap_zone *spz; @@ -313,7 +349,6 @@ static int scmi_powercap_register_zone(struct scmi_powercap_root *pr, parent ? &parent->zone : NULL, &zone_ops, spz->info->num_cpli, &constraint_ops); if (!IS_ERR(z)) { - spz->height = scmi_powercap_get_zone_height(spz); spz->registered = true; list_move(&spz->node, &pr->registered_zones[spz->height]); dev_dbg(spz->dev, "Registered node %s - parent %s - height:%d\n", @@ -384,6 +419,8 @@ static int scmi_zones_register(struct device *dev, struct scmi_powercap_zone *parent; parent = scmi_powercap_get_parent_zone(spz); + if (!parent) + parent = &pr->instance_root; if (parent && !parent->registered) { zones_stack[sp++] = spz; spz = parent; @@ -424,8 +461,11 @@ static int scmi_powercap_probe(struct scmi_device *sdev) int ret, i; struct scmi_powercap_root *pr; struct scmi_powercap_zone *spz; + struct scmi_powercap_zone *ir; struct scmi_protocol_handle *ph; struct device *dev = &sdev->dev; + char *instance_name; + struct powercap_zone *z; if (!sdev->handle) return -ENODEV; @@ -453,7 +493,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev) return -ENOMEM; /* Allocate for worst possible scenario of maximum tree height. */ - pr->registered_zones = devm_kcalloc(dev, pr->num_zones, + pr->registered_zones = devm_kcalloc(dev, pr->num_zones + 1, sizeof(*pr->registered_zones), GFP_KERNEL); if (!pr->registered_zones) @@ -491,6 +531,27 @@ static int scmi_powercap_probe(struct scmi_device *sdev) } } + ir = &pr->instance_root; + ir->dev = dev; + INIT_LIST_HEAD(&ir->node); + instance_name = devm_kasprintf(dev, GFP_KERNEL, "instance_%s", dev_name(dev)); + if (!instance_name) + return -ENOMEM; + + z = powercap_register_zone(&ir->zone, scmi_top_pcntrl, + instance_name, NULL, &instance_root_ops, 0, + &instance_root_const_ops); + + if (IS_ERR(z)) { + ret = PTR_ERR(z); + dev_err(dev, "Failed to register sysnthetic instance root: %d\n", ret); + return ret; + } + + ir->registered = true; + ir->height = 0; + list_add_tail(&ir->node, &pr->registered_zones[0]); + /* * Scan array of retrieved SCMI powercap domains and register them * recursively starting from the root domains. -- 2.47.3