From patchwork Tue Aug 16 07:24:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944395 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 29F7CC2BB41 for ; Tue, 16 Aug 2022 07:27:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=rfOgsB9SSb1UKIx31gts1cgmK85TyDsTK1LThULVT5Q=; b=tZZKNMbB0FPqhr o8Ff3j/8xRo3H2epgHbNNMLINIL8EZTT3n6w9kx/G14sbVZjGo3qYXA6rlMzQPtLlEJatyyMjVx6F i9aVPfN19s0UMqQFPfcBXaXrBF6OCm5HyK6EPP8bqy1WmfHtUyIr2Cp+b49J2YB2xGSY0iv5RZuJN HQPK6qEwXAhVtyN0INTXeIKBBJWZmx8qB3VAb8MxjKjOdpth6gO+xEssbDoufT5XDaTpceR2t1O3w 6TFr6w3ahbXmu9iBaDTIodLUam2XWzLNlqrnPjpQtcjnw6sNE8xvvwUMowxV7O9+TSiqqC81+sboG +fwkh1cvfU/Ogyw6Efbw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqx4-00F6P6-KY; Tue, 16 Aug 2022 07:25:26 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqws-00F61z-MC for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:18 +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 201321D31; Tue, 16 Aug 2022 00:25:10 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 83BA23F70D; Tue, 16 Aug 2022 00:25:07 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 1/6] firmware: arm_scmi: Refactor xfer in-flight registration routines Date: Tue, 16 Aug 2022 08:24:45 +0100 Message-Id: <20220816072450.3120959-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002514_890286_6710429A X-CRM114-Status: GOOD ( 17.75 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Move the whole xfer in-flight registration process out of scmi_xfer_get and while at that, split the sequence number selection steps from the in-flight registration procedure itself. No functional change. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 102 +++++++++++++++++++---------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 609ebedee9cb..e5193da2ce09 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -311,8 +311,6 @@ static int scmi_xfer_token_set(struct scmi_xfers_info *minfo, if (xfer_id != next_token) atomic_add((int)(xfer_id - next_token), &transfer_last_id); - /* Set in-flight */ - set_bit(xfer_id, minfo->xfer_alloc_table); xfer->hdr.seq = (u16)xfer_id; return 0; @@ -330,33 +328,77 @@ static inline void scmi_xfer_token_clear(struct scmi_xfers_info *minfo, clear_bit(xfer->hdr.seq, minfo->xfer_alloc_table); } +/** + * scmi_xfer_inflight_register_unlocked - Register the xfer as in-flight + * + * @xfer: The xfer to register + * @minfo: Pointer to Tx/Rx Message management info based on channel type + * + * Note that this helper assumes that the xfer to be registered as in-flight + * had been built using an xfer sequence number which still corresponds to a + * free slot in the xfer_alloc_table. + * + * Context: Assumes to be called with @xfer_lock already acquired. + */ +static inline void +scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer, + struct scmi_xfers_info *minfo) +{ + /* Set in-flight */ + set_bit(xfer->hdr.seq, minfo->xfer_alloc_table); + hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq); + xfer->pending = true; +} + +/** + * scmi_xfer_pending_set - Pick a proper sequence number and mark the xfer + * as pending in-flight + * + * @xfer: The xfer to act upon + * @minfo: Pointer to Tx/Rx Message management info based on channel type + * + * Return: 0 on Success or error otherwise + */ +static inline int scmi_xfer_pending_set(struct scmi_xfer *xfer, + struct scmi_xfers_info *minfo) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&minfo->xfer_lock, flags); + /* Set a new monotonic token as the xfer sequence number */ + ret = scmi_xfer_token_set(minfo, xfer); + if (!ret) + scmi_xfer_inflight_register_unlocked(xfer, minfo); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + + return ret; +} + /** * scmi_xfer_get() - Allocate one message * * @handle: Pointer to SCMI entity handle * @minfo: Pointer to Tx/Rx Message management info based on channel type - * @set_pending: If true a monotonic token is picked and the xfer is added to - * the pending hash table. * * Helper function which is used by various message functions that are * exposed to clients of this driver for allocating a message traffic event. * - * Picks an xfer from the free list @free_xfers (if any available) and, if - * required, sets a monotonically increasing token and stores the inflight xfer - * into the @pending_xfers hashtable for later retrieval. + * Picks an xfer from the free list @free_xfers (if any available) and perform + * a basic initialization. + * + * Note that, at this point, still no sequence number is assigned to the + * allocated xfer, nor it is registered as a pending transaction. * * The successfully initialized xfer is refcounted. * - * Context: Holds @xfer_lock while manipulating @xfer_alloc_table and - * @free_xfers. + * Context: Holds @xfer_lock while manipulating @free_xfers. * - * Return: 0 if all went fine, else corresponding error. + * Return: An initialized xfer if all went fine, else pointer error. */ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle, - struct scmi_xfers_info *minfo, - bool set_pending) + struct scmi_xfers_info *minfo) { - int ret; unsigned long flags; struct scmi_xfer *xfer; @@ -376,25 +418,8 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle, */ xfer->transfer_id = atomic_inc_return(&transfer_last_id); - if (set_pending) { - /* Pick and set monotonic token */ - ret = scmi_xfer_token_set(minfo, xfer); - if (!ret) { - hash_add(minfo->pending_xfers, &xfer->node, - xfer->hdr.seq); - xfer->pending = true; - } else { - dev_err(handle->dev, - "Failed to get monotonic token %d\n", ret); - hlist_add_head(&xfer->node, &minfo->free_xfers); - xfer = ERR_PTR(ret); - } - } - - if (!IS_ERR(xfer)) { - refcount_set(&xfer->users, 1); - atomic_set(&xfer->busy, SCMI_XFER_FREE); - } + refcount_set(&xfer->users, 1); + atomic_set(&xfer->busy, SCMI_XFER_FREE); spin_unlock_irqrestore(&minfo->xfer_lock, flags); return xfer; @@ -652,7 +677,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, ktime_t ts; ts = ktime_get_boottime(); - xfer = scmi_xfer_get(cinfo->handle, minfo, false); + xfer = scmi_xfer_get(cinfo->handle, minfo); if (IS_ERR(xfer)) { dev_err(dev, "failed to get free message slot (%ld)\n", PTR_ERR(xfer)); @@ -1041,13 +1066,22 @@ static int xfer_get_init(const struct scmi_protocol_handle *ph, tx_size > info->desc->max_msg_size) return -ERANGE; - xfer = scmi_xfer_get(pi->handle, minfo, true); + xfer = scmi_xfer_get(pi->handle, minfo); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); dev_err(dev, "failed to get free message slot(%d)\n", ret); return ret; } + /* Pick a sequence number and register this xfer as in-flight */ + ret = scmi_xfer_pending_set(xfer, minfo); + if (ret) { + dev_err(pi->handle->dev, + "Failed to get monotonic token %d\n", ret); + __scmi_xfer_put(minfo, xfer); + return ret; + } + xfer->tx.len = tx_size; xfer->rx.len = rx_size ? : info->desc->max_msg_size; xfer->hdr.type = MSG_TYPE_COMMAND; From patchwork Tue Aug 16 07:24:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944397 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 30BB6C3F6B0 for ; Tue, 16 Aug 2022 07:27:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=2i1rS+0pQYdyU+6nBzZu5qYfcM1Z3iQ7AEIZz0pFxJw=; b=W8X+dEgtBZD7Br mt1Xk7ruux00jWxgNaeV7cre/uXUE5eDOzj2QCKnUeUL0QlpQqIiNAcURfqmLsDMjPF7MfOp4fQ5y ykG8vZBdpkqrodiAFTEtJ6/aByo4RM6ZTRjdXTMvKYxVmufa3r28O9EuvubGICSQ/W0mftkgniJVw qecCneFj6PW3iDKY3MQebBLWz+9a+6b8XTJqTRfMOBQA5f8v2yjG/BFDcSD2bkEaa4OqpSuWnHzeB 4jSC4YfupeRTpY7h+AqHawaAcw9pt13iDeBb0CE2wKiQu4Aojqtb+v8CdRe6CEfofbXFDJZnmu4oJ gLkp8UJaN6icl2l9za1A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqxy-00F86y-U9; Tue, 16 Aug 2022 07:26:23 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqwt-00F65P-3a for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:21 +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 1FCBA1D34; Tue, 16 Aug 2022 00:25:12 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 83A1B3F70D; Tue, 16 Aug 2022 00:25:09 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 2/6] firmware: arm_scmi: Add bus helpers to enter raw mode Date: Tue, 16 Aug 2022 08:24:46 +0100 Message-Id: <20220816072450.3120959-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002515_313039_F2B70A7C X-CRM114-Status: GOOD ( 18.26 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a couple of helpers to be able to trigger the un-registration and the re-registration of the whole stack of SCMI drivers from/to the SCMI bus. Once this mode is enabled any new SCMI driver registration is inhibited and delayed till the this new mode is disabled. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/bus.c | 69 +++++++++++++++++++++++++++++- drivers/firmware/arm_scmi/common.h | 2 + include/linux/scmi_protocol.h | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index d4e23101448a..c4b3371dcb1b 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -19,6 +19,10 @@ static DEFINE_IDA(scmi_bus_id); static DEFINE_IDR(scmi_protocols); static DEFINE_SPINLOCK(protocol_lock); +static bool scmi_raw_mode_enabled; +static LIST_HEAD(scmi_registered_drivers); +static DEFINE_MUTEX(scmi_raw_mode_mtx); + static const struct scmi_device_id * scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv) { @@ -144,6 +148,18 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, driver->driver.owner = owner; driver->driver.mod_name = mod_name; + mutex_lock(&scmi_raw_mode_mtx); + list_add_tail(&driver->node, &scmi_registered_drivers); + /* + * If RAW mode is enabled here, the driver will be registered fully + * only later, when RAW will be (if ever) disabled. + */ + if (scmi_raw_mode_enabled) { + mutex_unlock(&scmi_raw_mode_mtx); + return 0; + } + mutex_unlock(&scmi_raw_mode_mtx); + retval = driver_register(&driver->driver); if (!retval) pr_debug("registered new scmi driver %s\n", driver->name); @@ -154,7 +170,18 @@ EXPORT_SYMBOL_GPL(scmi_driver_register); void scmi_driver_unregister(struct scmi_driver *driver) { - driver_unregister(&driver->driver); + mutex_lock(&scmi_raw_mode_mtx); + list_del_init(&driver->node); + /* + * No need to unregister a driver when RAW mode is enabled, it would + * have been already unregistered when RAW was enabled. + */ + if (!scmi_raw_mode_enabled) { + mutex_unlock(&scmi_raw_mode_mtx); + driver_unregister(&driver->driver); + mutex_lock(&scmi_raw_mode_mtx); + } + mutex_unlock(&scmi_raw_mode_mtx); scmi_protocol_device_unrequest(driver->id_table); } EXPORT_SYMBOL_GPL(scmi_driver_unregister); @@ -276,6 +303,46 @@ static void scmi_devices_unregister(void) bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister); } +void scmi_bus_raw_mode_enable(void) +{ + struct scmi_driver *driver; + + /* On enable any known SCMI driver is unregistered */ + mutex_lock(&scmi_raw_mode_mtx); + list_for_each_entry_reverse(driver, &scmi_registered_drivers, node) { + mutex_unlock(&scmi_raw_mode_mtx); + + driver_unregister(&driver->driver); + + mutex_lock(&scmi_raw_mode_mtx); + } + scmi_raw_mode_enabled = true; + mutex_unlock(&scmi_raw_mode_mtx); +} + +void scmi_bus_raw_mode_disable(void) +{ + int retval; + struct scmi_driver *driver; + + /* + * On disable any known SCMI driver is registered again unless it was + * removed already as a module. + */ + mutex_lock(&scmi_raw_mode_mtx); + list_for_each_entry(driver, &scmi_registered_drivers, node) { + mutex_unlock(&scmi_raw_mode_mtx); + + retval = driver_register(&driver->driver); + if (retval) + pr_warn("Failed to rebind driver %s\n", driver->name); + + mutex_lock(&scmi_raw_mode_mtx); + } + scmi_raw_mode_enabled = false; + mutex_unlock(&scmi_raw_mode_mtx); +} + int __init scmi_bus_init(void) { int retval; diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 61aba7447c32..bbaac20544a5 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -171,6 +171,8 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table); void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table); struct scmi_device *scmi_child_dev_find(struct device *parent, int prot_id, const char *name); +void scmi_bus_raw_mode_enable(void); +void scmi_bus_raw_mode_disable(void); /** * struct scmi_desc - Description of SoC integration diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 4f765bc788ff..39e64ec72984 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -820,6 +820,7 @@ struct scmi_driver { void (*remove)(struct scmi_device *sdev); const struct scmi_device_id *id_table; + struct list_head node; struct device_driver driver; }; From patchwork Tue Aug 16 07:24:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944398 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AA909C32772 for ; Tue, 16 Aug 2022 07:28:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=8aFeW7v8fNWjqkWgRLk3je09Xms8ym5hFFTvMSbpHL8=; b=msOQ9X1quP1NHu HqQxByXs4d/axba94V2UEWArp8oNL2/nP7dbNeW0OS7igf7UbBHPrvS1RdMe+0PYvnvO75pOrOyGe WHnxieHG9mr0NUdlvWKiaZG67EBPnSc2xGjcAPCYyoHfYXAsINsJqEjwmXpl9q1YUrJdOtWoE7on9 1tBTC6Slezbbs4zDpSWwemkWINnBqNe+BIIODdCV5+5Qe/HPgdi+i5kzxp3gy0WaX+VXyvdZp4Vg3 I68XHWb3dGjxMNhOBsFGk8CkJo3qgA+J9/uz9AmPo+E0QMcKUWGWrfr7IN8mFCwOTZRDpCWqkC7xu ipxzhDrnTQfZdd3ce6Fw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqyL-00F8zp-Sb; Tue, 16 Aug 2022 07:26:46 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqwt-00F680-8Y for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:21 +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 2064C1D6F; Tue, 16 Aug 2022 00:25:14 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8382B3F70D; Tue, 16 Aug 2022 00:25:11 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 3/6] firmware: arm_scmi: Add xfer raw helpers Date: Tue, 16 Aug 2022 08:24:47 +0100 Message-Id: <20220816072450.3120959-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002515_456953_5FFE546D X-CRM114-Status: GOOD ( 15.59 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a few SCMI helpers useful to implement SCMI Raw access support. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/common.h | 7 +++ drivers/firmware/arm_scmi/driver.c | 79 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index bbaac20544a5..3316bf9eb98a 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -214,6 +214,13 @@ struct scmi_desc { const bool atomic_enabled; }; +void scmi_xfer_raw_put(const struct scmi_handle *handle, + struct scmi_xfer *xfer); +struct scmi_xfer *scmi_xfer_raw_get(const struct scmi_handle *handle); + +int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle, + struct scmi_xfer *xfer); + #ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX extern const struct scmi_desc scmi_mailbox_desc; #endif diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index e5193da2ce09..797826237776 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -350,6 +350,53 @@ scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer, xfer->pending = true; } +/** + * scmi_xfer_inflight_register - Try to register an xfer as in-flight + * + * @xfer: The xfer to register + * @minfo: Pointer to Tx/Rx Message management info based on channel type + * + * Note that this helper does NOT assume anything about the sequence number + * that was baked into the provided xfer, so it checks at first if it can + * be mapped to a free slot and fails with an error if another xfer with the + * same sequence number is currently still registered as in-flight. + * + * Return: 0 on Success or -EBUSY if sequence number embedded in the xfer + * could not rbe mapped to a free slot in the xfer_alloc_table. + */ +static int scmi_xfer_inflight_register(struct scmi_xfer *xfer, + struct scmi_xfers_info *minfo) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&minfo->xfer_lock, flags); + if (!test_bit(xfer->hdr.seq, minfo->xfer_alloc_table)) + scmi_xfer_inflight_register_unlocked(xfer, minfo); + else + ret = -EBUSY; + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + + return ret; +} + +/** + * scmi_xfer_raw_inflight_register - An helper to register the given xfer as in + * flight on the TX channe, if possible. + * + * @handle: Pointer to SCMI entity handle + * @xfer: The xfer to register + * + * Return: 0 on Success, error otherwise + */ +int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle, + struct scmi_xfer *xfer) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + return scmi_xfer_inflight_register(xfer, &info->tx_minfo); +} + /** * scmi_xfer_pending_set - Pick a proper sequence number and mark the xfer * as pending in-flight @@ -425,6 +472,22 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle, return xfer; } +/** + * scmi_xfer_raw_get - Helper to get a bare free xfer from the TX channel + * + * @handle: Pointer to SCMI entity handle + * + * Note that xfer is taken from the TX channel structures. + * + * Return: A valid xfer on Success, or an error-pointer otherwise + */ +struct scmi_xfer *scmi_xfer_raw_get(const struct scmi_handle *handle) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + return scmi_xfer_get(handle, &info->tx_minfo); +} + /** * __scmi_xfer_put() - Release a message * @@ -453,6 +516,22 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) spin_unlock_irqrestore(&minfo->xfer_lock, flags); } +/** + * scmi_xfer_raw_put - Release an xfer that was taken by @scmi_xfer_raw_get + * + * @handle: Pointer to SCMI entity handle + * @xfer: A reference to the xfer to put + * + * Note that as with other xfer_put() handlers the xfer is really effectively + * released only if there are no more users on the system. + */ +void scmi_xfer_raw_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + return __scmi_xfer_put(&info->tx_minfo, xfer); +} + /** * scmi_xfer_lookup_unlocked - Helper to lookup an xfer_id * From patchwork Tue Aug 16 07:24:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944399 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 02C33C2BB41 for ; Tue, 16 Aug 2022 07:28:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1FNCy2BxpfRqY0eoabl3CbAMNZTVmdhlna4aK3AVXrg=; b=ZW1SllCx2iEmVm nLu/4gnpDfdeqPWt21SgMIofvbRqCrRu/juQF6lM+Ae55Mba+oJqFx60BJnvVmkujjfAz/8PV3mBk xcb4OQ7MC7dM5WPz/ppCtP7YaRpCRdvoS6B/8AMm0S8nZDWi0UcBS6fy8Zp/awwARSVRDP6o2Lp5J j5D84E+PUuStizDmNfglNU0hO8c95nM/dmEDtHjBreErET7odVvNsY1ABmF0tAMLfJzNweP8mMlGQ 9pDx1KsL9hs4j4ZzZOiHKn11EKA7rkcLliw1KSZqGVo6WMU2yU40W/+nnpKad+81oq9yqnarRF50R l+x+gt3yfcaF/EiYIZqw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqyn-00F9tU-S4; Tue, 16 Aug 2022 07:27:15 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqwu-00F6At-B7 for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:21 +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 20A201D70; Tue, 16 Aug 2022 00:25:16 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 83B323F70D; Tue, 16 Aug 2022 00:25:13 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 4/6] firmware: arm_scmi: Move errors defs and code to common.h Date: Tue, 16 Aug 2022 08:24:48 +0100 Message-Id: <20220816072450.3120959-5-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002516_525621_836AEF09 X-CRM114-Status: GOOD ( 13.36 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Move SCMI error codes definitions and helper to the common.h header together with the delayed response timeout define. No functional change. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/common.h | 40 ++++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/driver.c | 40 ------------------------------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 3316bf9eb98a..5ed64bfe9054 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -27,6 +27,46 @@ #include "protocols.h" #include "notify.h" +#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) + +enum scmi_error_codes { + SCMI_SUCCESS = 0, /* Success */ + SCMI_ERR_SUPPORT = -1, /* Not supported */ + SCMI_ERR_PARAMS = -2, /* Invalid Parameters */ + SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */ + SCMI_ERR_ENTRY = -4, /* Not found */ + SCMI_ERR_RANGE = -5, /* Value out of range */ + SCMI_ERR_BUSY = -6, /* Device busy */ + SCMI_ERR_COMMS = -7, /* Communication Error */ + SCMI_ERR_GENERIC = -8, /* Generic Error */ + SCMI_ERR_HARDWARE = -9, /* Hardware Error */ + SCMI_ERR_PROTOCOL = -10,/* Protocol Error */ +}; + +static const int scmi_linux_errmap[] = { + /* better than switch case as long as return value is continuous */ + 0, /* SCMI_SUCCESS */ + -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */ + -EINVAL, /* SCMI_ERR_PARAM */ + -EACCES, /* SCMI_ERR_ACCESS */ + -ENOENT, /* SCMI_ERR_ENTRY */ + -ERANGE, /* SCMI_ERR_RANGE */ + -EBUSY, /* SCMI_ERR_BUSY */ + -ECOMM, /* SCMI_ERR_COMMS */ + -EIO, /* SCMI_ERR_GENERIC */ + -EREMOTEIO, /* SCMI_ERR_HARDWARE */ + -EPROTO, /* SCMI_ERR_PROTOCOL */ +}; + +static inline int scmi_to_linux_errno(int errno) +{ + int err_idx = -errno; + + if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap)) + return scmi_linux_errmap[err_idx]; + return -EIO; +} + #define MSG_ID_MASK GENMASK(7, 0) #define MSG_XTRACT_ID(hdr) FIELD_GET(MSG_ID_MASK, (hdr)) #define MSG_TYPE_MASK GENMASK(9, 8) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 797826237776..141a140792a5 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -37,20 +37,6 @@ #define CREATE_TRACE_POINTS #include -enum scmi_error_codes { - SCMI_SUCCESS = 0, /* Success */ - SCMI_ERR_SUPPORT = -1, /* Not supported */ - SCMI_ERR_PARAMS = -2, /* Invalid Parameters */ - SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */ - SCMI_ERR_ENTRY = -4, /* Not found */ - SCMI_ERR_RANGE = -5, /* Value out of range */ - SCMI_ERR_BUSY = -6, /* Device busy */ - SCMI_ERR_COMMS = -7, /* Communication Error */ - SCMI_ERR_GENERIC = -8, /* Generic Error */ - SCMI_ERR_HARDWARE = -9, /* Hardware Error */ - SCMI_ERR_PROTOCOL = -10,/* Protocol Error */ -}; - /* List of all SCMI devices active in system */ static LIST_HEAD(scmi_list); /* Protection for the entire list */ @@ -170,30 +156,6 @@ struct scmi_info { #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) -static const int scmi_linux_errmap[] = { - /* better than switch case as long as return value is continuous */ - 0, /* SCMI_SUCCESS */ - -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */ - -EINVAL, /* SCMI_ERR_PARAM */ - -EACCES, /* SCMI_ERR_ACCESS */ - -ENOENT, /* SCMI_ERR_ENTRY */ - -ERANGE, /* SCMI_ERR_RANGE */ - -EBUSY, /* SCMI_ERR_BUSY */ - -ECOMM, /* SCMI_ERR_COMMS */ - -EIO, /* SCMI_ERR_GENERIC */ - -EREMOTEIO, /* SCMI_ERR_HARDWARE */ - -EPROTO, /* SCMI_ERR_PROTOCOL */ -}; - -static inline int scmi_to_linux_errno(int errno) -{ - int err_idx = -errno; - - if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap)) - return scmi_linux_errmap[err_idx]; - return -EIO; -} - void scmi_notification_instance_data_set(const struct scmi_handle *handle, void *priv) { @@ -1056,8 +1018,6 @@ static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph, xfer->rx.len = info->desc->max_msg_size; } -#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) - /** * do_xfer_with_response() - Do one transfer and wait until the delayed * response is received From patchwork Tue Aug 16 07:24:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944401 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BD0C0C2BB41 for ; Tue, 16 Aug 2022 07:29:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc: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/vb0gTzyv6qDmGKPeQXmuBDze0XsBJUJJfZkleCSlo=; b=Wt4kKsx8C7Y46/ aZUeZXkftPMsUGwrfvp03GqsgUkgrDDtu1X27mAyEv4ZLwHInLM7aLrcI6ewr2kst4Et1QR3KN4Cw 3+B9b3309j9CysgmBe+iDbGL/pkILNJ/wHTbeUVqJb9WXQQ9d/Lw+qSiczX20n8EI1qwfuvj37JVy 2CWZJWdXsPr6sz8ErbMdW+JxN85OeFOTwqXruXhBr/FfdXQAP1cb7e8YOGkZX7BIxzkHOyT7IXYG0 0RlDIjknUmG1d/LbGT71lKGUd1QA2l8YRpfgHUdF+Nt3knV0Q8QRySVSYIj+d9kqP+SmPVl0TYE3V ZW3fWH5KGVIIo62a7mFQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqzk-00FBGN-7Y; Tue, 16 Aug 2022 07:28:12 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqwy-00F6H0-1V for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:25 +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 5C28B1E2F; Tue, 16 Aug 2022 00:25:18 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 854C23F70D; Tue, 16 Aug 2022 00:25:15 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 5/6] firmware: arm_scmi: Add raw transmission support Date: Tue, 16 Aug 2022 08:24:49 +0100 Message-Id: <20220816072450.3120959-6-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002520_323872_D699E654 X-CRM114-Status: GOOD ( 28.25 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add SCMI Raw mode support which exposes a userspace interface rooted under /sys/kernel/debug/scmi_raw. Raw mode can be enabled/disabled at runtime via ./scmi_raw/enable. Once enabled, all the regular SCMI drivers activity is inhibited and a userspace application can then inject and read back bare SCMI messages writing and reading to/from ./scmi_raw/message* entries. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/Kconfig | 13 + drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/raw_mode.c | 1046 ++++++++++++++++++++++++++ drivers/firmware/arm_scmi/raw_mode.h | 28 + 4 files changed, 1088 insertions(+) create mode 100644 drivers/firmware/arm_scmi/raw_mode.c create mode 100644 drivers/firmware/arm_scmi/raw_mode.h diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index a14f65444b35..ab726a92ac2f 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -23,6 +23,19 @@ config ARM_SCMI_PROTOCOL if ARM_SCMI_PROTOCOL +config ARM_SCMI_RAW_MODE_SUPPORT + bool "Enable support for SCMI Raw transmission mode" + help + Enable support for SCMI Raw transmission mode. + + If enabled allows the direct injection and snooping of SCMI bare + messages through a dedicated debugfs interface. + It is meant to be used by SCMI compliance/testing suites. + + When enabled regular SCMI drivers interactions are inhibited in + order to avoid unexpected interactions with the SCMI Raw message + flow. If unsure say N. + config ARM_SCMI_HAVE_TRANSPORT bool help diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 9ea86f8cc8f7..7c1aca60c8ce 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only scmi-bus-y = bus.o scmi-driver-y = driver.o notify.o +scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c new file mode 100644 index 000000000000..c14cdd12b140 --- /dev/null +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -0,0 +1,1046 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) Raw mode support + * + * Copyright (C) 2022 ARM Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#include "raw_mode.h" + +#include + +#define SCMI_XFER_RAW_MAX_RETRIES 10 + +struct scmi_xfer_raw_work { + unsigned long max_tmo; + struct scmi_raw_mode_info *raw; + struct list_head free_waiters; + /* Protect free_waiters list */ + struct mutex free_mtx; + struct list_head active_waiters; + /* Protect active_waiters list */ + struct mutex active_mtx; + wait_queue_head_t waiters_wq; + struct work_struct waiters_work; + bool wait_wq_shutdown; + struct workqueue_struct *wait_wq; +}; + +struct scmi_raw_mode_info { + bool enabled; + struct scmi_chan_info *cinfo; + const struct scmi_desc *desc; + int tx_max_msg; + struct list_head free_raw_bufs[SCMI_RAW_MAX_QUEUE]; + /* Protect free_raw_bufs[] lists */ + spinlock_t free_bufs_lock[SCMI_RAW_MAX_QUEUE]; + struct list_head msg_q[SCMI_RAW_MAX_QUEUE]; + /* Protect msg_q[] lists */ + spinlock_t msg_q_lock[SCMI_RAW_MAX_QUEUE]; + wait_queue_head_t wqs[SCMI_RAW_MAX_QUEUE]; + struct scmi_xfer_raw_work *wrk; + struct dentry *dentry; + void *gid; +}; + +struct scmi_xfer_raw_waiter { + unsigned long start_jiffies; + struct scmi_xfer *xfer; + struct completion async_response; + struct list_head node; +}; + +struct scmi_raw_buffer { + size_t max_len; + struct scmi_msg msg; + struct list_head node; +}; + +struct scmi_raw_data { + struct scmi_raw_mode_info *raw; + struct scmi_msg tx; + size_t tx_size; + size_t tx_req; + struct scmi_msg rx; + size_t rx_size; +}; + +static inline +struct scmi_raw_buffer *scmi_raw_buffer_get(struct scmi_raw_mode_info *raw, + unsigned int idx) +{ + unsigned long flags; + struct scmi_raw_buffer *rb = NULL; + struct list_head *head = &raw->free_raw_bufs[idx]; + + spin_lock_irqsave(&raw->free_bufs_lock[idx], flags); + if (!list_empty(head)) { + rb = list_first_entry(head, struct scmi_raw_buffer, node); + list_del_init(&rb->node); + } + spin_unlock_irqrestore(&raw->free_bufs_lock[idx], flags); + + return rb; +} + +static inline void scmi_raw_buffer_put(struct scmi_raw_mode_info *raw, + struct scmi_raw_buffer *rb, + unsigned int idx) +{ + unsigned long flags; + + rb->msg.len = rb->max_len; + + spin_lock_irqsave(&raw->free_bufs_lock[idx], flags); + list_add_tail(&rb->node, &raw->free_raw_bufs[idx]); + spin_unlock_irqrestore(&raw->free_bufs_lock[idx], flags); +} + +static inline void scmi_raw_buffer_enqueue(struct scmi_raw_mode_info *raw, + struct scmi_raw_buffer *rb, + unsigned int idx) +{ + unsigned long flags; + + spin_lock_irqsave(&raw->msg_q_lock[idx], flags); + list_add_tail(&rb->node, &raw->msg_q[idx]); + spin_unlock_irqrestore(&raw->msg_q_lock[idx], flags); + + wake_up_interruptible(&raw->wqs[idx]); +} + +static inline struct scmi_raw_buffer* +scmi_raw_buffer_dequeue(struct scmi_raw_mode_info *raw, unsigned int idx) +{ + unsigned long flags; + struct scmi_raw_buffer *rb = NULL; + + spin_lock_irqsave(&raw->msg_q_lock[idx], flags); + if (!list_empty(&raw->msg_q[idx])) { + rb = list_first_entry(&raw->msg_q[idx], + struct scmi_raw_buffer, node); + list_del_init(&rb->node); + } + spin_unlock_irqrestore(&raw->msg_q_lock[idx], flags); + + return rb; +} + +static void scmi_raw_buffer_queue_flush(struct scmi_raw_mode_info *raw, + unsigned int idx) +{ + struct scmi_raw_buffer *rb; + + do { + rb = scmi_raw_buffer_dequeue(raw, idx); + if (rb) + scmi_raw_buffer_put(raw, rb, idx); + } while (rb); +} + +static inline struct scmi_xfer_raw_waiter * +scmi_xfer_raw_waiter_get(struct scmi_xfer_raw_work *wrk, struct scmi_xfer *xfer, + bool async) +{ + struct scmi_xfer_raw_waiter *rw = NULL; + + mutex_lock(&wrk->free_mtx); + if (!list_empty(&wrk->free_waiters)) { + rw = list_first_entry(&wrk->free_waiters, + struct scmi_xfer_raw_waiter, node); + list_del_init(&rw->node); + + if (async) { + reinit_completion(&rw->async_response); + xfer->async_done = &rw->async_response; + } + + rw->xfer = xfer; + } + //TODO this critS can be shortened... + mutex_unlock(&wrk->free_mtx); + + return rw; +} + +static inline +void scmi_xfer_raw_waiter_put(struct scmi_xfer_raw_work *wrk, + struct scmi_xfer_raw_waiter *rw) +{ + if (rw->xfer) { + rw->xfer->async_done = NULL; + rw->xfer = NULL; + } + + mutex_lock(&wrk->free_mtx); + list_add_tail(&rw->node, &wrk->free_waiters); + mutex_unlock(&wrk->free_mtx); +} + +static inline +void scmi_xfer_raw_waiter_enqueue(struct scmi_xfer_raw_work *wrk, + struct scmi_xfer_raw_waiter *rw) +{ + rw->start_jiffies = jiffies; + + trace_scmi_xfer_response_wait(rw->xfer->transfer_id, rw->xfer->hdr.id, + rw->xfer->hdr.protocol_id, + rw->xfer->hdr.seq, + wrk->raw->desc->max_rx_timeout_ms, + rw->xfer->hdr.poll_completion); + + mutex_lock(&wrk->active_mtx); + list_add_tail(&rw->node, &wrk->active_waiters); + mutex_unlock(&wrk->active_mtx); + + wake_up_interruptible(&wrk->waiters_wq); +} + +static struct scmi_xfer_raw_waiter* +scmi_xfer_raw_waiter_dequeue(struct scmi_xfer_raw_work *wrk) +{ + struct scmi_xfer_raw_waiter *rw; + + mutex_lock(&wrk->active_mtx); + while (list_empty(&wrk->active_waiters)) { + int ret; + + mutex_unlock(&wrk->active_mtx); + + ret = wait_event_interruptible(wrk->waiters_wq, + !list_empty(&wrk->active_waiters) || + wrk->wait_wq_shutdown); + if (ret || wrk->wait_wq_shutdown) + return NULL; + + mutex_lock(&wrk->active_mtx); + } + + rw = list_first_entry(&wrk->active_waiters, + struct scmi_xfer_raw_waiter, node); + list_del_init(&rw->node); + mutex_unlock(&wrk->active_mtx); + + return rw; +} + +static void scmi_xfer_raw_worker(struct work_struct *work) +{ + struct scmi_xfer_raw_work *wrk; + struct scmi_raw_mode_info *raw; + struct scmi_chan_info *cinfo; + struct device *dev; + + wrk = container_of(work, struct scmi_xfer_raw_work, waiters_work); + + raw = wrk->raw; + cinfo = raw->cinfo; + dev = raw->cinfo->handle->dev; + + do { + int ret = 0; + unsigned long aging, tmo; + struct scmi_xfer *xfer; + struct scmi_xfer_raw_waiter *rw; + + /* + * Waiters are queued by wait-deadline at the end, so some of + * them could have been already expired when processed, BUT we + * have to check the completion status anyway just in case a + * virtually expired (aged) transaction was indeed completed + * fine and we'll have to wait for the asynchronous part (if + * any). + */ + rw = scmi_xfer_raw_waiter_dequeue(wrk); + if (!rw) + return; + + xfer = rw->xfer; + + aging = jiffies - rw->start_jiffies; + tmo = wrk->max_tmo > aging ? wrk->max_tmo - aging : 0; + + if ((tmo && !wait_for_completion_timeout(&xfer->done, tmo)) || + (!tmo && !try_wait_for_completion(&xfer->done))) { + dev_err(dev, "timed out in RAW response - HDR:%08X\n", + pack_scmi_header(&xfer->hdr)); + ret = -ETIMEDOUT; + } + + /* Avoid unneeded async waits */ + if (!ret && xfer->hdr.status) + ret = scmi_to_linux_errno(xfer->hdr.status); + + if (raw->desc->ops->mark_txdone) + raw->desc->ops->mark_txdone(cinfo, ret, xfer); + + trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, + xfer->hdr.protocol_id, xfer->hdr.seq, ret); + + /* Wait also for an async delayed response if needed */ + if (!ret && xfer->async_done) { + tmo = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); + if (!wait_for_completion_timeout(xfer->async_done, tmo)) + dev_err(dev, + "timed out in RAW delayed resp - HDR:%08X\n", + pack_scmi_header(&xfer->hdr)); + } + + /* Release waiter and xfer */ + scmi_xfer_raw_put(raw->cinfo->handle, xfer); + scmi_xfer_raw_waiter_put(wrk, rw); + } while (1); +} + +static int scmi_xfer_raw_enable(struct scmi_raw_mode_info *raw, bool enable) +{ + struct device *dev = raw->cinfo->handle->dev; + + if (enable && !raw->enabled) { + dev_info(dev, "Enabling SCMI Raw access. Unbinding drivers.\n"); + scmi_bus_raw_mode_enable(); + + /* Make sure all changes are visible before enabling Raw mode */ + smp_store_mb(raw->enabled, true); + } else if (!enable && raw->enabled) { + //TODO Check about xfers registered as in-flight BUT never sent + int i; + + /* Make sure all changes are visible before disabling Raw mode */ + smp_store_mb(raw->enabled, false); + + /* + * Flush all message queues since nobody will read/dequeue these + * anymore. Note that, instead, active_waiters queue will flush + * on its own as soon as replies are received or time out. + */ + for (i = 0; i < SCMI_RAW_MAX_QUEUE; i++) + scmi_raw_buffer_queue_flush(raw, i); + + dev_info(dev, "Disabling SCMI Raw access. Binding drivers.\n"); + scmi_bus_raw_mode_disable(); + } + + return 0; +} + +static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *buf, + size_t len, struct scmi_xfer **p) +{ + u32 msg_hdr; + size_t tx_size; + struct scmi_xfer *xfer; + int ret, retry = SCMI_XFER_RAW_MAX_RETRIES; + struct device *dev = raw->cinfo->handle->dev; + + if (!buf || len < sizeof(u32)) + return -EINVAL; + + tx_size = len - sizeof(u32); + /* Ensure we have sane transfer sizes */ + if (tx_size > raw->desc->max_msg_size) + return -ERANGE; + + xfer = scmi_xfer_raw_get(raw->cinfo->handle); + if (IS_ERR(xfer)) { + dev_warn(dev, "RAW - Cannot get a free RAW xfer !\n"); + return PTR_ERR(xfer); + } + + /* Build xfer from provided SCMI bare message */ + msg_hdr = le32_to_cpu(*((u32 *)buf)); + unpack_scmi_header(msg_hdr, &xfer->hdr); + xfer->hdr.seq = (u16)MSG_XTRACT_TOKEN(msg_hdr); + xfer->hdr.poll_completion = false; + xfer->hdr.status = SCMI_SUCCESS; + xfer->tx.len = tx_size; + xfer->rx.len = raw->desc->max_msg_size; + memset(xfer->tx.buf, 0x00, raw->desc->max_msg_size); + if (tx_size) + memcpy(xfer->tx.buf, (u8 *)buf + sizeof(msg_hdr), tx_size); + *p = xfer; + + /* + * In flight registration can temporarily fail in case of Raw messages + * if the user injects messages without using monotonically increasing + * sequence numbers since the xfer (annd the token) is finally released + * by a deferred worker in Raw mode. Just retry. + */ + do { + ret = scmi_xfer_raw_inflight_register(raw->cinfo->handle, xfer); + if (ret) { + dev_warn(dev, + "RAW - Cannot register xfer %d as in-flight - HDR:0x%08X\n", + xfer->hdr.seq, msg_hdr); + + if (retry) { + dev_info(dev, + "...retrying[%d] inflight registration\n", + retry); + msleep(raw->desc->max_rx_timeout_ms / + SCMI_XFER_RAW_MAX_RETRIES); + } else { + scmi_xfer_raw_put(raw->cinfo->handle, xfer); + } + } + } while (ret && retry--); + + return ret; +} + +static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw, + struct scmi_xfer *xfer, bool async) +{ + int ret; + struct scmi_xfer_raw_waiter *rw; + struct device *dev = raw->cinfo->handle->dev; + struct scmi_chan_info *cinfo = raw->cinfo; + + rw = scmi_xfer_raw_waiter_get(raw->wrk, xfer, async); + if (!rw) { + dev_warn(dev, "RAW - Cannot get a free waiter !\n"); + return -ENOMEM; + } + + trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id, + xfer->hdr.protocol_id, xfer->hdr.seq, + xfer->hdr.poll_completion); + + reinit_completion(&xfer->done); + /* Make sure xfer state update is visible before sending */ + smp_store_mb(xfer->state, SCMI_XFER_SENT_OK); + + ret = raw->desc->ops->send_message(cinfo, xfer); + if (ret) { + dev_err(dev, "Failed to send RAW message %d\n", ret); + scmi_xfer_raw_waiter_put(raw->wrk, rw); + return ret; + } + + trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "CMND", + xfer->hdr.seq, xfer->hdr.status, + xfer->tx.buf, xfer->tx.len); + + scmi_xfer_raw_waiter_enqueue(raw->wrk, rw); + + return ret; +} + +static int scmi_raw_message_send(struct scmi_raw_mode_info *raw, + void *buf, size_t len, bool async) +{ + int ret; + struct scmi_xfer *xfer; + + if (!raw->enabled) + return -ENODEV; + + ret = scmi_xfer_raw_get_init(raw, buf, len, &xfer); + if (ret) + return ret; + + ret = scmi_do_xfer_raw_start(raw, xfer, async); + if (ret) + scmi_xfer_raw_put(raw->cinfo->handle, xfer); + + return ret; +} + +static struct scmi_raw_buffer * +scmi_raw_message_dequeue(struct scmi_raw_mode_info *raw, unsigned int idx) +{ + unsigned long flags; + + spin_lock_irqsave(&raw->msg_q_lock[idx], flags); + while (list_empty(&raw->msg_q[idx])) { + spin_unlock_irqrestore(&raw->msg_q_lock[idx], flags); + + if (wait_event_interruptible(raw->wqs[idx], + !list_empty(&raw->msg_q[idx]))) + return NULL; + + spin_lock_irqsave(&raw->msg_q_lock[idx], flags); + } + spin_unlock_irqrestore(&raw->msg_q_lock[idx], flags); + + return scmi_raw_buffer_dequeue(raw, idx); +} + +static int scmi_raw_message_receive(struct scmi_raw_mode_info *raw, + void *buf, size_t len, size_t *size, + unsigned int idx) +{ + int ret = 0; + struct scmi_raw_buffer *rb; + + if (!raw->enabled) + return -ENODEV; + + rb = scmi_raw_message_dequeue(raw, idx); + if (!rb) { + dev_warn(raw->cinfo->handle->dev, + "RAW - No message available!\n"); + return -ENODEV; + } + + if (rb->msg.len <= len) { + memcpy(buf, rb->msg.buf, rb->msg.len); + *size = rb->msg.len; + } else { + ret = -ENOSPC; + } + + scmi_raw_buffer_put(raw, rb, idx); + + return ret; +} + +static int scmi_xfer_raw_collect(struct scmi_xfer *xfer, + void *msg, size_t *msg_len) +{ + u32 *m; + size_t msg_size; + + if (!xfer || !msg || !msg_len) + return -EINVAL; + + /* Account for hdr ...*/ + msg_size = xfer->rx.len + sizeof(u32); + /* ... and status if needed */ + if (xfer->hdr.type != MSG_TYPE_NOTIFICATION) + msg_size += sizeof(u32); + + if (msg_size > *msg_len) + return -ENOSPC; + + m = msg; + *m = cpu_to_le32(pack_scmi_header(&xfer->hdr)); + if (xfer->hdr.type != MSG_TYPE_NOTIFICATION) + *++m = cpu_to_le32(xfer->hdr.status); + + memcpy(++m, xfer->rx.buf, xfer->rx.len); + + *msg_len = msg_size; + + return 0; +} + +void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, unsigned int idx) +{ + int ret; + struct scmi_raw_buffer *rb; + struct device *dev; + struct scmi_raw_mode_info *raw = r; + + if (!raw || !raw->enabled) + return; + + dev = raw->cinfo->handle->dev; + rb = scmi_raw_buffer_get(raw, idx); + if (!rb) { + dev_warn(dev, "RAW[%d] - Cannot get a free RAW buffer\n", idx); + return; + } + + ret = scmi_xfer_raw_collect(xfer, rb->msg.buf, &rb->msg.len); + if (ret) { + dev_warn(dev, "RAW - Cannot collect xfer into buffer !\n"); + scmi_raw_buffer_put(raw, rb, idx); + return; + } + + scmi_raw_buffer_enqueue(raw, rb, idx); +} + +static void scmi_xfer_raw_fill(struct scmi_raw_mode_info *raw, + struct scmi_xfer *xfer, u32 msg_hdr) +{ + /* Unpack received HDR as it is */ + unpack_scmi_header(msg_hdr, &xfer->hdr); + xfer->hdr.seq = MSG_XTRACT_TOKEN(msg_hdr); + + memset(xfer->rx.buf, 0x00, xfer->rx.len); + + raw->desc->ops->fetch_response(raw->cinfo, xfer); +} + +void scmi_raw_error_report(void *r, u32 msg_hdr, void *priv) +{ + struct scmi_xfer xfer; + struct scmi_raw_buffer *rb; + struct scmi_raw_mode_info *raw = r; + + if (!raw || !raw->enabled) + return; + + rb = scmi_raw_buffer_get(raw, SCMI_RAW_ERRS_QUEUE); + if (!rb) { + dev_warn(raw->cinfo->handle->dev, + "RAW[%d] - Cannot get a free RAW buffer\n", + SCMI_RAW_ERRS_QUEUE); + return; + } + + /* Use a raw buffer to provide rx space to the temp xfer */ + xfer.rx.buf = rb->msg.buf; + /* + * Allow max_msg_size...note that allocated rx.buf length is + * max_msg_size + sizeof(u32). + */ + xfer.rx.len = raw->desc->max_msg_size; + if (priv) + /* + * Any transport-provided priv must be passed back down + * to transport + */ + smp_store_mb(xfer.priv, priv); + + scmi_xfer_raw_fill(raw, &xfer, msg_hdr); + scmi_raw_message_report(raw, &xfer, SCMI_RAW_ERRS_QUEUE); + + scmi_raw_buffer_put(raw, rb, SCMI_RAW_ERRS_QUEUE); +} + +static inline ssize_t scmi_dbg_raw_mode_common_read(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos, + unsigned int idx) +{ + ssize_t cnt; + struct scmi_raw_data *rd = filp->private_data; + + if (!rd->rx_size) { + int ret; + + ret = scmi_raw_message_receive(rd->raw, rd->rx.buf, rd->rx.len, + &rd->rx_size, idx); + if (ret) { + rd->rx_size = 0; + return ret; + } + + /* Reset any previous filepos change, including writes */ + *ppos = 0; + } else if (*ppos == rd->rx_size) { + /* Return EOF once all the message has been read-out */ + rd->rx_size = 0; + return 0; + } + + cnt = simple_read_from_buffer(buf, count, ppos, + rd->rx.buf, rd->rx_size); + + return cnt; +} + +static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos, + bool async) +{ + int ret; + struct scmi_raw_data *rd = filp->private_data; + + if (count > rd->tx.len - rd->tx_size) + return -ENOSPC; + + /* On first write attempt @count carries the total full message size. */ + if (!rd->tx_size) + rd->tx_req = count; + + /* Gather a full message before sending it with a RAW xfer */ + if (rd->tx_size < rd->tx_req) { + size_t cnt; + + cnt = simple_write_to_buffer(rd->tx.buf, rd->tx.len, ppos, + buf, count); + rd->tx_size += cnt; + if (cnt < count) + return cnt; + } + + ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size, async); + + /* Reset ppos for next message ... */ + rd->tx_size = 0; + + return ret ?: count; +} + +static inline __poll_t +scmi_test_dbg_raw_common_poll(struct file *filp, struct poll_table_struct *wait, + unsigned int idx) +{ + unsigned long flags; + struct scmi_raw_data *rd = filp->private_data; + + if (!rd->raw->enabled) + return 0; + + poll_wait(filp, &rd->raw->wqs[idx], wait); + + spin_lock_irqsave(&rd->raw->msg_q_lock[idx], flags); + if (!list_empty(&rd->raw->msg_q[idx])) { + spin_unlock_irqrestore(&rd->raw->msg_q_lock[idx], flags); + return POLLIN | POLLRDNORM; + } + spin_unlock_irqrestore(&rd->raw->msg_q_lock[idx], flags); + + return 0; +} + +static ssize_t scmi_dbg_raw_mode_message_read(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos, + SCMI_RAW_REPLY_QUEUE); +} + +static ssize_t scmi_dbg_raw_mode_message_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, false); +} + +static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp, + struct poll_table_struct *wait) +{ + return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_REPLY_QUEUE); +} + +static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp) +{ + struct scmi_raw_mode_info *raw; + struct scmi_raw_data *rd; + + if (!inode->i_private) + return -ENODEV; + + raw = inode->i_private; + rd = kzalloc(sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + rd->rx.len = raw->desc->max_msg_size + sizeof(u32); + rd->rx.buf = kzalloc(rd->rx.len, GFP_KERNEL); + if (!rd->rx.buf) { + kfree(rd); + return -ENOMEM; + } + + rd->tx.len = raw->desc->max_msg_size + sizeof(u32); + rd->tx.buf = kzalloc(rd->tx.len, GFP_KERNEL); + if (!rd->tx.buf) { + kfree(rd->rx.buf); + kfree(rd); + return -ENOMEM; + } + + rd->raw = raw; + filp->private_data = rd; + + return 0; +} + +static int scmi_dbg_raw_mode_release(struct inode *inode, struct file *filp) +{ + struct scmi_raw_data *rd = filp->private_data; + + kfree(rd->rx.buf); + kfree(rd->tx.buf); + kfree(rd); + + return 0; +} + +static ssize_t scmi_dbg_raw_mode_enable_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + int ret; + bool enabled; + struct scmi_raw_data *rd = filp->private_data; + + ret = kstrtobool_from_user(buf, count, &enabled); + if (ret) + return ret; + + ret = scmi_xfer_raw_enable(rd->raw, enabled); + if (ret) + return ret; + + return count; +} + +static const struct file_operations scmi_dbg_raw_mode_enable_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .write = scmi_dbg_raw_mode_enable_write, + .owner = THIS_MODULE, +}; + +static const struct file_operations scmi_dbg_raw_mode_message_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_write, + .poll = scmi_dbg_raw_mode_message_poll, + .owner = THIS_MODULE, +}; + +static ssize_t scmi_dbg_raw_mode_message_async_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, true); +} + +static const struct file_operations scmi_dbg_raw_mode_message_async_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_async_write, + .poll = scmi_dbg_raw_mode_message_poll, + .owner = THIS_MODULE, +}; + +static ssize_t scmi_test_dbg_raw_mode_notif_read(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos, + SCMI_RAW_NOTIF_QUEUE); +} + +static __poll_t scmi_test_dbg_raw_mode_notif_poll(struct file *filp, + struct poll_table_struct *wait) +{ + return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_NOTIF_QUEUE); +} + +static const struct file_operations scmi_dbg_raw_mode_notification_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_test_dbg_raw_mode_notif_read, + .poll = scmi_test_dbg_raw_mode_notif_poll, + .owner = THIS_MODULE, +}; + +static ssize_t scmi_test_dbg_raw_mode_errors_read(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos, + SCMI_RAW_ERRS_QUEUE); +} + +static __poll_t scmi_test_dbg_raw_mode_errors_poll(struct file *filp, + struct poll_table_struct *wait) +{ + return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_ERRS_QUEUE); +} + +static const struct file_operations scmi_dbg_raw_mode_errors_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_test_dbg_raw_mode_errors_read, + .poll = scmi_test_dbg_raw_mode_errors_poll, + .owner = THIS_MODULE, +}; + +static int scmi_xfer_raw_free_bufs_init(struct scmi_raw_mode_info *raw, int idx) +{ + int i; + struct scmi_raw_buffer *rb; + struct device *dev = raw->cinfo->handle->dev; + + rb = devm_kcalloc(dev, raw->tx_max_msg, sizeof(*rb), GFP_KERNEL); + if (!rb) + return -ENOMEM; + + spin_lock_init(&raw->free_bufs_lock[idx]); + INIT_LIST_HEAD(&raw->free_raw_bufs[idx]); + for (i = 0; i < raw->tx_max_msg; i++, rb++) { + rb->max_len = raw->desc->max_msg_size + sizeof(u32); + rb->msg.buf = devm_kzalloc(dev, rb->max_len, GFP_KERNEL); + if (!rb->msg.buf) + return -ENOMEM; + scmi_raw_buffer_put(raw, rb, idx); + } + + spin_lock_init(&raw->msg_q_lock[idx]); + INIT_LIST_HEAD(&raw->msg_q[idx]); + init_waitqueue_head(&raw->wqs[idx]); + + return 0; +} + +static int scmi_xfer_raw_worker_init(struct scmi_raw_mode_info *raw) +{ + int i; + struct scmi_xfer_raw_waiter *rw; + struct device *dev = raw->cinfo->handle->dev; + + rw = devm_kcalloc(dev, raw->tx_max_msg, sizeof(*rw), GFP_KERNEL); + if (!rw) + return -ENOMEM; + + raw->wrk = devm_kzalloc(dev, sizeof(*raw->wrk), GFP_KERNEL); + if (!raw->wrk) + return -ENOMEM; + + raw->wrk->wait_wq = alloc_workqueue("scmi-raw-wait-wq-%d", + WQ_UNBOUND | WQ_FREEZABLE | + WQ_HIGHPRI, WQ_SYSFS, 0); + if (!raw->wrk->wait_wq) + return -ENOMEM; + + raw->wrk->max_tmo = msecs_to_jiffies(raw->desc->max_rx_timeout_ms); + + raw->wrk->raw = raw; + mutex_init(&raw->wrk->free_mtx); + INIT_LIST_HEAD(&raw->wrk->active_waiters); + mutex_init(&raw->wrk->active_mtx); + INIT_LIST_HEAD(&raw->wrk->free_waiters); + for (i = 0; i < raw->tx_max_msg; i++, rw++) { + init_completion(&rw->async_response); + scmi_xfer_raw_waiter_put(raw->wrk, rw); + } + INIT_WORK(&raw->wrk->waiters_work, scmi_xfer_raw_worker); + init_waitqueue_head(&raw->wrk->waiters_wq); + + /* kick waiter work */ + queue_work(raw->wrk->wait_wq, &raw->wrk->waiters_work); + + return 0; +} + +static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw) +{ + int ret; + void *gid; + struct device *dev = raw->cinfo->handle->dev; + + gid = devres_open_group(dev, NULL, GFP_KERNEL); + if (!gid) + return -ENOMEM; + + ret = scmi_xfer_raw_free_bufs_init(raw, SCMI_RAW_REPLY_QUEUE); + if (ret) + goto err; + + ret = scmi_xfer_raw_free_bufs_init(raw, SCMI_RAW_NOTIF_QUEUE); + if (ret) + goto err; + + ret = scmi_xfer_raw_free_bufs_init(raw, SCMI_RAW_ERRS_QUEUE); + if (ret) + goto err; + + ret = scmi_xfer_raw_worker_init(raw); + if (ret) + goto err; + + devres_close_group(dev, gid); + raw->gid = gid; + + return 0; + +err: + devres_release_group(dev, gid); + return ret; +} + +void *scmi_raw_mode_init(struct scmi_chan_info *cinfo, + const struct scmi_desc *desc, int tx_max_msg) +{ + int ret; + struct scmi_raw_mode_info *raw; + struct device *dev; + + if (!cinfo || !desc) + return ERR_PTR(-EINVAL); + + dev = cinfo->handle->dev; + raw = devm_kzalloc(dev, sizeof(*raw), GFP_KERNEL); + if (!raw) + return ERR_PTR(-ENOMEM); + + raw->cinfo = cinfo; + raw->desc = desc; + raw->tx_max_msg = tx_max_msg; + + ret = scmi_raw_mode_setup(raw); + if (ret) { + devm_kfree(dev, raw); + return ERR_PTR(ret); + } + + raw->dentry = debugfs_create_dir("scmi_raw", NULL); + if (IS_ERR(raw->dentry)) { + ret = PTR_ERR(raw->dentry); + devres_release_group(dev, raw->gid); + devm_kfree(dev, raw); + return ERR_PTR(ret); + } + + debugfs_create_file("enable", 0200, raw->dentry, raw, + &scmi_dbg_raw_mode_enable_fops); + + debugfs_create_u32("transport_rx_timeout_ms", 0400, raw->dentry, + (u32 *)&raw->desc->max_rx_timeout_ms); + + debugfs_create_u32("transport_max_msg_size", 0400, raw->dentry, + (u32 *)&raw->desc->max_msg_size); + + debugfs_create_u32("transport_tx_max_msg", 0400, raw->dentry, + (u32 *)&raw->tx_max_msg); + + debugfs_create_file("message", 0600, raw->dentry, raw, + &scmi_dbg_raw_mode_message_fops); + + debugfs_create_file("message_async", 0600, raw->dentry, raw, + &scmi_dbg_raw_mode_message_async_fops); + + debugfs_create_file("notification", 0400, raw->dentry, raw, + &scmi_dbg_raw_mode_notification_fops); + + debugfs_create_file("errors", 0400, raw->dentry, raw, + &scmi_dbg_raw_mode_errors_fops); + + return raw; +} + +void scmi_raw_mode_cleanup(void *r) +{ + struct scmi_raw_mode_info *raw = r; + + if (!raw) + return; + + debugfs_remove_recursive(raw->dentry); + scmi_xfer_raw_enable(raw, false); + + raw->wrk->wait_wq_shutdown = true; + wake_up_interruptible(&raw->wrk->waiters_wq); + cancel_work_sync(&raw->wrk->waiters_work); + destroy_workqueue(raw->wrk->wait_wq); +} diff --git a/drivers/firmware/arm_scmi/raw_mode.h b/drivers/firmware/arm_scmi/raw_mode.h new file mode 100644 index 000000000000..9988fd31ec91 --- /dev/null +++ b/drivers/firmware/arm_scmi/raw_mode.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * System Control and Management Interface (SCMI) Message Protocol + * Raw mode support header. + * + * Copyright (C) 2022 ARM Ltd. + */ +#ifndef _SCMI_RAW_MODE_H +#define _SCMI_RAW_MODE_H + +#include "common.h" + +enum { + SCMI_RAW_REPLY_QUEUE, + SCMI_RAW_NOTIF_QUEUE, + SCMI_RAW_ERRS_QUEUE, + SCMI_RAW_MAX_QUEUE +}; + +void *scmi_raw_mode_init(struct scmi_chan_info *cinfo, + const struct scmi_desc *desc, int tx_max_msg); +void scmi_raw_mode_cleanup(void *raw); + +void scmi_raw_message_report(void *raw, struct scmi_xfer *xfer, + unsigned int idx); +void scmi_raw_error_report(void *raw, u32 msg_hdr, void *priv); + +#endif /* _SCMI_RAW_MODE_H */ From patchwork Tue Aug 16 07:24:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12944400 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 332BCC32771 for ; Tue, 16 Aug 2022 07:28:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=UaTFARYomEoeZ8EGlBLM+FIhmDLv7OVrfbqE7G4y4gI=; b=b9y9IgWSdEreaa wASPT/NuHkPP3wKqm+vmvEDc8en8wLOJ3HJzprp8UJRNUYxAn8UgN5S0xdtFx3r7YQFJdR6CUD4yi KHSlTlLH9pdoQwteZ3/5ceRon5b6P/SKUZGC9vGH3EnypyrttMZAzKPJWVIDO48MZhBHHMMdGak2u 4bxF/9+pLUqOqNeVzUcF/e0fQV0MWX4HyxozVKDd4qvQdNLZzaUGqA2VyDMQaxNI72s6RjGL77Z/U vQUMrLZ+9FTHmcGJxb7Ar4cg8ODXMzozmRX3MU8HX/fh5miYxsoUerw0PUn7qzIXDD+V1dsw9HAAu uFch/ki92iku9mU8twqg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqz7-00FAOX-My; Tue, 16 Aug 2022 07:27:33 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oNqwy-00F6Ih-S7 for linux-arm-kernel@lists.infradead.org; Tue, 16 Aug 2022 07:25:23 +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 59D021DB5; Tue, 16 Aug 2022 00:25:20 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BDD443F70D; Tue, 16 Aug 2022 00:25:17 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, etienne.carriere@linaro.org, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, wleavitt@marvell.com, peter.hilber@opensynergy.com, nicola.mazzucato@arm.com, tarek.el-sherbiny@arm.com, cristian.marussi@arm.com Subject: [RFC PATCH 6/6] firmware: arm_scmi: Call Raw mode hooks from the core stack Date: Tue, 16 Aug 2022 08:24:50 +0100 Message-Id: <20220816072450.3120959-7-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220816072450.3120959-1-cristian.marussi@arm.com> References: <20220816072450.3120959-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220816_002521_092357_8B519980 X-CRM114-Status: GOOD ( 14.82 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a few call sites where, if SCMI Raw mode access had been enabled in Kconfig, the needed SCMI Raw initialization and hooks are called. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 141a140792a5..0068a2ec3b4d 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -34,6 +36,8 @@ #include "common.h" #include "notify.h" +#include "raw_mode.h" + #define CREATE_TRACE_POINTS #include @@ -133,6 +137,7 @@ struct scmi_protocol_instance { * @notify_priv: Pointer to private data structure specific to notifications. * @node: List head * @users: Number of users of this instance + * @raw: An opaque reference handle used by SCMI Raw mode. */ struct scmi_info { struct device *dev; @@ -152,6 +157,7 @@ struct scmi_info { void *notify_priv; struct list_head node; int users; + void *raw; }; #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) @@ -678,6 +684,9 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) static inline void scmi_xfer_command_release(struct scmi_info *info, struct scmi_xfer *xfer) { + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) + scmi_raw_message_report(info->raw, xfer, SCMI_RAW_REPLY_QUEUE); + atomic_set(&xfer->busy, SCMI_XFER_FREE); __scmi_xfer_put(&info->tx_minfo, xfer); } @@ -744,6 +753,11 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, xfer->hdr.protocol_id, xfer->hdr.seq, MSG_TYPE_NOTIFICATION); + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + xfer->hdr.seq = MSG_XTRACT_TOKEN(msg_hdr); + scmi_raw_message_report(info->raw, xfer, SCMI_RAW_NOTIF_QUEUE); + } + __scmi_xfer_put(minfo, xfer); scmi_clear_channel(info, cinfo); @@ -757,6 +771,9 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, xfer = scmi_xfer_command_acquire(cinfo, msg_hdr); if (IS_ERR(xfer)) { + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) + scmi_raw_error_report(info->raw, msg_hdr, priv); + if (MSG_XTRACT_TYPE(msg_hdr) == MSG_TYPE_DELAYED_RESP) scmi_clear_channel(info, cinfo); return; @@ -2486,6 +2503,18 @@ static int scmi_probe(struct platform_device *pdev) dev_err(dev, "Transport is not polling capable. Atomic mode not supported.\n"); + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + struct scmi_chan_info *cinfo; + + cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE); + info->raw = scmi_raw_mode_init(cinfo, info->desc, + info->tx_minfo.max_msg); + if (IS_ERR(info->raw)) { + dev_err(dev, "Failed to initialize SCMI RAW Mode !\n"); + info->raw = NULL; + } + } + /* * Trigger SCMI Base protocol initialization. * It's mandatory and won't be ever released/deinit until the @@ -2552,6 +2581,9 @@ static int scmi_remove(struct platform_device *pdev) struct scmi_info *info = platform_get_drvdata(pdev); struct device_node *child; + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) + scmi_raw_mode_cleanup(info->raw); + mutex_lock(&scmi_list_mutex); if (info->users) ret = -EBUSY;