From nobody Fri Dec 19 22:05:24 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C31EF2D320C; Tue, 29 Apr 2025 14:11:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935895; cv=none; b=qN1IBTizc4N2gS0eRywoUF/0h395OTLSwbnb6dsS8jJN0Gm1q7fT3SgfaYDhw8mA0kRupDgkZsSXKoDq8ZkMx5yVVAUa9LGtaF7D2r3k7++EImUoNGtcI+IT+oDpfHSRHwcxAsxjkBAjUoc08WYsVtrPWTfp8bc/OwZt6TD/p3k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935895; c=relaxed/simple; bh=0Vv2AcoNpHwsxsDVc/KHAkPjydfEUGrPsFOSCt1cGd0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QRaAXhkDninsS2hqrN5lvBfJAs9lA82U4HT4FNrTq6ys5nfqyv/kNW/kByoI6aGQsv7q5HBPzci0ECzVHWDSwed1sIPUWjDfZ865IXaKNs17mRoSCxuuGJ9mzB5VxJ05ppAaI6KbyvAwgLOI8fm3K78JzS5yal/JnbO2iBPUQx0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com 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 7C4011516; Tue, 29 Apr 2025 07:11:26 -0700 (PDT) Received: from pluto.guest.local (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F23813F66E; Tue, 29 Apr 2025 07:11:30 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, peng.fan@oss.nxp.com, michal.simek@amd.com, quic_sibis@quicinc.com, dan.carpenter@linaro.org, maz@kernel.org, johan@kernel.org, stable@vger.kernel.org, Johan Hovold , Cristian Marussi Subject: [PATCH v3 1/3] firmware: arm_scmi: Ensure that the message-id supports fastchannel Date: Tue, 29 Apr 2025 15:11:06 +0100 Message-ID: <20250429141108.406045-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250429141108.406045-1-cristian.marussi@arm.com> References: <20250429141108.406045-1-cristian.marussi@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sibi Sankar Currently the perf and powercap protocol relies on the protocol domain attributes, which just ensures that one fastchannel per domain, before instantiating fastchannels for all possible message-ids. Fix this by ensuring that each message-id supports fastchannel before initialization. Logs: scmi: Failed to get FC for protocol 13 [MSG_ID:6 / RES_ID:0] - ret:-95. Usi= ng regular messaging. scmi: Failed to get FC for protocol 13 [MSG_ID:6 / RES_ID:1] - ret:-95. Usi= ng regular messaging. scmi: Failed to get FC for protocol 13 [MSG_ID:6 / RES_ID:2] - ret:-95. Usi= ng regular messaging. CC: stable@vger.kernel.org Reported-by: Johan Hovold Closes: https://lore.kernel.org/lkml/ZoQjAWse2YxwyRJv@hovoldconsulting.com/ Fixes: 6f9ea4dabd2d ("firmware: arm_scmi: Generalize the fast channel suppo= rt") Reviewed-by: Johan Hovold Tested-by: Johan Hovold Signed-off-by: Sibi Sankar [Cristian: Modified the condition checked to establish support or not] Signed-off-by: Cristian Marussi --- RFC -> V1 - picked up a few tags Since PROTOCOL_MESSAGE_ATTRIBUTES, used to check if message_id is supported, is a mandatory command, it cannot fail so we must bail-out NOT only if FC w= as not supported for that command but also if the query fails as a whole; so t= he condition checked for bailing out is modified to: if (ret || !MSG_SUPPORTS_FASTCHANNEL(attributes)) { --- drivers/firmware/arm_scmi/driver.c | 76 +++++++++++++++------------ drivers/firmware/arm_scmi/protocols.h | 2 + 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 1cf18cc8e63f..0e281fca0a38 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1738,6 +1738,39 @@ static int scmi_common_get_max_msg_size(const struct= scmi_protocol_handle *ph) return info->desc->max_msg_size; } =20 +/** + * scmi_protocol_msg_check - Check protocol message attributes + * + * @ph: A reference to the protocol handle. + * @message_id: The ID of the message to check. + * @attributes: A parameter to optionally return the retrieved message + * attributes, in case of Success. + * + * An helper to check protocol message attributes for a specific protocol + * and message pair. + * + * Return: 0 on SUCCESS + */ +static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, + u32 message_id, u32 *attributes) +{ + int ret; + struct scmi_xfer *t; + + ret =3D xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, + sizeof(__le32), 0, &t); + if (ret) + return ret; + + put_unaligned_le32(message_id, t->tx.buf); + ret =3D do_xfer(ph, t); + if (!ret && attributes) + *attributes =3D get_unaligned_le32(t->rx.buf); + xfer_put(ph, t); + + return ret; +} + /** * struct scmi_iterator - Iterator descriptor * @msg: A reference to the message TX buffer; filled by @prepare_message = with @@ -1879,6 +1912,7 @@ scmi_common_fastchannel_init(const struct scmi_protoc= ol_handle *ph, int ret; u32 flags; u64 phys_addr; + u32 attributes; u8 size; void __iomem *addr; struct scmi_xfer *t; @@ -1887,6 +1921,15 @@ scmi_common_fastchannel_init(const struct scmi_proto= col_handle *ph, struct scmi_msg_resp_desc_fc *resp; const struct scmi_protocol_instance *pi =3D ph_to_pi(ph); =20 + /* Check if the MSG_ID supports fastchannel */ + ret =3D scmi_protocol_msg_check(ph, message_id, &attributes); + if (ret || !MSG_SUPPORTS_FASTCHANNEL(attributes)) { + dev_dbg(ph->dev, + "Skip FC init for 0x%02X/%d domain:%d - ret:%d\n", + pi->proto->id, message_id, domain, ret); + return; + } + if (!p_addr) { ret =3D -EINVAL; goto err_out; @@ -2004,39 +2047,6 @@ static void scmi_common_fastchannel_db_ring(struct s= cmi_fc_db_info *db) SCMI_PROTO_FC_RING_DB(64); } =20 -/** - * scmi_protocol_msg_check - Check protocol message attributes - * - * @ph: A reference to the protocol handle. - * @message_id: The ID of the message to check. - * @attributes: A parameter to optionally return the retrieved message - * attributes, in case of Success. - * - * An helper to check protocol message attributes for a specific protocol - * and message pair. - * - * Return: 0 on SUCCESS - */ -static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, - u32 message_id, u32 *attributes) -{ - int ret; - struct scmi_xfer *t; - - ret =3D xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, - sizeof(__le32), 0, &t); - if (ret) - return ret; - - put_unaligned_le32(message_id, t->tx.buf); - ret =3D do_xfer(ph, t); - if (!ret && attributes) - *attributes =3D get_unaligned_le32(t->rx.buf); - xfer_put(ph, t); - - return ret; -} - static const struct scmi_proto_helpers_ops helpers_ops =3D { .extended_name_get =3D scmi_common_extended_name_get, .get_max_msg_size =3D scmi_common_get_max_msg_size, diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_s= cmi/protocols.h index aaee57cdcd55..d62c4469d1fd 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -31,6 +31,8 @@ =20 #define SCMI_PROTOCOL_VENDOR_BASE 0x80 =20 +#define MSG_SUPPORTS_FASTCHANNEL(x) ((x) & BIT(0)) + enum scmi_common_cmd { PROTOCOL_VERSION =3D 0x0, PROTOCOL_ATTRIBUTES =3D 0x1, --=20 2.47.0 From nobody Fri Dec 19 22:05:24 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CB1282D86B5; Tue, 29 Apr 2025 14:11:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935899; cv=none; b=c+TMHILQxEAIjIqYKc8Y11Rc2TMcz1STq2xb5i71Pc5Qo8ybDuqGlNpHE7vqig7hXO4YS4JELErTJRRjHfLn8xVbT4C7NXVaKyLO6WySx/3JUfeYfElxNP5cxUwWIL5BPrmL1SoEy+SMh2C/RUb83pChMN4w3KIQHoyzlNpyqnQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935899; c=relaxed/simple; bh=uOQeOJfq8fH4r5wU926/0xiBs6BPheEF1Q4VD6AnWOs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IvV93UkZia61yg4iN2yM10cvilRZLw2KLVeI9HpGERo6cuJUtTpEg0mEm++sW4e65TG00Zixr9lZQYAEE2p4ngOmNbCvDImbEquPlX+BAFj4ePCw/cDFVudotPewNhMFHkAEiXXI6HwgtOjtJS6HLzrQleiXJSyrGppN+9gf3A8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com 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 580BB1515; Tue, 29 Apr 2025 07:11:29 -0700 (PDT) Received: from pluto.guest.local (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AA6B53F66E; Tue, 29 Apr 2025 07:11:33 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, peng.fan@oss.nxp.com, michal.simek@amd.com, quic_sibis@quicinc.com, dan.carpenter@linaro.org, maz@kernel.org, johan@kernel.org, Cristian Marussi , Johan Hovold Subject: [PATCH v3 2/3] firmware: arm_scmi: Add Quirks framework Date: Tue, 29 Apr 2025 15:11:07 +0100 Message-ID: <20250429141108.406045-3-cristian.marussi@arm.com> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250429141108.406045-1-cristian.marussi@arm.com> References: <20250429141108.406045-1-cristian.marussi@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a common framework to describe SCMI quirks and associate them with a specific platform or a specific set of SCMI firmware versions. All the matching SCMI quirks will be enabled when the SCMI core stack probes and after all the needed SCMI firmware versioning information was retrieved using Base protocol. Tested-by: Johan Hovold Signed-off-by: Cristian Marussi --- V2 -> V3 - a few typos fixed - collected tag - drop machine compatible lookup for dev_dbg() V1 -> V2 - compile quirk snippets even when SCMI Quirks are disabled - added support for quirks matches on multiple compatibles (via NULl terminated compats strings) - removed stale unneeded include - added some more docs RFC->V1 - added handling of impl_ver ranges in quirk definition - make Quirks Framework default-y - match on all NULL/0 too..these are quirks that apply always anywhere ! - depends on COMPILE_TEST too - move quirk enable calling logic out of Base protocol init (triggers a LOCKDEP issues around cpu locks (cpufreq, static_branch_enable interactio= ns..) --- drivers/firmware/arm_scmi/Kconfig | 13 ++ drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/driver.c | 19 +- drivers/firmware/arm_scmi/quirks.c | 316 +++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/quirks.h | 48 +++++ 5 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/quirks.c create mode 100644 drivers/firmware/arm_scmi/quirks.h diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/= Kconfig index dabd874641d0..e3fb36825978 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -69,6 +69,19 @@ config ARM_SCMI_DEBUG_COUNTERS such useful debug counters. This can be helpful for debugging and SCMI monitoring. =20 +config ARM_SCMI_QUIRKS + bool "Enable SCMI Quirks framework" + depends on JUMP_LABEL || COMPILE_TEST + default y + help + Enables support for SCMI Quirks framework to workaround SCMI platform + firmware bugs on system already deployed in the wild. + + The framework allows the definition of platform-specific code quirks + that will be associated and enabled only on the desired platforms + depending on the SCMI firmware advertised versions and/or machine + compatibles. + source "drivers/firmware/arm_scmi/transports/Kconfig" source "drivers/firmware/arm_scmi/vendors/imx/Kconfig" =20 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi= /Makefile index 9ac81adff567..780cd62b2f78 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -3,6 +3,7 @@ scmi-bus-y =3D bus.o scmi-core-objs :=3D $(scmi-bus-y) =20 scmi-driver-y =3D driver.o notify.o +scmi-driver-$(CONFIG_ARM_SCMI_QUIRKS) +=3D quirks.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_HAVE_MSG) +=3D msg.o diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 0e281fca0a38..de35e7413755 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -11,7 +11,7 @@ * various power domain DVFS including the core/cluster, certain system * clocks configuration, thermal sensors and many others. * - * Copyright (C) 2018-2024 ARM Ltd. + * Copyright (C) 2018-2025 ARM Ltd. */ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -38,6 +38,7 @@ =20 #include "common.h" #include "notify.h" +#include "quirks.h" =20 #include "raw_mode.h" =20 @@ -3112,6 +3113,18 @@ static const struct scmi_desc *scmi_transport_setup(= struct device *dev) return &trans->desc; } =20 +static void scmi_enable_matching_quirks(struct scmi_info *info) +{ + struct scmi_revision_info *rev =3D &info->version; + + dev_dbg(info->dev, "Looking for quirks matching: %s/%s/0x%08X\n", + rev->vendor_id, rev->sub_vendor_id, rev->impl_ver); + + /* Enable applicable quirks */ + scmi_quirks_enable(info->dev, rev->vendor_id, + rev->sub_vendor_id, rev->impl_ver); +} + static int scmi_probe(struct platform_device *pdev) { int ret; @@ -3233,6 +3246,8 @@ static int scmi_probe(struct platform_device *pdev) list_add_tail(&info->node, &scmi_list); mutex_unlock(&scmi_list_mutex); =20 + scmi_enable_matching_quirks(info); + for_each_available_child_of_node(np, child) { u32 prot_id; =20 @@ -3391,6 +3406,8 @@ static struct dentry *scmi_debugfs_init(void) =20 static int __init scmi_driver_init(void) { + scmi_quirks_initialize(); + /* Bail out if no SCMI transport was configured */ if (WARN_ON(!IS_ENABLED(CONFIG_ARM_SCMI_HAVE_TRANSPORT))) return -EINVAL; diff --git a/drivers/firmware/arm_scmi/quirks.c b/drivers/firmware/arm_scmi= /quirks.c new file mode 100644 index 000000000000..eff03a89de85 --- /dev/null +++ b/drivers/firmware/arm_scmi/quirks.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) Message Protocol Quirks + * + * Copyright (C) 2025 ARM Ltd. + */ + +/** + * DOC: Theory of operation + * + * A framework to define SCMI quirks and their activation conditions based= on + * existing static_keys kernel facilities. + * + * Quirks are named and their activation conditions defined using the macro + * DEFINE_SCMI_QUIRK() in this file. + * + * After a quirk is defined, a corresponding entry must also be added to t= he + * global @scmi_quirks_table in this file using __DECLARE_SCMI_QUIRK_ENTRY= (). + * + * Additionally a corresponding quirk declaration must be added also to the + * quirk.h file using DECLARE_SCMI_QUIRK(). + * + * The needed quirk code-snippet itself will be defined local to the SCMI = code + * that is meant to fix and will be associated to the previously defined q= uirk + * and related activation conditions using the macro SCMI_QUIRK(). + * + * At runtime, during the SCMI stack probe sequence, once the SCMI Server = had + * advertised the running platform Vendor, SubVendor and Implementation Ve= rsion + * data, all the defined quirks matching the activation conditions will be + * enabled. + * + * Example + * + * quirk.c + * ------- + * DEFINE_SCMI_QUIRK(fix_me, "vendor", "subvend", "0x12000-0x30000", + * "someone,plat_A", "another,plat_b", "vend,sku"); + * + * static struct scmi_quirk *scmi_quirks_table[] =3D { + * ... + * __DECLARE_SCMI_QUIRK_ENTRY(fix_me), + * NULL + * }; + * + * quirk.h + * ------- + * DECLARE_SCMI_QUIRK(fix_me); + * + * + * ------------------------------ + * + * #define QUIRK_CODE_SNIPPET_FIX_ME() \ + * ({ \ + * if (p->condition) \ + * a_ptr->calculated_val =3D 123; \ + * }) + * + * + * int some_function_to_fix(int param, struct something *p) + * { + * struct some_strut *a_ptr; + * + * a_ptr =3D some_load_func(p); + * SCMI_QUIRK(fix_me, QUIRK_CODE_SNIPPET_FIX_ME); + * some_more_func(a_ptr); + * ... + * + * return 0; + * } + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "quirks.h" + +#define SCMI_QUIRKS_HT_SZ 4 + +struct scmi_quirk { + bool enabled; + const char *name; + char *vendor; + char *sub_vendor_id; + char *impl_ver_range; + u32 start_range; + u32 end_range; + struct static_key_false *key; + struct hlist_node hash; + unsigned int hkey; + const char *const compats[]; +}; + +#define __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ...) \ + static struct scmi_quirk scmi_quirk_entry_ ## _qn =3D { \ + .name =3D __stringify(quirk_ ## _qn), \ + .vendor =3D _ven, \ + .sub_vendor_id =3D _sub, \ + .impl_ver_range =3D _impl, \ + .key =3D &(scmi_quirk_ ## _qn), \ + .compats =3D { __VA_ARGS__ __VA_OPT__(,) NULL }, \ + } + +#define __DECLARE_SCMI_QUIRK_ENTRY(_qn) (&(scmi_quirk_entry_ ## _qn)) + +/* + * Define a quirk by name and provide the matching tokens where: + * + * _qn: A string which will be used to build the quirk and the global + * static_key names. + * _ven : SCMI Vendor ID string match, NULL means any. + * _sub : SCMI SubVendor ID string match, NULL means any. + * _impl : SCMI Implementation Version string match, NULL means any. + * This string can be used to express version ranges which will be + * interpreted as follows: + * + * NULL [0, 0xFFFFFFFF] + * "X" [X, X] + * "X-" [X, 0xFFFFFFFF] + * "-X" [0, X] + * "X-Y" [X, Y] + * + * with X <=3D Y and in [X, Y] meaning X <=3D <=3D Y + * + * ... : An optional variadic macros argument used to provide a comma-sep= arated + * list of compatible strings matches; when no variadic argument is + * provided, ANY compatible will match this quirk. + * + * This implicitly define also a properly named global static-key that + * will be used to dynamically enable the quirk at initialization time. + * + * Note that it is possible to associate multiple quirks to the same + * matching pattern, if your firmware quality is really astounding :P + * + * Example: + * + * Compatibles list NOT provided, so ANY compatible will match: + * + * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000"); + * + * + * A few compatibles provided to match against: + * + * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000", + * "xvend,plat_a", "xvend,plat_b", "xvend,sku_name"); + */ +#define DEFINE_SCMI_QUIRK(_qn, _ven, _sub, _impl, ...) \ + DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ + __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) + +/* + * Same as DEFINE_SCMI_QUIRK but EXPORTED: this is meant to address quirks + * that possibly reside in code that is included in loadable kernel modules + * that needs to be able to access the global static keys at runtime to + * determine if enabled or not. (see SCMI_QUIRK to understand usage) + */ +#define DEFINE_SCMI_QUIRK_EXPORTED(_qn, _ven, _sub, _impl, ...) \ + DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ + EXPORT_SYMBOL_GPL(scmi_quirk_ ## _qn); \ + __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) + +/* Global Quirks Definitions */ + +/* + * Quirks Pointers Array + * + * This is filled at compile-time with the list of pointers to all the cur= rently + * defined quirks descriptors. + */ +static struct scmi_quirk *scmi_quirks_table[] =3D { + NULL +}; + +/* + * Quirks HashTable + * + * A run-time populated hashtable containing all the defined quirks descri= ptors + * hashed by matching pattern. + */ +static DEFINE_READ_MOSTLY_HASHTABLE(scmi_quirks_ht, SCMI_QUIRKS_HT_SZ); + +static unsigned int scmi_quirk_signature(const char *vend, const char *sub= _vend) +{ + char *signature, *p; + unsigned int hash32; + unsigned long hash =3D 0; + + /* vendor_id/sub_vendor_id guaranteed <=3D SCMI_SHORT_NAME_MAX_SIZE */ + signature =3D kasprintf(GFP_KERNEL, "|%s|%s|", vend ?: "", sub_vend ?: ""= ); + if (!signature) + return 0; + + pr_debug("SCMI Quirk Signature >>>%s<<<\n", signature); + + p =3D signature; + while (*p) + hash =3D partial_name_hash(tolower(*p++), hash); + hash32 =3D end_name_hash(hash); + + kfree(signature); + + return hash32; +} + +static int scmi_quirk_range_parse(struct scmi_quirk *quirk) +{ + const char *last, *first =3D quirk->impl_ver_range; + size_t len; + char *sep; + int ret; + + quirk->start_range =3D 0; + quirk->end_range =3D 0xFFFFFFFF; + len =3D quirk->impl_ver_range ? strlen(quirk->impl_ver_range) : 0; + if (!len) + return 0; + + last =3D first + len - 1; + sep =3D strchr(quirk->impl_ver_range, '-'); + if (sep) + *sep =3D '\0'; + + if (sep =3D=3D first) /* -X */ + ret =3D kstrtouint(first + 1, 0, &quirk->end_range); + else /* X OR X- OR X-y */ + ret =3D kstrtouint(first, 0, &quirk->start_range); + if (ret) + return ret; + + if (!sep) + quirk->end_range =3D quirk->start_range; + else if (sep !=3D last) /* x-Y */ + ret =3D kstrtouint(sep + 1, 0, &quirk->end_range); + + if (quirk->start_range > quirk->end_range) + return -EINVAL; + + return ret; +} + +void scmi_quirks_initialize(void) +{ + struct scmi_quirk *quirk; + int i; + + for (i =3D 0, quirk =3D scmi_quirks_table[0]; quirk; + i++, quirk =3D scmi_quirks_table[i]) { + int ret; + + ret =3D scmi_quirk_range_parse(quirk); + if (ret) { + pr_err("SCMI skip QUIRK [%s] - BAD RANGE - |%s|\n", + quirk->name, quirk->impl_ver_range); + continue; + } + quirk->hkey =3D scmi_quirk_signature(quirk->vendor, + quirk->sub_vendor_id); + + hash_add(scmi_quirks_ht, &quirk->hash, quirk->hkey); + + pr_debug("Registered SCMI QUIRK [%s] -- %p - Key [0x%08X] - %s/%s/[0x%08= X-0x%08X]\n", + quirk->name, quirk, quirk->hkey, + quirk->vendor, quirk->sub_vendor_id, + quirk->start_range, quirk->end_range); + } + + pr_debug("SCMI Quirks initialized\n"); +} + +void scmi_quirks_enable(struct device *dev, const char *vend, + const char *subv, const u32 impl) +{ + for (int i =3D 3; i >=3D 0; i--) { + struct scmi_quirk *quirk; + unsigned int hkey; + + hkey =3D scmi_quirk_signature(i > 1 ? vend : NULL, + i > 2 ? subv : NULL); + + /* + * Note that there could be multiple matches so we + * will enable multiple quirk part of a hash collision + * domain...BUT we cannot assume that ALL quirks on the + * same collision domain are a full match. + */ + hash_for_each_possible(scmi_quirks_ht, quirk, hash, hkey) { + if (quirk->enabled || quirk->hkey !=3D hkey || + impl < quirk->start_range || + impl > quirk->end_range) + continue; + + if (quirk->compats[0] && + !of_machine_compatible_match(quirk->compats)) + continue; + + dev_info(dev, "Enabling SCMI Quirk [%s]\n", + quirk->name); + + dev_dbg(dev, + "Quirk matched on: %s/%s/%s/[0x%08X-0x%08X]\n", + quirk->compats[0], quirk->vendor, + quirk->sub_vendor_id, + quirk->start_range, quirk->end_range); + + static_branch_enable(quirk->key); + quirk->enabled =3D true; + } + } +} diff --git a/drivers/firmware/arm_scmi/quirks.h b/drivers/firmware/arm_scmi= /quirks.h new file mode 100644 index 000000000000..28829b4f0646 --- /dev/null +++ b/drivers/firmware/arm_scmi/quirks.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * System Control and Management Interface (SCMI) Message Protocol Quirks + * + * Copyright (C) 2025 ARM Ltd. + */ +#ifndef _SCMI_QUIRKS_H +#define _SCMI_QUIRKS_H + +#include +#include + +#ifdef CONFIG_ARM_SCMI_QUIRKS + +#define DECLARE_SCMI_QUIRK(_qn) \ + DECLARE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn) + +/* + * A helper to associate the actual code snippet to use as a quirk + * named as _qn. + */ +#define SCMI_QUIRK(_qn, _blk) \ + do { \ + if (static_branch_unlikely(&(scmi_quirk_ ## _qn))) \ + (_blk); \ + } while (0) + +void scmi_quirks_initialize(void); +void scmi_quirks_enable(struct device *dev, const char *vend, + const char *subv, const u32 impl); + +#else + +#define DECLARE_SCMI_QUIRK(_qn) +/* Force quirks compilation even when SCMI Quirks are disabled */ +#define SCMI_QUIRK(_qn, _blk) \ + do { \ + if (0) \ + (_blk); \ + } while (0) + +static inline void scmi_quirks_initialize(void) { } +static inline void scmi_quirks_enable(struct device *dev, const char *vend, + const char *sub_vend, const u32 impl) { } + +#endif /* CONFIG_ARM_SCMI_QUIRKS */ + +#endif /* _SCMI_QUIRKS_H */ --=20 2.47.0 From nobody Fri Dec 19 22:05:24 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7FC0E2D8DAA; Tue, 29 Apr 2025 14:11:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935901; cv=none; b=YNREQ3cTlGS4jZbwPy5uev/Pn6HAR2rlRXwbKxqIeRcjnwPTzLT1Gg41d0DoQTcaj+49DRnJxBMwD0BXsv4qqKQ4PIaT1p6+hwkpe9GuYHxz/aBCYX0WTMOqne/dQ9AY+tfNDCayK+wk33breUfadChUvaIMQWhyOMuHSvuTAds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745935901; c=relaxed/simple; bh=p+MF+cbIVqQ81P67tantyBp6k9dyANtN4BgAnfsJXNc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cCpUgwkSMOqx6lqLPrDUelPv6+HwlOoHczerUl7m55aNmyHkjcpTqzyGmxpx2sRtibCFaDpPwlVABHEWI2QZavNZjHgVJs4aZc+1k080hh/iuvVCScn6syN3n2uGdctdku4wOEqvmHKi1Ww3BoP46jjo9u566zD2SgdERTdnksA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com 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 071E81516; Tue, 29 Apr 2025 07:11:32 -0700 (PDT) Received: from pluto.guest.local (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9FAF53F66E; Tue, 29 Apr 2025 07:11:36 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, peng.fan@oss.nxp.com, michal.simek@amd.com, quic_sibis@quicinc.com, dan.carpenter@linaro.org, maz@kernel.org, johan@kernel.org, Cristian Marussi Subject: [PATCH v3 3/3] firmware: arm_scmi: quirk: Fix CLOCK_DESCRIBE_RATES triplet Date: Tue, 29 Apr 2025 15:11:08 +0100 Message-ID: <20250429141108.406045-4-cristian.marussi@arm.com> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250429141108.406045-1-cristian.marussi@arm.com> References: <20250429141108.406045-1-cristian.marussi@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Convert an existing quirk in CLOCK_DESCRIBE_RATES parsing to the new quirk framework. This is a sort of a peculiar quirk since it matches any platform and any firmware. Signed-off-by: Cristian Marussi --- V1 -> V2 - reduced the quirk size by placing the warn outside - using new compatibles conditions --- drivers/firmware/arm_scmi/clock.c | 33 ++++++++++++++++++------------ drivers/firmware/arm_scmi/quirks.c | 2 ++ drivers/firmware/arm_scmi/quirks.h | 3 +++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/= clock.c index 2ed2279388f0..afa7981efe82 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -11,6 +11,7 @@ =20 #include "protocols.h" #include "notify.h" +#include "quirks.h" =20 /* Updated only after ALL the mandatory features for that version are merg= ed */ #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 @@ -429,6 +430,23 @@ static void iter_clk_describe_prepare_message(void *me= ssage, msg->rate_index =3D cpu_to_le32(desc_index); } =20 +#define QUIRK_OUT_OF_SPEC_TRIPLET \ + ({ \ + /* \ + * A known quirk: a triplet is returned but num_returned !=3D 3 \ + * Check for a safe payload size and fix. \ + */ \ + if (st->num_returned !=3D 3 && st->num_remaining =3D=3D 0 && \ + st->rx_len =3D=3D sizeof(*r) + sizeof(__le32) * 2 * 3) { \ + st->num_returned =3D 3; \ + st->num_remaining =3D 0; \ + } else { \ + dev_err(p->dev, \ + "Cannot fix out-of-spec reply !\n"); \ + return -EPROTO; \ + } \ + }) + static int iter_clk_describe_update_state(struct scmi_iterator_state *st, const void *response, void *priv) @@ -450,19 +468,8 @@ iter_clk_describe_update_state(struct scmi_iterator_st= ate *st, p->clk->name, st->num_returned, st->num_remaining, st->rx_len); =20 - /* - * A known quirk: a triplet is returned but num_returned !=3D 3 - * Check for a safe payload size and fix. - */ - if (st->num_returned !=3D 3 && st->num_remaining =3D=3D 0 && - st->rx_len =3D=3D sizeof(*r) + sizeof(__le32) * 2 * 3) { - st->num_returned =3D 3; - st->num_remaining =3D 0; - } else { - dev_err(p->dev, - "Cannot fix out-of-spec reply !\n"); - return -EPROTO; - } + SCMI_QUIRK(clock_rates_triplet_out_of_spec, + QUIRK_OUT_OF_SPEC_TRIPLET); } =20 return 0; diff --git a/drivers/firmware/arm_scmi/quirks.c b/drivers/firmware/arm_scmi= /quirks.c index eff03a89de85..8958f1fa4c89 100644 --- a/drivers/firmware/arm_scmi/quirks.c +++ b/drivers/firmware/arm_scmi/quirks.c @@ -167,6 +167,7 @@ struct scmi_quirk { __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) =20 /* Global Quirks Definitions */ +DEFINE_SCMI_QUIRK(clock_rates_triplet_out_of_spec, NULL, NULL, NULL); =20 /* * Quirks Pointers Array @@ -175,6 +176,7 @@ struct scmi_quirk { * defined quirks descriptors. */ static struct scmi_quirk *scmi_quirks_table[] =3D { + __DECLARE_SCMI_QUIRK_ENTRY(clock_rates_triplet_out_of_spec), NULL }; =20 diff --git a/drivers/firmware/arm_scmi/quirks.h b/drivers/firmware/arm_scmi= /quirks.h index 28829b4f0646..7fdc496c94c7 100644 --- a/drivers/firmware/arm_scmi/quirks.h +++ b/drivers/firmware/arm_scmi/quirks.h @@ -45,4 +45,7 @@ static inline void scmi_quirks_enable(struct device *dev,= const char *vend, =20 #endif /* CONFIG_ARM_SCMI_QUIRKS */ =20 +/* Quirk delarations */ +DECLARE_SCMI_QUIRK(clock_rates_triplet_out_of_spec); + #endif /* _SCMI_QUIRKS_H */ --=20 2.47.0