From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F734ECAAD5 for ; Sat, 3 Sep 2022 18:31:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229657AbiICSbQ (ORCPT ); Sat, 3 Sep 2022 14:31:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231617AbiICSbM (ORCPT ); Sat, 3 Sep 2022 14:31:12 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 12ED152E4B for ; Sat, 3 Sep 2022 11:31:11 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1031E113E; Sat, 3 Sep 2022 11:31:17 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 01F343F71A; Sat, 3 Sep 2022 11:31:08 -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: [PATCH v3 1/9] firmware: arm_scmi: Refactor xfer in-flight registration routines Date: Sat, 3 Sep 2022 19:30:34 +0100 Message-Id: <20220903183042.3913053-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 !=3D next_token) atomic_add((int)(xfer_id - next_token), &transfer_last_id); =20 - /* Set in-flight */ - set_bit(xfer_id, minfo->xfer_alloc_table); xfer->hdr.seq =3D (u16)xfer_id; =20 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); } =20 +/** + * 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-flig= ht + * 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 =3D 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 =3D 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 even= t. * - * 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 per= form + * 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; =20 @@ -376,25 +418,8 @@ static struct scmi_xfer *scmi_xfer_get(const struct sc= mi_handle *handle, */ xfer->transfer_id =3D atomic_inc_return(&transfer_last_id); =20 - if (set_pending) { - /* Pick and set monotonic token */ - ret =3D scmi_xfer_token_set(minfo, xfer); - if (!ret) { - hash_add(minfo->pending_xfers, &xfer->node, - xfer->hdr.seq); - xfer->pending =3D true; - } else { - dev_err(handle->dev, - "Failed to get monotonic token %d\n", ret); - hlist_add_head(&xfer->node, &minfo->free_xfers); - xfer =3D 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); =20 return xfer; @@ -652,7 +677,7 @@ static void scmi_handle_notification(struct scmi_chan_i= nfo *cinfo, ktime_t ts; =20 ts =3D ktime_get_boottime(); - xfer =3D scmi_xfer_get(cinfo->handle, minfo, false); + xfer =3D 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; =20 - xfer =3D scmi_xfer_get(pi->handle, minfo, true); + xfer =3D scmi_xfer_get(pi->handle, minfo); if (IS_ERR(xfer)) { ret =3D PTR_ERR(xfer); dev_err(dev, "failed to get free message slot(%d)\n", ret); return ret; } =20 + /* Pick a sequence number and register this xfer as in-flight */ + ret =3D 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 =3D tx_size; xfer->rx.len =3D rx_size ? : info->desc->max_msg_size; xfer->hdr.type =3D MSG_TYPE_COMMAND; --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 562D8ECAAD4 for ; Sat, 3 Sep 2022 18:31:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230163AbiICSbW (ORCPT ); Sat, 3 Sep 2022 14:31:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42996 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231516AbiICSbO (ORCPT ); Sat, 3 Sep 2022 14:31:14 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 213A652809 for ; Sat, 3 Sep 2022 11:31:13 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 212871424; Sat, 3 Sep 2022 11:31:19 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 14DB83F71A; Sat, 3 Sep 2022 11:31:10 -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: [PATCH v3 2/9] firmware: arm_scmi: Simplify chan_available transport operation Date: Sat, 3 Sep 2022 19:30:35 +0100 Message-Id: <20220903183042.3913053-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" SCMI transport operation .chan_available determines in a transport-specific way if an SCMI channel is still available and to be configured: such information is derived analyzing bits of DT in a transport specific way; al it needs is a DT node to operate upon, not necessarily a full blown device. Fix to receive in input a reference to adevice_node instead of a device carrying a pointer to such device_node. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/common.h | 2 +- drivers/firmware/arm_scmi/driver.c | 2 +- drivers/firmware/arm_scmi/mailbox.c | 4 ++-- drivers/firmware/arm_scmi/optee.c | 4 ++-- drivers/firmware/arm_scmi/smc.c | 4 ++-- drivers/firmware/arm_scmi/virtio.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi= /common.h index 61aba7447c32..096b66442d84 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -150,7 +150,7 @@ struct scmi_chan_info { */ struct scmi_transport_ops { int (*link_supplier)(struct device *dev); - bool (*chan_available)(struct device *dev, int idx); + bool (*chan_available)(struct device_node *of_node, int idx); int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev, bool tx); int (*chan_free)(int id, void *p, void *data); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index e5193da2ce09..62e02b6475ff 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2035,7 +2035,7 @@ static int scmi_chan_setup(struct scmi_info *info, st= ruct device *dev, if (cinfo) return 0; =20 - if (!info->desc->ops->chan_available(dev, idx)) { + if (!info->desc->ops->chan_available(dev->of_node, idx)) { cinfo =3D idr_find(idr, SCMI_PROTOCOL_BASE); if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ return -EINVAL; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scm= i/mailbox.c index 08ff4d110beb..ed7e66788134 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -46,9 +46,9 @@ static void rx_callback(struct mbox_client *cl, void *m) scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); } =20 -static bool mailbox_chan_available(struct device *dev, int idx) +static bool mailbox_chan_available(struct device_node *of_node, int idx) { - return !of_parse_phandle_with_args(dev->of_node, "mboxes", + return !of_parse_phandle_with_args(of_node, "mboxes", "#mbox-cells", idx, NULL); } =20 diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/= optee.c index f42dad997ac9..59e688767af2 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -328,11 +328,11 @@ static int scmi_optee_link_supplier(struct device *de= v) return 0; } =20 -static bool scmi_optee_chan_available(struct device *dev, int idx) +static bool scmi_optee_chan_available(struct device_node *of_node, int idx) { u32 channel_id; =20 - return !of_property_read_u32_index(dev->of_node, "linaro,optee-channel-id= ", + return !of_property_read_u32_index(of_node, "linaro,optee-channel-id", idx, &channel_id); } =20 diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/sm= c.c index 745acfdd0b3d..0e21bd01348b 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -52,9 +52,9 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data) return IRQ_HANDLED; } =20 -static bool smc_chan_available(struct device *dev, int idx) +static bool smc_chan_available(struct device_node *of_node, int idx) { - struct device_node *np =3D of_parse_phandle(dev->of_node, "shmem", 0); + struct device_node *np =3D of_parse_phandle(of_node, "shmem", 0); if (!np) return false; =20 diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi= /virtio.c index 14709dbc96a1..e0c92037a9e6 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -392,7 +392,7 @@ static int virtio_link_supplier(struct device *dev) return 0; } =20 -static bool virtio_chan_available(struct device *dev, int idx) +static bool virtio_chan_available(struct device_node *of_node, int idx) { struct scmi_vio_channel *channels, *vioch =3D NULL; =20 --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3728DECAAD5 for ; Sat, 3 Sep 2022 18:31:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232026AbiICSb1 (ORCPT ); Sat, 3 Sep 2022 14:31:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43056 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231614AbiICSbQ (ORCPT ); Sat, 3 Sep 2022 14:31:16 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 355CF52FDD for ; Sat, 3 Sep 2022 11:31:15 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 336C01595; Sat, 3 Sep 2022 11:31:21 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 262B73F71A; Sat, 3 Sep 2022 11:31: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: [PATCH v3 3/9] firmware: arm_scmi: Use dedicated devices to initialize channels Date: Sat, 3 Sep 2022 19:30:36 +0100 Message-Id: <20220903183042.3913053-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Refactor channels initialization to use dedicated devices instead of using devices borrowed from the SCMI drivers. Initialize all channels as described in the DT upfront. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 94 ++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 62e02b6475ff..56b1a917f618 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2019,23 +2019,20 @@ static int scmi_xfer_info_init(struct scmi_info *si= nfo) return ret; } =20 -static int scmi_chan_setup(struct scmi_info *info, struct device *dev, +static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_= node, int prot_id, bool tx) { int ret, idx; + char name[32]; struct scmi_chan_info *cinfo; struct idr *idr; + struct scmi_device *tdev =3D NULL; =20 /* Transmit channel is first entry i.e. index 0 */ idx =3D tx ? 0 : 1; idr =3D tx ? &info->tx_idr : &info->rx_idr; =20 - /* check if already allocated, used for multiple device per protocol */ - cinfo =3D idr_find(idr, prot_id); - if (cinfo) - return 0; - - if (!info->desc->ops->chan_available(dev->of_node, idx)) { + if (!info->desc->ops->chan_available(of_node, idx)) { cinfo =3D idr_find(idr, SCMI_PROTOCOL_BASE); if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ return -EINVAL; @@ -2046,26 +2043,41 @@ static int scmi_chan_setup(struct scmi_info *info, = struct device *dev, if (!cinfo) return -ENOMEM; =20 - cinfo->dev =3D dev; + /* Create a unique name for this transport device */ + snprintf(name, 32, "__scmi_transport_device_%s_%02X", + idx ? "rx" : "tx", prot_id); + /* Create a uniquely named, dedicated transport device for this chan */ + tdev =3D scmi_device_create(of_node, info->dev, prot_id, name); + if (!tdev) { + devm_kfree(info->dev, cinfo); + return -EINVAL; + } =20 + cinfo->dev =3D &tdev->dev; ret =3D info->desc->ops->chan_setup(cinfo, info->dev, tx); - if (ret) + if (ret) { + scmi_device_destroy(tdev); + devm_kfree(info->dev, cinfo); return ret; + } =20 if (tx && is_polling_required(cinfo, info)) { if (is_transport_polling_capable(info)) - dev_info(dev, + dev_info(&tdev->dev, "Enabled polling mode TX channel - prot_id:%d\n", prot_id); else - dev_warn(dev, + dev_warn(&tdev->dev, "Polling mode NOT supported by transport.\n"); } =20 idr_alloc: ret =3D idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); if (ret !=3D prot_id) { - dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret); + dev_err(info->dev, + "unable to allocate SCMI idr slot err %d\n", ret); + if (tdev) + scmi_device_destroy(tdev); return ret; } =20 @@ -2074,16 +2086,57 @@ static int scmi_chan_setup(struct scmi_info *info, = struct device *dev, } =20 static inline int -scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) +scmi_txrx_setup(struct scmi_info *info, struct device_node *of_node, + int prot_id) { - int ret =3D scmi_chan_setup(info, dev, prot_id, true); + int ret =3D scmi_chan_setup(info, of_node, prot_id, true); =20 if (!ret) /* Rx is optional, hence no error check */ - scmi_chan_setup(info, dev, prot_id, false); + scmi_chan_setup(info, of_node, prot_id, false); =20 return ret; } =20 +/** + * scmi_channels_setup - Helper to initialize all required channels + * + * @info: The SCMI instance descriptor. + * + * Initialize all the channels found described in the DT against the under= lying + * configured transport using custom defined dedicated devices instead of + * borrowing devices from the SCMI drivers; this way channels are initiali= zed + * upfront during core SCMI stack probing and are operational even if then= no + * SCMI driver is loaded. (useful to operate in Raw mode) + * + * Return: 0 on Success + */ +static int scmi_channels_setup(struct scmi_info *info) +{ + int ret; + struct device_node *child, *top_np =3D info->dev->of_node; + + ret =3D scmi_txrx_setup(info, top_np, SCMI_PROTOCOL_BASE); + if (ret) + return ret; + + for_each_available_child_of_node(top_np, child) { + u32 prot_id; + + if (of_property_read_u32(child, "reg", &prot_id)) + continue; + + if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) + dev_err(info->dev, + "Out of range protocol %d\n", prot_id); + + ret =3D scmi_txrx_setup(info, child, prot_id); + if (ret) + return ret; + } + + return 0; +} + /** * scmi_get_protocol_device - Helper to get/create an SCMI device. * @@ -2133,14 +2186,6 @@ scmi_get_protocol_device(struct device_node *np, str= uct scmi_info *info, return NULL; } =20 - if (scmi_txrx_setup(info, &sdev->dev, prot_id)) { - dev_err(&sdev->dev, "failed to setup transport\n"); - scmi_device_destroy(sdev); - mutex_unlock(&scmi_syspower_mtx); - - return NULL; - } - if (prot_id =3D=3D SCMI_PROTOCOL_SYSTEM) scmi_syspower_registered =3D true; =20 @@ -2432,7 +2477,8 @@ static int scmi_probe(struct platform_device *pdev) return ret; } =20 - ret =3D scmi_txrx_setup(info, dev, SCMI_PROTOCOL_BASE); + /* Setup all channels described in the DT at first */ + ret =3D scmi_channels_setup(info); if (ret) return ret; =20 --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9E12DECAAD5 for ; Sat, 3 Sep 2022 18:31:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232054AbiICSba (ORCPT ); Sat, 3 Sep 2022 14:31:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43210 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231902AbiICSbV (ORCPT ); Sat, 3 Sep 2022 14:31:21 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 43EDB53D13 for ; Sat, 3 Sep 2022 11:31:17 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4521416A3; Sat, 3 Sep 2022 11:31:23 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 381243F71A; Sat, 3 Sep 2022 11:31: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: [PATCH v3 4/9] firmware: arm_scmi: Add xfer raw helpers Date: Sat, 3 Sep 2022 19:30:37 +0100 Message-Id: <20220903183042.3913053-5-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add a few SCMI helpers useful to implement SCMI Raw access support. Signed-off-by: Cristian Marussi --- v1 --> v2 - added scmi_xfer_raw_channel_get v2 --> v3 - allow for DT-unknown protocols to get a channel --- drivers/firmware/arm_scmi/common.h | 9 +++ drivers/firmware/arm_scmi/driver.c | 115 +++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi= /common.h index 096b66442d84..6d2a57a696d8 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -212,6 +212,15 @@ struct scmi_desc { const bool atomic_enabled; }; =20 +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); +struct scmi_chan_info * +scmi_xfer_raw_channel_get(const struct scmi_handle *handle, u8 protocol_id= ); + +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 56b1a917f618..c1292452e41f 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 =3D true; } =20 +/** + * 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 t= he + * 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 =3D 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 =3D -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 =3D 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,58 @@ static struct scmi_xfer *scmi_xfer_get(const struct sc= mi_handle *handle, return xfer; } =20 +/** + * 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 =3D handle_to_scmi_info(handle); + + return scmi_xfer_get(handle, &info->tx_minfo); +} + +/** + * scmi_xfer_raw_channel_get - Helper to get a reference to the proper ch= annel + * to use for a specific protocol_id Raw transaction. + * + * @handle: Pointer to SCMI entity handle + * @protocol_id: Identifier of the protocol + * + * Note that in a regular SCMI stack, usually, a protocol has to be define= d in + * the DT to have an associated channel and be usable; but in Raw mode any + * protocol in range is allowed, resusing the Base channel, so as to enable + * fuzzing on any protocol without the need of a fully compiled DT. + * + * Return: A reference to the channel to use, or an ERR_PTR + */ +struct scmi_chan_info * +scmi_xfer_raw_channel_get(const struct scmi_handle *handle, u8 protocol_id) +{ + struct scmi_chan_info *cinfo; + struct scmi_info *info =3D handle_to_scmi_info(handle); + + cinfo =3D idr_find(&info->tx_idr, protocol_id); + if (!cinfo) { + if (protocol_id =3D=3D SCMI_PROTOCOL_BASE) + return ERR_PTR(-EINVAL); + /* Use Base channel for protocols not defined for DT */ + cinfo =3D idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE); + if (!cinfo) + return ERR_PTR(-EINVAL); + dev_warn_once(handle->dev, + "Using Base channel for protocol 0x%X\n", + protocol_id); + } + + return cinfo; +} + /** * __scmi_xfer_put() - Release a message * @@ -453,6 +552,22 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct = scmi_xfer *xfer) spin_unlock_irqrestore(&minfo->xfer_lock, flags); } =20 +/** + * scmi_xfer_raw_put - Release an xfer that was taken by @scmi_xfer_raw_g= et + * + * @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 effectiv= ely + * 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 =3D handle_to_scmi_info(handle); + + return __scmi_xfer_put(&info->tx_minfo, xfer); +} + /** * scmi_xfer_lookup_unlocked - Helper to lookup an xfer_id * --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAFA7ECAAD5 for ; Sat, 3 Sep 2022 18:31:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229771AbiICSbe (ORCPT ); Sat, 3 Sep 2022 14:31:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231977AbiICSbZ (ORCPT ); Sat, 3 Sep 2022 14:31:25 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7D17854CB7 for ; Sat, 3 Sep 2022 11:31:20 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 56E9B16F2; Sat, 3 Sep 2022 11:31:25 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 49AB83F71A; Sat, 3 Sep 2022 11:31: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: [PATCH v3 5/9] firmware: arm_scmi: Move errors defs and code to common.h Date: Sat, 3 Sep 2022 19:30:38 +0100 Message-Id: <20220903183042.3913053-6-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 6d2a57a696d8..5334a2b272bf 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" =20 +#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) + +enum scmi_error_codes { + SCMI_SUCCESS =3D 0, /* Success */ + SCMI_ERR_SUPPORT =3D -1, /* Not supported */ + SCMI_ERR_PARAMS =3D -2, /* Invalid Parameters */ + SCMI_ERR_ACCESS =3D -3, /* Invalid access/permission denied */ + SCMI_ERR_ENTRY =3D -4, /* Not found */ + SCMI_ERR_RANGE =3D -5, /* Value out of range */ + SCMI_ERR_BUSY =3D -6, /* Device busy */ + SCMI_ERR_COMMS =3D -7, /* Communication Error */ + SCMI_ERR_GENERIC =3D -8, /* Generic Error */ + SCMI_ERR_HARDWARE =3D -9, /* Hardware Error */ + SCMI_ERR_PROTOCOL =3D -10,/* Protocol Error */ +}; + +static const int scmi_linux_errmap[] =3D { + /* 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 =3D -errno; + + if (err_idx >=3D 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 c1292452e41f..056796b2dcae 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -37,20 +37,6 @@ #define CREATE_TRACE_POINTS #include =20 -enum scmi_error_codes { - SCMI_SUCCESS =3D 0, /* Success */ - SCMI_ERR_SUPPORT =3D -1, /* Not supported */ - SCMI_ERR_PARAMS =3D -2, /* Invalid Parameters */ - SCMI_ERR_ACCESS =3D -3, /* Invalid access/permission denied */ - SCMI_ERR_ENTRY =3D -4, /* Not found */ - SCMI_ERR_RANGE =3D -5, /* Value out of range */ - SCMI_ERR_BUSY =3D -6, /* Device busy */ - SCMI_ERR_COMMS =3D -7, /* Communication Error */ - SCMI_ERR_GENERIC =3D -8, /* Generic Error */ - SCMI_ERR_HARDWARE =3D -9, /* Hardware Error */ - SCMI_ERR_PROTOCOL =3D -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 { =20 #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) =20 -static const int scmi_linux_errmap[] =3D { - /* 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 =3D -errno; - - if (err_idx >=3D 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) { @@ -1092,8 +1054,6 @@ static void reset_rx_to_maxsz(const struct scmi_proto= col_handle *ph, xfer->rx.len =3D info->desc->max_msg_size; } =20 -#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) - /** * do_xfer_with_response() - Do one transfer and wait until the delayed * response is received --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3DAE1ECAAD5 for ; Sat, 3 Sep 2022 18:31:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229698AbiICSbk (ORCPT ); Sat, 3 Sep 2022 14:31:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43354 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231573AbiICSb2 (ORCPT ); Sat, 3 Sep 2022 14:31:28 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A01AF54679 for ; Sat, 3 Sep 2022 11:31:22 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A1FA316F3; Sat, 3 Sep 2022 11:31:27 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5D53E3F71A; Sat, 3 Sep 2022 11:31:19 -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: [PATCH v3 6/9] firmware: arm_scmi: Add raw transmission support Date: Sat, 3 Sep 2022 19:30:39 +0100 Message-Id: <20220903183042.3913053-7-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add SCMI Raw mode support which exposes a userspace interface to allow for bare SCMI command injection and snooping from userspace. Signed-off-by: Cristian Marussi --- v1 --> v2 - make use of proper channel depending on protocol at hand (using scmi_xfer_raw_channel_get to lookup related DT config) - refactored scmi_inflight_register call - added debugfs docs and comments v2 --> v3 - changed to dev_dbg when retrying inflight reg - refactored and simplfiied waiters deferred worker - fixed sparse errors about LE and __poll_t --- drivers/firmware/arm_scmi/Kconfig | 13 + drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/raw_mode.c | 1235 ++++++++++++++++++++++++++ drivers/firmware/arm_scmi/raw_mode.h | 29 + 4 files changed, 1278 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 =20 if ARM_SCMI_PROTOCOL =20 +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 =3D bus.o scmi-driver-y =3D driver.o notify.o +scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) +=3D raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) =3D shmem.o scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) +=3D mailbox.o scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) +=3D smc.o diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_sc= mi/raw_mode.c new file mode 100644 index 000000000000..3ff333874724 --- /dev/null +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -0,0 +1,1235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) Raw mode support + * + * Copyright (C) 2022 ARM Ltd. + */ +/** + * DOC: Theory of operation + * + * When enabled the SCMI Raw mode support exposes a userspace API which al= lows + * to send and receive SCMI commands, replies and notifications from a user + * application through injection and snooping of bare SCMI messages in bin= ary + * little-endian format. + * + * Such injected SCMI transactions will then be routed through the SCMI co= re + * stack towards the SCMI backend server using whatever SCMI transport is + * currently configured on the system under test. + * + * It is meant to help in running any sort of SCMI backend server testing,= no + * matter where the server is placed, as long as it is normally reachable = via + * the transport configured on the system. + * + * It is activated by a Kernel configuration option since it is NOT meant = to + * be used in production but only during development and in CI deployement= s. + * + * In order to avoid possible interferences between the SCMI Raw transacti= ons + * originated from a test-suite and the normal operations of the SCMI driv= ers, + * when Raw mode is enabled, by default, all the regular SCMI drivers are + * inhibited. + * + * The exposed API is as follows: + * + * /sys/kernel/debug/scmi_raw/ + * |-- errors + * |-- message + * |-- message_async + * |-- notification + * |-- reset + * |-- transport_max_msg_size + * |-- transport_rx_timeout_ms + * |-- transport_tx_max_msg + * + * where: + * + * - errors: used to read back timed-out and unexpected replies + * - message*: used to send sync/async commands and read back immediate a= nd + * delayed reponses (if any) + * - notification: used to read any notification being emitted by the sys= tem + * (if previously enabled by the user app) + * - reset: used to flush the queues of messages (of any kind) still pend= ing + * to be read; this is useful at test-suite start/stop to get + * rid of any unread messages from the previous run. + * - transport*: a bunch of configurations useful to setup the user + * application expectations in terms of timeouts and message + * characteristics. + * + * Each write to the message* entries causes one command request to be bui= lt + * and sent while the replies or delayed response are read back from those= same + * entries one message at time (receiving an EOF at each message boundary). + * + * The user application running the test is in charge of handling timeouts + * on replies and properly choosing SCMI sequence numbers for the outgoing + * requests (using the same sequence number is supported but discouraged). + * + * Injection of multiple in-flight requests is supported as long as the us= er + * application uses properly distinct sequence numbers for concurrent requ= ests + * and takes care to properly manage all the related issues about concurre= ncy + * and command/reply pairing. Keep in mind that, anyway, the real level of + * parallelism attainable in such scenario is dependent on the characteris= tics + * of the underlying transport being used. + * + * Since the SCMI core regular stack is partially used to deliver and coll= ect + * the messages, late replies arrived after timeouts and any other sort of + * unexpected message can be identified by the SCMI core as usual and they= will + * be reported as messages under "errors" for later analysis. + */ + +#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_raw_mode_info - Structure holding SCMI Raw instance data + * + * @handle: Pointer to SCMI entity handle to use + * @desc: Pointer to the transport descriptor to use + * @tx_max_msg: Maximum number of concurrent TX in-flight messages + * @free_raw_bufs: An array of freelists heads used to keep unused raw buf= fers + * @free_bufs_lock: Spinlocks used to protect access to each @free_raw_bufs + * @msg_q: An array of lists to queue snooped messages waiting to be read = out + * @msg_q_lock: Spinlocks used to protect access to each @msg_q + * @wqs: An array of waitqueues used to wait and poll on related @msg_q + * @free_waiters: Head of freelist for unused waiters + * @free_mtx: A mutex to protect the waiters freelist + * @active_waiters: Head of list for currently active and used waiters + * @active_mtx: A mutex to protect the active waiters list + * @waiters_work: A work descriptor to be used with the workqueue machinery + * @wait_wq: A workqueue reference to the created workqueue + * @dentry: Top debugfs root dentry for SCMI Raw + * @gid: A group ID used for devres accounting + * + * Note that this descriptor is passed back to the core after SCMI Raw is + * initialized as an opaque handle to use by subsequent SCMI Raw call hook= s. + * + */ +struct scmi_raw_mode_info { + const struct scmi_handle *handle; + 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 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; + struct work_struct waiters_work; + struct workqueue_struct *wait_wq; + struct dentry *dentry; + void *gid; +}; + +/** + * struct scmi_xfer_raw_waiter - Structure to describe an xfer to be wait= ed for + * + * @start_jiffies: The timestamp in jiffies of when this structure was que= ued. + * @cinfo: A reference to the channel to use for this transaction + * @xfer: A reference to the xfer to be waited for + * @async_response: A completion to be, optionally, used for async waits: = it + * will be setup by @scmi_do_xfer_raw_start, if needed, to be + * pointed at by xfer->async_done. + * @node: A list node. + */ +struct scmi_xfer_raw_waiter { + unsigned long start_jiffies; + struct scmi_chan_info *cinfo; + struct scmi_xfer *xfer; + struct completion async_response; + struct list_head node; +}; + +/** + * struct scmi_raw_buffer - Structure to hold a full SCMI message + * + * @max_len: The maximum allowed message size (header included) that can be + * stored into @msg + * @msg: A message buffer used to collect a full message grabbed from an x= fer. + * @node: A list node. + */ +struct scmi_raw_buffer { + size_t max_len; + struct scmi_msg msg; + struct list_head node; +}; + +/** + * struct scmi_dbg_raw_data - Structure holding data needed by the debugfs + * layer + * + * @raw: A reference to the Raw instance. + * @tx: A message buffer used to collect TX message on write. + * @tx_size: The effective size of the TX message. + * @tx_req_size: The final expected size of the complete TX message. + * @rx: A message buffer to collect RX message on read. + * @rx_size: The effective size of the RX message. + */ +struct scmi_dbg_raw_data { + struct scmi_raw_mode_info *raw; + struct scmi_msg tx; + size_t tx_size; + size_t tx_req_size; + 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 =3D NULL; + struct list_head *head =3D &raw->free_raw_bufs[idx]; + + spin_lock_irqsave(&raw->free_bufs_lock[idx], flags); + if (!list_empty(head)) { + rb =3D 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; + + /* Reset to full buffer length */ + rb->msg.len =3D 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 =3D NULL; + + spin_lock_irqsave(&raw->msg_q_lock[idx], flags); + if (!list_empty(&raw->msg_q[idx])) { + rb =3D 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 =3D 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_raw_mode_info *raw, struct scmi_xfer = *xfer, + struct scmi_chan_info *cinfo, bool async) +{ + struct scmi_xfer_raw_waiter *rw =3D NULL; + + mutex_lock(&raw->free_mtx); + if (!list_empty(&raw->free_waiters)) { + rw =3D list_first_entry(&raw->free_waiters, + struct scmi_xfer_raw_waiter, node); + list_del_init(&rw->node); + + if (async) { + reinit_completion(&rw->async_response); + xfer->async_done =3D &rw->async_response; + } + + rw->cinfo =3D cinfo; + rw->xfer =3D xfer; + } + mutex_unlock(&raw->free_mtx); + + return rw; +} + +static inline void scmi_xfer_raw_waiter_put(struct scmi_raw_mode_info *raw, + struct scmi_xfer_raw_waiter *rw) +{ + if (rw->xfer) { + rw->xfer->async_done =3D NULL; + rw->xfer =3D NULL; + } + + mutex_lock(&raw->free_mtx); + list_add_tail(&rw->node, &raw->free_waiters); + mutex_unlock(&raw->free_mtx); +} + +static inline void scmi_xfer_raw_waiter_enqueue(struct scmi_raw_mode_info = *raw, + struct scmi_xfer_raw_waiter *rw) +{ + /* A timestamp for the deferred worker to know how much this has aged */ + rw->start_jiffies =3D jiffies; + + trace_scmi_xfer_response_wait(rw->xfer->transfer_id, rw->xfer->hdr.id, + rw->xfer->hdr.protocol_id, + rw->xfer->hdr.seq, + raw->desc->max_rx_timeout_ms, + rw->xfer->hdr.poll_completion); + + mutex_lock(&raw->active_mtx); + list_add_tail(&rw->node, &raw->active_waiters); + mutex_unlock(&raw->active_mtx); + /* kick waiter work */ + queue_work(raw->wait_wq, &raw->waiters_work); +} + +static struct scmi_xfer_raw_waiter* +scmi_xfer_raw_waiter_dequeue(struct scmi_raw_mode_info *raw) +{ + struct scmi_xfer_raw_waiter *rw =3D NULL; + + mutex_lock(&raw->active_mtx); + if (!list_empty(&raw->active_waiters)) { + rw =3D list_first_entry(&raw->active_waiters, + struct scmi_xfer_raw_waiter, node); + list_del_init(&rw->node); + } + mutex_unlock(&raw->active_mtx); + + return rw; +} + +/** + * scmi_xfer_raw_worker - Work function to wait for Raw xfers completions + * + * @work: A reference to the work. + * + * In SCMI Raw mode, once a user-provided injected SCMI message is sent, we + * cannot wait to receive its response (if any) in the context of the inje= ction + * routines so as not to leave the userspace write syscall, which delivere= d the + * SCMI message to send, pending till eventually a reply is received. + * Userspace should and will poll/wait instead on the read syscalls which = will + * be in charge of reading a received reply (if any). + * + * Even though reply messages are collected and reported into the SCMI Raw= layer + * on the RX path, nonetheless we have to properly wait for their completi= on as + * usual (and async_completion too if needed) in order to properly release= the + * xfer structure at the end: to do this out of the context of the write/s= end + * these waiting jobs are delegated to this deferred worker. + * + * Any sent xfer, to be waited for, is timestamped and queued for later + * consumption by this worker: queue aging is accounted for while choosing= a + * timeout for the completion, BUT we do not really care here if we end up + * accidentally waiting for a bit too long. + */ +static void scmi_xfer_raw_worker(struct work_struct *work) +{ + struct scmi_raw_mode_info *raw; + struct device *dev; + unsigned long max_tmo; + + raw =3D container_of(work, struct scmi_raw_mode_info, waiters_work); + dev =3D raw->handle->dev; + max_tmo =3D msecs_to_jiffies(raw->desc->max_rx_timeout_ms); + + do { + int ret =3D 0; + unsigned long aging, tmo; + struct scmi_xfer *xfer; + struct scmi_xfer_raw_waiter *rw; + + rw =3D scmi_xfer_raw_waiter_dequeue(raw); + if (!rw) + return; + + xfer =3D rw->xfer; + + /* + * 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). + */ + aging =3D jiffies - rw->start_jiffies; + tmo =3D max_tmo > aging ? 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 =3D -ETIMEDOUT; + } + + /* Avoid unneeded async waits */ + if (!ret && xfer->hdr.status) + ret =3D scmi_to_linux_errno(xfer->hdr.status); + + if (raw->desc->ops->mark_txdone) + raw->desc->ops->mark_txdone(rw->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 =3D 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->handle, xfer); + scmi_xfer_raw_waiter_put(raw, rw); + } while (1); +} + +static void scmi_xfer_raw_reset(struct scmi_raw_mode_info *raw) +{ + int i; + + dev_info(raw->handle->dev, "Resetting SCMI Raw stack.\n"); + + for (i =3D 0; i < SCMI_RAW_MAX_QUEUE; i++) + scmi_raw_buffer_queue_flush(raw, i); +} + +/** + * scmi_xfer_raw_get_init - An helper to build a valid xfer from the prov= ided + * bare SCMI message. + * + * @raw: A reference to the Raw instance. + * @buf: A buffer containing the whole SCMI message to send (including the + * header) in little-endian binary formmat. + * @len: Length of the message in @buf. + * @p: A pointer to return the initialized Raw xfer. + * + * After an xfer is picked from the TX pool and filled in with the message + * content, the xfer is registered as pending with the core in the usual w= ay + * using the original sequence number provided by the user with the messag= e. + * + * Note that, in case the testing user application is NOT using distinct + * sequence-numbers between successive SCMI messages such registration cou= ld + * fail temporarily if the previous message, using the same sequence numbe= r, + * had still not released; in such a case we just wait and retry. + * + * Return: 0 on Success + */ +static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *bu= f, + size_t len, struct scmi_xfer **p) +{ + u32 msg_hdr; + size_t tx_size; + struct scmi_xfer *xfer; + int ret, retry =3D SCMI_XFER_RAW_MAX_RETRIES; + struct device *dev =3D raw->handle->dev; + + if (!buf || len < sizeof(u32)) + return -EINVAL; + + tx_size =3D len - sizeof(u32); + /* Ensure we have sane transfer sizes */ + if (tx_size > raw->desc->max_msg_size) + return -ERANGE; + + xfer =3D scmi_xfer_raw_get(raw->handle); + if (IS_ERR(xfer)) { + dev_warn(dev, "RAW - Cannot get a free RAW xfer !\n"); + return PTR_ERR(xfer); + } + + /* Build xfer from the provided SCMI bare LE message */ + msg_hdr =3D le32_to_cpu(*((__le32 *)buf)); + unpack_scmi_header(msg_hdr, &xfer->hdr); + xfer->hdr.seq =3D (u16)MSG_XTRACT_TOKEN(msg_hdr); + /* Polling not supported */ + xfer->hdr.poll_completion =3D false; + xfer->hdr.status =3D SCMI_SUCCESS; + xfer->tx.len =3D tx_size; + xfer->rx.len =3D raw->desc->max_msg_size; + /* Clear the whole TX buffer */ + memset(xfer->tx.buf, 0x00, raw->desc->max_msg_size); + if (xfer->tx.len) + memcpy(xfer->tx.buf, (u8 *)buf + sizeof(msg_hdr), xfer->tx.len); + *p =3D xfer; + + /* + * In flight registration can temporarily fail in case of Raw messages + * if the user injects messages without using monotonically increasing + * sequence numbers since, in Raw mode, the xfer (and the token) is + * finally released later by a deferred worker. Just retry for a while. + */ + do { + ret =3D scmi_xfer_raw_inflight_register(raw->handle, xfer); + if (ret) { + dev_dbg(dev, + "...retrying[%d] inflight registration\n", + retry); + msleep(raw->desc->max_rx_timeout_ms / + SCMI_XFER_RAW_MAX_RETRIES); + } + } while (ret && --retry); + + if (ret) { + dev_warn(dev, + "RAW - Could NOT register xfer %d in-flight HDR:0x%08X\n", + xfer->hdr.seq, msg_hdr); + scmi_xfer_raw_put(raw->handle, xfer); + } + + return ret; +} + +/** + * scmi_do_xfer_raw_start - An helper to send a valid raw xfer + * + * @raw: A reference to the Raw instance. + * @xfer: The xfer to send + * @async: A flag stating if an asynchronous command is required. + * + * This function send a previously built raw xfer using an appropriate cha= nnel + * and queues the related waiting work. + * + * Note that we need to know explicitly if the required command is meant t= o be + * asynchronous in kind since we have to properly setup the waiter. + * (and deducing this from the payload is weak and do not scale given ther= e is + * NOT a common header-flag stating if the command is asynchronous or not) + * + * Return: 0 on Success + */ +static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw, + struct scmi_xfer *xfer, bool async) +{ + int ret; + struct scmi_chan_info *cinfo; + struct scmi_xfer_raw_waiter *rw; + struct device *dev =3D raw->handle->dev; + + cinfo =3D scmi_xfer_raw_channel_get(raw->handle, xfer->hdr.protocol_id); + if (IS_ERR(cinfo)) + return PTR_ERR(cinfo); + + rw =3D scmi_xfer_raw_waiter_get(raw, xfer, cinfo, 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 =3D raw->desc->ops->send_message(rw->cinfo, xfer); + if (ret) { + dev_err(dev, "Failed to send RAW message %d\n", ret); + scmi_xfer_raw_waiter_put(raw, 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, rw); + + return ret; +} + +/** + * scmi_raw_message_send - An helper to build and send an SCMI command us= ing + * the provided SCMI bare message buffer + * + * @raw: A reference to the Raw instance. + * @buf: A buffer containing the whole SCMI message to send (including the + * header) in little-endian binary format. + * @len: Length of the message in @buf. + * @async: A flag stating if an asynchronous command is required. + * + * Return: 0 on Success + */ +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; + + ret =3D scmi_xfer_raw_get_init(raw, buf, len, &xfer); + if (ret) + return ret; + + ret =3D scmi_do_xfer_raw_start(raw, xfer, async); + if (ret) + scmi_xfer_raw_put(raw->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); +} + +/** + * scmi_raw_message_receive - An helper to dequeue and report the next + * available enqueued raw message payload that has been collected. + * + * @raw: A reference to the Raw instance. + * @buf: A buffer to get hold of the whole SCMI message received and repre= sented + * in little-endian binary format. + * @len: Length of @buf. + * @size: The effective size of the message copied into @buf + * @idx: The index of the queue to pick the next queued message from. + * + * Return: 0 on Success + */ +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 =3D 0; + struct scmi_raw_buffer *rb; + + rb =3D scmi_raw_message_dequeue(raw, idx); + if (!rb) { + dev_dbg(raw->handle->dev, "RAW - No message available!\n"); + return -ENODEV; + } + + if (rb->msg.len <=3D len) { + memcpy(buf, rb->msg.buf, rb->msg.len); + *size =3D rb->msg.len; + } else { + ret =3D -ENOSPC; + } + + scmi_raw_buffer_put(raw, rb, idx); + + return ret; +} + +/* SCMI Raw debugfs helpers */ + +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_dbg_raw_data *rd =3D filp->private_data; + + if (!rd->rx_size) { + int ret; + + ret =3D scmi_raw_message_receive(rd->raw, rd->rx.buf, rd->rx.len, + &rd->rx_size, idx); + if (ret) { + rd->rx_size =3D 0; + return ret; + } + + /* Reset any previous filepos change, including writes */ + *ppos =3D 0; + } else if (*ppos =3D=3D rd->rx_size) { + /* Return EOF once all the message has been read-out */ + rd->rx_size =3D 0; + return 0; + } + + cnt =3D 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_dbg_raw_data *rd =3D 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_size =3D count; + + /* + * Gather a full message, possibly across multiple interrupted wrrtes, + * before sending it with a single RAW xfer. + */ + if (rd->tx_size < rd->tx_req_size) { + size_t cnt; + + cnt =3D simple_write_to_buffer(rd->tx.buf, rd->tx.len, ppos, + buf, count); + rd->tx_size +=3D cnt; + if (cnt < count) + return cnt; + } + + ret =3D scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size, async); + + /* Reset ppos for next message ... */ + rd->tx_size =3D 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_dbg_raw_data *rd =3D filp->private_data; + __poll_t mask =3D 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])) + mask =3D EPOLLIN | EPOLLRDNORM; + spin_unlock_irqrestore(&rd->raw->msg_q_lock[idx], flags); + + return mask; +} + +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_dbg_raw_data *rd; + + if (!inode->i_private) + return -ENODEV; + + raw =3D inode->i_private; + rd =3D kzalloc(sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + rd->rx.len =3D raw->desc->max_msg_size + sizeof(u32); + rd->rx.buf =3D kzalloc(rd->rx.len, GFP_KERNEL); + if (!rd->rx.buf) { + kfree(rd); + return -ENOMEM; + } + + rd->tx.len =3D raw->desc->max_msg_size + sizeof(u32); + rd->tx.buf =3D kzalloc(rd->tx.len, GFP_KERNEL); + if (!rd->tx.buf) { + kfree(rd->rx.buf); + kfree(rd); + return -ENOMEM; + } + + rd->raw =3D raw; + filp->private_data =3D rd; + + return 0; +} + +static int scmi_dbg_raw_mode_release(struct inode *inode, struct file *fil= p) +{ + struct scmi_dbg_raw_data *rd =3D filp->private_data; + + kfree(rd->rx.buf); + kfree(rd->tx.buf); + kfree(rd); + + return 0; +} + +static ssize_t scmi_dbg_raw_mode_reset_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct scmi_dbg_raw_data *rd =3D filp->private_data; + + scmi_xfer_raw_reset(rd->raw); + + return count; +} + +static const struct file_operations scmi_dbg_raw_mode_reset_fops =3D { + .open =3D scmi_dbg_raw_mode_open, + .release =3D scmi_dbg_raw_mode_release, + .write =3D scmi_dbg_raw_mode_reset_write, + .owner =3D THIS_MODULE, +}; + +static const struct file_operations scmi_dbg_raw_mode_message_fops =3D { + .open =3D scmi_dbg_raw_mode_open, + .release =3D scmi_dbg_raw_mode_release, + .read =3D scmi_dbg_raw_mode_message_read, + .write =3D scmi_dbg_raw_mode_message_write, + .poll =3D scmi_dbg_raw_mode_message_poll, + .owner =3D 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 = =3D { + .open =3D scmi_dbg_raw_mode_open, + .release =3D scmi_dbg_raw_mode_release, + .read =3D scmi_dbg_raw_mode_message_read, + .write =3D scmi_dbg_raw_mode_message_async_write, + .poll =3D scmi_dbg_raw_mode_message_poll, + .owner =3D 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 = =3D { + .open =3D scmi_dbg_raw_mode_open, + .release =3D scmi_dbg_raw_mode_release, + .read =3D scmi_test_dbg_raw_mode_notif_read, + .poll =3D scmi_test_dbg_raw_mode_notif_poll, + .owner =3D 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 =3D { + .open =3D scmi_dbg_raw_mode_open, + .release =3D scmi_dbg_raw_mode_release, + .read =3D scmi_test_dbg_raw_mode_errors_read, + .poll =3D scmi_test_dbg_raw_mode_errors_poll, + .owner =3D THIS_MODULE, +}; + +static int scmi_xfer_raw_free_bufs_init(struct scmi_raw_mode_info *raw, in= t idx) +{ + int i; + struct scmi_raw_buffer *rb; + struct device *dev =3D raw->handle->dev; + + rb =3D 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 =3D 0; i < raw->tx_max_msg; i++, rb++) { + rb->max_len =3D raw->desc->max_msg_size + sizeof(u32); + rb->msg.buf =3D 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 =3D raw->handle->dev; + + rw =3D devm_kcalloc(dev, raw->tx_max_msg, sizeof(*rw), GFP_KERNEL); + if (!rw) + return -ENOMEM; + + raw->wait_wq =3D alloc_workqueue("scmi-raw-wait-wq-%d", + WQ_UNBOUND | WQ_FREEZABLE | + WQ_HIGHPRI, WQ_SYSFS, 0); + if (!raw->wait_wq) + return -ENOMEM; + + mutex_init(&raw->free_mtx); + INIT_LIST_HEAD(&raw->free_waiters); + mutex_init(&raw->active_mtx); + INIT_LIST_HEAD(&raw->active_waiters); + + for (i =3D 0; i < raw->tx_max_msg; i++, rw++) { + init_completion(&rw->async_response); + scmi_xfer_raw_waiter_put(raw, rw); + } + INIT_WORK(&raw->waiters_work, scmi_xfer_raw_worker); + + return 0; +} + +static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw) +{ + int ret, idx; + void *gid; + struct device *dev =3D raw->handle->dev; + + gid =3D devres_open_group(dev, NULL, GFP_KERNEL); + if (!gid) + return -ENOMEM; + + for (idx =3D 0; idx < SCMI_RAW_MAX_QUEUE; idx++) { + ret =3D scmi_xfer_raw_free_bufs_init(raw, idx); + if (ret) + goto err; + } + + ret =3D scmi_xfer_raw_worker_init(raw); + if (ret) + goto err; + + devres_close_group(dev, gid); + raw->gid =3D gid; + + return 0; + +err: + devres_release_group(dev, gid); + return ret; +} + +/** + * scmi_raw_mode_init - Function to initialize the SCMI Raw stack + * + * @handle: Pointer to SCMI entity handle + * @desc: Reference to the transport operations + * @tx_max_msg: Max number of in-flight messages allowed by the transport + * + * This function prepare the SCMI Raw stack and creates the debugfs API. + * + * Return: An opaque handle to the Raw instance on Success, an ERR_PTR oth= erwise + */ +void *scmi_raw_mode_init(const struct scmi_handle *handle, + const struct scmi_desc *desc, int tx_max_msg) +{ + int ret; + struct scmi_raw_mode_info *raw; + struct device *dev; + + if (!handle || !desc) + return ERR_PTR(-EINVAL); + + dev =3D handle->dev; + raw =3D devm_kzalloc(dev, sizeof(*raw), GFP_KERNEL); + if (!raw) + return ERR_PTR(-ENOMEM); + + raw->handle =3D handle; + raw->desc =3D desc; + raw->tx_max_msg =3D tx_max_msg; + + ret =3D scmi_raw_mode_setup(raw); + if (ret) { + devm_kfree(dev, raw); + return ERR_PTR(ret); + } + + raw->dentry =3D debugfs_create_dir("scmi_raw", NULL); + if (IS_ERR(raw->dentry)) { + ret =3D PTR_ERR(raw->dentry); + devres_release_group(dev, raw->gid); + devm_kfree(dev, raw); + return ERR_PTR(ret); + } + + debugfs_create_file("reset", 0200, raw->dentry, raw, + &scmi_dbg_raw_mode_reset_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; +} + +/** + * scmi_raw_mode_cleanup - Function to cleanup the SCMI Raw stack + * + * @r: An opaque handle to an initialized SCMI Raw instance + */ +void scmi_raw_mode_cleanup(void *r) +{ + struct scmi_raw_mode_info *raw =3D r; + + if (!raw) + return; + + debugfs_remove_recursive(raw->dentry); + + cancel_work_sync(&raw->waiters_work); + destroy_workqueue(raw->wait_wq); +} + +static int scmi_xfer_raw_collect(struct scmi_xfer *xfer, + void *msg, size_t *msg_len) +{ + __le32 *m; + size_t msg_size; + + if (!xfer || !msg || !msg_len) + return -EINVAL; + + /* Account for hdr ...*/ + msg_size =3D xfer->rx.len + sizeof(u32); + /* ... and status if needed */ + if (xfer->hdr.type !=3D MSG_TYPE_NOTIFICATION) + msg_size +=3D sizeof(u32); + + if (msg_size > *msg_len) + return -ENOSPC; + + m =3D msg; + *m =3D cpu_to_le32(pack_scmi_header(&xfer->hdr)); + if (xfer->hdr.type !=3D MSG_TYPE_NOTIFICATION) + *++m =3D cpu_to_le32(xfer->hdr.status); + + memcpy(++m, xfer->rx.buf, xfer->rx.len); + + *msg_len =3D msg_size; + + return 0; +} + +/** + * scmi_raw_message_report - Helper to report back valid reponses/notific= ations + * to raw message requests. + * + * @r: An opaque reference to the raw instance configuration + * @xfer: The xfer containing the message to be reported + * @idx: The index of the queue. + * + * If Raw mode is enabled, this is called from the SCMI core on the regula= r RX + * path to save and enqueue the response/notification payload carried by t= his + * xfer into a dedicated scmi_raw_buffer for later consumption by the user. + * + * This way the caller can free the related xfer immediately afterwards an= d the + * user can read back the raw message payload at its own pace (if ever) wi= thout + * holding an xfer for too long. + */ +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 =3D r; + + if (!raw) + return; + + dev =3D raw->handle->dev; + rb =3D scmi_raw_buffer_get(raw, idx); + if (!rb) { + dev_warn(dev, "RAW[%d] - Cannot get a free RAW buffer\n", idx); + return; + } + + ret =3D 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_chan_info *cinfo, + struct scmi_xfer *xfer, u32 msg_hdr) +{ + /* Unpack received HDR as it is */ + unpack_scmi_header(msg_hdr, &xfer->hdr); + xfer->hdr.seq =3D MSG_XTRACT_TOKEN(msg_hdr); + + memset(xfer->rx.buf, 0x00, xfer->rx.len); + + raw->desc->ops->fetch_response(cinfo, xfer); +} + +/** + * scmi_raw_error_report - Helper to report back timed-out or generally + * unexpected replies. + * + * @r: An opaque reference to the raw instance configuration + * @cinfo: A reference to the channel to use to retrieve the broken xfer + * @msg_hdr: The SCMI message header of the message to fetch and report + * @priv: Any private data related to the xfer. + * + * If Raw mode is enabled, this is called from the SCMI core on the RX pat= h in + * case of errors to save and enqueue the bad message payload carried by t= he + * message that has just been received. + * + * Note that we have to manually fetch any available payload into a tempor= ary + * xfer to be able to save and enqueue the message, since the regular RX e= rror + * path which had called this would have not fetched the message payload h= aving + * classified it as an error. + */ +void scmi_raw_error_report(void *r, struct scmi_chan_info *cinfo, + u32 msg_hdr, void *priv) +{ + struct scmi_xfer xfer; + struct scmi_raw_buffer *rb; + struct scmi_raw_mode_info *raw =3D r; + + if (!raw) + return; + + rb =3D scmi_raw_buffer_get(raw, SCMI_RAW_ERRS_QUEUE); + if (!rb) { + dev_warn(raw->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 =3D rb->msg.buf; + /* + * Allow max_msg_size...note that allocated rx.buf length is + * max_msg_size + sizeof(u32). + */ + xfer.rx.len =3D 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, cinfo, &xfer, msg_hdr); + scmi_raw_message_report(raw, &xfer, SCMI_RAW_ERRS_QUEUE); + + scmi_raw_buffer_put(raw, rb, SCMI_RAW_ERRS_QUEUE); +} diff --git a/drivers/firmware/arm_scmi/raw_mode.h b/drivers/firmware/arm_sc= mi/raw_mode.h new file mode 100644 index 000000000000..e2d8672e1f8b --- /dev/null +++ b/drivers/firmware/arm_scmi/raw_mode.h @@ -0,0 +1,29 @@ +/* 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(const struct scmi_handle *handle, + 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, struct scmi_chan_info *cinfo, + u32 msg_hdr, void *priv); + +#endif /* _SCMI_RAW_MODE_H */ --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57CD3ECAAD5 for ; Sat, 3 Sep 2022 18:31:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231701AbiICSbx (ORCPT ); Sat, 3 Sep 2022 14:31:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44020 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231573AbiICSbm (ORCPT ); Sat, 3 Sep 2022 14:31:42 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 955CD5509A for ; Sat, 3 Sep 2022 11:31:24 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B2C7CED1; Sat, 3 Sep 2022 11:31:29 -0700 (PDT) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A6C793F71A; Sat, 3 Sep 2022 11:31:21 -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: [PATCH v3 7/9] firmware: arm_scmi: Add debugfs ABI documentation for Raw mode Date: Sat, 3 Sep 2022 19:30:40 +0100 Message-Id: <20220903183042.3913053-8-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add description of the debugfs SCMI Raw ABI. Signed-off-by: Cristian Marussi --- Documentation/ABI/testing/debugfs-scmi-raw | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/ABI/testing/debugfs-scmi-raw diff --git a/Documentation/ABI/testing/debugfs-scmi-raw b/Documentation/ABI= /testing/debugfs-scmi-raw new file mode 100644 index 000000000000..183ec678cb3e --- /dev/null +++ b/Documentation/ABI/testing/debugfs-scmi-raw @@ -0,0 +1,88 @@ +What: /sys/kernel/debug/scmi_raw/transport_max_msg_size +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: Max message size of allowed SCMI messages for the currently + configured SCMI transport. +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/transport_tx_max_msg +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: Max number of concurrently allowed in-flight SCMI messages for + the currently configured SCMI transport. +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/transport_rx_timeout_ms +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: Timeout in milliseconds allowed for SCMI synchronous replies + for the currently configured SCMI transport. +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/message +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: SCMI Raw synchronous message injection/snooping facility; wri= te + a complete SCMI synchronous command message (header included) + in little-endian binary format to have it sent to the configured + backend SCMI server. + Any subsequently received response can be read from this same + entry if it arrived within the configured timeout. + Each write to the entry causes one command request to be built + and sent while the replies are read back one message at time + (receiving an EOF at each message boundary). +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/message_async +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: SCMI Raw asynchronous message injection/snooping facility; wr= ite + a complete SCMI asynchronous command message (header included) + in little-endian binary format to have it sent to the configured + backend SCMI server. + Any subsequently received response can be read from this same + entry if it arrived within the configured timeout. + Any additional delayed response received afterwards can be read + from this same entry too if it arrived within the configured + timeout. + Each write to the entry causes one command request to be built + and sent while the replies are read back one message at time + (receiving an EOF at each message boundary). +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/errors +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: SCMI Raw message errors facility; any kind of timed-out or + generally unexpectedly received SCMI message can be read from + this entry. + Each read gives back one message at time (receiving an EOF at + each message boundary). +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/notification +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: SCMI Raw notification snooping facility; any notification + emitted by the backend SCMI server can be read from this entry. + Each read gives back one message at time (receiving an EOF at + each message boundary). +Users: Debugging, any userspace test suite + +What: /sys/kernel/debug/scmi_raw/reset +Date: December 2022 +KernelVersion: 6.1 +Contact: cristian.marussi@arm.com +Description: SCMI Raw stack reset facility; writing a value to this entry + causes the internal queues of any kind of received message, + still pending to be read out, to be flushed. + Can be used to reset and clean the SCMI Raw stack between to + different test-run. +Users: Debugging, any userspace test suite --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 680C1ECAAD4 for ; Sat, 3 Sep 2022 18:32:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232252AbiICScH (ORCPT ); Sat, 3 Sep 2022 14:32:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43992 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230160AbiICSbp (ORCPT ); Sat, 3 Sep 2022 14:31:45 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 70235558E6 for ; Sat, 3 Sep 2022 11:31:26 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C351C113E; Sat, 3 Sep 2022 11:31: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 B7CC23F71A; Sat, 3 Sep 2022 11:31:23 -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: [PATCH v3 8/9] firmware: arm_scmi: Reject SCMI drivers while in Raw mode Date: Sat, 3 Sep 2022 19:30:41 +0100 Message-Id: <20220903183042.3913053-9-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reject SCMI driver registration when SCMI Raw mode support is configured, so as to avoid interferences between the SCMI Raw mode transactions and the normal SCMI stack operations. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 056796b2dcae..78879e23fef8 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2345,6 +2345,12 @@ int scmi_protocol_device_request(const struct scmi_d= evice_id *id_table) pr_debug("Requesting SCMI device (%s) for protocol %x\n", id_table->name, id_table->protocol_id); =20 + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + pr_warn("SCMI Raw mode active. Rejecting '%s'/0x%02X\n", + id_table->name, id_table->protocol_id); + return -EINVAL; + } + /* * Search for the matching protocol rdev list and then search * of any existent equally named device...fails if any duplicate found. --=20 2.32.0 From nobody Mon Apr 6 18:44:45 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E27CECAAD5 for ; Sat, 3 Sep 2022 18:32:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233291AbiICScP (ORCPT ); Sat, 3 Sep 2022 14:32:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231719AbiICScC (ORCPT ); Sat, 3 Sep 2022 14:32:02 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3C793564CE for ; Sat, 3 Sep 2022 11:31:29 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D41A41424; Sat, 3 Sep 2022 11:31: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 C7FE13F71A; Sat, 3 Sep 2022 11:31:25 -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: [PATCH v3 9/9] firmware: arm_scmi: Call Raw mode hooks from the core stack Date: Sat, 3 Sep 2022 19:30:42 +0100 Message-Id: <20220903183042.3913053-10-cristian.marussi@arm.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220903183042.3913053-1-cristian.marussi@arm.com> References: <20220903183042.3913053-1-cristian.marussi@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add a 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 --- v1 --> v2 - fixes need to use multiple cinfo if available --- 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 78879e23fef8..fd4f3ac54077 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" =20 +#include "raw_mode.h" + #define CREATE_TRACE_POINTS #include =20 @@ -133,6 +137,7 @@ struct scmi_protocol_instance { * @notify_priv: Pointer to private data structure specific to notificatio= ns. * @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; }; =20 #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) @@ -780,6 +786,11 @@ static void scmi_handle_notification(struct scmi_chan_= info *cinfo, xfer->hdr.protocol_id, xfer->hdr.seq, MSG_TYPE_NOTIFICATION); =20 + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + xfer->hdr.seq =3D MSG_XTRACT_TOKEN(msg_hdr); + scmi_raw_message_report(info->raw, xfer, SCMI_RAW_NOTIF_QUEUE); + } + __scmi_xfer_put(minfo, xfer); =20 scmi_clear_channel(info, cinfo); @@ -793,6 +804,9 @@ static void scmi_handle_response(struct scmi_chan_info = *cinfo, =20 xfer =3D 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, cinfo, msg_hdr, priv); + if (MSG_XTRACT_TYPE(msg_hdr) =3D=3D MSG_TYPE_DELAYED_RESP) scmi_clear_channel(info, cinfo); return; @@ -824,6 +838,9 @@ static void scmi_handle_response(struct scmi_chan_info = *cinfo, complete(&xfer->done); } =20 + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) + scmi_raw_message_report(info->raw, xfer, SCMI_RAW_REPLY_QUEUE); + scmi_xfer_command_release(info, xfer); } =20 @@ -2567,6 +2584,18 @@ static int scmi_probe(struct platform_device *pdev) if (ret) goto clear_txrx_setup; =20 + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + info->raw =3D scmi_raw_mode_init(handle, info->desc, + info->tx_minfo.max_msg); + if (!IS_ERR(info->raw)) { + dev_info(dev, "SCMI RAW Mode initialized.\n"); + return 0; + } + + dev_err(dev, "Failed to initialize SCMI RAW Mode !\n"); + info->raw =3D NULL; + } + if (scmi_notification_init(handle)) dev_err(dev, "SCMI Notifications NOT available.\n"); =20 @@ -2640,6 +2669,9 @@ static int scmi_remove(struct platform_device *pdev) struct scmi_info *info =3D platform_get_drvdata(pdev); struct device_node *child; =20 + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) + scmi_raw_mode_cleanup(info->raw); + mutex_lock(&scmi_list_mutex); if (info->users) ret =3D -EBUSY; --=20 2.32.0