mirror of https://github.com/torvalds/linux.git
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.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmjvtCIACgkQAEG6vDF+
4phtFw//em6TYEkBTgJVq94ULfLcuzOVRwH+WmhK1VaXKz0jLlzrN6sVEiJnwQA3
p9gDIJ+TjXozgVZzBa5eZIfeP/BmbPSPtsSGDlvhQl5smT4r/CG7fS17VhFNGx/o
6DYP8X44Fx3qGuDe3tJiuw9F7IaXmDE03uslD7a9MdtPR2K1KwfD/Y6fXmZbx36B
M67E48dyWQymE0gDnYupQtUe7+JENDHYXuLySMfAEjk7+Fjis/u5aFXH2aCWAM5P
PV1VVAq4f8QEs2sI3Lwd45cJsYBu4dEpKTTWEpBc1vASkdFhUIXJ9FUKVvNunwi1
yW038FsyRsmnc+4Aq7Aj0hAJsyaFEogHMS6zqoTX/0QGjKPdrHgS+CkBNk7OTDyo
WlBAi4HbInIzYDC8tbo1hiXBvcZzZnPvbFCEpi521W1bJN79hhflC09mNg5uRI+T
obkmVMjlYq4vH+kY56cfVTVoejG38T3S5UYp97NmmP4/ilxpJ7oeoSLO3vC2IE7F
GN9mOqHpbwdpN4zN259bepBkrRbySUlPi9MB+HvdBJZqxEbedkuOPtBQUiYA2Opf
Xcg1WcHEdImrMyjJkYPk92MtWaHpTDZ6WlKe00oK7YJS+qpNaO5uOTvtbtOZsMwW
MBvrdxBBcmZpZiosjMQPNXHMi/P8UeswLBrjqjzznUnwteOLyUE=
=2mq1
-----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmj6kE0ACgkQmmx57+YA
GNlItw/+KprSMkb+gVY8DgCgMXpku4ObDwryI16UbBxjIVlLlhE0mc58vooY43nz
NQLZ9GU7rQygVr8mEK0LxWMt7Fm0x8w/omvwgsKuPVifNCGWEvOlEXqJGGLoThGB
msU3CJDPDo0C3bgXDu9sbQZOxEYMnIwqnBzUuuzHxiftGP14XevSjy/dlCjSRy0K
DlfIxZaQY0Rwhe5XoH6TLC99QHNRvvP1MmoMyerzTi91Lwvcx98URgZta7N230Me
R9uQLStxKyBRDIW+Z0uDnCDAltQvy3UHtGd240GS9aK1Cs2tbBQ9G79hHEMfj/us
N7cgDFZHEHuTk8d71bMSiwmoQLFsmjbAAS6pBUbE3K3WP76w37N7/cIA78WVvG1O
FcIDM0cTePHimlI9bDF12GJ1tT6punh6NtjBJVGx1NIjo9LFJaTx1rBC/BgQzIY7
Um1eF76/ciZK3gOnlPRrYSuAEIhoPSxRIgOBlWLCuAZmjW5v/F3SdqNPkZ8i5Oo/
PkJEIPIT2nFEtvGg34RcRsh/9OtGQi03HM7/iFuc8dCUuJDwj/h7luN5FOCwcQqE
Cu1eEqWIWiE0rdI4pjmzTXRHqH8LrWk7oTakrvL9WWGdjF72Ceay3Z0disFDPN1c
85N5mXohiznQsdv+p62DnyW4ZoRn6uOy9YpJjRAN+5PezV5nXDc=
=12z8
-----END PGP SIGNATURE-----
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>
This commit is contained in:
commit
71a5970259
|
|
@ -309,16 +309,36 @@ enum debug_counters {
|
|||
SCMI_DEBUG_COUNTERS_LAST
|
||||
};
|
||||
|
||||
static inline void scmi_inc_count(atomic_t *arr, int stat)
|
||||
/**
|
||||
* struct scmi_debug_info - Debug common info
|
||||
* @top_dentry: A reference to the top debugfs dentry
|
||||
* @name: Name of this SCMI instance
|
||||
* @type: Type of this SCMI instance
|
||||
* @is_atomic: Flag to state if the transport of this instance is atomic
|
||||
* @counters: An array of atomic_c's used for tracking statistics (if enabled)
|
||||
*/
|
||||
struct scmi_debug_info {
|
||||
struct dentry *top_dentry;
|
||||
const char *name;
|
||||
const char *type;
|
||||
bool is_atomic;
|
||||
atomic_t counters[SCMI_DEBUG_COUNTERS_LAST];
|
||||
};
|
||||
|
||||
static inline void scmi_inc_count(struct scmi_debug_info *dbg, int stat)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS))
|
||||
atomic_inc(&arr[stat]);
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) {
|
||||
if (dbg)
|
||||
atomic_inc(&dbg->counters[stat]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scmi_dec_count(atomic_t *arr, int stat)
|
||||
static inline void scmi_dec_count(struct scmi_debug_info *dbg, int stat)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS))
|
||||
atomic_dec(&arr[stat]);
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) {
|
||||
if (dbg)
|
||||
atomic_dec(&dbg->counters[stat]);
|
||||
}
|
||||
}
|
||||
|
||||
enum scmi_bad_msg {
|
||||
|
|
|
|||
|
|
@ -115,22 +115,6 @@ struct scmi_protocol_instance {
|
|||
|
||||
#define ph_to_pi(h) container_of(h, struct scmi_protocol_instance, ph)
|
||||
|
||||
/**
|
||||
* struct scmi_debug_info - Debug common info
|
||||
* @top_dentry: A reference to the top debugfs dentry
|
||||
* @name: Name of this SCMI instance
|
||||
* @type: Type of this SCMI instance
|
||||
* @is_atomic: Flag to state if the transport of this instance is atomic
|
||||
* @counters: An array of atomic_c's used for tracking statistics (if enabled)
|
||||
*/
|
||||
struct scmi_debug_info {
|
||||
struct dentry *top_dentry;
|
||||
const char *name;
|
||||
const char *type;
|
||||
bool is_atomic;
|
||||
atomic_t counters[SCMI_DEBUG_COUNTERS_LAST];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_info - Structure representing a SCMI instance
|
||||
*
|
||||
|
|
@ -610,7 +594,7 @@ scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer,
|
|||
/* Set in-flight */
|
||||
set_bit(xfer->hdr.seq, minfo->xfer_alloc_table);
|
||||
hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq);
|
||||
scmi_inc_count(info->dbg->counters, XFERS_INFLIGHT);
|
||||
scmi_inc_count(info->dbg, XFERS_INFLIGHT);
|
||||
|
||||
xfer->pending = true;
|
||||
}
|
||||
|
|
@ -819,8 +803,9 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer)
|
|||
hash_del(&xfer->node);
|
||||
xfer->pending = false;
|
||||
|
||||
scmi_dec_count(info->dbg->counters, XFERS_INFLIGHT);
|
||||
scmi_dec_count(info->dbg, XFERS_INFLIGHT);
|
||||
}
|
||||
xfer->flags = 0;
|
||||
hlist_add_head(&xfer->node, &minfo->free_xfers);
|
||||
}
|
||||
spin_unlock_irqrestore(&minfo->xfer_lock, flags);
|
||||
|
|
@ -839,8 +824,6 @@ void scmi_xfer_raw_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
|
|||
{
|
||||
struct scmi_info *info = handle_to_scmi_info(handle);
|
||||
|
||||
xfer->flags &= ~SCMI_XFER_FLAG_IS_RAW;
|
||||
xfer->flags &= ~SCMI_XFER_FLAG_CHAN_SET;
|
||||
return __scmi_xfer_put(&info->tx_minfo, xfer);
|
||||
}
|
||||
|
||||
|
|
@ -1034,7 +1017,7 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr)
|
|||
spin_unlock_irqrestore(&minfo->xfer_lock, flags);
|
||||
|
||||
scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED);
|
||||
scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED);
|
||||
scmi_inc_count(info->dbg, ERR_MSG_UNEXPECTED);
|
||||
|
||||
return xfer;
|
||||
}
|
||||
|
|
@ -1062,7 +1045,7 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr)
|
|||
msg_type, xfer_id, msg_hdr, xfer->state);
|
||||
|
||||
scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID);
|
||||
scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID);
|
||||
scmi_inc_count(info->dbg, ERR_MSG_INVALID);
|
||||
|
||||
/* On error the refcount incremented above has to be dropped */
|
||||
__scmi_xfer_put(minfo, xfer);
|
||||
|
|
@ -1107,7 +1090,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
|||
PTR_ERR(xfer));
|
||||
|
||||
scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM);
|
||||
scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM);
|
||||
scmi_inc_count(info->dbg, ERR_MSG_NOMEM);
|
||||
|
||||
scmi_clear_channel(info, cinfo);
|
||||
return;
|
||||
|
|
@ -1123,7 +1106,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
|||
trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id,
|
||||
xfer->hdr.id, "NOTI", xfer->hdr.seq,
|
||||
xfer->hdr.status, xfer->rx.buf, xfer->rx.len);
|
||||
scmi_inc_count(info->dbg->counters, NOTIFICATION_OK);
|
||||
scmi_inc_count(info->dbg, NOTIFICATION_OK);
|
||||
|
||||
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
|
||||
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
|
||||
|
|
@ -1183,10 +1166,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
|
|||
if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) {
|
||||
scmi_clear_channel(info, cinfo);
|
||||
complete(xfer->async_done);
|
||||
scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK);
|
||||
scmi_inc_count(info->dbg, DELAYED_RESPONSE_OK);
|
||||
} else {
|
||||
complete(&xfer->done);
|
||||
scmi_inc_count(info->dbg->counters, RESPONSE_OK);
|
||||
scmi_inc_count(info->dbg, RESPONSE_OK);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
|
||||
|
|
@ -1296,7 +1279,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
|
|||
"timed out in resp(caller: %pS) - polling\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT);
|
||||
scmi_inc_count(info->dbg, XFERS_RESPONSE_POLLED_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1321,7 +1304,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
|
|||
"RESP" : "resp",
|
||||
xfer->hdr.seq, xfer->hdr.status,
|
||||
xfer->rx.buf, xfer->rx.len);
|
||||
scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK);
|
||||
scmi_inc_count(info->dbg, RESPONSE_POLLED_OK);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
|
||||
scmi_raw_message_report(info->raw, xfer,
|
||||
|
|
@ -1336,7 +1319,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
|
|||
dev_err(dev, "timed out in resp(caller: %pS)\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT);
|
||||
scmi_inc_count(info->dbg, XFERS_RESPONSE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1420,13 +1403,13 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||
!is_transport_polling_capable(info->desc)) {
|
||||
dev_warn_once(dev,
|
||||
"Polling mode is not supported by transport.\n");
|
||||
scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED);
|
||||
scmi_inc_count(info->dbg, SENT_FAIL_POLLING_UNSUPPORTED);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cinfo = idr_find(&info->tx_idr, pi->proto->id);
|
||||
if (unlikely(!cinfo)) {
|
||||
scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND);
|
||||
scmi_inc_count(info->dbg, SENT_FAIL_CHANNEL_NOT_FOUND);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* True ONLY if also supported by transport. */
|
||||
|
|
@ -1461,19 +1444,19 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||
ret = info->desc->ops->send_message(cinfo, xfer);
|
||||
if (ret < 0) {
|
||||
dev_dbg(dev, "Failed to send message %d\n", ret);
|
||||
scmi_inc_count(info->dbg->counters, SENT_FAIL);
|
||||
scmi_inc_count(info->dbg, SENT_FAIL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id,
|
||||
xfer->hdr.id, "CMND", xfer->hdr.seq,
|
||||
xfer->hdr.status, xfer->tx.buf, xfer->tx.len);
|
||||
scmi_inc_count(info->dbg->counters, SENT_OK);
|
||||
scmi_inc_count(info->dbg, SENT_OK);
|
||||
|
||||
ret = scmi_wait_for_message_response(cinfo, xfer);
|
||||
if (!ret && xfer->hdr.status) {
|
||||
ret = scmi_to_linux_errno(xfer->hdr.status);
|
||||
scmi_inc_count(info->dbg->counters, ERR_PROTOCOL);
|
||||
scmi_inc_count(info->dbg, ERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (info->desc->ops->mark_txdone)
|
||||
|
|
@ -3044,9 +3027,6 @@ static int scmi_debugfs_raw_mode_setup(struct scmi_info *info)
|
|||
u8 channels[SCMI_MAX_CHANNELS] = {};
|
||||
DECLARE_BITMAP(protos, SCMI_MAX_CHANNELS) = {};
|
||||
|
||||
if (!info->dbg)
|
||||
return -EINVAL;
|
||||
|
||||
/* Enumerate all channels to collect their ids */
|
||||
idr_for_each_entry(&info->tx_idr, cinfo, id) {
|
||||
/*
|
||||
|
|
@ -3218,7 +3198,7 @@ static int scmi_probe(struct platform_device *pdev)
|
|||
if (!info->dbg)
|
||||
dev_warn(dev, "Failed to setup SCMI debugfs.\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
|
||||
if (info->dbg && IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
|
||||
ret = scmi_debugfs_raw_mode_setup(info);
|
||||
if (!coex) {
|
||||
if (ret)
|
||||
|
|
@ -3423,6 +3403,9 @@ int scmi_inflight_count(const struct scmi_handle *handle)
|
|||
if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) {
|
||||
struct scmi_info *info = handle_to_scmi_info(handle);
|
||||
|
||||
if (!info->dbg)
|
||||
return 0;
|
||||
|
||||
return atomic_read(&info->dbg->counters[XFERS_INFLIGHT]);
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue