From: sashiko-bot@kernel.org
To: "Doug Ledford" <doug.ledford@hpe.com>,
"Slingshot Open Source Team"
<slingshot-os-team@groups.ext.hpe.com>,
"Nathan Chancellor" <nathan@kernel.org>,
"Nicolas Schier" <nsc@kernel.org>,
"Richard Cochran" <richardcochran@gmail.com>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Guenter Roeck" <linux@roeck-us.net>
Cc: linux-kbuild@vger.kernel.org
Subject: Re: [PATCH 07/23] net: hpe: sbl: add the SBM serial bus layer
Date: Sat, 31 Oct 2026 21:02:09 +0000 [thread overview]
Message-ID: <sashiko-outbox-192139@kernel.org> (raw)
In-Reply-To: <20261030-cxi-netdev-submission-v1-7-8c2c391cc283@hpe.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] net: hpe: sbl: mask before shift zeroes data in sbl_sbm_spico_int()
- [High] net: hpe: sbl: clobbered err and uninit result read in sbl_sbus_op_aux()
- [High] net: hpe: sbl: ABBA lock inversion in sbl_serdes_spico_int() via spico_reset
- [Low] net: hpe: sbl: non-static inline helpers in sbl_sbm.h lack prototypes
- [Low] net: hpe: sbl: excessive stack buffers in sbus_msg() and sbus_cmd_to_string()
--
commit 631299f2193252311d8e118f2c871a0e2587bd5a
Author: Doug Ledford <doug.ledford@hpe.com>
net: hpe: sbl: add the SBM serial bus layer
This commit adds the Serial Bus Master (SBM) layer for accessing SerDes
and PMI registers along with NIC-specific SerDes address helpers.
> diff --git a/drivers/net/ethernet/hpe/sbl/sbl_sbm_serdes.c b/drivers/net/ethernet/hpe/sbl/sbl_sbm_serdes.c
> new file mode 100644
> index 0000000000000..1d1c4d01e1598
> --- /dev/null
> +++ b/drivers/net/ethernet/hpe/sbl/sbl_sbm_serdes.c
> @@ -0,0 +1,1114 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/* Copyright 2025-2026 Hewlett Packard Enterprise Development LP. All Rights Reserved. */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +
> +#include <uapi/ethernet/sbl_sbm_constants.h>
> +
> +#include "sbl_sbm_serdes.h"
> +#include "sbl_serdes_map.h"
> +#include "sbl_sbm.h"
[Severity: Low]
In drivers/net/ethernet/hpe/sbl/sbl_sbm.h, the nine inline helper functions
(sbl_sbm_sbus_op(), sbl_sbm_sbus_op_reset(), sbl_sbm_pml_serdes_op(),
sbl_sbm_get_sbus_op_timeout_ms(), sbl_sbm_get_sbus_int_timeout(),
sbl_sbm_get_sbus_int_poll_interval(), sbl_sbm_get_serdes_op_timeout_ms(),
sbl_sbm_get_sbus_op_flags(), and sbl_sbm_get_serdes_op_flags()) are defined
with bare inline rather than static inline:
drivers/net/ethernet/hpe/sbl/sbl_sbm.h:
inline int sbl_sbm_sbus_op(struct sbl_inst *sbl, int ring, u32 req_data,
u8 data_addr, u8 rx_addr, u8 command,
u32 *rsp_data, u8 *result_code, u8 *overrun,
int timeout, u32 flags)
{
return sbl_sbus_op(sbl, ring, req_data, data_addr, rx_addr, command,
rsp_data, result_code, overrun, timeout, flags);
}
Because the kernel defines inline with __gnu_inline, bare inline functions
without static or extern have external linkage and emit out-of-line global
definitions without prior prototypes when sbl_sbm.h is included here.
Should these helpers in sbl_sbm.h be marked static inline to avoid
-Wmissing-prototypes and -Wmissing-declarations warnings (and multiple
definition errors if sbl_sbm.h is included elsewhere)?
[ ... ]
> +static void
> +sbus_cmd_to_string(u8 command, char *cmd_str)
> +{
> + char str0[SBL_MAX_STR_LEN], str1[SBL_MAX_STR_LEN], str2[SBL_MAX_STR_LEN];
> +
> + switch (command & SBUS_CMD_MODE_MASK) {
> + case SBUS_CMD_MODE_CTLR:
> + sprintf(str0, "CM_CTLR");
> + break;
> + case SBUS_CMD_MODE_RCVR:
> + sprintf(str0, "CM_RCVR");
> + break;
> + default:
> + sprintf(str0, "CM_UNKNOWN");
> + break;
> + }
[ ... ]
> + sprintf(cmd_str, "%s:%s:%s", str0, str1, str2);
> +}
[ ... ]
> +static void sbus_msg(void *inst, u32 sbus_addr, u32 req_data,
> + u8 reg_addr, u8 command, u32 rsp_data,
> + u8 result_code, u8 overrun, int timeout,
> + u32 flags, int rc, int severity)
> +{
> + struct sbl_inst *sbl = inst;
> + char sbus_addr_str[SBL_HALF_MAX_STR_LEN];
> + char reg_addr_str[SBL_HALF_MAX_STR_LEN];
> + char cmd_str[SBL_HALF_MAX_STR_LEN];
> + char rc_str[SBL_HALF_MAX_STR_LEN];
> + char message[SBL_MAX_STR_LEN];
> +
> + if (!sbl)
> + return;
> +
> + sbus_addr_to_string(sbus_addr, sbus_addr_str);
> + sbus_reg_addr_to_string(sbus_addr, reg_addr, reg_addr_str);
> + sbus_cmd_to_string(command, cmd_str);
[Severity: Low]
sbus_msg() allocates four SBL_HALF_MAX_STR_LEN (128-byte) arrays and one
SBL_MAX_STR_LEN (256-byte) array on the stack (768 bytes total), and its
single-caller helper sbus_cmd_to_string() allocates another three
SBL_MAX_STR_LEN (256-byte) arrays (768 bytes) just to copy string literals
before formatting them into the 128-byte cmd_str buffer.
When sbus_cmd_to_string() is inlined into sbus_msg(), the combined stack
frame exceeds 1536 bytes (and over 1792 bytes when called via
sbl_sbm_spico_int()), which triggers -Wframe-larger-than= warnings when
CONFIG_FRAME_WARN is 1024 or 1280.
Could sbus_cmd_to_string() use const char * pointers for str0, str1, and
str2 instead of stack arrays?
[ ... ]
> +int sbl_sbus_wr(void *inst, u32 sbus_addr, u8 reg_addr,
> + u32 sbus_data)
> +{
> + struct sbl_inst *sbl = inst;
> + u32 unused;
> +
> + return sbl_sbus_op_aux(sbl, sbus_addr, reg_addr, SBUS_IFACE_DST_CORE |
> + SBUS_CMD_WRITE, sbus_data, &unused);
> +}
[ ... ]
> +int sbl_sbus_op_aux(void *inst, u32 sbus_addr, u8 reg_addr,
> + u8 command, u32 sbus_data, u32 *result)
> +{
> + struct sbl_inst *sbl = inst;
> + u8 result_code = 0, overrun = 0;
> + int err = -1;
> + int retry_cnt = 0;
> + int retry_limit = 5;
> + u32 sbus_ring = SBUS_RING(sbus_addr);
> + u32 rx_addr = SBUS_RX_ADDR(sbus_addr);
> + bool valid_result = false;
> + int sbus_op_timeout_ms = sbl_sbm_get_sbus_op_timeout_ms(sbl);
> + int sbus_op_flags = sbl_sbm_get_sbus_op_flags(sbl);
> + void *accessor = sbl;
> +
> + if (!sbl->is_hw) {
> + *result = 0;
> + return 0;
> + }
> + /* Safety check */
> + if (!mutex_is_locked(SBUS_RING_MTX(sbl, sbus_ring))) {
> + sbus_msg(sbl, sbus_addr, sbus_data, reg_addr, command,
> + 0, result_code, overrun, sbus_op_timeout_ms,
> + sbus_op_flags, err, LEVEL_WARN);
> + WARN(1, "%s: Unlocked SBUS ring %d!", __func__, sbus_ring);
> + }
> +
> + /* Perform SBus operation */
> + while (retry_cnt++ < retry_limit) {
> + err = sbl_sbm_sbus_op(accessor, sbus_ring, sbus_data,
> + reg_addr, rx_addr, command, result,
> + &result_code, &overrun,
> + sbus_op_timeout_ms,
> + sbus_op_flags);
> + if (err) {
> + sbus_msg(sbl, sbus_addr, sbus_data, reg_addr, command,
> + 0, result_code, overrun, sbus_op_timeout_ms,
> + sbus_op_flags, err, LEVEL_WARN);
> + }
> + if (err || overrun) {
> + SBL_INFO(sbl->dev, "Resetting SBUS ring %d!", sbus_ring);
> + err = sbl_sbm_sbus_op_reset(sbl, sbus_ring);
> + if (err) {
> + SBL_WARN(sbl->dev,
> + "sbl_sbm_sbus_op_reset failed! sbus_ring:%d rc:%d",
> + sbus_ring, err);
> + return err;
> + }
> + } else {
> + break;
> + }
> + }
> +
> + /* Validate results */
> + if (err || overrun) {
> + SBL_WARN(sbl->dev, "roshms_sbus_op failed!");
> + return -EIO;
> + }
> + switch (command & 0x3) {
> + case SBUS_CMD_RESET:
> + if (result_code == SBUS_RC_RESET)
> + valid_result = true;
> +
> + break;
> + case SBUS_CMD_WRITE:
> + if (result_code == SBUS_RC_WRITE_COMPLETE)
> + valid_result = true;
> +
> + break;
> + case SBUS_CMD_READ:
> + if (result_code == SBUS_RC_READ_COMPLETE)
> + valid_result = true;
> +
> + break;
> + case SBUS_CMD_READ_RESULT:
> + if (result_code == SBUS_RC_READ_ALL_COMPLETE)
> + valid_result = true;
> +
> + break;
> + }
> +
> + if (!valid_result) {
> + SBL_WARN(sbl->dev, "Unexpected result code (%d) 0x%x!",
> + result_code, command);
> + sbus_msg(sbl, sbus_addr, sbus_data, reg_addr, command,
> + *result, result_code, overrun, sbus_op_timeout_ms,
> + sbus_op_flags, err, LEVEL_WARN);
> + return -ENOMSG;
> + }
> + sbus_msg(sbl, sbus_addr, sbus_data, reg_addr, command,
> + *result, result_code, overrun, sbus_op_timeout_ms,
> + sbus_op_flags, err, LEVEL_DBG);
> +
> + return 0;
> +}
[Severity: High]
In sbl_sbus_op_aux(), when sbl_sbm_sbus_op() fails (err != 0), the error
recovery path overwrites err with the return value of
sbl_sbm_sbus_op_reset(sbl, sbus_ring).
If sbl_sbm_sbus_op() fails on all 5 retries with overrun == 0 while
sbl_sbm_sbus_op_reset() succeeds (returns 0), the loop terminates with
err == 0 and overrun == 0, bypassing the post-loop if (err || overrun)
check.
Because result_code was initialized to 0 (which equals SBUS_RC_RESET), a
failed SBUS_CMD_RESET operation (such as in sbl_sbm_firm_upload() and
sbl_serdes_soft_reset()) will set valid_result = true and return 0
(success), while failed read or write operations will return -ENOMSG
instead of -EIO.
In addition, sbl_sbus_wr() (as well as sbl_sbm_firm_upload() and
sbl_serdes_soft_reset()) passes an uninitialized stack variable (u32 unused)
as result to sbl_sbus_op_aux(), which unconditionally dereferences *result
when calling sbus_msg() even if sbl_sbm_sbus_op() did not write to *result.
Should sbl_sbm_sbus_op_reset() use a separate return variable so err from
sbl_sbm_sbus_op() is preserved, and should *result (or unused in callers)
be initialized to 0 before the operation?
> +
> +/**
> + * sbl_sbm_spico_int() - spico intilization
> + * @inst: Generic pointer used by various framework
> + * @sbus_addr: address describing a serdes ring and rxaddr
> + * @code: interrupt command
> + * @data: interrupt data
> + * @result: location to store result of interrupt
> + *
> + * Write an interrupt request to a target SBM Spico
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int sbl_sbm_spico_int(void *inst, u32 sbus_addr, int code, int data,
> + u32 *result)
> +{
> + struct sbl_inst *sbl = inst;
> + int err;
> + u32 intr_out;
> + u32 intr_in;
> + char intr_str[SBL_MAX_STR_LEN];
> + int sbus_int_timeout = sbl_sbm_get_sbus_int_timeout(sbl);
> + int sbus_int_poll_interval = sbl_sbm_get_sbus_int_poll_interval(sbl);
> + unsigned long last_jiffy;
> + u32 sbus_ring = SBUS_RING(sbus_addr);
> +
> + if (!sbl->is_hw) {
> + *result = 0;
> + return 0;
> + }
> + /* Safety check */
> + if (!mutex_is_locked(SBUS_RING_MTX(sbl, sbus_ring))) {
> + SBL_WARN(sbl->dev, "%s: Unlocked SBUS ring %d!", __func__, sbus_ring);
> + WARN(1, "sbl_sbus_op_aux: Unlocked SBUS ring %d!", sbus_ring);
> + }
> +
> + spico_interrupt_to_string(sbus_addr, code, intr_str);
> +
> + /* Inject the interrupt via SBus writes */
> + intr_in = ((data & SBMS_INTERRUPT_DATA_MASK) << SBMS_INTERRUPT_DATA_OFFSET) |
> + ((code & SBMS_INTERRUPT_CODE_MASK) << SBMS_INTERRUPT_CODE_OFFSET);
[Severity: High]
In include/uapi/ethernet/sbl_sbm_constants.h, SBMS_INTERRUPT_DATA_MASK is
defined as the already-shifted upper 16-bit mask:
#define SBMS_INTERRUPT_DATA_MASK 0xffff0000
#define SBMS_INTERRUPT_DATA_OFFSET 16
which matches how sbl_sbm_spico_int() extracts the result further down:
*result = (intr_out & SBMS_INTERRUPT_DATA_MASK) >>
SBMS_INTERRUPT_DATA_OFFSET;
When packing intr_in above, masking the 32-bit data with 0xffff0000 before
shifting left by 16 clears bits 15:0 and then shifts bits 31:16 out of the
32-bit word, so the data portion always evaluates to 0.
Should this shift data before masking with SBMS_INTERRUPT_DATA_MASK:
intr_in = ((data << SBMS_INTERRUPT_DATA_OFFSET) & SBMS_INTERRUPT_DATA_MASK) |
((code << SBMS_INTERRUPT_CODE_OFFSET) & SBMS_INTERRUPT_CODE_MASK);
so that the interrupt data payload is not zeroed out?
[ ... ]
> +int sbl_serdes_spico_int(void *inst, u32 port_num, u32 serdes,
> + int code, int data, u16 *result, u8 result_action)
> +{
> + struct sbl_inst *sbl = inst;
> + int err;
> + char intr_str[SBL_MAX_STR_LEN];
> + u16 result_out = 0;
> + u16 *p_result;
> + u32 sbus_addr;
> + int serdes_op_timeout_ms = sbl_sbm_get_serdes_op_timeout_ms(sbl);
> + int serdes_op_flags = sbl_sbm_get_serdes_op_flags(sbl);
> + void *accessor = sbl;
> +
> + if ((result_action == SPICO_INT_RETURN_RESULT) && (result == NULL)) {
> + SBL_ERR(sbl->dev, "result pointer was NULL!");
> + return -1;
> + }
> + if (result_action != SPICO_INT_RETURN_RESULT)
> + p_result = &result_out;
> + else
> + p_result = result;
> +
> + if (!sbl->is_hw) {
> + *p_result = code;
> + return 0;
> + }
> + /* Make a fake SerDes sbus_addr so spico_interrupt_to_string gives us the
> + right debug string. This function is only called for CM4 SerDes, so this
> + will always give the correct string. */
> + sbl_sbus_addr_get(&sbus_addr);
> + spico_interrupt_to_string(sbus_addr, code, intr_str);
> +
> + err = sbl_sbm_pml_serdes_op(accessor, port_num, serdes, code,
> + data, p_result, serdes_op_timeout_ms,
> + serdes_op_flags);
[Severity: High]
Can calling sbl_sbm_pml_serdes_op() here cause an ABBA deadlock between
sbl->link[port_num].serdes_mtx and SBUS_RING_MTX(sbl, sbus_ring)?
In drivers/net/ethernet/hpe/sbl/sbl_serdes_fn.c, sbl_serdes_soft_reset()
and sbl_serdes_firm_upload() acquire serdes_mtx before sbus_ring_mtx:
sbl_serdes_soft_reset()
mutex_lock(&sbl->link[port_num].serdes_mtx);
mutex_lock(SBUS_RING_MTX(sbl, sbus_ring));
However, sbl_spico_reset() (called from sbl_serdes_stop_internal() and
sbl_test_serdes_stop()) acquires SBUS_RING_MTX(sbl, sbus_ring) first and
then calls sbl_serdes_spico_int() -> sbl_sbm_pml_serdes_op() ->
sbl_pml_serdes_op(), which locks &link->serdes_mtx:
sbl_spico_reset()
mutex_lock(SBUS_RING_MTX(sbl, sbus_ring));
sbl_serdes_spico_int()
sbl_sbm_pml_serdes_op()
sbl_pml_serdes_op()
mutex_lock_interruptible(&link->serdes_mtx);
This inverts the lock order to sbus_ring_mtx -> serdes_mtx. Should
sbl_spico_reset() and its callers follow the serdes_mtx -> sbus_ring_mtx
lock hierarchy (or release sbus_ring_mtx before invoking
sbl_serdes_spico_int())?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261030-cxi-netdev-submission-v1-0-8c2c391cc283@hpe.com?part=7
next prev parent reply other threads:[~2026-10-31 21:02 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 20:58 [PATCH 00/23] Subject: [PATCH net-next 00/23] net/hpe: add HPE Slingshot NIC drivers Doug Ledford
2026-10-30 20:58 ` [PATCH 01/23] net: hpe: ss1: add the Cassini headers Doug Ledford
2026-10-31 13:58 ` Andrew Lunn
2026-10-31 19:34 ` Doug Ledford
2026-10-30 20:58 ` [PATCH 02/23] net: hpe: sbl: add the Slingshot Base Link headers Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:58 ` [PATCH 03/23] net: hpe: sbl: add the core instance and configuration layer Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 04/23] net: hpe: sbl: add the SerDes layer Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 05/23] net: hpe: sbl: add the PML link layer Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 06/23] net: hpe: sbl: add link state management Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 07/23] net: hpe: sbl: add the SBM serial bus layer Doug Ledford
2026-10-31 21:02 ` sashiko-bot [this message]
2026-10-30 20:59 ` [PATCH 08/23] net: hpe: sbl: add media, FEC and counter support Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 09/23] net: hpe: sl: add the Slingshot Link headers Doug Ledford
2026-10-30 20:59 ` [PATCH 10/23] net: hpe: sl: add the module entry points Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 11/23] net: hpe: sl: add the core link state machines Doug Ledford
2026-10-30 20:59 ` [PATCH 12/23] net: hpe: sl: add the control layer Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 13/23] net: hpe: sl: add media and cable handling Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 14/23] net: hpe: sl: add the sysfs interface Doug Ledford
2026-10-30 20:59 ` [PATCH 15/23] net: hpe: sl: add the NIC binding and logging helpers Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 16/23] net: hpe: ss1: add the Cassini core device layer Doug Ledford
2026-10-30 20:59 ` [PATCH 17/23] net: hpe: ss1: add the datapath and memory translation layers Doug Ledford
2026-10-30 20:59 ` [PATCH 18/23] net: hpe: ss1: add the link layer glue Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 19/23] net: hpe: ss1: add SR-IOV support Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 20/23] net: hpe: ss1: add the CXI core interfaces Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 21/23] net: hpe: ss1: add resource groups, QoS and services Doug Ledford
2026-10-30 20:59 ` [PATCH 22/23] net: hpe: ss1: add the Ethernet personality Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 20:59 ` [PATCH 23/23] net: hpe: wire up the Slingshot NIC drivers Doug Ledford
2026-10-31 21:02 ` sashiko-bot
2026-10-30 22:11 ` [PATCH 00/23] Subject: [PATCH net-next 00/23] net/hpe: add HPE " Jakub Kicinski
2026-10-31 20:17 ` Andrew Lunn
2026-11-02 1:02 ` Doug Ledford
2026-11-02 1:35 ` Andrew Lunn
2026-11-02 3:45 ` Doug Ledford
2026-11-02 14:26 ` Andrew Lunn
2026-11-02 3:01 ` Guenter Roeck
2026-11-02 17:01 ` Doug Ledford
2026-11-02 17:39 ` Andrew Lunn
2026-11-02 18:12 ` Doug Ledford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-192139@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=christian.koenig@amd.com \
--cc=davem@davemloft.net \
--cc=doug.ledford@hpe.com \
--cc=edumazet@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=slingshot-os-team@groups.ext.hpe.com \
--cc=sumit.semwal@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox