Skip to content

Commit 753355d

Browse files
committed
Merge tag 'scmi-updates-6.17' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers
Arm SCMI updates for v6.17 1. A fix is introduced to correct turbo frequency marking for 64-bit devices with sustained frequencies over 4GHz, ensuring accurate turbo frequency identification. 2. Debug capabilities are being improved by introducing in-flight transfer tracking using debug counters, which help diagnose transfer congestion and behavior. Additional tracepoints are added to log in-flight counts at transfer begin and end, offering better runtime insight. The debug counters now support decrement operations using a newly added scmi_dec_count helper, making counter tracking symmetric and more robust. 3. A race condition in suspend-resume logic is being resolved by ensuring SCMI_SYSPOWER_IDLE state is set early during resume, improving suspend reliability under certain conditions. New suspend and resume operations are added to the scmi_bus_type to enable finer power management control for SCMI-based devices. 4. Finally enhancements are also made to avoid registering notifiers for events that a platform does not support, reducing unnecessary overhead by checking for unsupported event types during protocolinitialization. * tag 'scmi-updates-6.17' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_scmi: Convert to SYSTEM_SLEEP_PM_OPS firmware: arm_scmi: Avoid notifier registration for unsupported events firmware: arm_scmi: power_control: Ensure SCMI_SYSPOWER_IDLE is set early during resume firmware: arm_scmi: Add power management operations to SCMI bus include: trace: Add tracepoint support for inflight xfer count firmware: arm_scmi: Track number of inflight SCMI transfers firmware: arm_scmi: Add support for debug counter decrement firmware: arm_scmi: Fix up turbo frequencies selection Link: https://lore.kernel.org/r/20250709122907.1171913-1-sudeep.holla@arm.com Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 7edf259 + 62d6b81 commit 753355d

8 files changed

Lines changed: 126 additions & 29 deletions

File tree

drivers/firmware/arm_scmi/bus.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,39 @@ static struct attribute *scmi_device_attributes_attrs[] = {
323323
};
324324
ATTRIBUTE_GROUPS(scmi_device_attributes);
325325

326+
static int scmi_pm_suspend(struct device *dev)
327+
{
328+
const struct device_driver *drv = dev->driver;
329+
330+
if (drv && drv->pm && drv->pm->suspend)
331+
return drv->pm->suspend(dev);
332+
333+
return 0;
334+
}
335+
336+
static int scmi_pm_resume(struct device *dev)
337+
{
338+
const struct device_driver *drv = dev->driver;
339+
340+
if (drv && drv->pm && drv->pm->resume)
341+
return drv->pm->resume(dev);
342+
343+
return 0;
344+
}
345+
346+
static const struct dev_pm_ops scmi_dev_pm_ops = {
347+
.suspend = pm_sleep_ptr(scmi_pm_suspend),
348+
.resume = pm_sleep_ptr(scmi_pm_resume),
349+
};
350+
326351
const struct bus_type scmi_bus_type = {
327352
.name = "scmi_protocol",
328353
.match = scmi_dev_match,
329354
.probe = scmi_dev_probe,
330355
.remove = scmi_dev_remove,
331356
.uevent = scmi_device_uevent,
332357
.dev_groups = scmi_device_attributes_groups,
358+
.pm = &scmi_dev_pm_ops,
333359
};
334360
EXPORT_SYMBOL_GPL(scmi_bus_type);
335361

drivers/firmware/arm_scmi/common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ enum debug_counters {
305305
ERR_MSG_INVALID,
306306
ERR_MSG_NOMEM,
307307
ERR_PROTOCOL,
308+
XFERS_INFLIGHT,
308309
SCMI_DEBUG_COUNTERS_LAST
309310
};
310311

@@ -314,6 +315,12 @@ static inline void scmi_inc_count(atomic_t *arr, int stat)
314315
atomic_inc(&arr[stat]);
315316
}
316317

318+
static inline void scmi_dec_count(atomic_t *arr, int stat)
319+
{
320+
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS))
321+
atomic_dec(&arr[stat]);
322+
}
323+
317324
enum scmi_bad_msg {
318325
MSG_UNEXPECTED = -1,
319326
MSG_INVALID = -2,
@@ -498,4 +505,5 @@ static struct platform_driver __drv = { \
498505
void scmi_notification_instance_data_set(const struct scmi_handle *handle,
499506
void *priv);
500507
void *scmi_notification_instance_data_get(const struct scmi_handle *handle);
508+
int scmi_inflight_count(const struct scmi_handle *handle);
501509
#endif /* _SCMI_COMMON_H */

drivers/firmware/arm_scmi/driver.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ struct scmi_info {
190190
};
191191

192192
#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle)
193+
#define tx_minfo_to_scmi_info(h) container_of(h, struct scmi_info, tx_minfo)
193194
#define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb)
194195
#define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb)
195196

@@ -603,9 +604,14 @@ static inline void
603604
scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer,
604605
struct scmi_xfers_info *minfo)
605606
{
607+
/* In this context minfo will be tx_minfo due to the xfer pending */
608+
struct scmi_info *info = tx_minfo_to_scmi_info(minfo);
609+
606610
/* Set in-flight */
607611
set_bit(xfer->hdr.seq, minfo->xfer_alloc_table);
608612
hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq);
613+
scmi_inc_count(info->dbg->counters, XFERS_INFLIGHT);
614+
609615
xfer->pending = true;
610616
}
611617

@@ -807,9 +813,13 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer)
807813
spin_lock_irqsave(&minfo->xfer_lock, flags);
808814
if (refcount_dec_and_test(&xfer->users)) {
809815
if (xfer->pending) {
816+
struct scmi_info *info = tx_minfo_to_scmi_info(minfo);
817+
810818
scmi_xfer_token_clear(minfo, xfer);
811819
hash_del(&xfer->node);
812820
xfer->pending = false;
821+
822+
scmi_dec_count(info->dbg->counters, XFERS_INFLIGHT);
813823
}
814824
hlist_add_head(&xfer->node, &minfo->free_xfers);
815825
}
@@ -1433,7 +1443,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
14331443

14341444
trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
14351445
xfer->hdr.protocol_id, xfer->hdr.seq,
1436-
xfer->hdr.poll_completion);
1446+
xfer->hdr.poll_completion,
1447+
scmi_inflight_count(&info->handle));
14371448

14381449
/* Clear any stale status */
14391450
xfer->hdr.status = SCMI_SUCCESS;
@@ -1469,7 +1480,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
14691480
info->desc->ops->mark_txdone(cinfo, ret, xfer);
14701481

14711482
trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
1472-
xfer->hdr.protocol_id, xfer->hdr.seq, ret);
1483+
xfer->hdr.protocol_id, xfer->hdr.seq, ret,
1484+
scmi_inflight_count(&info->handle));
14731485

14741486
return ret;
14751487
}
@@ -2912,6 +2924,7 @@ static const char * const dbg_counter_strs[] = {
29122924
"err_msg_invalid",
29132925
"err_msg_nomem",
29142926
"err_protocol",
2927+
"xfers_inflight",
29152928
};
29162929

29172930
static ssize_t reset_all_on_write(struct file *filp, const char __user *buf,
@@ -3405,6 +3418,17 @@ static struct dentry *scmi_debugfs_init(void)
34053418
return d;
34063419
}
34073420

