Linux kbuild/kconfig development
 help / color / mirror / Atom feed
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,
	"Sandeep Bhoot" <sandeep.bhoot@hpe.com>,
	"Mamila Santosh" <santosh-kumar.mamila@hpe.com>
Subject: Re: [PATCH 05/23] net: hpe: sbl: add the PML link layer
Date: Sat, 31 Oct 2026 21:02:06 +0000	[thread overview]
Message-ID: <sashiko-outbox-192137@kernel.org> (raw)
In-Reply-To: <20261030-cxi-netdev-submission-v1-5-8c2c391cc283@hpe.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] net: hpe: sbl: non-raw spinlock_t acquired in TIMER_IRQSAFE recovery timer
- [Medium] net: hpe: sbl: down_origin overwritten after degrade failure in sbl_pml_hdlr()
- [Medium] net: hpe: sbl: race in sbl_pml_recovery_monitor_fallback_timer() drops faults
- [Medium] net: hpe: sbl: non-zero llr_loop_time left on error in sbl_pml_llr_start()
- [Medium] net: hpe: sbl: stale link->llr_options across restarts in sbl_pml_llr_config()
- [Medium] net: hpe: sbl: missing link_info flag update in sbl_pml_llr_enable()
- [Low] net: hpe: sbl: duplicate state flag in sbl_pml_pcs_am_start()
--

commit aeafa8bdeb0e8da16241c976b7c17b49fa65d4a5
Author: Doug Ledford <doug.ledford@hpe.com>

net: hpe: sbl: add the PML link layer

This commit adds the physical media layer (PML) implementation for the HPE
Slingshot base link driver, covering MAC, PCS, LLR configuration, and SerDes
operation hooks.

> diff --git a/drivers/net/ethernet/hpe/sbl/sbl_pml.c b/drivers/net/ethernet/hpe/sbl/sbl_pml.c
> new file mode 100644
> index 0000000000000..367c3184fb799
> --- /dev/null
> +++ b/drivers/net/ethernet/hpe/sbl/sbl_pml.c
> @@ -0,0 +1,787 @@

[ ... ]

> +static void sbl_pml_recovery_monitor_fallback_timer(struct timer_list *t)
> +{
> +	struct sbl_pml_recovery *pml_recovery = container_of(t, struct sbl_pml_recovery, timer);
> +	struct sbl_inst *sbl;
> +	struct sbl_link *link;
> +	int port_num;
> +	enum sbl_link_down_origin down_origin;
> +	u32 elapsed;
> +	u32 rl_total_time;
> +	unsigned long timeout;
> +	unsigned long irq_flags;
> +
> +	if (!pml_recovery || !pml_recovery->sbl)
> +		return;
> +
> +	spin_lock_irqsave(&pml_recovery->lock, irq_flags);
> +	if (!pml_recovery->enabled || !pml_recovery->started) {
> +		spin_unlock_irqrestore(&pml_recovery->lock, irq_flags);
> +		return;
> +	}
> +	spin_unlock_irqrestore(&pml_recovery->lock, irq_flags);
> +
> +	sbl = pml_recovery->sbl;
> +	port_num = pml_recovery->port_num;
> +	down_origin = pml_recovery->down_origin;
> +	link = sbl->link + port_num;
> +	timeout = pml_recovery->init_jiffies + msecs_to_jiffies(pml_recovery->timeout);
> +	elapsed = jiffies_to_msecs(jiffies - link->pml_recovery.init_jiffies);
> +	link->pml_recovery.rl_time_remaining -=
> +		jiffies_to_msecs(jiffies -
> +				 link->pml_recovery.last_poll_jiffies);
> +	link->pml_recovery.last_poll_jiffies  = jiffies;
> +
> +	if (sbl_pml_recovery_no_faults(sbl, port_num)) {
> +		sbl_dev_info(sbl->dev, "%d: PML recovered successfully in %ums", port_num, elapsed);
> +		sbl_link_counters_incr(sbl, port_num, pml_recovery_successes);
> +		sbl_pml_recovery_origin_counter_update(sbl, port_num, down_origin);
> +		sbl_link_counters_incr(sbl, port_num, (elapsed < SBL_PML_REC_HISTOGRAM_MAX) ?
> +				      (pml_recovery_histogram_0_9ms + elapsed / 10) :
> +				       pml_recovery_histogram_high);
> +		goto out;
> +	} else if (time_is_before_eq_jiffies(timeout)) {
> +		sbl_dev_info(sbl->dev, "%d: PML recovery monitor timed out (%ums)", port_num, elapsed);
> +		goto out_fail;
> +	} else if (!sbl_pml_recovery_rate_test(sbl, port_num)) {
> +		rl_total_time = link->blattr.pml_recovery.rl_max_duration - link->pml_recovery.rl_time_remaining;
> +		sbl_dev_err(sbl->dev, "%d: PML recovery rate exceeded (%ums/%ums) after %ums", port_num, rl_total_time,
> +			    link->blattr.pml_recovery.rl_window_size, elapsed);
> +		sbl_link_counters_incr(sbl, port_num, pml_recovery_rate_exceeded);
> +		goto out_fail;
> +	}
> +
> +	/* start timer for next poll */
> +	spin_lock_irqsave(&pml_recovery->lock, irq_flags);
> +	if (pml_recovery->enabled)
> +		mod_timer(&pml_recovery->timer,
> +			  jiffies + msecs_to_jiffies(SBL_PML_REC_POLL_INTERVAL));
> +	spin_unlock_irqrestore(&pml_recovery->lock, irq_flags);
> +	return;
> +
> +out_fail:
> +	sbl_pml_link_down_async_alert(sbl, port_num, down_origin);
> +
> +out:
> +	spin_lock_irqsave(&link->fec_discard_lock, irq_flags);
> +	link->fec_discard_time = jiffies;
> +	link->fec_discard_type = SBL_FEC_DISCARD_TYPE_PML_REC_END;
> +	spin_unlock_irqrestore(&link->fec_discard_lock, irq_flags);
> +	spin_lock_irqsave(&pml_recovery->lock, irq_flags);
> +	pml_recovery->started = false;
> +	spin_unlock_irqrestore(&pml_recovery->lock, irq_flags);
> +}

