Skip to content

Commit 4e61c01

Browse files
committed
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/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 5dcee6d + 397f802 commit 4e61c01

File tree

24 files changed

+2371
-100
lines changed

24 files changed

+2371
-100
lines changed

Documentation/ABI/testing/debugfs-scmi-raw

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,42 @@ Description: SCMI Raw asynchronous message injection/snooping facility; write
3131
(receiving an EOF at each message boundary).
3232
Users: Debugging, any userspace test suite
3333

34+
What: /sys/kernel/debug/scmi/<n>/raw/message_poll
35+
Date: June 2025
36+
KernelVersion: 6.16
37+
38+
Description: SCMI Raw message injection/snooping facility using polling mode;
39+
write a complete SCMI command message (header included) in
40+
little-endian binary format to have it sent to the configured
41+
backend SCMI server for instance <n>, using polling mode on
42+
the reception path. (if transport is polling capable)
43+
Any subsequently received response can be read from this same
44+
entry if it arrived within the configured timeout.
45+
Each write to the entry causes one command request to be built
46+
and sent while the replies are read back one message at time
47+
(receiving an EOF at each message boundary).
48+
Users: Debugging, any userspace test suite
49+
50+
What: /sys/kernel/debug/scmi/<n>/raw/message_poll_async
51+
Date: June 2025
52+
KernelVersion: 6.16
53+
54+
Description: SCMI Raw asynchronous message injection/snooping facility using
55+
polling-mode; write a complete SCMI asynchronous command message
56+
(header included) in little-endian binary format to have it sent
57+
to the configured backend SCMI server for instance <n>, using
58+
polling-mode on the reception path of the immediate part of the
59+
asynchronous command. (if transport is polling capable)
60+
Any subsequently received response can be read from this same
61+
entry if it arrived within the configured timeout.
62+
Any additional delayed response received afterwards can be read
63+
from this same entry too if it arrived within the configured
64+
timeout.
65+
Each write to the entry causes one command request to be built
66+
and sent while the replies are read back one message at time
67+
(receiving an EOF at each message boundary).
68+
Users: Debugging, any userspace test suite
69+
3470
What: /sys/kernel/debug/scmi/<n>/raw/errors
3571
Date: March 2023
3672
KernelVersion: 6.3
@@ -115,3 +151,58 @@ Description: SCMI Raw asynchronous message injection/snooping facility; write
115151
exist only if the transport is configured to have more than
116152
one default channel.
117153
Users: Debugging, any userspace test suite
154+
155+
156+
What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message_poll
157+
Date: June 2025
158+
KernelVersion: 6.16
159+
160+
Description: SCMI Raw message injection/snooping facility using polling mode;
161+
write a complete SCMI command message (header included) in
162+
little-endian binary format to have it sent to the configured
163+
backend SCMI server for instance <n> through the <m> transport
164+
channel, using polling mode on the reception path.
165+
(if transport is polling capable)
166+
Any subsequently received response can be read from this same
167+
entry if it arrived on channel <m> within the configured
168+
timeout.
169+
Each write to the entry causes one command request to be built
170+
and sent while the replies are read back one message at time
171+
(receiving an EOF at each message boundary).
172+
Channel identifier <m> matches the SCMI protocol number which
173+
has been associated with this transport channel in the DT
174+
description, with base protocol number 0x10 being the default
175+
channel for this instance.
176+
Note that these per-channel entries rooted at <..>/channels
177+
exist only if the transport is configured to have more than
178+
one default channel.
179+
Users: Debugging, any userspace test suite
180+
181+
What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message_poll_async
182+
Date: June 2025
183+
KernelVersion: 6.16
184+
185+
Description: SCMI Raw asynchronous message injection/snooping facility using
186+
polling-mode; write a complete SCMI asynchronous command message
187+
(header included) in little-endian binary format to have it sent
188+
to the configured backend SCMI server for instance <n> through
189+
the <m> transport channel, using polling mode on the reception
190+
path of the immediate part of the asynchronous command.
191+
(if transport is polling capable)
192+
Any subsequently received response can be read from this same
193+
entry if it arrived on channel <m> within the configured
194+
timeout.
195+
Any additional delayed response received afterwards can be read
196+
from this same entry too if it arrived within the configured
197+
timeout.
198+
Each write to the entry causes one command request to be built
199+
and sent while the replies are read back one message at time
200+
(receiving an EOF at each message boundary).
201+
Channel identifier <m> matches the SCMI protocol number which
202+
has been associated with this transport channel in the DT
203+
description, with base protocol number 0x10 being the default
204+
channel for this instance.
205+
Note that these per-channel entries rooted at <..>/channels
206+
exist only if the transport is configured to have more than
207+
one default channel.
208+
Users: Debugging, any userspace test suite

Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ maintainers:
1111
- Peng Fan <[email protected]>
1212

