From patchwork Thu Feb 4 16:59:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12067871 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=-17.1 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,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 A4D16C433E0 for ; Thu, 4 Feb 2021 17:01:54 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6D2A964F65 for ; Thu, 4 Feb 2021 17:01:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6D2A964F65 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=NAZsvSLkBTOQVTb/pwRYroVVvmN6hAhWV0WQqRUBJow=; b=XqWEvIyZkfXbPw5V1kgXUennYp +6LLvW8E933TnIAF07K1IKkkABfgleffG0XVNLTZdXkJakiLdxKuxNFYw/un8WxNJw4m8gq/jGtVo dzBMra2EufkXqKXpZRIDqPG7gXVuivjuEMEIZHE/LVEtHUJEKGMzQEe9R0CA8zlNBqpy74A7hdH/f EBHKLFbSHu11UKzO8dddWk7nr1m+FIkop5xiRR4DpkJDkIOlIxq4iry6ohBD3cuW+z9XPmxvmM2kt qPQ2r+t6q0cJoIkOMiBOwNFf3thSrWCs3uFEAF0Dd879kmRyhN0s59ZL9vewfwU6Fkeb3cameUetl Fjp2f0NQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hzj-00086X-CY; Thu, 04 Feb 2021 17:00:39 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hzc-000844-49 for linux-arm-kernel@lists.infradead.org; Thu, 04 Feb 2021 17:00:33 +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 084F711FB; Thu, 4 Feb 2021 09:00:24 -0800 (PST) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 477BC3F73B; Thu, 4 Feb 2021 09:00:22 -0800 (PST) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v5 1/3] firmware: arm_scmi: support only one single SystemPower device Date: Thu, 4 Feb 2021 16:59:11 +0000 Message-Id: <20210204165913.42582-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210204165913.42582-1-cristian.marussi@arm.com> References: <20210204165913.42582-1-cristian.marussi@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210204_120032_515829_CB024D06 X-CRM114-Status: GOOD ( 13.81 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: robh@kernel.org, arnd@arndb.de, gregkh@linuxfoundation.org, sudeep.holla@arm.com, lukasz.luba@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org In order to minimize SCMI platform fw-side complexity, only one 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 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index 88149a46e6d9..e8542a7e8862 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -19,6 +19,9 @@ static DEFINE_IDA(scmi_bus_id); static DEFINE_IDR(scmi_available_protocols); static DEFINE_SPINLOCK(protocol_lock); +/* Track globally the creation of SCMI SystemPower related devices */ +static bool scmi_syspower_registered; + static const struct scmi_device_id * scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv) { @@ -175,6 +178,23 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol, int id, retval; struct scmi_device *scmi_dev; + /* + * Check if any SCMI SystemPower device was already created. + * + * Note that, shared global @scmi_syspower_registered is not protected + * by a mutex since: + * - scmi_device_create() is not concurrently invoked by the SCMI core + * - scmi_device_destroy() is effectively called only upon SCMI core + * unloading/unbinding, so no race is either possible between create + * and destroy. + */ + if (protocol == SCMI_PROTOCOL_SYSTEM && scmi_syspower_registered) { + dev_warn(parent, + "SCMI SystemPower protocol device must be unique !\n"); + dump_stack(); + return NULL; + } + scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL); if (!scmi_dev) return NULL; @@ -204,6 +224,9 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol, if (retval) goto put_dev; + if (protocol == SCMI_PROTOCOL_SYSTEM) + scmi_syspower_registered = true; + return scmi_dev; put_dev: kfree_const(scmi_dev->name); @@ -218,6 +241,8 @@ void scmi_device_destroy(struct scmi_device *scmi_dev) scmi_handle_put(scmi_dev->handle); ida_simple_remove(&scmi_bus_id, scmi_dev->id); device_unregister(&scmi_dev->dev); + if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM) + scmi_syspower_registered = false; } void scmi_set_handle(struct scmi_device *scmi_dev) From patchwork Thu Feb 4 16:59:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12067869 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=-17.1 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,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 026EEC433DB for ; Thu, 4 Feb 2021 17:01:50 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C108564F65 for ; Thu, 4 Feb 2021 17:01:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C108564F65 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=ArTRvjaIh3/BeRFlzt6GvdZTti5flZiUQGoW+3N5CHk=; b=Y04nC9DSXO8p4buI8YlsNp+7Tw 62aamY+QfE8TbjDlEMBnA0pW7EZVJZTILdam4cBjIT7WC1XLBRFpGHvLZ0YEJHI/SjJh6vtZCdtvN LJETKX4V82wydf6+VkT8miqeAdrW44pvtS9tEG+/LHPiItPdKioKd6+2z22R/u8ygoB0bjQ/L++mI SoKySgGT306e9sctpa3JH23d4bA1RkQQVpf57UttKbWgZ4OUlM66VIK1s1Ug8eecbFRzdi0R1bjWu cuXKx6rA3/fjJB4HoqyQ8xN4Gz1JpCHd3hryo+MDoetj5aIerPc5RQgNm0tW8au+2A43Pn87RJ1dL m79KoQhA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hze-00084r-Dy; Thu, 04 Feb 2021 17:00:34 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hza-00083O-HO for linux-arm-kernel@lists.infradead.org; Thu, 04 Feb 2021 17:00:31 +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 03F0D12FC; Thu, 4 Feb 2021 09:00:26 -0800 (PST) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 414F03F73B; Thu, 4 Feb 2021 09:00:24 -0800 (PST) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v5 2/3] firmware: arm_scmi: add System Power utility macro Date: Thu, 4 Feb 2021 16:59:12 +0000 Message-Id: <20210204165913.42582-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210204165913.42582-1-cristian.marussi@arm.com> References: <20210204165913.42582-1-cristian.marussi@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210204_120030_653186_7D8D76DF X-CRM114-Status: GOOD ( 11.64 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: robh@kernel.org, arnd@arndb.de, gregkh@linuxfoundation.org, sudeep.holla@arm.com, lukasz.luba@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a trivial macro to check the kind of SCMI SystemPower request. Signed-off-by: Cristian Marussi --- include/linux/scmi_protocol.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index fb8c8f16a49b..ecc14251a547 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -747,6 +747,7 @@ struct scmi_power_state_changed_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; }; From patchwork Thu Feb 4 16:59:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12067935 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=-17.1 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,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 6A5E9C433DB for ; Thu, 4 Feb 2021 17:02:00 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1C76064F3C for ; Thu, 4 Feb 2021 17:02:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1C76064F3C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=v6u/J6NeiWf+HdbrTGhzn2tjf/ehq1D+g/zZoDUXzss=; b=J3oYzSdWJ+s6xZJnRfQr0Sm1fJ PgC13eqsGYtG+TxHGVWw1DugLo7Bus97eCdMoY+dgzdwM/RTpc59cPhSTOpXsFrjWMAjklG8tD/4H tnWwbCBIUoyt346IF1mKfLTp++gNq0WOkQUzpBgPJ3rBWx2GV6zBko4yHZrnMs6iNa1gvjQtxLQWa HLWW/XIANFJeGqbyhe/q/8pXVWVIpLApw5jtE6mzf3dDlwOZKUrMRWq23UE067CcNawlZZOdWNBLN Bru2Uf1RZE6BfcXkamiUcFbFGWNkVz03LFLIyWsrl9zTGcbZgYmxhVnL1BxER4Wfy8Dv3xsOkuC2w Hq8DaTQg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hzn-00087l-1o; Thu, 04 Feb 2021 17:00:43 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l7hzg-00085V-4m for linux-arm-kernel@lists.infradead.org; Thu, 04 Feb 2021 17:00:39 +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 028AE1396; Thu, 4 Feb 2021 09:00:28 -0800 (PST) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3B8A93F73B; Thu, 4 Feb 2021 09:00:26 -0800 (PST) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v5 3/3] firmware: arm_scmi: add SCMI System Power Control driver Date: Thu, 4 Feb 2021 16:59:13 +0000 Message-Id: <20210204165913.42582-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210204165913.42582-1-cristian.marussi@arm.com> References: <20210204165913.42582-1-cristian.marussi@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210204_120036_378075_D160911C X-CRM114-Status: GOOD ( 38.31 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: robh@kernel.org, arnd@arndb.de, gregkh@linuxfoundation.org, sudeep.holla@arm.com, lukasz.luba@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org 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. Signed-off-by: Cristian Marussi --- v4 --> v5 - rebased on SCMI Modules v5 series to use new SCMI protocols interface - removed signal based shutdown/reboot - removed all module parameters - added 60secs fixed timeout to shutdwon/reboot requests - make it modularizable to cope with SCMI core modularization - refactored all data config structs - using dev_* instead of pr_* v3 --> v4 - rebased v5.11-rc2 - removed unneeded ugly usage of atomics and barriers - simplfied SysPower shutdown state machine - split out macro definition to different patch v2 --> v3 - rebased - some minor cleanup in codestyle and commit message v1 --> v2 - split out of SCMI System Power Protocol series now merged --- drivers/firmware/Kconfig | 12 + drivers/firmware/arm_scmi/Makefile | 1 + .../firmware/arm_scmi/scmi_power_control.c | 347 ++++++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 drivers/firmware/arm_scmi/scmi_power_control.c diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 3f14dffb9669..73e27925f1e3 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -40,6 +40,18 @@ config ARM_SCMI_POWER_DOMAIN will be called scmi_pm_domain. Note this may needed early in boot before rootfs may be available. +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. + config ARM_SCPI_PROTOCOL tristate "ARM System Control and Power Interface (SCPI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 6a2ef63306d6..ddddb4636ebd 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -9,3 +9,4 @@ scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \ $(scmi-transport-y) obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o +obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o diff --git a/drivers/firmware/arm_scmi/scmi_power_control.c b/drivers/firmware/arm_scmi/scmi_power_control.c new file mode 100644 index 000000000000..60d976c2facc --- /dev/null +++ b/drivers/firmware/arm_scmi/scmi_power_control.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SCMI Generic SystemPower Control driver. + * + * Copyright (C) 2020-2021 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 platform. + * + * 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. + * + * Forceful requests, instead, will simply cause an immediate emergency_sync() + * (only if this driver was not built as a module) and subsequent Kernel-only + * shutdown/reboot. + * + * Additionally, graceful requests are allowed a maximum amount of time to + * complete, after which they are converted to forceful ones: the assumption + * here is that even graceful requests can be upper-bound by a maximum final + * timeout strictly enforced by the platform itself which can ultimately cut + * 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 notifier + * converting timed-out graceful requests to forceful ones, so at least we + * perform a clean sync and shutdown/restart before the power is cut. + * + * 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 matter + * how many SCMI platforms are defined on the system, only one can be designated + * to support System Power: as a consequence this driver will never be probed + * 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 + +#ifndef MODULE +#include +#endif + +#define SCMI_GRACEFUL_REQ_TMO_MS (60 * MSEC_PER_SEC) + +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 received + * SCMI SystemPower notification + * @userspace_nb: The notifier_block registered against the SCMI SystemPower + * notification to start the needed userspace interactions. + * @reboot_nb: A notifier_block optionally used to track reboot progress + * @request_timer: A timer optionally used to detect late/unresponsive userspace + * @forceful_work: A worker used to trigger a forceful transition once a + * graceful has timed out. + */ +static 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 timer_list request_timer; + struct work_struct forceful_work; +} *sc; + +/** + * 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 timer work. + * + * Return: NOTIFY_OK in any case + */ +static int scmi_reboot_notifier(struct notifier_block *nb, + unsigned long reason, void *__unused) +{ + mutex_lock(&sc->state_mtx); + switch (reason) { + case SYS_HALT: + case SYS_POWER_OFF: + if (sc->required_transition == SCMI_SYSTEM_SHUTDOWN) + sc->state = SCMI_SYSPOWER_REBOOTING; + break; + case SYS_RESTART: + if (sc->required_transition == SCMI_SYSTEM_COLDRESET || + sc->required_transition == SCMI_SYSTEM_WARMRESET) + sc->state = SCMI_SYSPOWER_REBOOTING; + break; + default: + break; + } + + if (sc->state == SCMI_SYSPOWER_REBOOTING) { + dev_dbg(sc->dev, "Reboot in progress...cancel timer.\n"); + del_timer_sync(&sc->request_timer); + } + mutex_unlock(&sc->state_mtx); + + return NOTIFY_OK; +} + +/** + * scmi_request_forceful_transition - Request forceful SystemPower transition + * + * Initiates the required SystemPower transition without involving userspace: + * just trigger the action at the kernel level after issuing an emergency + * sync. (if possible at all) + */ +static void scmi_request_forceful_transition(void) +{ + 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) +{ + if (system_state > SYSTEM_RUNNING) + return; + + mutex_lock(&sc->state_mtx); + /* avoid deadlock by unregistering reboot notifier first */ + unregister_reboot_notifier(&sc->reboot_nb); + if (sc->state == SCMI_SYSPOWER_IN_PROGRESS) + scmi_request_forceful_transition(); + mutex_unlock(&sc->state_mtx); +} + +/** + * scmi_request_timeout - On timeout trigger a forceful transition + * @t: The timer reference + * + * Actual work is deferred out of the timer IRQ context since shutdown/reboot + * code do not play well when !in_task(). + */ +static void scmi_request_timeout(struct timer_list *t) +{ + dev_dbg(sc->dev, "Graceful request timed out...forcing !\n"); + + schedule_work(&sc->forceful_work); +} + +/** + * scmi_request_graceful_transition - Request graceful SystemPower transition + * + * Initiates the required SystemPower transition, requesting userspace + * co-operation: it uses the same orderly_ methods used by ACPI Shutdown event + * processing. + * + * Takes care also to register a reboot notifier and a timer callback in order + * to detect if userspace actions are taking too long and in such a case falls + * back to a forceful transition. + */ +static void scmi_request_graceful_transition(void) +{ + int ret; + + sc->reboot_nb.notifier_call = &scmi_reboot_notifier; + ret = register_reboot_notifier(&sc->reboot_nb); + if (!ret) { + INIT_WORK(&sc->forceful_work, scmi_forceful_work_func); + sc->request_timer.expires = jiffies + + msecs_to_jiffies(SCMI_GRACEFUL_REQ_TMO_MS); + timer_setup(&sc->request_timer, + scmi_request_timeout, 0); + add_timer(&sc->request_timer); + } 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 request: %d (timeout_ms:%ld)\n", + sc->required_transition, SCMI_GRACEFUL_REQ_TMO_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=true 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 = data; + + if (er->system_state >= SCMI_SYSTEM_POWERUP) { + dev_err(sc->dev, "Ignoring invalid request: %d\n", + er->system_state); + 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 != SCMI_SYSPOWER_IDLE) { + dev_dbg(sc->dev, + "Transition already in progress...ignore.\n"); + mutex_unlock(&sc->state_mtx); + return NOTIFY_DONE; + } + sc->state = SCMI_SYSPOWER_IN_PROGRESS; + mutex_unlock(&sc->state_mtx); + + sc->required_transition = 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); + + if (SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(er->flags)) + scmi_request_graceful_transition(); + else + scmi_request_forceful_transition(); + + return NOTIFY_OK; +} + +static int scmi_syspower_probe(struct scmi_device *sdev) +{ + int ret; + struct scmi_handle *handle = sdev->handle; + + if (!handle) + return -ENODEV; + + ret = handle->devm_acquire_protocol(sdev, SCMI_PROTOCOL_SYSTEM); + if (ret) + return ret; + + sc = devm_kzalloc(&sdev->dev, sizeof(*sc), GFP_KERNEL); + if (!sc) + return -ENOMEM; + + sc->state = SCMI_SYSPOWER_IDLE; + mutex_init(&sc->state_mtx); + sc->required_transition = SCMI_SYSTEM_MAX; + sc->userspace_nb.notifier_call = &scmi_userspace_notifier; + sc->dev = &sdev->dev; + + return handle->notify_ops->devm_register_event_notifier(sdev, + SCMI_PROTOCOL_SYSTEM, + SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + NULL, &sc->userspace_nb); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_SYSTEM, "syspower" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_system_power_driver = { + .name = "scmi-system-power", + .probe = scmi_syspower_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_system_power_driver); + +MODULE_AUTHOR("Cristian Marussi "); +MODULE_DESCRIPTION("ARM SCMI SystemPower Control driver"); +MODULE_LICENSE("GPL v2");