[Severity: Medium]
Can releasing pml_recovery->lock before polling hardware status and only
clearing pml_recovery->started at the end of
sbl_pml_recovery_monitor_fallback_timer() cause a concurrent fault interrupt
to be dropped?

After sbl_pml_recovery_no_faults() reads SBL_PML_STS_RX_PCS_OFFSET and
returns true, the callback logs recovery success, updates counters, and
takes link->fec_discard_lock before re-acquiring pml_recovery->lock to set
pml_recovery->started = false.

If a new fault interrupt arrives in sbl_pml_hdlr() during that window:

CPU0 (timer)                                  CPU1 (interrupt)
sbl_pml_recovery_monitor_fallback_timer()
  sbl_pml_recovery_no_faults() -> true
                                              sbl_pml_hdlr()
                                                sbl_pml_recovery_monitor()
                                                  if (!recovery->enabled ||
                                                      recovery->started)
                                                    return;
                                                sbl_write64(... SBL_PML_ERR_CLR_OFFSET,
                                                            raised_flgs);
  pml_recovery->started = false;

Wouldn't sbl_pml_recovery_monitor() return early without restarting alignment
or arming the timer while sbl_pml_hdlr() clears the hardware error flag?

Also, on the out_fail path, sbl_pml_link_down_async_alert() is called without
re-checking pml_recovery->enabled, and rl_time_remaining, last_poll_jiffies,
and rl_window_start are updated without holding pml_recovery->lock. If
sbl_pml_recovery_cancel() sets recovery->enabled = false and waits in
timer_delete_sync(), could out_fail still emit a spurious link-down alert?

> +
> +void sbl_pml_recovery_init(struct sbl_pml_recovery *recovery)
> +{
> +	spin_lock_init(&recovery->lock);
> +	recovery->enabled = false;
> +	timer_setup(&recovery->timer, sbl_pml_recovery_monitor_fallback_timer,
> +		    TIMER_IRQSAFE);
> +}

[Severity: High]
Does setting up recovery->timer with TIMER_IRQSAFE in sbl_pml_recovery_init()
trigger an invalid wait context warning on PREEMPT_RT?