1313
properties:
14+
protocol@80:
15+
description:
16+
SCMI LMM protocol which is for boot, shutdown, and reset of other logical
17+
machines (LM). It is usually used to allow one LM to manage another used
18+
as an offload or accelerator engine.
19+
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
20+
unevaluatedProperties: false
21+
22+
properties:
23+
reg:
24+
const: 0x80
25+
1426
protocol@81:
1527
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
1628
unevaluatedProperties: false
@@ -19,6 +31,17 @@ properties:
1931
reg:
2032
const: 0x81
2133

34+
protocol@82:
35+
description:
36+
SCMI CPU Protocol which allows an agent to start or stop a CPU. It is
37+
used to manage auxiliary CPUs in a LM.
38+
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
39+
unevaluatedProperties: false
40+
41+
properties:
42+
reg:
43+
const: 0x82
44+
2245
protocol@84:
2346
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
2447
unevaluatedProperties: false

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23565,6 +23565,15 @@ F: include/linux/sc[mp]i_protocol.h
2356523565
F: include/trace/events/scmi.h
2356623566
F: include/uapi/linux/virtio_scmi.h
2356723567

23568+
SYSTEM CONTROL MANAGEMENT INTERFACE (SCMI) i.MX Extension Message Protocol drivers
23569+
M: Peng Fan <[email protected]>
23570+
23571+
23572+
L: [email protected] (moderated for non-subscribers)
23573+
S: Maintained
23574+
F: Documentation/devicetree/bindings/firmware/nxp,*scmi.yaml
23575+
F: drivers/firmware/arm_scmi/vendors/imx/
23576+
2356823577
SYSTEM RESET/SHUTDOWN DRIVERS
2356923578
M: Sebastian Reichel <[email protected]>
2357023579

drivers/firmware/arm_scmi/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ config ARM_SCMI_DEBUG_COUNTERS
6969
such useful debug counters. This can be helpful for debugging and
7070
SCMI monitoring.
7171

72+
config ARM_SCMI_QUIRKS
73+
bool "Enable SCMI Quirks framework"
74+
depends on JUMP_LABEL || COMPILE_TEST
75+
default y
76+
help
77+
Enables support for SCMI Quirks framework to workaround SCMI platform
78+
firmware bugs on system already deployed in the wild.
79+
80+
The framework allows the definition of platform-specific code quirks
81+
that will be associated and enabled only on the desired platforms
82+
depending on the SCMI firmware advertised versions and/or machine
83+
compatibles.
84+
7285
source "drivers/firmware/arm_scmi/transports/Kconfig"
7386
source "drivers/firmware/arm_scmi/vendors/imx/Kconfig"
7487

drivers/firmware/arm_scmi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ scmi-bus-y = bus.o
33
scmi-core-objs := $(scmi-bus-y)
44

55
scmi-driver-y = driver.o notify.o
6+
scmi-driver-$(CONFIG_ARM_SCMI_QUIRKS) += quirks.o
67
scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o
78
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o
89
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o

