All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.