Because TIMER_IRQSAFE callbacks run with hardware interrupts disabled,
sbl_pml_recovery_monitor_fallback_timer() acquires non-raw spinlock_t locks
(pml_recovery->lock, link->fec_discard_lock, and sbl->name_lock via
sbl_dev_info() and sbl_dev_err()) while IRQs are disabled. Since
sbl_pml_recovery_cancel() is called from process context, is TIMER_IRQSAFE
needed here?

[ ... ]

> +int sbl_pml_hdlr(struct sbl_inst *sbl, int port_num, void *data)
> +{

[ ... ]

> +	result = SBL_PML_ERR_FLG_PCS_TX_DEGRADE_FAILURE_GET(raised_flgs);
> +
> +	if (result) {
> +		alert = SBL_ASYNC_ALERT_TX_DEGRADE_FAILURE;
> +		sbl_async_alert(sbl, port_num, alert, NULL, 0);
> +	}
> +
> +	result = SBL_PML_ERR_FLG_PCS_RX_DEGRADE_FAILURE_GET(raised_flgs);
> +
> +	if (result) {
> +		alert = SBL_ASYNC_ALERT_RX_DEGRADE_FAILURE;
> +		sbl_async_alert(sbl, port_num, alert, NULL, 0);
> +	}
> +
> +	if (alert != SBL_ASYNC_ALERT_INVALID) {
> +		/* if Auto Lane Degrade is enabled, we will print this message regardless of whether
> +		 * the link went down because of lane degrade failure or not
> +		 */
> +		sbl_dev_err(sbl->dev, "%d: pml hdlr - link going down - all lanes down [%d]", port_num, alert);
> +		down_origin = SBL_LINK_DOWN_ORIGIN_DEGRADE_FAILURE;
> +	}
> +
> +	/* autoneg err flags */
> +	if (raised_flgs & SBL_AUTONEG_ERR_FLGS) {
> +		sbl_pml_disable_intr_handler(sbl, port_num, SBL_AUTONEG_ERR_FLGS);
> +		complete(&link->an_hw_change);
> +	}
> +
> +	/* link faults */
> +	if (SBL_PML_ERR_FLG_PCS_HI_SER_GET(raised_flgs)) {
> +		if (sbl_debug_option(sbl, port_num, SBL_DEBUG_IGNORE_HISER)) {
> +			sbl_dev_warn(sbl->dev, "%d: pml hdlr - hiser - ignored", port_num);
> +		} else {
> +			sbl_dev_dbg(sbl->dev, "%d: pml hdlr - hiser", port_num);
> +			down_origin = SBL_LINK_DOWN_ORIGIN_HISER;
> +		}
> +	}
> +
> +	val64 = sbl_read64(sbl, base | SBL_PML_CFG_LLR_SM_OFFSET);
> +	if (SBL_PML_ERR_FLG_LLR_REPLAY_AT_MAX_GET(raised_flgs) &&
> +	    SBL_PML_CFG_LLR_SM_REPLAY_CT_MAX_GET(val64) < SBL_LLR_REPLAY_CT_MAX_UNLIMITED) {
> +		sbl_dev_dbg(sbl->dev, "%d: pml hdlr - max llr replay", port_num);
> +		down_origin = SBL_LINK_DOWN_ORIGIN_LLR_MAX;
> +	}
> +
> +	if (SBL_PML_ERR_FLG_PCS_LINK_DOWN_GET(raised_flgs)) {
> +		val64 = sbl_read64(sbl, base | SBL_PML_STS_RX_PCS_OFFSET);
> +
> +		if (sbl_debug_option(sbl, port_num, SBL_DEBUG_TRACE_PML_INT)) {
> +			sbl_dev_info(sbl->dev, "%d: pml hdlr - link down (%s)", port_num,
> +				     sbl_pml_pcs_state_str(sbl, port_num, pcs_state_str,
> +							   SBL_PCS_STATE_STR_LEN));
> +		}
> +
> +		if (!SBL_PML_STS_RX_PCS_ALIGN_STATUS_GET(val64)) {
> +			if (sbl_debug_option(sbl, port_num, SBL_DEBUG_IGNORE_ALIGN)) {
> +				sbl_dev_warn(sbl->dev, "%d: pml hdlr - align - ignored", port_num);
> +			} else {
> +				sbl_dev_dbg(sbl->dev, "%d: pml hdlr - align", port_num);
> +				down_origin = SBL_LINK_DOWN_ORIGIN_ALIGN;
> +			}
> +		} else if (SBL_PML_STS_RX_PCS_LOCAL_FAULT_GET(val64)) {
> +			sbl_dev_dbg(sbl->dev, "%d: pml hdlr - local fault", port_num);
> +			down_origin = SBL_LINK_DOWN_ORIGIN_LOCAL_FAULT;
> +		} else if (SBL_PML_STS_RX_PCS_FAULT_GET(val64)) {
> +			if (link->blattr.options & SBL_DISABLE_PML_RECOVERY ||
> +			    sbl_debug_option(sbl, port_num, SBL_DEBUG_REMOTE_FAULT_RECOVERY)) {
> +				sbl_dev_dbg(sbl->dev, "%d: pml hdlr - remote fault", port_num);
> +				down_origin = SBL_LINK_DOWN_ORIGIN_REMOTE_FAULT;
> +			} else {
> +				sbl_dev_dbg(sbl->dev, "%d: pml hdlr - remote fault - ignored", port_num);
> +			}
> +		} else {
> +			sbl_dev_dbg(sbl->dev, "%d: pml hdlr - link down", port_num);
> +			down_origin = SBL_LINK_DOWN_ORIGIN_LINK_DOWN;
> +		}
> +	}
> +
> +	if (down_origin != SBL_LINK_DOWN_ORIGIN_UNKNOWN) {
> +		if (!(link->blattr.options & SBL_DISABLE_PML_RECOVERY) && !link->is_degraded) {
> +			if (sbl_pml_recovery_ignore_down_origin_fault(down_origin)) {
> +				sbl_dev_dbg(sbl->dev, "%d: PML recovery, pml hdlr fault(%d) is ignored", port_num, down_origin);
> +				sbl_pml_recovery_monitor(sbl, port_num, down_origin);
> +
> +			} else
> +				sbl_pml_link_down_async_alert(sbl, port_num, down_origin);
> +		} else {
> +			sbl_dev_info(sbl->dev, "%d: PML recovery is disabled", port_num);
> +			sbl_pml_link_down_async_alert(sbl, port_num, down_origin);
> +		}
> +	}

[Severity: Medium]
In sbl_pml_hdlr(), when a TX or RX degrade failure occurs, down_origin is set
to SBL_LINK_DOWN_ORIGIN_DEGRADE_FAILURE. In
sbl_pml_recovery_ignore_down_origin_fault(), that is the only origin that
returns false so that the fault bypasses sbl_pml_recovery_monitor() and
immediately calls sbl_pml_link_down_async_alert().

However, if SBL_PML_ERR_FLG_PCS_HI_SER, SBL_PML_ERR_FLG_LLR_REPLAY_AT_MAX, or
SBL_PML_ERR_FLG_PCS_LINK_DOWN is raised in raised_flgs at the same time, the
subsequent checks unconditionally overwrite down_origin with a recoverable
origin (such as SBL_LINK_DOWN_ORIGIN_ALIGN or SBL_LINK_DOWN_ORIGIN_LINK_DOWN).

Won't that cause sbl_pml_recovery_ignore_down_origin_fault(down_origin) to
return true and enter sbl_pml_recovery_monitor() instead of immediately
sending the link-down alert with SBL_LINK_DOWN_ORIGIN_DEGRADE_FAILURE?

[ ... ]

> diff --git a/drivers/net/ethernet/hpe/sbl/sbl_pml_llr.c b/drivers/net/ethernet/hpe/sbl/sbl_pml_llr.c
> new file mode 100644
> index 0000000000000..a190f6890b4ef
> --- /dev/null
> +++ b/drivers/net/ethernet/hpe/sbl/sbl_pml_llr.c
> @@ -0,0 +1,736 @@

[ ... ]

> +static int sbl_pml_llr_measure_loop_time_ns(struct sbl_inst *sbl, int port_num,
> +					    u64 *llr_loop_time)
> +{
> +	struct sbl_link *link;
> +	u32              base;
> +	u64              min_loop_time;
> +	u64              max_loop_time;
> +	int              x;
> +	u64              val64;
> +	u64              time64;
> +	int              err;
> +
> +	sbl_link_info_set(sbl, port_num, SBL_LINK_INFO_LLR_MEASURE);
> +
> +	link = sbl->link + port_num;
> +	base = SBL_PML_BASE(port_num);
> +
> +	min_loop_time  = SBL_PML_LLR_MIN_LOOP_TIME;
> +	max_loop_time  = SBL_PML_LLR_MAX_LOOP_TIME;
> +	*llr_loop_time = SBL_PML_LLR_MAX_LOOP_TIME;
> +	time64         = 0ULL;
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR measure loop time (len = %s)(media = %s)",
> +		    port_num, sbl_link_len_str(link->mattr.len),
> +		    sbl_link_media_str(link->mattr.media));
> +
> +	/* calc loop time bounds */
> +	if (link->mattr.len != SBL_LINK_LEN_INVALID) {
> +		err = sbl_media_calc_loop_time(sbl, port_num, &min_loop_time);
> +		if (err) {
> +			sbl_dev_err(sbl->dev, "%d: LLR measure calc loop time failed [%d]", port_num, err);
> +			goto out;
> +		}
> +		/* arbitrary range for max */
> +		max_loop_time = min_loop_time + 100 /* ns */;
> +	}
> +	sbl_dev_dbg(sbl->dev, "%d: LLR measure loop time bounds: min = %lldns, max = %lldns",
> +		    port_num, min_loop_time, max_loop_time);
> +
> +	/* measure loop time */
> +	for (x = 0; x < SBL_PML_LLR_TIMING_LOOPS; ++x) {
> +
> +		if (sbl_start_timeout(sbl, port_num)) {
> +			sbl_dev_err(sbl->dev, "%d: LLR measure loop time timeout", port_num);
> +			err = -ETIMEDOUT;
> +			goto out;
> +		}
> +
> +		if (sbl_base_link_start_cancelled(sbl, port_num)) {
> +			sbl_dev_err(sbl->dev, "%d: LLR measure loop time cancelled", port_num);
> +			err = -ECANCELED;
> +			goto out;
> +		}
> +
> +		/* start a measurement */
> +		sbl_write64(sbl, base | SBL_PML_STS_LLR_LOOP_TIME_OFFSET, 0ULL);
> +		sbl_read64(sbl, base | SBL_PML_STS_LLR_LOOP_TIME_OFFSET);  /* flush */
> +		/* give the measurement time to complete */
> +		udelay(SBL_PML_LLR_TIMING_MEASURE_DELAY);
> +		/* read the measurement */
> +		val64 = sbl_read64(sbl, base | SBL_PML_STS_LLR_LOOP_TIME_OFFSET);
> +
> +		time64 = SBL_PML_STS_LLR_LOOP_TIME_LOOP_TIME_GET(val64); /* ns */
> +		sbl_dev_dbg(sbl->dev, "%d: LLR measure time = %lldns (%d)", port_num, time64, x);
> +
> +		/* if we didn't get a valid time, then wait to retry */
> +		if (!time64)
> +			msleep(SBL_PML_LLR_TIMING_RETRY_DELAY);
> +
> +		/* if we did get a valid time, then check it here */
> +		else if ((time64 >= min_loop_time) && (time64 <= max_loop_time)) {
> +			/* save the fastest time here */
> +			if (time64 < *llr_loop_time)
> +				*llr_loop_time = time64;
> +		}
> +	}
> +
> +	/* check result here */
> +	if (*llr_loop_time == SBL_PML_LLR_MAX_LOOP_TIME) {
> +		if (sbl_debug_option(sbl, port_num, SBL_DEBUG_ALLOW_LOOP_TIME_FAIL)) {
> +			sbl_dev_err(sbl->dev, "%d: LLR measure loop time failed (min = %lld, max = %lld, last = %lld)",
> +				    port_num, min_loop_time, max_loop_time, time64);
> +			err = -ENODATA;
> +			goto out;
> +		}
> +		/* set to max calculated loop time */
> +		*llr_loop_time = max_loop_time;
> +	}
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR measure loop time = %lldns", port_num, *llr_loop_time);
> +	err = 0;
> +
> +out:
> +	sbl_link_info_clear(sbl, port_num, SBL_LINK_INFO_LLR_MEASURE);
> +	return err;
> +}