drivers/firmware/arm_scmi/bus.c

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -201,55 +201,51 @@ scmi_protocol_table_unregister(const struct scmi_device_id *id_table)
201201
scmi_protocol_device_unrequest(entry);
202202
}
203203

204-
static const struct scmi_device_id *
205-
scmi_dev_match_id(struct scmi_device *scmi_dev, const struct scmi_driver *scmi_drv)
204+
static int scmi_dev_match_by_id_table(struct scmi_device *scmi_dev,
205+
const struct scmi_device_id *id_table)
206206
{
207-
const struct scmi_device_id *id = scmi_drv->id_table;
208-
209-
if (!id)
210-
return NULL;
211-
212-
for (; id->protocol_id; id++)
213-
if (id->protocol_id == scmi_dev->protocol_id) {
214-
if (!id->name)
215-
return id;
216-
else if (!strcmp(id->name, scmi_dev->name))
217-
return id;
218-
}
207+
if (!id_table || !id_table->name)
208+
return 0;
209+
210+
/* Always skip transport devices from matching */
211+
for (; id_table->protocol_id && id_table->name; id_table++)
212+
if (id_table->protocol_id == scmi_dev->protocol_id &&
213+
strncmp(scmi_dev->name, "__scmi_transport_device", 23) &&
214+
!strcmp(id_table->name, scmi_dev->name))
215+
return 1;
216+
return 0;
217+
}
219218

220-
return NULL;
219+
static int scmi_dev_match_id(struct scmi_device *scmi_dev,
220+
const struct scmi_driver *scmi_drv)
221+
{
222+
return scmi_dev_match_by_id_table(scmi_dev, scmi_drv->id_table);
221223
}
222224

223225
static int scmi_dev_match(struct device *dev, const struct device_driver *drv)
224226
{
225227
const struct scmi_driver *scmi_drv = to_scmi_driver(drv);
226228
struct scmi_device *scmi_dev = to_scmi_dev(dev);
227-
const struct scmi_device_id *id;
228-
229-
id = scmi_dev_match_id(scmi_dev, scmi_drv);
230-
if (id)
231-
return 1;
232229

233-
return 0;
230+
return scmi_dev_match_id(scmi_dev, scmi_drv);
234231
}
235232

236233
static int scmi_match_by_id_table(struct device *dev, const void *data)
237234
{
238-
struct scmi_device *sdev = to_scmi_dev(dev);
235+
struct scmi_device *scmi_dev = to_scmi_dev(dev);
239236
const struct scmi_device_id *id_table = data;
240237

241-
return sdev->protocol_id == id_table->protocol_id &&
242-
(id_table->name && !strcmp(sdev->name, id_table->name));
238+
return scmi_dev_match_by_id_table(scmi_dev, id_table);
243239
}
244240

