From nobody Thu Apr 2 00:14:15 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 78CAD3DFC9F; Wed, 1 Apr 2026 09:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775037275; cv=none; b=aw2fCnj6QyCNAiOiSO6VsTsiIo8X2ndArJM5z0M06jLAptEx8tvVXSXERcIZCXUIGrwLYTZ+oYHyXxgUHCmi2Mlobgrq6ULjol+YJtTiQT4zAXyOdnu2JRFBEXZnn9lk21fzx8NyyM43dI0uGkTxYfvtW1OHvV10EAXTIyFD0rM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775037275; c=relaxed/simple; bh=0catYH8MP7g4V0ZHjfDpu8smhUmiJwvdHfntcdSFuCM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KbvAY3EukLIjMKF8RUPypcAnBq6iC51I+cnOQ2hykWQekMNCNrLOqAiR79AEO41Rkdabz1YCzZsBSkiNO/6ZiHCJ4cC5G7u5F2LbUemug6D31t4gjIuEj4GDeOEBxOzdV6fZ8xMJckw+THvWgGBUGwl1ZZe6Uhf/mQ/V04WmoDM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=XSw2NBUL; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="XSw2NBUL" 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 AE1E62F60; Wed, 1 Apr 2026 02:54:18 -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 9E34E3F7D8; Wed, 1 Apr 2026 02:54:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1775037264; bh=0catYH8MP7g4V0ZHjfDpu8smhUmiJwvdHfntcdSFuCM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XSw2NBUL0DG778Qf+BudmNSKpYZIUw8y3kTrDbR04yL2n63KUBKqLVLQ6JDAtsVRX w5lnSVckTMO8vmzpJzgA2Rbig6CMXfyKjbXeGjWQRuHAmTIBWg5bGdaT0bbhOiAGkM 61LSSeyHC4YTOAd/ZsGXA6C/8Kk4KiUJNv4ttyk0= 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 v4 10/11] powercap: arm_scmi: Create synthetic parent node for multi-instance Date: Wed, 1 Apr 2026 10:53:48 +0100 Message-ID: <20260401095349.2217840-11-philip.radford@arm.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260401095349.2217840-1-philip.radford@arm.com> References: <20260401095349.2217840-1-philip.radford@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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_sc= mi_powercap.c index 7f2bb162f96c..6fc2cab30b05 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; }; =20 static struct powercap_control_type *scmi_top_pcntrl; @@ -263,12 +264,47 @@ static const struct powercap_zone_constraint_ops cons= traint_ops =3D { .get_name =3D scmi_powercap_get_name, }; =20 +/* Multi-agent 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 =3D 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 =3D { + .get_max_power_range_uw =3D scmi_powercap_get_max_power_range_uw, + .get_power_uw =3D instance_root_get_power_uw, + .release =3D instance_root_release, +}; + +static const struct powercap_zone_constraint_ops instance_root_const_ops = =3D { + .set_power_limit_uw =3D instance_root_set_constraint, + .get_power_limit_uw =3D instance_root_get_constraint, + .set_time_window_us =3D instance_root_set_constraint, + .get_time_window_us =3D instance_root_get_constraint, +}; + static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *= pr) { int i; =20 /* Un-register children zones first starting from the leaves */ - for (i =3D pr->num_zones - 1; i >=3D 0; i--) { + for (i =3D pr->num_zones; i >=3D 0; i--) { if (!list_empty(&pr->registered_zones[i])) { struct scmi_powercap_zone *spz; =20 @@ -313,7 +349,6 @@ static int scmi_powercap_register_zone(struct scmi_powe= rcap_root *pr, parent ? &parent->zone : NULL, &zone_ops, spz->info->num_cpli, &constraint_ops); if (!IS_ERR(z)) { - spz->height =3D scmi_powercap_get_zone_height(spz); spz->registered =3D 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; =20 parent =3D scmi_powercap_get_parent_zone(spz); + if (!parent) + parent =3D &pr->instance_root; if (parent && !parent->registered) { zones_stack[sp++] =3D spz; spz =3D parent; @@ -424,8 +461,11 @@ static int scmi_powercap_probe(struct scmi_device *sde= v) 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 =3D &sdev->dev; + char *instance_name; + struct powercap_zone *z; =20 if (!sdev->handle) return -ENODEV; @@ -453,7 +493,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev) return -ENOMEM; =20 /* Allocate for worst possible scenario of maximum tree height. */ - pr->registered_zones =3D devm_kcalloc(dev, pr->num_zones, + pr->registered_zones =3D 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 *sde= v) } } =20 + ir =3D &pr->instance_root; + ir->dev =3D dev; + INIT_LIST_HEAD(&ir->node); + instance_name =3D devm_kasprintf(dev, GFP_KERNEL, "instance_%s", dev_name= (dev)); + if (!instance_name) + return -ENOMEM; + + z =3D powercap_register_zone(&ir->zone, scmi_top_pcntrl, + instance_name, NULL, &instance_root_ops, 0, + &instance_root_const_ops); + + if (IS_ERR(z)) { + ret =3D PTR_ERR(z); + dev_err(dev, "Failed to register sysnthetic instance root: %d\n", ret); + return ret; + } + + ir->registered =3D true; + ir->height =3D 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. --=20 2.47.3