[Severity: Medium]
In sbl_pml_llr_measure_loop_time_ns(), *llr_loop_time (which points to
link->llr_loop_time in sbl_pml_llr_start()) is initialized to
SBL_PML_LLR_MAX_LOOP_TIME at entry.

If sbl_media_calc_loop_time() fails, or the measurement loop times out, is
cancelled, or fails with SBL_DEBUG_ALLOW_LOOP_TIME_FAIL set, the function
jumps to out and returns a negative error code while leaving
link->llr_loop_time non-zero.

Since sbl_pml_llr_start() only calls sbl_pml_llr_measure_loop_time_ns() when
!link->llr_loop_time, won't a subsequent call to sbl_pml_llr_start() skip
measuring the loop time and program the LLR replay timer and capacity using
that stale value?

[ ... ]

> +/* get LLR mode */
> +static int sbl_pml_llr_mode_get(struct sbl_inst *sbl, int port_num, u32 *llr_mode)
> +{
> +	struct sbl_link *link = sbl->link + port_num;
> +	int               err = -1;
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR mode get (%d)", port_num, link->blattr.llr_mode);
> +
> +	switch (link->blattr.llr_mode) {

[ ... ]

> +	case SBL_LLR_MODE_AUTO:
> +		/* check fabric link here */
> +		if (link->blattr.options & SBL_OPT_FABRIC_LINK) {
> +			sbl_dev_dbg(sbl->dev, "%d: LLR mode on fabric", port_num);
> +			goto out_on;
> +		}
> +		/* check ether link here */
> +		if (!(link->blattr.options & SBL_OPT_ENABLE_ETHER_LLR))
> +			goto out_off;
> +		/* check AN options here */
> +		if (link->an_options & AN_OPT_LLR) {
> +			if (link->an_options & AN_OPT_ETHER_LLR) {
> +				if (link->an_options & AN_OPT_HPC_WITH_LLR) {
> +					link->llr_options |= SBL_PML_LLR_OPTION_HPC_WIH_LLR;
> +					link->ifg_config = SBL_IFG_CONFIG_HPC;
> +					sbl_dev_dbg(sbl->dev, "%d: LLR mode on with HPC from AN", port_num);
> +					goto out_on;
> +				}
> +				sbl_dev_dbg(sbl->dev, "%d: LLR mode on without HPC from AN", port_num);
> +				goto out_on;
> +			}
> +			goto out_off;
> +		}
> +		/* do loop detect here */
> +		err = sbl_pml_llr_detect(sbl, port_num, &(link->llr_mode));
> +		switch (err) {
> +		case 0:
> +			if (link->llr_mode == SBL_LLR_MODE_OFF)
> +				goto out_off;
> +			if (link->blattr.options & SBL_OPT_ENABLE_IFG_HPC_WITH_LLR) {
> +				link->llr_options |= SBL_PML_LLR_OPTION_HPC_WIH_LLR;
> +				link->ifg_config = SBL_IFG_CONFIG_HPC;
> +				sbl_dev_dbg(sbl->dev, "%d: LLR mode on with HPC from LOOP", port_num);
> +				goto out_on;
> +			}
> +			sbl_dev_dbg(sbl->dev, "%d: LLR mode on without HPC from LOOP", port_num);
> +			goto out_on;

[ ... ]

> +/* configure */
> +void sbl_pml_llr_config(struct sbl_inst *sbl, int port_num)
> +{
> +	struct sbl_link *link = sbl->link + port_num;
> +	u32 base = SBL_PML_BASE(port_num);
> +	u64 val64;
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR config", port_num);
> +
> +	/* init to original requested */
> +	link->llr_mode = link->blattr.llr_mode;

[Severity: Medium]
Should sbl_pml_llr_config() (or sbl_pml_llr_stop()) also reset
link->llr_options to 0?

In sbl_pml_llr_mode_get(), SBL_PML_LLR_OPTION_HPC_WIH_LLR is ORed into
link->llr_options when AN_OPT_HPC_WITH_LLR or SBL_OPT_ENABLE_IFG_HPC_WITH_LLR
is active, and sbl_pml_llr_start() checks that bit to call
sbl_pml_mac_hpc_set(). Because link->llr_options is never cleared when the
link is stopped or reconfigured, won't a subsequent link start without HPC
still see SBL_PML_LLR_OPTION_HPC_WIH_LLR set and overwrite TX MAC IFG with
HPC mode?

[ ... ]

> +void sbl_pml_llr_disable(struct sbl_inst *sbl, int port_num)
> +{
> +	u32 base = SBL_PML_BASE(port_num);
> +	u64 val64;
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR disable", port_num);
> +
> +	val64 = sbl_read64(sbl, base | SBL_PML_CFG_LLR_OFFSET);
> +	val64 = SBL_PML_CFG_LLR_LLR_MODE_UPDATE(val64, 0ULL); /* LLR OFF */
> +	sbl_write64(sbl, base | SBL_PML_CFG_LLR_OFFSET, val64);
> +	sbl_read64(sbl, base | SBL_PML_CFG_LLR_OFFSET);  /* flush */
> +
> +	sbl_link_info_set(sbl, port_num, SBL_LINK_INFO_LLR_DISABLED);
> +	sbl_link_info_clear(sbl, port_num, SBL_LINK_INFO_LLR_RUN);
> +}
> +EXPORT_SYMBOL(sbl_pml_llr_disable);
> +
> +/**
> + * sbl_pml_llr_enable() - Enable pml llr
> + * @sbl: A slingshot base link device instance
> + * @port_num: port number
> + *
> + * Sets the LLR mode based on the link configuration to
> + * enable the LLR feature.
> + */
> +void sbl_pml_llr_enable(struct sbl_inst *sbl, int port_num)
> +{
> +	struct sbl_link *link = sbl->link + port_num;
> +
> +	sbl_dev_dbg(sbl->dev, "%d: LLR enable", port_num);
> +
> +	sbl_pml_llr_mode_set(sbl, port_num, link->llr_mode);
> +}
> +EXPORT_SYMBOL(sbl_pml_llr_enable);

[Severity: Medium]
sbl_pml_llr_disable() sets SBL_LINK_INFO_LLR_DISABLED and clears
SBL_LINK_INFO_LLR_RUN in link->link_info, but sbl_pml_llr_enable() (and
sbl_pml_llr_check_is_ready()) does not update link->link_info when LLR is
re-enabled. Should sbl_pml_llr_enable() clear SBL_LINK_INFO_LLR_DISABLED and
restore SBL_LINK_INFO_LLR_RUN when link->llr_mode != SBL_LLR_MODE_OFF?

[ ... ]

> diff --git a/drivers/net/ethernet/hpe/sbl/sbl_pml_pcs.c b/drivers/net/ethernet/hpe/sbl/sbl_pml_pcs.c
> new file mode 100644
> index 0000000000000..81484e1773943
> --- /dev/null
> +++ b/drivers/net/ethernet/hpe/sbl/sbl_pml_pcs.c
> @@ -0,0 +1,1085 @@

[ ... ]

> +int  sbl_pml_pcs_am_start(struct sbl_inst *sbl, int port_num)
> +{
> +	struct sbl_link *link;
> +	int err;
> +
> +	err = sbl_validate_instance(sbl);
> +	if (err)
> +		return err;
> +
> +	err = sbl_validate_port_num(sbl, port_num);
> +	if (err)
> +		return err;
> +
> +	link = sbl->link + port_num;
> +
> +	if (!(link->blstate & (SBL_BASE_LINK_STATUS_STARTING | SBL_BASE_LINK_STATUS_STARTING))) {
> +		sbl_dev_err(sbl->dev, "pcs_am_start %d: wrong state (%s)\n", port_num,
> +			    sbl_link_state_str(link->blstate));
> +		return -ENAVAIL;
> +	}

[Severity: Low]
In sbl_pml_pcs_am_start(), SBL_BASE_LINK_STATUS_STARTING is bitwise-ORed with
itself when checking link->blstate. Was another SBL_BASE_LINK_STATUS_* flag
intended here, or should the duplicate operand be removed?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261030-cxi-netdev-submission-v1-0-8c2c391cc283@hpe.com?part=5

  reply	other threads:[~2026-10-31 21:02 UTC|newest]

Thread overview: 48+ 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 [this message]
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
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  3:01       ` Guenter Roeck

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-192137@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=sandeep.bhoot@hpe.com \
    --cc=santosh-kumar.mamila@hpe.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