Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'scmi-fixes-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes

Arm SCMI fixes for v6.18

This series contains a set of small, focused fixes that address
robustness and lifecycle issues in the Arm SCMI core and debug support,
ensuring safer handling of debug initialization failures, correct flag
management in raw mode, and consistent inflight counter tracking.

Brief summary:

- Fix raw xfer flag clearing
- Skip RAW debug initialization on failure
- Make inflight counter helpers null-safe, preventing crashes if debug
initialization fails
- Account for failed debug initialization globally

There is no functional change for standard SCMI operation, but these
fixes improve stability in debug and raw modes, particularly in error
paths.

* tag 'scmi-fixes-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
firmware: arm_scmi: Fix premature SCMI_XFER_FLAG_IS_RAW clearing in raw mode
firmware: arm_scmi: Skip RAW initialization on failure
include: trace: Fix inflight count helper on failed initialization
firmware: arm_scmi: Account for failed debug initialization

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+47 -44
+26 -6
drivers/firmware/arm_scmi/common.h
··· 309 309 SCMI_DEBUG_COUNTERS_LAST 310 310 }; 311 311 312 - static inline void scmi_inc_count(atomic_t *arr, int stat) 312 + /** 313 + * struct scmi_debug_info - Debug common info 314 + * @top_dentry: A reference to the top debugfs dentry 315 + * @name: Name of this SCMI instance 316 + * @type: Type of this SCMI instance 317 + * @is_atomic: Flag to state if the transport of this instance is atomic 318 + * @counters: An array of atomic_c's used for tracking statistics (if enabled) 319 + */ 320 + struct scmi_debug_info { 321 + struct dentry *top_dentry; 322 + const char *name; 323 + const char *type; 324 + bool is_atomic; 325 + atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; 326 + }; 327 + 328 + static inline void scmi_inc_count(struct scmi_debug_info *dbg, int stat) 313 329 { 314 - if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) 315 - atomic_inc(&arr[stat]); 330 + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) { 331 + if (dbg) 332 + atomic_inc(&dbg->counters[stat]); 333 + } 316 334 } 317 335 318 - static inline void scmi_dec_count(atomic_t *arr, int stat) 336 + static inline void scmi_dec_count(struct scmi_debug_info *dbg, int stat) 319 337 { 320 - if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) 321 - atomic_dec(&arr[stat]); 338 + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) { 339 + if (dbg) 340 + atomic_dec(&dbg->counters[stat]); 341 + } 322 342 } 323 343 324 344 enum scmi_bad_msg {
+21 -38
drivers/firmware/arm_scmi/driver.c
··· 116 116 #define ph_to_pi(h) container_of(h, struct scmi_protocol_instance, ph) 117 117 118 118 /** 119 - * struct scmi_debug_info - Debug common info 120 - * @top_dentry: A reference to the top debugfs dentry 121 - * @name: Name of this SCMI instance 122 - * @type: Type of this SCMI instance 123 - * @is_atomic: Flag to state if the transport of this instance is atomic 124 - * @counters: An array of atomic_c's used for tracking statistics (if enabled) 125 - */ 126 - struct scmi_debug_info { 127 - struct dentry *top_dentry; 128 - const char *name; 129 - const char *type; 130 - bool is_atomic; 131 - atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; 132 - }; 133 - 134 - /** 135 119 * struct scmi_info - Structure representing a SCMI instance 136 120 * 137 121 * @id: A sequence number starting from zero identifying this instance ··· 594 610 /* Set in-flight */ 595 611 set_bit(xfer->hdr.seq, minfo->xfer_alloc_table); 596 612 hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq); 597 - scmi_inc_count(info->dbg->counters, XFERS_INFLIGHT); 613 + scmi_inc_count(info->dbg, XFERS_INFLIGHT); 598 614 599 615 xfer->pending = true; 600 616 } ··· 803 819 hash_del(&xfer->node); 804 820 xfer->pending = false; 805 821 806 - scmi_dec_count(info->dbg->counters, XFERS_INFLIGHT); 822 + scmi_dec_count(info->dbg, XFERS_INFLIGHT); 807 823 } 824 + xfer->flags = 0; 808 825 hlist_add_head(&xfer->node, &minfo->free_xfers); 809 826 } 810 827 spin_unlock_irqrestore(&minfo->xfer_lock, flags); ··· 824 839 { 825 840 struct scmi_info *info = handle_to_scmi_info(handle); 826 841 827 - xfer->flags &= ~SCMI_XFER_FLAG_IS_RAW; 828 - xfer->flags &= ~SCMI_XFER_FLAG_CHAN_SET; 829 842 return __scmi_xfer_put(&info->tx_minfo, xfer); 830 843 } 831 844 ··· 1017 1034 spin_unlock_irqrestore(&minfo->xfer_lock, flags); 1018 1035 1019 1036 scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED); 1020 - scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED); 1037 + scmi_inc_count(info->dbg, ERR_MSG_UNEXPECTED); 1021 1038 1022 1039 return xfer; 1023 1040 } ··· 1045 1062 msg_type, xfer_id, msg_hdr, xfer->state); 1046 1063 1047 1064 scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); 1048 - scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); 1065 + scmi_inc_count(info->dbg, ERR_MSG_INVALID); 1049 1066 1050 1067 /* On error the refcount incremented above has to be dropped */ 1051 1068 __scmi_xfer_put(minfo, xfer); ··· 1090 1107 PTR_ERR(xfer)); 1091 1108 1092 1109 scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM); 1093 - scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM); 1110 + scmi_inc_count(info->dbg, ERR_MSG_NOMEM); 1094 1111 1095 1112 scmi_clear_channel(info, cinfo); 1096 1113 return; ··· 1106 1123 trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, 1107 1124 xfer->hdr.id, "NOTI", xfer->hdr.seq, 1108 1125 xfer->hdr.status, xfer->rx.buf, xfer->rx.len); 1109 - scmi_inc_count(info->dbg->counters, NOTIFICATION_OK); 1126 + scmi_inc_count(info->dbg, NOTIFICATION_OK); 1110 1127 1111 1128 scmi_notify(cinfo->handle, xfer->hdr.protocol_id, 1112 1129 xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts); ··· 1166 1183 if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) { 1167 1184 scmi_clear_channel(info, cinfo); 1168 1185 complete(xfer->async_done); 1169 - scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK); 1186 + scmi_inc_count(info->dbg, DELAYED_RESPONSE_OK); 1170 1187 } else { 1171 1188 complete(&xfer->done); 1172 - scmi_inc_count(info->dbg->counters, RESPONSE_OK); 1189 + scmi_inc_count(info->dbg, RESPONSE_OK); 1173 1190 } 1174 1191 1175 1192 if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { ··· 1279 1296 "timed out in resp(caller: %pS) - polling\n", 1280 1297 (void *)_RET_IP_); 1281 1298 ret = -ETIMEDOUT; 1282 - scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT); 1299 + scmi_inc_count(info->dbg, XFERS_RESPONSE_POLLED_TIMEOUT); 1283 1300 } 1284 1301 } 1285 1302 ··· 1304 1321 "RESP" : "resp", 1305 1322 xfer->hdr.seq, xfer->hdr.status, 1306 1323 xfer->rx.buf, xfer->rx.len); 1307 - scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK); 1324 + scmi_inc_count(info->dbg, RESPONSE_POLLED_OK); 1308 1325 1309 1326 if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { 1310 1327 scmi_raw_message_report(info->raw, xfer, ··· 1319 1336 dev_err(dev, "timed out in resp(caller: %pS)\n", 1320 1337 (void *)_RET_IP_); 1321 1338 ret = -ETIMEDOUT; 1322 - scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT); 1339 + scmi_inc_count(info->dbg, XFERS_RESPONSE_TIMEOUT); 1323 1340 } 1324 1341 } 1325 1342 ··· 1403 1420 !is_transport_polling_capable(info->desc)) { 1404 1421 dev_warn_once(dev, 1405 1422 "Polling mode is not supported by transport.\n"); 1406 - scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED); 1423 + scmi_inc_count(info->dbg, SENT_FAIL_POLLING_UNSUPPORTED); 1407 1424 return -EINVAL; 1408 1425 } 1409 1426 1410 1427 cinfo = idr_find(&info->tx_idr, pi->proto->id); 1411 1428 if (unlikely(!cinfo)) { 1412 - scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND); 1429 + scmi_inc_count(info->dbg, SENT_FAIL_CHANNEL_NOT_FOUND); 1413 1430 return -EINVAL; 1414 1431 } 1415 1432 /* True ONLY if also supported by transport. */ ··· 1444 1461 ret = info->desc->ops->send_message(cinfo, xfer); 1445 1462 if (ret < 0) { 1446 1463 dev_dbg(dev, "Failed to send message %d\n", ret); 1447 - scmi_inc_count(info->dbg->counters, SENT_FAIL); 1464 + scmi_inc_count(info->dbg, SENT_FAIL); 1448 1465 return ret; 1449 1466 } 1450 1467 1451 1468 trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, 1452 1469 xfer->hdr.id, "CMND", xfer->hdr.seq, 1453 1470 xfer->hdr.status, xfer->tx.buf, xfer->tx.len); 1454 - scmi_inc_count(info->dbg->counters, SENT_OK); 1471 + scmi_inc_count(info->dbg, SENT_OK); 1455 1472 1456 1473 ret = scmi_wait_for_message_response(cinfo, xfer); 1457 1474 if (!ret && xfer->hdr.status) { 1458 1475 ret = scmi_to_linux_errno(xfer->hdr.status); 1459 - scmi_inc_count(info->dbg->counters, ERR_PROTOCOL); 1476 + scmi_inc_count(info->dbg, ERR_PROTOCOL); 1460 1477 } 1461 1478 1462 1479 if (info->desc->ops->mark_txdone) ··· 3027 3044 u8 channels[SCMI_MAX_CHANNELS] = {}; 3028 3045 DECLARE_BITMAP(protos, SCMI_MAX_CHANNELS) = {}; 3029 3046 3030 - if (!info->dbg) 3031 - return -EINVAL; 3032 - 3033 3047 /* Enumerate all channels to collect their ids */ 3034 3048 idr_for_each_entry(&info->tx_idr, cinfo, id) { 3035 3049 /* ··· 3198 3218 if (!info->dbg) 3199 3219 dev_warn(dev, "Failed to setup SCMI debugfs.\n"); 3200 3220 3201 - if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { 3221 + if (info->dbg && IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { 3202 3222 ret = scmi_debugfs_raw_mode_setup(info); 3203 3223 if (!coex) { 3204 3224 if (ret) ··· 3402 3422 { 3403 3423 if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) { 3404 3424 struct scmi_info *info = handle_to_scmi_info(handle); 3425 + 3426 + if (!info->dbg) 3427 + return 0; 3405 3428 3406 3429 return atomic_read(&info->dbg->counters[XFERS_INFLIGHT]); 3407 3430 } else {