From nobody Mon Apr 20 01:11:38 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B0D8C43334 for ; Thu, 23 Jun 2022 12:48:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231200AbiFWMsD (ORCPT ); Thu, 23 Jun 2022 08:48:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229996AbiFWMsA (ORCPT ); Thu, 23 Jun 2022 08:48:00 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9B264BCAF for ; Thu, 23 Jun 2022 05:47:59 -0700 (PDT) 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 8812913D5; Thu, 23 Jun 2022 05:47:59 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 755903F534; Thu, 23 Jun 2022 05:47:58 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, vincent.guittot@linaro.org, f.fainelli@gmail.com, Cristian Marussi Subject: [PATCH 1/5] firmware: arm_scmi: Remove deprecated ida_simple_ calls Date: Thu, 23 Jun 2022 13:47:38 +0100 Message-Id: <20220623124742.2492164-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220623124742.2492164-1-cristian.marussi@arm.com> References: <20220623124742.2492164-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Remove deprecated calls to ida_simple_get/ida_simple_remove. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bu= s.c index e95085a66bc4..a7cbf4d09081 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -192,7 +192,7 @@ scmi_device_create(struct device_node *np, struct devic= e *parent, int protocol, return NULL; } =20 - id =3D ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL); + id =3D ida_alloc(&scmi_bus_id, GFP_KERNEL); if (id < 0) { kfree_const(scmi_dev->name); kfree(scmi_dev); @@ -215,7 +215,7 @@ scmi_device_create(struct device_node *np, struct devic= e *parent, int protocol, put_dev: kfree_const(scmi_dev->name); put_device(&scmi_dev->dev); - ida_simple_remove(&scmi_bus_id, id); + ida_free(&scmi_bus_id, id); return NULL; } =20 @@ -223,7 +223,7 @@ void scmi_device_destroy(struct scmi_device *scmi_dev) { kfree_const(scmi_dev->name); scmi_handle_put(scmi_dev->handle); - ida_simple_remove(&scmi_bus_id, scmi_dev->id); + ida_free(&scmi_bus_id, scmi_dev->id); device_unregister(&scmi_dev->dev); } =20 --=20 2.32.0 From nobody Mon Apr 20 01:11:38 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74765C43334 for ; Thu, 23 Jun 2022 12:48:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231460AbiFWMsF (ORCPT ); Thu, 23 Jun 2022 08:48:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58792 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230361AbiFWMsC (ORCPT ); Thu, 23 Jun 2022 08:48:02 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B07C9193F1 for ; Thu, 23 Jun 2022 05:48:00 -0700 (PDT) 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 A454D1474; Thu, 23 Jun 2022 05:48:00 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9184B3F534; Thu, 23 Jun 2022 05:47:59 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, vincent.guittot@linaro.org, f.fainelli@gmail.com, Cristian Marussi Subject: [PATCH 2/5] firmware: arm_scmi: Support only one single SystemPower device Date: Thu, 23 Jun 2022 13:47:39 +0100 Message-Id: <20220623124742.2492164-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220623124742.2492164-1-cristian.marussi@arm.com> References: <20220623124742.2492164-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In order to minimize SCMI platform fw-side complexity, only one single SCMI platform should be in charge of SCMI SystemPower protocol communications with the OSPM: enforce the existence of one single unique device associated with SystemPower protocol across any possible number of SCMI platforms, and warn if a system tries to register different SystemPower devices from multiple platforms. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/bus.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bu= s.c index a7cbf4d09081..476855d3dccb 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -19,6 +19,11 @@ static DEFINE_IDA(scmi_bus_id); static DEFINE_IDR(scmi_protocols); static DEFINE_SPINLOCK(protocol_lock); =20 +/* Track globally the creation of SCMI SystemPower related devices */ +static bool scmi_syspower_registered; +/* Protect access to scmi_syspower_registered */ +static DEFINE_MUTEX(scmi_syspower_mtx); + static const struct scmi_device_id * scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_d= rv) { @@ -207,11 +212,31 @@ scmi_device_create(struct device_node *np, struct dev= ice *parent, int protocol, scmi_dev->dev.release =3D scmi_device_release; dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id); =20 + mutex_lock(&scmi_syspower_mtx); + if (protocol =3D=3D SCMI_PROTOCOL_SYSTEM && scmi_syspower_registered) { + dev_warn(parent, + "SCMI SystemPower protocol device must be unique !\n"); + + mutex_unlock(&scmi_syspower_mtx); + ida_free(&scmi_bus_id, id); + kfree_const(scmi_dev->name); + kfree(scmi_dev); + return NULL; + } + retval =3D device_register(&scmi_dev->dev); - if (retval) + if (retval) { + mutex_unlock(&scmi_syspower_mtx); goto put_dev; + } + + if (protocol =3D=3D SCMI_PROTOCOL_SYSTEM) + scmi_syspower_registered =3D true; + + mutex_unlock(&scmi_syspower_mtx); =20 return scmi_dev; + put_dev: kfree_const(scmi_dev->name); put_device(&scmi_dev->dev); @@ -221,6 +246,10 @@ scmi_device_create(struct device_node *np, struct devi= ce *parent, int protocol, =20 void scmi_device_destroy(struct scmi_device *scmi_dev) { + mutex_lock(&scmi_syspower_mtx); + if (scmi_dev->protocol_id =3D=3D SCMI_PROTOCOL_SYSTEM) + scmi_syspower_registered =3D false; + mutex_unlock(&scmi_syspower_mtx); kfree_const(scmi_dev->name); scmi_handle_put(scmi_dev->handle); ida_free(&scmi_bus_id, scmi_dev->id); --=20 2.32.0 From nobody Mon Apr 20 01:11:38 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 44FA9C433EF for ; Thu, 23 Jun 2022 12:48:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231666AbiFWMsI (ORCPT ); Thu, 23 Jun 2022 08:48:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231254AbiFWMsD (ORCPT ); Thu, 23 Jun 2022 08:48:03 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C707120BF9 for ; Thu, 23 Jun 2022 05:48:01 -0700 (PDT) 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 C12191570; Thu, 23 Jun 2022 05:48:01 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AD9753F534; Thu, 23 Jun 2022 05:48:00 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, vincent.guittot@linaro.org, f.fainelli@gmail.com, Cristian Marussi Subject: [PATCH 3/5] firmware: arm_scmi: Add SCMIv3.1 SystemPower extensions Date: Thu, 23 Jun 2022 13:47:40 +0100 Message-Id: <20220623124742.2492164-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220623124742.2492164-1-cristian.marussi@arm.com> References: <20220623124742.2492164-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add support for SCMIv3.1 SystemPower optional timeout field while dispatching SYSTEM_POWER_STATE_NOTIFIER notification. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/system.c | 17 ++++++++++++++++- include/linux/scmi_protocol.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi= /system.c index 220e399118ad..9383d7584539 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -27,10 +27,12 @@ struct scmi_system_power_state_notifier_payld { __le32 agent_id; __le32 flags; __le32 system_state; + __le32 timeout; }; =20 struct scmi_system_info { u32 version; + bool graceful_timeout_supported; }; =20 static int scmi_system_request_notify(const struct scmi_protocol_handle *p= h, @@ -72,17 +74,27 @@ scmi_system_fill_custom_report(const struct scmi_protoc= ol_handle *ph, const void *payld, size_t payld_sz, void *report, u32 *src_id) { + size_t expected_sz; const struct scmi_system_power_state_notifier_payld *p =3D payld; struct scmi_system_power_state_notifier_report *r =3D report; + struct scmi_system_info *pinfo =3D ph->get_priv(ph); =20 + expected_sz =3D pinfo->graceful_timeout_supported ? + sizeof(*p) : sizeof(*p) - sizeof(__le32); if (evt_id !=3D SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER || - sizeof(*p) !=3D payld_sz) + payld_sz !=3D expected_sz) return NULL; =20 r->timestamp =3D timestamp; r->agent_id =3D le32_to_cpu(p->agent_id); r->flags =3D le32_to_cpu(p->flags); r->system_state =3D le32_to_cpu(p->system_state); + if (pinfo->graceful_timeout_supported && + r->system_state =3D=3D SCMI_SYSTEM_SHUTDOWN && + SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(r->flags)) + r->timeout =3D le32_to_cpu(p->timeout); + else + r->timeout =3D 0x00; *src_id =3D 0; =20 return r; @@ -129,6 +141,9 @@ static int scmi_system_protocol_init(const struct scmi_= protocol_handle *ph) return -ENOMEM; =20 pinfo->version =3D version; + if (PROTOCOL_REV_MAJOR(pinfo->version) >=3D 0x2) + pinfo->graceful_timeout_supported =3D true; + return ph->set_priv(ph, pinfo); } =20 diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index a922707bdfe8..37d8603816c2 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -896,8 +896,10 @@ struct scmi_clock_rate_notif_report { struct scmi_system_power_state_notifier_report { ktime_t timestamp; unsigned int agent_id; +#define SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(flags) ((flags) & BIT(0)) unsigned int flags; unsigned int system_state; + unsigned int timeout; }; =20 struct scmi_perf_limits_report { --=20 2.32.0 From nobody Mon Apr 20 01:11:38 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6C20C433EF for ; Thu, 23 Jun 2022 12:48:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231802AbiFWMsK (ORCPT ); Thu, 23 Jun 2022 08:48:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231320AbiFWMsE (ORCPT ); Thu, 23 Jun 2022 08:48:04 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id CBA9931236 for ; Thu, 23 Jun 2022 05:48:02 -0700 (PDT) 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 DDDF11576; Thu, 23 Jun 2022 05:48:02 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id CB0923F534; Thu, 23 Jun 2022 05:48:01 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, vincent.guittot@linaro.org, f.fainelli@gmail.com, Cristian Marussi Subject: [PATCH 4/5] firmware: arm_scmi: Add devm_protocol_acquire helper Date: Thu, 23 Jun 2022 13:47:41 +0100 Message-Id: <20220623124742.2492164-5-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220623124742.2492164-1-cristian.marussi@arm.com> References: <20220623124742.2492164-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add a method to get hold of a protocol, causing it to be initialized and its resource accounting updated, without getting access to its operations and handle. Some protocols, like SCMI SystemPower, do not expose any protocol ops to the Kernel OSPM agent but still need to be at least initialized: this helper avoids the need to invoke a full devm_get_protocol() only to get the protocol initialized while throwing away unused the protocol ops and handle. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 70 +++++++++++++++++++++++------- include/linux/scmi_protocol.h | 5 +++ 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 00b7f2aff4ec..7c91fd44baf5 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1662,6 +1662,30 @@ static void scmi_devm_release_protocol(struct device= *dev, void *res) scmi_protocol_release(dres->handle, dres->protocol_id); } =20 +static struct scmi_protocol_instance __must_check * +scmi_devres_protocol_instance_get(struct scmi_device *sdev, u8 protocol_id) +{ + struct scmi_protocol_instance *pi; + struct scmi_protocol_devres *dres; + + dres =3D devres_alloc(scmi_devm_release_protocol, + sizeof(*dres), GFP_KERNEL); + if (!dres) + return ERR_PTR(-ENOMEM); + + pi =3D scmi_get_protocol_instance(sdev->handle, protocol_id); + if (IS_ERR(pi)) { + devres_free(dres); + return pi; + } + + dres->handle =3D sdev->handle; + dres->protocol_id =3D protocol_id; + devres_add(&sdev->dev, dres); + + return pi; +} + /** * scmi_devm_protocol_get - Devres managed get protocol operations and ha= ndle * @sdev: A reference to an scmi_device whose embedded struct device is to @@ -1685,32 +1709,47 @@ scmi_devm_protocol_get(struct scmi_device *sdev, u8= protocol_id, struct scmi_protocol_handle **ph) { struct scmi_protocol_instance *pi; - struct scmi_protocol_devres *dres; - struct scmi_handle *handle =3D sdev->handle; =20 if (!ph) return ERR_PTR(-EINVAL); =20 - dres =3D devres_alloc(scmi_devm_release_protocol, - sizeof(*dres), GFP_KERNEL); - if (!dres) - return ERR_PTR(-ENOMEM); - - pi =3D scmi_get_protocol_instance(handle, protocol_id); - if (IS_ERR(pi)) { - devres_free(dres); + pi =3D scmi_devres_protocol_instance_get(sdev, protocol_id); + if (IS_ERR(pi)) return pi; - } - - dres->handle =3D handle; - dres->protocol_id =3D protocol_id; - devres_add(&sdev->dev, dres); =20 *ph =3D &pi->ph; =20 return pi->proto->ops; } =20 +/** + * scmi_devm_protocol_acquire - Devres managed helper to get hold of a pr= otocol + * @sdev: A reference to an scmi_device whose embedded struct device is to + * be used for devres accounting. + * @protocol_id: The protocol being requested. + * + * Get hold of a protocol accounting for its usage, possibly triggering its + * initialization but without getting access to its protocol specific oper= ations + * and handle. + * + * Being a devres based managed method, protocol hold will be automatically + * released, and possibly de-initialized on last user, once the SCMI driver + * owning the scmi_device is unbound from it. + * + * Return: 0 on SUCCESS + */ +static int __must_check scmi_devm_protocol_acquire(struct scmi_device *sde= v, + u8 protocol_id) +{ + struct scmi_protocol_instance *pi; + + pi =3D scmi_devres_protocol_instance_get(sdev, protocol_id); + if (IS_ERR(pi)) + return PTR_ERR(pi); + + return 0; +} + static int scmi_devm_protocol_match(struct device *dev, void *res, void *d= ata) { struct scmi_protocol_devres *dres =3D res; @@ -2297,6 +2336,7 @@ static int scmi_probe(struct platform_device *pdev) handle =3D &info->handle; handle->dev =3D info->dev; handle->version =3D &info->version; + handle->devm_protocol_acquire =3D scmi_devm_protocol_acquire; handle->devm_protocol_get =3D scmi_devm_protocol_get; handle->devm_protocol_put =3D scmi_devm_protocol_put; =20 diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 37d8603816c2..1846b4a870cf 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -734,6 +734,9 @@ struct scmi_notify_ops { * * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information + * @devm_protocol_acquire: devres managed method to get hold of a protocol, + * causing its initialization and related resource + * accounting * @devm_protocol_get: devres managed method to acquire a protocol and get= specific * operations and a dedicated protocol handler * @devm_protocol_put: devres managed method to release a protocol @@ -752,6 +755,8 @@ struct scmi_handle { struct device *dev; struct scmi_revision_info *version; =20 + int __must_check (*devm_protocol_acquire)(struct scmi_device *sdev, + u8 proto); const void __must_check * (*devm_protocol_get)(struct scmi_device *sdev, u8 proto, struct scmi_protocol_handle **ph); --=20 2.32.0 From nobody Mon Apr 20 01:11:38 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A88FDC43334 for ; Thu, 23 Jun 2022 12:48:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231863AbiFWMsO (ORCPT ); Thu, 23 Jun 2022 08:48:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231558AbiFWMsG (ORCPT ); Thu, 23 Jun 2022 08:48:06 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 468F4193F1 for ; Thu, 23 Jun 2022 05:48:04 -0700 (PDT) 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 3E8FA15BF; Thu, 23 Jun 2022 05:48:04 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E87993F534; Thu, 23 Jun 2022 05:48:02 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, vincent.guittot@linaro.org, f.fainelli@gmail.com, Cristian Marussi , Greg Kroah-Hartman Subject: [PATCH 5/5] firmware: arm_scmi: Add SCMI System Power Control driver Date: Thu, 23 Jun 2022 13:47:42 +0100 Message-Id: <20220623124742.2492164-6-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220623124742.2492164-1-cristian.marussi@arm.com> References: <20220623124742.2492164-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add an SCMI System Power control driver to handle platform's requests carried by SYSTEM_POWER_STATE_NOTIFIER notifications: such platform requested system-wide power state transitions are handled accordingly, gracefully or forcefully, depending on the notifications' message flags. Graceful requests are relayed to userspace using the same Kernel API used to handle ACPI Shutdown bus events. Cc: Greg Kroah-Hartman Signed-off-by: Cristian Marussi Reviewed-by: Greg Kroah-Hartman --- drivers/firmware/arm_scmi/Kconfig | 12 + drivers/firmware/arm_scmi/Makefile | 1 + .../firmware/arm_scmi/scmi_power_control.c | 362 ++++++++++++++++++ 3 files changed, 375 insertions(+) create mode 100644 drivers/firmware/arm_scmi/scmi_power_control.c diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/= Kconfig index cb5d97c2d8bc..c9bcfab00b76 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -162,4 +162,16 @@ config ARM_SCMI_POWER_DOMAIN will be called scmi_pm_domain. Note this may needed early in boot before rootfs may be available. =20 +config ARM_SCMI_POWER_CONTROL + tristate "SCMI system power control driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + help + This enables System Power control logic which binds system shutdown or + reboot actions to SCMI System Power notifications generated by SCP + firmware. + + This driver can also be built as a module. If so, the module will be + called scmi_power_control. Note this may needed early in boot to catch + early shutdown/reboot SCMI requests. + endmenu diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi= /Makefile index a02dc8ce5a7f..9ea86f8cc8f7 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -12,6 +12,7 @@ scmi-module-objs :=3D $(scmi-bus-y) $(scmi-driver-y) $(sc= mi-protocols-y) \ $(scmi-transport-y) obj-$(CONFIG_ARM_SCMI_PROTOCOL) +=3D scmi-module.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) +=3D scmi_pm_domain.o +obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) +=3D scmi_power_control.o =20 ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a = frame diff --git a/drivers/firmware/arm_scmi/scmi_power_control.c b/drivers/firmw= are/arm_scmi/scmi_power_control.c new file mode 100644 index 000000000000..6eb7d2a4b6b1 --- /dev/null +++ b/drivers/firmware/arm_scmi/scmi_power_control.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SCMI Generic SystemPower Control driver. + * + * Copyright (C) 2020-2022 ARM Ltd. + */ +/* + * In order to handle platform originated SCMI SystemPower requests (like + * shutdowns or cold/warm resets) we register an SCMI Notification notifier + * block to react when such SCMI SystemPower events are emitted by platfor= m. + * + * Once such a notification is received we act accordingly to perform the + * required system transition depending on the kind of request. + * + * Graceful requests are routed to userspace through the same API methods + * (orderly_poweroff/reboot()) used by ACPI when handling ACPI Shutdown bus + * events. + * + * Direct forceful requests are not supported since are not meant to be se= nt + * by the SCMI platform to an OSPM like Linux. + * + * Additionally, graceful request notifications can carry an optional time= out + * field stating the maximum amount of time allowed by the platform for + * completion after which they are converted to forceful ones: the assumpt= ion + * here is that even graceful requests can be upper-bound by a maximum fin= al + * timeout strictly enforced by the platform itself which can ultimately c= ut + * the power off at will anytime; in order to avoid such extreme scenario,= we + * track progress of graceful requests through the means of a reboot notif= ier + * converting timed-out graceful requests to forceful ones, so at least we + * try to perform a clean sync and shutdown/restart before the power is cu= t. + * + * Given the peculiar nature of SCMI SystemPower protocol, that is being in + * charge of triggering system wide shutdown/reboot events, there should be + * only one SCMI platform actively emitting SystemPower events. + * For this reason the SCMI core takes care to enforce the creation of one + * single unique device associated to the SCMI System Power protocol; no m= atter + * how many SCMI platforms are defined on the system, only one can be desi= gnated + * to support System Power: as a consequence this driver will never be pro= bed + * more than once. + * + * For similar reasons as soon as the first valid SystemPower is received = by + * this driver and the shutdown/reboot is started, any further notification + * possibly emitted by the platform will be ignored. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MODULE +#include +#endif + +enum scmi_syspower_state { + SCMI_SYSPOWER_IDLE, + SCMI_SYSPOWER_IN_PROGRESS, + SCMI_SYSPOWER_REBOOTING +}; + +/** + * struct scmi_syspower_conf - Common configuration + * + * @dev: A reference device + * @state: Current SystemPower state + * @state_mtx: @state related mutex + * @required_transition: The requested transition as decribed in the recei= ved + * SCMI SystemPower notification + * @userspace_nb: The notifier_block registered against the SCMI SystemPow= er + * notification to start the needed userspace interactions. + * @reboot_nb: A notifier_block optionally used to track reboot progress + * @forceful_work: A worker used to trigger a forceful transition once a + * graceful has timed out. + */ +struct scmi_syspower_conf { + struct device *dev; + enum scmi_syspower_state state; + /* Protect access to state */ + struct mutex state_mtx; + enum scmi_system_events required_transition; + + struct notifier_block userspace_nb; + struct notifier_block reboot_nb; + + struct delayed_work forceful_work; +}; + +#define userspace_nb_to_sconf(x) \ + container_of(x, struct scmi_syspower_conf, userspace_nb) + +#define reboot_nb_to_sconf(x) \ + container_of(x, struct scmi_syspower_conf, reboot_nb) + +#define dwork_to_sconf(x) \ + container_of(x, struct scmi_syspower_conf, forceful_work) + +/** + * scmi_reboot_notifier - A reboot notifier to catch an ongoing successful + * system transition + * @nb: Reference to the related notifier block + * @reason: The reason for the ongoing reboot + * @__unused: The cmd being executed on a restart request (unused) + * + * When an ongoing system transition is detected, compatible with the one + * requested by SCMI, cancel the delayed work. + * + * Return: NOTIFY_OK in any case + */ +static int scmi_reboot_notifier(struct notifier_block *nb, + unsigned long reason, void *__unused) +{ + struct scmi_syspower_conf *sc =3D reboot_nb_to_sconf(nb); + + mutex_lock(&sc->state_mtx); + switch (reason) { + case SYS_HALT: + case SYS_POWER_OFF: + if (sc->required_transition =3D=3D SCMI_SYSTEM_SHUTDOWN) + sc->state =3D SCMI_SYSPOWER_REBOOTING; + break; + case SYS_RESTART: + if (sc->required_transition =3D=3D SCMI_SYSTEM_COLDRESET || + sc->required_transition =3D=3D SCMI_SYSTEM_WARMRESET) + sc->state =3D SCMI_SYSPOWER_REBOOTING; + break; + default: + break; + } + + if (sc->state =3D=3D SCMI_SYSPOWER_REBOOTING) { + dev_dbg(sc->dev, "Reboot in progress...cancel delayed work.\n"); + cancel_delayed_work_sync(&sc->forceful_work); + } + mutex_unlock(&sc->state_mtx); + + return NOTIFY_OK; +} + +/** + * scmi_request_forceful_transition - Request forceful SystemPower transi= tion + * @sc: A reference to the configuration data + * + * Initiates the required SystemPower transition without involving userspa= ce: + * just trigger the action at the kernel level after issuing an emergency + * sync. (if possible at all) + */ +static inline void +scmi_request_forceful_transition(struct scmi_syspower_conf *sc) +{ + dev_dbg(sc->dev, "Serving forceful request:%d\n", + sc->required_transition); + +#ifndef MODULE + emergency_sync(); +#endif + switch (sc->required_transition) { + case SCMI_SYSTEM_SHUTDOWN: + kernel_power_off(); + break; + case SCMI_SYSTEM_COLDRESET: + case SCMI_SYSTEM_WARMRESET: + kernel_restart(NULL); + break; + default: + break; + } +} + +static void scmi_forceful_work_func(struct work_struct *work) +{ + struct scmi_syspower_conf *sc; + struct delayed_work *dwork; + + if (system_state > SYSTEM_RUNNING) + return; + + dwork =3D to_delayed_work(work); + sc =3D dwork_to_sconf(dwork); + + dev_dbg(sc->dev, "Graceful request timed out...forcing !\n"); + mutex_lock(&sc->state_mtx); + /* avoid deadlock by unregistering reboot notifier first */ + unregister_reboot_notifier(&sc->reboot_nb); + if (sc->state =3D=3D SCMI_SYSPOWER_IN_PROGRESS) + scmi_request_forceful_transition(sc); + mutex_unlock(&sc->state_mtx); +} + +/** + * scmi_request_graceful_transition - Request graceful SystemPower transi= tion + * @sc: A reference to the configuration data + * @timeout_ms: The desired timeout to wait for the shutdown to complete b= efore + * system is forcibly shutdown. + * + * Initiates the required SystemPower transition, requesting userspace + * co-operation: it uses the same orderly_ methods used by ACPI Shutdown e= vent + * processing. + * + * Takes care also to register a reboot notifier and to schedule a delayed= work + * in order to detect if userspace actions are taking too long and in such= a + * case to trigger a forceful transition. + */ +static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc, + unsigned int timeout_ms) +{ + unsigned int adj_timeout_ms =3D 0; + + if (timeout_ms) { + int ret; + + sc->reboot_nb.notifier_call =3D &scmi_reboot_notifier; + ret =3D register_reboot_notifier(&sc->reboot_nb); + if (!ret) { + /* Wait only up to 75% of the advertised timeout */ + adj_timeout_ms =3D mult_frac(timeout_ms, 3, 4); + INIT_DELAYED_WORK(&sc->forceful_work, + scmi_forceful_work_func); + schedule_delayed_work(&sc->forceful_work, + msecs_to_jiffies(adj_timeout_ms)); + } else { + /* Carry on best effort even without a reboot notifier */ + dev_warn(sc->dev, + "Cannot register reboot notifier !\n"); + } + } + + dev_dbg(sc->dev, + "Serving graceful req:%d (timeout_ms:%u adj_timeout_ms:%u)\n", + sc->required_transition, timeout_ms, adj_timeout_ms); + + switch (sc->required_transition) { + case SCMI_SYSTEM_SHUTDOWN: + /* + * When triggered early at boot-time the 'orderly' call will + * partially fail due to the lack of userspace itself, but + * the force=3Dtrue argument will start anyway a successful + * forced shutdown. + */ + orderly_poweroff(true); + break; + case SCMI_SYSTEM_COLDRESET: + case SCMI_SYSTEM_WARMRESET: + orderly_reboot(); + break; + default: + break; + } +} + +/** + * scmi_userspace_notifier - Notifier callback to act on SystemPower + * Notifications + * @nb: Reference to the related notifier block + * @event: The SystemPower notification event id + * @data: The SystemPower event report + * + * This callback is in charge of decoding the received SystemPower report + * and act accordingly triggering a graceful or forceful system transition. + * + * Note that once a valid SCMI SystemPower event starts being served, any + * other following SystemPower notification received from the same SCMI + * instance (handle) will be ignored. + * + * Return: NOTIFY_OK once a valid SystemPower event has been successfully + * processed. + */ +static int scmi_userspace_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct scmi_system_power_state_notifier_report *er =3D data; + struct scmi_syspower_conf *sc =3D userspace_nb_to_sconf(nb); + + if (er->system_state >=3D SCMI_SYSTEM_POWERUP) { + dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n", + er->system_state); + return NOTIFY_DONE; + } + + if (!SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(er->flags)) { + dev_err(sc->dev, "Ignoring forceful notification.\n"); + return NOTIFY_DONE; + } + + /* + * Bail out if system is already shutting down or an SCMI SystemPower + * requested is already being served. + */ + if (system_state > SYSTEM_RUNNING) + return NOTIFY_DONE; + mutex_lock(&sc->state_mtx); + if (sc->state !=3D SCMI_SYSPOWER_IDLE) { + dev_dbg(sc->dev, + "Transition already in progress...ignore.\n"); + mutex_unlock(&sc->state_mtx); + return NOTIFY_DONE; + } + sc->state =3D SCMI_SYSPOWER_IN_PROGRESS; + mutex_unlock(&sc->state_mtx); + + sc->required_transition =3D er->system_state; + + /* Leaving a trace in logs of who triggered the shutdown/reboot. */ + dev_info(sc->dev, "Serving shutdown/reboot request: %d\n", + sc->required_transition); + + scmi_request_graceful_transition(sc, er->timeout); + + return NOTIFY_OK; +} + +static int scmi_syspower_probe(struct scmi_device *sdev) +{ + int ret; + struct scmi_syspower_conf *sc; + struct scmi_handle *handle =3D sdev->handle; + + if (!handle) + return -ENODEV; + + ret =3D handle->devm_protocol_acquire(sdev, SCMI_PROTOCOL_SYSTEM); + if (ret) + return ret; + + sc =3D devm_kzalloc(&sdev->dev, sizeof(*sc), GFP_KERNEL); + if (!sc) + return -ENOMEM; + + sc->state =3D SCMI_SYSPOWER_IDLE; + mutex_init(&sc->state_mtx); + sc->required_transition =3D SCMI_SYSTEM_MAX; + sc->userspace_nb.notifier_call =3D &scmi_userspace_notifier; + sc->dev =3D &sdev->dev; + + return handle->notify_ops->devm_event_notifier_register(sdev, + SCMI_PROTOCOL_SYSTEM, + SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + NULL, &sc->userspace_nb); +} + +static const struct scmi_device_id scmi_id_table[] =3D { + { SCMI_PROTOCOL_SYSTEM, "syspower" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_system_power_driver =3D { + .name =3D "scmi-system-power", + .probe =3D scmi_syspower_probe, + .id_table =3D scmi_id_table, +}; +module_scmi_driver(scmi_system_power_driver); + +MODULE_AUTHOR("Cristian Marussi "); +MODULE_DESCRIPTION("ARM SCMI SystemPower Control driver"); +MODULE_LICENSE("GPL"); --=20 2.32.0