From patchwork Mon Jun 22 15:18:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 11618171 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7209F14B7 for ; Mon, 22 Jun 2020 15:20: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 42D362073E for ; Mon, 22 Jun 2020 15:20:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="jUy7xf05" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 42D362073E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.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=STwwH5U0rzyodVHQW4xRW3zAzw8QizmVJuKOQLKWTdA=; b=jUy7xf05LZLovVImFm4+gL2u9P 3W6iJkMl/CDF+IvKOZp6x1yTldvCNScnhXZdgmbKUdsmYy5Moj4GOJSFe6VsKr+gpzYj1OjIsrRGd 69ry8qj+fA1IkbPtzr1/mfIRUlFNqo+G/rpX6LIB/afVNMfOngXpoRsDgzpKN+JNwEvQArpJ8AD19 TJE3luPSm2T3soRuBpE5PNnKQvzj0EMXw/OL+ZEx1/zkFuXQNSCVcZ6aCfMjtwXzub0ARgbNbQ5md OuBLwcm9dYx7EH9ELLo8wqp355WLCiseY+347nEzr4l33/9of/KyXpyjT640WZCTgDFkRSj+CuyeH qB87t/EA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jnODw-0008LF-MS; Mon, 22 Jun 2020 15:19:04 +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 1jnODu-0008Js-55 for linux-arm-kernel@lists.infradead.org; Mon, 22 Jun 2020 15:19:03 +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 7D915D6E; Mon, 22 Jun 2020 08:18:30 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 754983F6CF; Mon, 22 Jun 2020 08:18:29 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v3 1/3] firmware: arm_scmi: Add System Power Protocol support Date: Mon, 22 Jun 2020 16:18:14 +0100 Message-Id: <20200622151816.15491-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200622151816.15491-1-cristian.marussi@arm.com> References: <20200622151816.15491-1-cristian.marussi@arm.com> X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [217.140.110.172 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 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: Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com, james.quinlan@broadcom.com, lukasz.luba@arm.com, sudeep.holla@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Add bare protocol support for SCMI SystemPower as needed by an OSPM agent: basic initialization and SYSTEM_POWER_STATE_NOTIFIER core notification support. No event-handling logic is attached to such notification by this commit. Signed-off-by: Cristian Marussi --- V2 --> V3 - fixes related to SCMI Notifications core support V10 V1 --> V2 - use common event enums --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/system.c | 136 +++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 18 ++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/system.c diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 11f1e07f603e..2bb446c3df67 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -5,5 +5,5 @@ scmi-driver-y = driver.o notify.o scmi-transport-y = shmem.o scmi-transport-$(CONFIG_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o -scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o +scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c new file mode 100644 index 000000000000..e5d6dfa66009 --- /dev/null +++ b/drivers/firmware/arm_scmi/system.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) System Power Protocol + * + * Copyright (C) 2020 ARM Ltd. + */ + +#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt + +#include + +#include "common.h" +#include "notify.h" + +#define SCMI_SYSTEM_NUM_SOURCES 1 + +enum scmi_system_protocol_cmd { + SYSTEM_POWER_STATE_NOTIFY = 0x5, +}; + +struct scmi_system_power_state_notify { + __le32 notify_enable; +}; + +struct scmi_system_power_state_notifier_payld { + __le32 agent_id; + __le32 flags; + __le32 system_state; +}; + +struct scmi_system_info { + u32 version; +}; + +static int scmi_system_request_notify(const struct scmi_handle *handle, + bool enable) +{ + int ret; + struct scmi_xfer *t; + struct scmi_system_power_state_notify *notify; + + ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY, + SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t); + if (ret) + return ret; + + notify = t->tx.buf; + notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; + + ret = scmi_do_xfer(handle, t); + + scmi_xfer_put(handle, t); + return ret; +} + +static bool scmi_system_set_notify_enabled(const struct scmi_handle *handle, + u8 evt_id, u32 src_id, bool enable) +{ + int ret; + + ret = scmi_system_request_notify(handle, enable); + if (ret) + pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret); + + return !ret; +} + +static void *scmi_system_fill_custom_report(const struct scmi_handle *handle, + u8 evt_id, u64 timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) +{ + const struct scmi_system_power_state_notifier_payld *p = payld; + struct scmi_system_power_state_notifier_report *r = report; + + if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER || + sizeof(*p) != payld_sz) + return NULL; + + r->timestamp = timestamp; + r->agent_id = le32_to_cpu(p->agent_id); + r->flags = le32_to_cpu(p->flags); + r->system_state = le32_to_cpu(p->system_state); + *src_id = 0; + + return r; +} + +static const struct scmi_event system_events[] = { + { + .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + .max_payld_sz = + sizeof(struct scmi_system_power_state_notifier_payld), + .max_report_sz = + sizeof(struct scmi_system_power_state_notifier_report), + }, +}; + +static const struct scmi_event_ops system_event_ops = { + .set_notify_enabled = scmi_system_set_notify_enabled, + .fill_custom_report = scmi_system_fill_custom_report, +}; + +static int scmi_system_protocol_init(struct scmi_handle *handle) +{ + u32 version; + struct scmi_system_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version); + + dev_dbg(handle->dev, "System Power Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + scmi_register_protocol_events(handle, + SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ, + &system_event_ops, + system_events, + ARRAY_SIZE(system_events), + SCMI_SYSTEM_NUM_SOURCES); + + pinfo->version = version; + handle->system_priv = pinfo; + + return 0; +} + +static int __init scmi_system_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_SYSTEM, + &scmi_system_protocol_init); +} +subsys_initcall(scmi_system_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 46d98be92466..f59e5df1a61e 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -292,6 +292,7 @@ struct scmi_handle { void *sensor_priv; void *reset_priv; void *notify_priv; + void *system_priv; }; enum scmi_std_protocol { @@ -304,6 +305,15 @@ enum scmi_std_protocol { SCMI_PROTOCOL_RESET = 0x16, }; +enum scmi_system_events { + SCMI_SYSTEM_SHUTDOWN, + SCMI_SYSTEM_COLDRESET, + SCMI_SYSTEM_WARMRESET, + SCMI_SYSTEM_POWERUP, + SCMI_SYSTEM_SUSPEND, + SCMI_SYSTEM_MAX +}; + struct scmi_device { u32 id; u8 protocol_id; @@ -378,6 +388,7 @@ enum scmi_notification_events { SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0, SCMI_EVENT_RESET_ISSUED = 0x0, SCMI_EVENT_BASE_ERROR_EVENT = 0x0, + SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER = 0x0, }; struct scmi_power_state_changed_report { @@ -387,6 +398,13 @@ struct scmi_power_state_changed_report { u32 power_state; }; +struct scmi_system_power_state_notifier_report { + u64 timestamp; + u32 agent_id; + u32 flags; + u32 system_state; +}; + struct scmi_perf_limits_report { u64 timestamp; u32 agent_id; From patchwork Mon Jun 22 15:18:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 11618177 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 111C814B7 for ; Mon, 22 Jun 2020 15:21:14 +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 D13FC206D7 for ; Mon, 22 Jun 2020 15:21:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="EeLud1a1" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D13FC206D7 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.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=v+8u6FiFcf85YZ6d3rfzYsA9jKV2hM8QKrT+9sIwyWA=; b=EeLud1a1YqB7ANnk7cFpyY1rqg ZFym3N5+1z7I8raQQUp9Bp0RAQlfyEWqPSScBUUlNwyRoCSvyCprdwJGLKziddng0iJw/ukeoBytc CMEgz6mFT0+rOpKFnRAh9DQ3E6oWqcF8WlFT1ZAOzxIq2oM9Omxtc3ikMfCC/sb5fvJz4yL1befqK 2g5iAc7vRNAQsoXW2RJSrwWij5BcDlgnjkS+EdXkePW9+uQZab+t46ScJozByPpdXgpN9CxKfE19m NgwrHs+ejxhtnmJvEyHCJXKNm807hAPLH8qCYo+o5whAlvCLY8lYUwt7NISU0AqOwgUpmm81FaiKz LyhZjgbQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jnOE1-0008M9-Cb; Mon, 22 Jun 2020 15:19:09 +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 1jnODu-0008KI-56 for linux-arm-kernel@lists.infradead.org; Mon, 22 Jun 2020 15:19:03 +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 BC5361045; Mon, 22 Jun 2020 08:18:31 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B2F823F6CF; Mon, 22 Jun 2020 08:18:30 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v3 2/3] firmware: arm_scmi: Add SCMI System Power Control driver Date: Mon, 22 Jun 2020 16:18:15 +0100 Message-Id: <20200622151816.15491-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200622151816.15491-1-cristian.marussi@arm.com> References: <20200622151816.15491-1-cristian.marussi@arm.com> X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [217.140.110.172 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 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: Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com, james.quinlan@broadcom.com, lukasz.luba@arm.com, sudeep.holla@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.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 power state transitions are handled accordingly, gracefully or forcefully, depending on the notifications' message flags. Graceful requests are by default relayed to userspace using the same Kernel API used to handle ACPI Shutdown bus events: alternatively, instead, a few available module parameters can be used to tunnel instead such requests to userspace via signals addressed to CAD pid. When handling graceful requests, grant userspace processes a maximum (configurable) time to perform their duties and then revert to a forceful transition, so avoiding completely timing out platform's maximum grace time and hitting possible abrupt power-cuts. Signed-off-by: Cristian Marussi ---- V2 --> V3 - changed Kconfig to fix naming and defaulting to n V1 --> V2 - use common event enums - introduced optioanl alternative signal based comms 2 userspace --- drivers/firmware/Kconfig | 12 + drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/driver.c | 1 + .../firmware/arm_scmi/scmi_power_control.c | 389 ++++++++++++++++++ 4 files changed, 403 insertions(+) create mode 100644 drivers/firmware/arm_scmi/scmi_power_control.c diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index fbd785dd0513..a77545c08040 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 + bool "SCMI system power control driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default n + help + This enables System Power control logic which binds system shutdown or + reboot actions to SCMI System Power notifications generated by SCP + firmware. + + Graceful requests' methods and timeout and can be configured using + a few available module parameters. + 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 2bb446c3df67..54a1b08f51e2 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -7,3 +7,4 @@ scmi-transport-$(CONFIG_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.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/driver.c b/drivers/firmware/arm_scmi/driver.c index 1ba2ecafbd96..a212bc5ce527 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -732,6 +732,7 @@ struct scmi_prot_devnames { static struct scmi_prot_devnames devnames[] = { { SCMI_PROTOCOL_POWER, { "genpd" },}, + { SCMI_PROTOCOL_SYSTEM, {"syspower" },}, { SCMI_PROTOCOL_PERF, { "cpufreq" },}, { SCMI_PROTOCOL_CLOCK, { "clocks" },}, { SCMI_PROTOCOL_SENSOR, { "hwmon" },}, 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..56d01f3ffe91 --- /dev/null +++ b/drivers/firmware/arm_scmi/scmi_power_control.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SCMI Generic System Power support. + * + * Copyright (C) 2020 ARM Ltd. + */ +/** + * DOC: Theory of operation + * + * In order to handle platform originated SCMI System Power requests (like + * shutdowns or cold/warm resets) we register an SCMI Notification notifier + * block to react when such SCMI System Power events are emitted. + * + * Once such a notification is received we act accordingly to perform the + * required system transition depending on the kind of request. + * + * By default graceful requests are routed to userspace through the same + * API methods (orderly_poweroff/reboot()) used by ACPI when handling ACPI + * Shutdown bus events: alternatively, by properly setting a couple of module + * parameters, it is possible to choose to use signals to CAD pid as a mean + * to communicate such graceful requests. + * + * Forceful requests instead simply cause and immediate emergency_sync() and + * subsequent Kernel-only shutdown/reboot. + * + * 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 + * finally cuts the power off at will: in such a scenario, which we want to + * avoid, we track the graceful requests progress through the means of a + * reboot_notifier and promptly convert a timed-out graceful request to a + * forceful one when userspace is late, in order to at least perform a clean + * sync and shutdown/restart. + * + * Given that such platform hard-timeout, when present, is anyway highly + * platform/event specific and not exposed at run-time, we make it configurable + * via the Kernel module param @scmi_graceful_request_tmo_ms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_GRACE_TMO_MS 5000 +static unsigned int scmi_graceful_request_tmo_ms = DEFAULT_GRACE_TMO_MS; +static unsigned int scmi_graceful_poweroff_signum; +static unsigned int scmi_graceful_reboot_signum; + +enum scmi_system_request_status { + SCMI_SYSPOWER_IDLE, + SCMI_SYSPOWER_SERVED, + SCMI_SYSPOWER_INPROGRESS, + SCMI_SYSPOWER_FORCING, +}; + +struct scmi_syspower_config { + struct device *dev; + + atomic_t status; + + u32 required_state; + + void (*request_graceful_transition)(struct scmi_syspower_config *conf); + void (*request_forceful_transition)(struct scmi_syspower_config *conf); + + struct notifier_block userspace_nb; + struct notifier_block reboot_nb; + + struct timer_list request_timer; + struct work_struct forceful_work; +}; + +static void scmi_forceful_work_func(struct work_struct *work) +{ + struct scmi_syspower_config *conf = + container_of(work, struct scmi_syspower_config, forceful_work); + + conf->request_forceful_transition(conf); +} + +/** + * 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) +{ + struct scmi_syspower_config *conf = from_timer(conf, t, request_timer); + + dev_warn(conf->dev, + "SCMI Graceful System Transition request timed out !\n"); + atomic_set(&conf->status, SCMI_SYSPOWER_FORCING); + /* Ensure atomic values are updated */ + smp_mb__after_atomic(); + schedule_work(&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 requested + * one, cancel the timer work. + * + * Return: NOTIFY_OK in any case + */ +static int scmi_reboot_notifier(struct notifier_block *nb, + unsigned long reason, void *__unused) +{ + struct scmi_syspower_config *conf; + + conf = container_of(nb, struct scmi_syspower_config, reboot_nb); + + /* Ensure atomic values are updated */ + smp_mb__before_atomic(); + if (unlikely(atomic_read(&conf->status) == SCMI_SYSPOWER_FORCING)) + return NOTIFY_OK; + + switch (reason) { + case SYS_HALT: + case SYS_POWER_OFF: + if (conf->required_state == SCMI_SYSTEM_SHUTDOWN) + atomic_set(&conf->status, SCMI_SYSPOWER_INPROGRESS); + break; + case SYS_RESTART: + if (conf->required_state == SCMI_SYSTEM_COLDRESET || + conf->required_state == SCMI_SYSTEM_WARMRESET) + atomic_set(&conf->status, SCMI_SYSPOWER_INPROGRESS); + break; + default: + break; + } + + /* Ensure atomic values are updated */ + smp_mb__after_atomic(); + if (atomic_read(&conf->status) == SCMI_SYSPOWER_INPROGRESS) { + dev_info(conf->dev, + "SCMI System State request in progress...\n"); + del_timer_sync(&conf->request_timer); + } + + return NOTIFY_OK; +} + +static inline void scmi_send_cad_signal(struct device *dev, unsigned int sig) +{ + dev_info(dev, "SCMI Sending signal %d to CAD pid\n", sig); + + kill_cad_pid(sig, 1); +} + +/** + * scmi_request_graceful_transition - Request graceful SystemPower transition + * @conf: The current SystemPower configuration descriptor + * + * Initiates the required SystemPower transition, requesting userspace + * co-operation using the same orderly_ methods used by ACPI Shutdown event + * processing. + * + * This takes care also to register a reboot notifier and a timer callback in + * order to detect if userspace actions are taking too long; in such a case + * the timeout callback will finally perform a forceful transition, ignoring + * lagging userspace: the aim here is to at least perform an emergency_sync() + * and a clean shutdown or reboot transition when userspace is late, avoiding + * the brutal final power-cut from platform. + */ +static void scmi_request_graceful_transition(struct scmi_syspower_config *conf) +{ + int ret; + u32 status; + + if (conf->required_state >= SCMI_SYSTEM_POWERUP) { + dev_warn(conf->dev, + "Received unexpected SYSTEM POWER request: %d\n", + conf->required_state); + return; + } + + status = atomic_cmpxchg(&conf->status, SCMI_SYSPOWER_IDLE, + SCMI_SYSPOWER_SERVED); + if (status != SCMI_SYSPOWER_IDLE) + return; + + ret = devm_register_reboot_notifier(conf->dev, &conf->reboot_nb); + if (ret) + dev_warn(conf->dev, "Cannot register reboot notifier !\n"); + + INIT_WORK(&conf->forceful_work, scmi_forceful_work_func); + conf->request_timer.expires = jiffies + + msecs_to_jiffies(scmi_graceful_request_tmo_ms); + timer_setup(&conf->request_timer, scmi_request_timeout, 0); + add_timer(&conf->request_timer); + + dev_info(conf->dev, + "Serving SCMI Graceful request: %d (timeout_ms:%d)\n", + conf->required_state, scmi_graceful_request_tmo_ms); + + switch (conf->required_state) { + case SCMI_SYSTEM_SHUTDOWN: + /* + * When received early at boot-time the 'orderly' part will + * fail due to the lack of userspace itself, but the force=true + * argument will anyway be able trigger a successful forced + * shutdown. + */ + if (!scmi_graceful_poweroff_signum) + orderly_poweroff(true); + else + scmi_send_cad_signal(conf->dev, + scmi_graceful_poweroff_signum); + break; + case SCMI_SYSTEM_COLDRESET: + case SCMI_SYSTEM_WARMRESET: + if (!scmi_graceful_reboot_signum) + orderly_reboot(); + else + scmi_send_cad_signal(conf->dev, + scmi_graceful_reboot_signum); + break; + default: + break; + } +} + +static void scmi_request_forceful_transition(struct scmi_syspower_config *conf) +{ + /* Ensure atomic values are updated */ + smp_mb__before_atomic(); + if (unlikely(atomic_read(&conf->status) == SCMI_SYSPOWER_INPROGRESS)) + return; + + dev_info(conf->dev, "Serving SCMI FORCEFUL SystemPower request:%d\n", + conf->required_state); + + emergency_sync(); + switch (conf->required_state) { + case SCMI_SYSTEM_SHUTDOWN: + kernel_power_off(); + break; + case SCMI_SYSTEM_COLDRESET: + case SCMI_SYSTEM_WARMRESET: + kernel_restart(NULL); + break; + default: + break; + } +} + +#define SCMI_IS_REQUEST_GRACEFUL(flags) ((flags) & BIT(0)) + +/** + * 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. + * + * Return: NOTIFY_OK in any case + */ +static int scmi_userspace_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct scmi_system_power_state_notifier_report *er = data; + struct scmi_syspower_config *conf; + + if (unlikely(system_state > SYSTEM_RUNNING)) + return NOTIFY_OK; + + conf = container_of(nb, struct scmi_syspower_config, userspace_nb); + conf->required_state = er->system_state; + + if (conf->required_state >= SCMI_SYSTEM_MAX) + return NOTIFY_OK; + + if (SCMI_IS_REQUEST_GRACEFUL(er->flags)) + conf->request_graceful_transition(conf); + else + conf->request_forceful_transition(conf); + + return NOTIFY_OK; +} + +/** + * scmi_syspower_configure - General SystemPower configuration init + * @dev: The associated struct device + * + * Return: SystemPower configuration descriptor on Success, NULL otherwise + */ +static void *scmi_syspower_configure(struct device *dev) +{ + struct scmi_syspower_config *conf; + + conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL); + if (!conf) + return NULL; + + conf->dev = dev; + conf->required_state = SCMI_SYSTEM_MAX; + conf->request_graceful_transition = &scmi_request_graceful_transition; + conf->request_forceful_transition = &scmi_request_forceful_transition; + conf->userspace_nb.notifier_call = &scmi_userspace_notifier; + conf->reboot_nb.notifier_call = &scmi_reboot_notifier; + atomic_set(&conf->status, SCMI_SYSPOWER_IDLE); + /* Ensure atomic values are updated */ + smp_mb__after_atomic(); + + return conf; +} + +static int scmi_syspower_probe(struct scmi_device *sdev) +{ + int ret; + struct scmi_handle *handle = sdev->handle; + struct scmi_syspower_config *syspower_conf; + + if (!handle) + return -ENODEV; + + syspower_conf = scmi_syspower_configure(&sdev->dev); + if (!syspower_conf) + return -ENOMEM; + + dev_set_drvdata(&sdev->dev, syspower_conf); + ret = handle->notify_ops->register_event_notifier(handle, + SCMI_PROTOCOL_SYSTEM, + SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + NULL, &syspower_conf->userspace_nb); + + return 0; +} + +static void scmi_syspower_remove(struct scmi_device *sdev) +{ + int ret; + const struct scmi_handle *handle = sdev->handle; + struct scmi_syspower_config *syspower_conf; + + syspower_conf = dev_get_drvdata(&sdev->dev); + ret = handle->notify_ops->unregister_event_notifier(handle, + SCMI_PROTOCOL_SYSTEM, + SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + NULL, &syspower_conf->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, + .remove = scmi_syspower_remove, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_system_power_driver); + +module_param(scmi_graceful_request_tmo_ms, uint, 0644); +MODULE_PARM_DESC(scmi_graceful_request_tmo_ms, + "Maximum time(ms) allowed to userspace for complying to the request."); + +module_param(scmi_graceful_poweroff_signum, uint, 0644); +MODULE_PARM_DESC(scmi_graceful_poweroff_signum, + "Signal to request graceful poweroff to CAD process. Ignored if zero."); + +module_param(scmi_graceful_reboot_signum, uint, 0644); +MODULE_PARM_DESC(scmi_graceful_reboot_signum, + "Signal to request graceful reboot to CAD process. Ignored if zero."); + +MODULE_AUTHOR("Cristian Marussi "); +MODULE_DESCRIPTION("ARM SCMI System Power driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Jun 22 15:18:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 11618173 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2C25460D for ; Mon, 22 Jun 2020 15:21:05 +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 DDD96206D7 for ; Mon, 22 Jun 2020 15:21:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="zJlmhBvC" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DDD96206D7 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.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=Rv8xlTjA2mOGwhkn7XbDcTBUnDP35GyCSJEOzkiiubg=; b=zJlmhBvCdr+QNtayJ6/UQXnTxz PZlh6areAS/vGHGjtXfX4XHFkn52KapObwDYVGtskrWqHJP7WNANCdj4zGuCVVDSArDXXEG55CRKY ypjFAvecLCDS8CEBzpakjs7/08YLs2rebDmBHCvMHUncJDoqtfa15Ktvxpq8pLMHy/bqHbTXegkVW 5EWZ/TkMeBB37D92C8eSWcQXThW0ciSOsNojCwk5jFfulFHiReoZi/6ucykGVsNijA2UGGBESKnH9 BIlSY6KosFcmVabCItoNj5N6SlIRY1Wv2NVenNC1RfcgO0of4IbGKuiUYk0Tb5agzYi9pPLFjKtrh 0GPsCqPQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jnOE9-0008P7-T4; Mon, 22 Jun 2020 15:19:17 +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 1jnODv-0008Jg-7n for linux-arm-kernel@lists.infradead.org; Mon, 22 Jun 2020 15:19:04 +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 0E42611B3; Mon, 22 Jun 2020 08:18:33 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F1D6E3F6CF; Mon, 22 Jun 2020 08:18:31 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v3 3/3] arm64: dts: juno: add SCMI SystemPower Protocol support Date: Mon, 22 Jun 2020 16:18:16 +0100 Message-Id: <20200622151816.15491-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200622151816.15491-1-cristian.marussi@arm.com> References: <20200622151816.15491-1-cristian.marussi@arm.com> X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [217.140.110.172 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 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: Jonathan.Cameron@Huawei.com, cristian.marussi@arm.com, james.quinlan@broadcom.com, lukasz.luba@arm.com, sudeep.holla@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org arm64: dts: juno: add SCMI SystemPower Protocol support Signed-off-by: Cristian Marussi --- arch/arm64/boot/dts/arm/juno-base.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index dd20a5242c45..41e602ce71e2 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -581,6 +581,10 @@ #power-domain-cells = <1>; }; + scmi_system: protocol@12 { + reg = <0x12>; + }; + scmi_dvfs: protocol@13 { reg = <0x13>; #clock-cells = <1>;