245241
static struct scmi_device *scmi_child_dev_find(struct device *parent,
246242
int prot_id, const char *name)
247243
{
248-
struct scmi_device_id id_table;
244+
struct scmi_device_id id_table[2] = { 0 };
249245
struct device *dev;
250246

251-
id_table.protocol_id = prot_id;
252-
id_table.name = name;
247+
id_table[0].protocol_id = prot_id;
248+
id_table[0].name = name;
253249

254250
dev = device_find_child(parent, &id_table, scmi_match_by_id_table);
255251
if (!dev)
@@ -460,6 +456,20 @@ __scmi_device_create(struct device_node *np, struct device *parent,
460456
return NULL;
461457
}
462458

459+
static struct scmi_device *
460+
_scmi_device_create(struct device_node *np, struct device *parent,
461+
int protocol, const char *name)
462+
{
463+
struct scmi_device *sdev;
464+
465+
sdev = __scmi_device_create(np, parent, protocol, name);
466+
if (!sdev)
467+
pr_err("(%s) Failed to create device for protocol 0x%x (%s)\n",
468+
of_node_full_name(parent->of_node), protocol, name);
469+
470+
return sdev;
471+
}
472+
463473
/**
464474
* scmi_device_create - A method to create one or more SCMI devices
465475
*
@@ -492,7 +502,7 @@ struct scmi_device *scmi_device_create(struct device_node *np,
492502
struct scmi_device *scmi_dev = NULL;
493503

494504
if (name)
495-
return __scmi_device_create(np, parent, protocol, name);
505+
return _scmi_device_create(np, parent, protocol, name);
496506

497507
mutex_lock(&scmi_requested_devices_mtx);
498508
phead = idr_find(&scmi_requested_devices, protocol);
@@ -506,18 +516,13 @@ struct scmi_device *scmi_device_create(struct device_node *np,
506516
list_for_each_entry(rdev, phead, node) {
507517
struct scmi_device *sdev;
508518

509-
sdev = __scmi_device_create(np, parent,
510-
rdev->id_table->protocol_id,
511-
rdev->id_table->name);
512-
/* Report errors and carry on... */
519+
sdev = _scmi_device_create(np, parent,
520+
rdev->id_table->protocol_id,
521+
rdev->id_table->name);
513522
if (sdev)
514523
scmi_dev = sdev;
515-
else
516-
pr_err("(%s) Failed to create device for protocol 0x%x (%s)\n",
517-
of_node_full_name(parent->of_node),
518-
rdev->id_table->protocol_id,
519-
rdev->id_table->name);
520524
}
525+
521526
mutex_unlock(&scmi_requested_devices_mtx);
522527

523528
return scmi_dev;

drivers/firmware/arm_scmi/clock.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "protocols.h"
1313
#include "notify.h"
14+
#include "quirks.h"
1415

1516
/* Updated only after ALL the mandatory features for that version are merged */
1617
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000
@@ -429,6 +430,23 @@ static void iter_clk_describe_prepare_message(void *message,
429430
msg->rate_index = cpu_to_le32(desc_index);
430431
}
431432

433+
#define QUIRK_OUT_OF_SPEC_TRIPLET \
434+
({ \
435+
/* \
436+
* A known quirk: a triplet is returned but num_returned != 3 \
437+
* Check for a safe payload size and fix. \
438+
*/ \
439+
if (st->num_returned != 3 && st->num_remaining == 0 && \
440+
st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) { \
441+
st->num_returned = 3; \
442+
st->num_remaining = 0; \
443+
} else { \
444+
dev_err(p->dev, \
445+
"Cannot fix out-of-spec reply !\n"); \
446+
return -EPROTO; \
447+
} \
448+
})
449+
432450
static int
433451
iter_clk_describe_update_state(struct scmi_iterator_state *st,
434452
const void *response, void *priv)
@@ -450,19 +468,8 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
450468
p->clk->name, st->num_returned, st->num_remaining,
451469
st->rx_len);
452470

453-
/*
454-
* A known quirk: a triplet is returned but num_returned != 3
455-
* Check for a safe payload size and fix.
456-
*/
457-
if (st->num_returned != 3 && st->num_remaining == 0 &&
458-
st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
459-
st->num_returned = 3;
460-
st->num_remaining = 0;
461-
} else {
462-
dev_err(p->dev,
463-
"Cannot fix out-of-spec reply !\n");
464-
return -EPROTO;
465-
}
471+
SCMI_QUIRK(clock_rates_triplet_out_of_spec,
472+
QUIRK_OUT_OF_SPEC_TRIPLET);
466473
}
467474

468475
return 0;

drivers/firmware/arm_scmi/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ static int __tag##_probe(struct platform_device *pdev) \
475475
if (ret) \
476476
goto err; \
477477
\
478+
spdev->dev.parent = dev; \
478479
ret = platform_device_add(spdev); \
479480
if (ret) \
480481
goto err; \

0 commit comments

Comments
 (0)