diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2025-05-09 23:08:52 +0200 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2025-05-09 23:09:01 +0200 |
| commit | 4e61c011b00b0e9914eaf9fe38f0c2230115842d (patch) | |
| tree | 955e597c0c28ad338abb9f339bbc5a0111210be2 /drivers/firmware/arm_scmi/raw_mode.c | |
| parent | 5dcee6dd09abea5c685f8f6be28fc02e1ec6e3e6 (diff) | |
| parent | 397f802d06c418efa636e46083edbeb00c91369e (diff) | |
Merge tag 'scmi-updates-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers
Arm SCMI updates for v6.16
1. Quirk framework to handle buggy firmware
With SCMI gaining broader adoption across arm64 platforms, it's
increasingly important to address how we consistently manage out-of-spec
SCMI firmware already deployed in the field. This change introduces a
lightweight quirk framework built around static_keys, enabling developers to:
- Define quirks and their match criteria, which can include:
o A list of compatibles ({ comp, comp2, NULL })
o Vendor ID / Sub-Vendor ID
o Firmware implementation version ranges ([Min_Vers, Max_Vers])
Matching proceeds from the most specific (longest match) to the least
specific. NULL entries are treated as wildcards (i.e., match any value).
This flexibility allows matching very specific combinations or just a
general compatible string.
The quirk code blocks/snippets implementing the workaround are placed near
their intended usage and guarded by a static_key that's tied to the quirk.
Once the SCMI core stack is initialized and retrieves platform info via the
base protocol, any matching quirks will have their associated static_keys
enabled.
2. Quirk for Qualcomm X1E platforms
On some Qualcomm X1E platforms, such as the Lenovo ThinkPad T14s, the
SCMI firmware fails to set the FastChannel support bit for PERF_LEVEL_GET,
yet it crashes when the driver attempts to fall back to standard messaging
which is clearly out-of-spec behavior.
To work around this, the new SCMI quirk framework is used to
unconditionally enable FC initialization for this firmware version.
In the future, once the fixed firmware version is identified, an upper
version bound can be added to the quirk match criteria. Alternatively,
matching can be further restricted using a SoC-specific compatible string
if always enabling FC proves problematic elsewhere.
3. Support for NXP i.MX LMM/CPU vendor protocol extensions
The i.MX95 System Manager (SM) implements Logical Machine Management (LMM)
and a CPU protocol to manage Logical Machines (LM) and CPUs (e.g., M7).
These changes integrate the vendor-specific protocol extensions
implementing the LMM and CPU protocols for the i.MX95, facilitating
standardized communication between the operating system and the platform's
firmware, which will be used by remoteproc drivers. The changes also
include the necessary device tree bindings.
4. Miscellaneous cleanups/changes
These mainly include polling support in SCMI raw mode. The cleanups
centralize error logging for SCMI device creation into a single helper
function, consolidate the device matching logic into a single function, and
ensure that devices must have a name for registration—removing support for
unnamed devices when matching drivers and devices for probing. Transport
devices are now excluded from bus matching, and the correct assignment of
the parent device for the arm-scmi platform device is ensured in the
transport drivers.
* tag 'scmi-updates-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
firmware: arm_scmi: quirk: Force perf level get fastchannel
firmware: arm_scmi: quirk: Fix CLOCK_DESCRIBE_RATES triplet
firmware: arm_scmi: Add common framework to handle firmware quirks
firmware: arm_scmi: Ensure that the message-id supports fastchannel
MAINTAINERS: add entry for i.MX SCMI extensions
firmware: imx: Add i.MX95 SCMI CPU driver
firmware: imx: Add i.MX95 SCMI LMM driver
firmware: arm_scmi: imx: Add i.MX95 CPU Protocol
firmware: arm_scmi: imx: Add i.MX95 LMM protocol
dt-bindings: firmware: Add i.MX95 SCMI LMM and CPU protocol
firmware: arm_scmi: imx: Add LMM and CPU documentation
firmware: arm_scmi: Add polling support to raw mode
firmware: arm_scmi: Exclude transport devices from bus matching
firmware: arm_scmi: Assign correct parent to arm-scmi platform device
firmware: arm_scmi: Refactor error logging from SCMI device creation to single helper
firmware: arm_scmi: Refactor device matching logic to eliminate duplication
firmware: arm_scmi: Ensure scmi_devices are always matched by name as well
Link: https://lore.kernel.org/r/20250507134713.49039-1-sudeep.holla@arm.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/firmware/arm_scmi/raw_mode.c')
| -rw-r--r-- | drivers/firmware/arm_scmi/raw_mode.c | 72 |
1 files changed, 67 insertions, 5 deletions
diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index 7cc0d616b8de..3d543b1d8947 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -671,11 +671,13 @@ static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw, * @len: Length of the message in @buf. * @chan_id: The channel ID to use. * @async: A flag stating if an asynchronous command is required. + * @poll: A flag stating if a polling transmission is required. * * Return: 0 on Success */ static int scmi_raw_message_send(struct scmi_raw_mode_info *raw, - void *buf, size_t len, u8 chan_id, bool async) + void *buf, size_t len, u8 chan_id, + bool async, bool poll) { int ret; struct scmi_xfer *xfer; @@ -684,6 +686,16 @@ static int scmi_raw_message_send(struct scmi_raw_mode_info *raw, if (ret) return ret; + if (poll) { + if (is_transport_polling_capable(raw->desc)) { + xfer->hdr.poll_completion = true; + } else { + dev_err(raw->handle->dev, + "Failed to send RAW message - Polling NOT supported\n"); + return -EINVAL; + } + } + ret = scmi_do_xfer_raw_start(raw, xfer, chan_id, async); if (ret) scmi_xfer_raw_put(raw->handle, xfer); @@ -801,7 +813,7 @@ static ssize_t scmi_dbg_raw_mode_common_read(struct file *filp, static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos, - bool async) + bool async, bool poll) { int ret; struct scmi_dbg_raw_data *rd = filp->private_data; @@ -831,7 +843,7 @@ static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp, } ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size, - rd->chan_id, async); + rd->chan_id, async, poll); /* Reset ppos for next message ... */ rd->tx_size = 0; @@ -875,7 +887,8 @@ 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); + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, + false, false); } static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp, @@ -964,7 +977,8 @@ 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); + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, + true, false); } static const struct file_operations scmi_dbg_raw_mode_message_async_fops = { @@ -976,6 +990,40 @@ static const struct file_operations scmi_dbg_raw_mode_message_async_fops = { .owner = THIS_MODULE, }; +static ssize_t scmi_dbg_raw_mode_message_poll_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, true); +} + +static const struct file_operations scmi_dbg_raw_mode_message_poll_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_poll_write, + .poll = scmi_dbg_raw_mode_message_poll, + .owner = THIS_MODULE, +}; + +static ssize_t scmi_dbg_raw_mode_message_poll_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, true); +} + +static const struct file_operations scmi_dbg_raw_mode_message_poll_async_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_poll_async_write, + .poll = scmi_dbg_raw_mode_message_poll, + .owner = THIS_MODULE, +}; + static ssize_t scmi_test_dbg_raw_mode_notif_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) @@ -1199,6 +1247,12 @@ void *scmi_raw_mode_init(const struct scmi_handle *handle, debugfs_create_file("message_async", 0600, raw->dentry, raw, &scmi_dbg_raw_mode_message_async_fops); + debugfs_create_file("message_poll", 0600, raw->dentry, raw, + &scmi_dbg_raw_mode_message_poll_fops); + + debugfs_create_file("message_poll_async", 0600, raw->dentry, raw, + &scmi_dbg_raw_mode_message_poll_async_fops); + debugfs_create_file("notification", 0400, raw->dentry, raw, &scmi_dbg_raw_mode_notification_fops); @@ -1230,6 +1284,14 @@ void *scmi_raw_mode_init(const struct scmi_handle *handle, debugfs_create_file_aux_num("message_async", 0600, chd, raw, channels[i], &scmi_dbg_raw_mode_message_async_fops); + + debugfs_create_file_aux_num("message_poll", 0600, chd, + raw, channels[i], + &scmi_dbg_raw_mode_message_poll_fops); + + debugfs_create_file_aux_num("message_poll_async", 0600, + chd, raw, channels[i], + &scmi_dbg_raw_mode_message_poll_async_fops); } } |