3421+
int scmi_inflight_count(const struct scmi_handle *handle)
3422+
{
3423+
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) {
3424+
struct scmi_info *info = handle_to_scmi_info(handle);
3425+
3426+
return atomic_read(&info->dbg->counters[XFERS_INFLIGHT]);
3427+
} else {
3428+
return 0;
3429+
}
3430+
}
3431+
34083432
static int __init scmi_driver_init(void)
34093433
{
34103434
scmi_quirks_initialize();

drivers/firmware/arm_scmi/notify.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ struct scmi_registered_events_desc {
318318
* customized event report
319319
* @num_sources: The number of possible sources for this event as stated at
320320
* events' registration time
321+
* @not_supported_by_platform: A flag to indicate that not even one source was
322+
* found to be supported by the platform for this
323+
* event
321324
* @sources: A reference to a dynamically allocated array used to refcount the
322325
* events' enable requests for all the existing sources
323326
* @sources_mtx: A mutex to serialize the access to @sources
@@ -334,6 +337,7 @@ struct scmi_registered_event {
334337
const struct scmi_event *evt;
335338
void *report;
336339
u32 num_sources;
340+
bool not_supported_by_platform;
337341
refcount_t *sources;
338342
/* locking to serialize the access to sources */
339343
struct mutex sources_mtx;
@@ -811,10 +815,19 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
811815
if (!r_evt->report)
812816
return -ENOMEM;
813817

814-
for (id = 0; id < r_evt->num_sources; id++)
815-
if (ee->ops->is_notify_supported &&
816-
!ee->ops->is_notify_supported(ph, r_evt->evt->id, id))
817-
refcount_set(&r_evt->sources[id], NOTIF_UNSUPP);
818+
if (ee->ops->is_notify_supported) {
819+
int supported = 0;
820+
821+
for (id = 0; id < r_evt->num_sources; id++) {
822+
if (!ee->ops->is_notify_supported(ph, r_evt->evt->id, id))
823+
refcount_set(&r_evt->sources[id], NOTIF_UNSUPP);
824+
else
825+
supported++;
826+
}
827+
828+
/* Not even one source has been found to be supported */
829+
r_evt->not_supported_by_platform = !supported;
830+
}
818831

819832
pd->registered_events[i] = r_evt;
820833
/* Ensure events are updated */
@@ -936,6 +949,11 @@ static inline int scmi_bind_event_handler(struct scmi_notify_instance *ni,
936949
* of protocol instance.
937950
*/
938951
hash_del(&hndl->hash);
952+
953+
/* Bailout if event is not supported at all */
954+
if (r_evt->not_supported_by_platform)
955+
return -EOPNOTSUPP;
956+
939957
/*
940958
* Acquire protocols only for NON pending handlers, so as NOT to trigger
941959
* protocol initialization when a notifier is registered against a still
@@ -1060,6 +1078,9 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
10601078
r_evt = SCMI_GET_REVT(ni, KEY_XTRACT_PROTO_ID(evt_key),
10611079
KEY_XTRACT_EVT_ID(evt_key));
10621080

1081+
if (r_evt && r_evt->not_supported_by_platform)
1082+
return ERR_PTR(-EOPNOTSUPP);
1083+
10631084
mutex_lock(&ni->pending_mtx);
10641085
/* Search registered events at first ... if possible at all */
10651086
if (r_evt) {
@@ -1087,7 +1108,7 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
10871108
hndl->key);
10881109
/* this hndl can be only a pending one */
10891110
scmi_put_handler_unlocked(ni, hndl);
1090-
hndl = NULL;
1111+
hndl = ERR_PTR(-EINVAL);
10911112
}
10921113
}
10931114
mutex_unlock(&ni->pending_mtx);
@@ -1370,8 +1391,8 @@ static int scmi_notifier_register(const struct scmi_handle *handle,
13701391
evt_key = MAKE_HASH_KEY(proto_id, evt_id,
13711392
src_id ? *src_id : SRC_ID_MASK);
13721393
hndl = scmi_get_or_create_handler(ni, evt_key);
1373-
if (!hndl)
1374-
return -EINVAL;
1394+
if (IS_ERR(hndl))
1395+
return PTR_ERR(hndl);
13751396

13761397
blocking_notifier_chain_register(&hndl->chain, nb);
13771398

@@ -1416,8 +1437,8 @@ static int scmi_notifier_unregister(const struct scmi_handle *handle,
14161437
evt_key = MAKE_HASH_KEY(proto_id, evt_id,
14171438
src_id ? *src_id : SRC_ID_MASK);
14181439
hndl = scmi_get_handler(ni, evt_key);
1419-
if (!hndl)
1420-
return -EINVAL;
1440+
if (IS_ERR(hndl))
1441+
return PTR_ERR(hndl);
14211442

14221443
/*
14231444
* Note that this chain unregistration call is safe on its own

drivers/firmware/arm_scmi/perf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
892892
freq = dom->opp[idx].indicative_freq * dom->mult_factor;
893893

894894
/* All OPPs above the sustained frequency are treated as turbo */
895-
data.turbo = freq > dom->sustained_freq_khz * 1000;
895+
data.turbo = freq > dom->sustained_freq_khz * 1000UL;
896896

897897
data.level = dom->opp[idx].perf;
898898
data.freq = freq;

drivers/firmware/arm_scmi/raw_mode.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,8 @@ static void scmi_xfer_raw_worker(struct work_struct *work)
475475
raw->desc->ops->mark_txdone(rw->cinfo, ret, xfer);
476476

477477
trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
478-
xfer->hdr.protocol_id, xfer->hdr.seq, ret);
478+
xfer->hdr.protocol_id, xfer->hdr.seq,
479+
ret, scmi_inflight_count(raw->handle));
479480

480481
/* Wait also for an async delayed response if needed */
481482
if (!ret && xfer->async_done) {
@@ -642,7 +643,8 @@ static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw,
642643

643644
trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
644645
xfer->hdr.protocol_id, xfer->hdr.seq,
645-
xfer->hdr.poll_completion);
646+
xfer->hdr.poll_completion,
647+
scmi_inflight_count(raw->handle));
646648

647649
ret = raw->desc->ops->send_message(rw->cinfo, xfer);
648650
if (ret) {

drivers/firmware/arm_scmi/scmi_power_control.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <linux/math.h>
4747
#include <linux/module.h>
4848
#include <linux/mutex.h>
49+
#include <linux/pm.h>
4950
#include <linux/printk.h>
5051
#include <linux/reboot.h>
5152
#include <linux/scmi_protocol.h>
@@ -324,12 +325,7 @@ static int scmi_userspace_notifier(struct notifier_block *nb,
324325

325326
static void scmi_suspend_work_func(struct work_struct *work)
326327
{
327-
struct scmi_syspower_conf *sc =
328-
container_of(work, struct scmi_syspower_conf, suspend_work);
329-
330328
pm_suspend(PM_SUSPEND_MEM);
331-
332-
sc->state = SCMI_SYSPOWER_IDLE;
333329
}
334330

335331
static int scmi_syspower_probe(struct scmi_device *sdev)
@@ -354,6 +350,7 @@ static int scmi_syspower_probe(struct scmi_device *sdev)
354350
sc->required_transition = SCMI_SYSTEM_MAX;
355351
sc->userspace_nb.notifier_call = &scmi_userspace_notifier;
356352
sc->dev = &sdev->dev;
353+
dev_set_drvdata(&sdev->dev, sc);
357354

358355
INIT_WORK(&sc->suspend_work, scmi_suspend_work_func);
359356

@@ -363,13 +360,28 @@ static int scmi_syspower_probe(struct scmi_device *sdev)
363360
NULL, &sc->userspace_nb);
364361
}
365362

363+
static int scmi_system_power_resume(struct device *dev)
364+
{
365+
struct scmi_syspower_conf *sc = dev_get_drvdata(dev);
366+
367+
sc->state = SCMI_SYSPOWER_IDLE;
368+
return 0;
369+
}
370+
371+
static const struct dev_pm_ops scmi_system_power_pmops = {
372+
SYSTEM_SLEEP_PM_OPS(NULL, scmi_system_power_resume)
373+
};
374+
366375
static const struct scmi_device_id scmi_id_table[] = {
367376
{ SCMI_PROTOCOL_SYSTEM, "syspower" },
368377
{ },
369378
};
370379
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
371380

372381
static struct scmi_driver scmi_system_power_driver = {
382+
.driver = {
383+
.pm = pm_sleep_ptr(&scmi_system_power_pmops),
384+
},
373385
.name = "scmi-system-power",
374386
.probe = scmi_syspower_probe,
375387
.id_table = scmi_id_table,

0 commit comments

Comments
 (0)