All of lore.kernel.org
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: javen_xu@realsil.com.cn
Cc: hkallweit1@gmail.com, nic_swsd@realtek.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com,
	maxime.chevallier@bootlin.com, horms@kernel.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	daniel@makrotopia.org, linux@armlinux.org.uk,
	enelsonmoore@gmail.com, daniel@thingy.jp
Subject: Re: [PATCH net-next v9 4/7] r8169: add support for RTL8116af
Date: Fri, 04 Sep 2026 22:25:19 +0000	[thread overview]
Message-ID: <178856071965.219967.14695801109001005732@kernel.org> (raw)
In-Reply-To: <20260831053745.1197-5-javen_xu@realsil.com.cn>

Thank you for your contribution! Sashiko AI review found 4 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 3 · Low: 1

- [Medium] For RTL_SFP_8168_AF the driver registers a phylink PCS and
  declares in-band 1000BASE-X autonegotiation (tp->pcs.ops =…
- [Medium] The phylink conversion in this series removed phy_stop() from
  rtl8169_down() and phy_start() from rtl8169_up() (both present at…
- [Medium] The newly added PCS callback rtl8169_pcs_get_state() (via
  rtl8169_sds_read()) performs indirect OCP/SerDes MMIO accesses with no…
- [Low] For the new no-PHY 1000BASEX mode the driver still advertises
  EEE/LPI capabilities derived from the copper-PHY version check:…

--

r8169: add support for RTL8116af

This adds detection of the RTL8116af SFP variant of RTL_GIGA_MAC_VER_52,
registers a phylink PCS that reads link state from the SerDes registers,
and guards the existing internal-PHY code paths against a NULL
tp->phydev.  A few review questions below.

> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index 823763e4f4456..a04acb42e995d 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c

[ ... ]

> @@ -4891,8 +4939,13 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  		goto out;
>  	}
>  
> -	if (status & LinkChg)
> -		phy_mac_interrupt(tp->phydev);
> +	if (status & LinkChg) {
> +		if (tp->phydev)
> +			phy_mac_interrupt(tp->phydev);
> +		else if (tp->sfp_mode == RTL_SFP_8168_AF)
> +			phylink_mac_change(tp->phylink,
> +					   !!(RTL_R8(tp, PHYstatus) & LinkStatus));
> +	}
>  
>  	rtl_irq_disable(tp);
>  	napi_schedule(&tp->napi);

[ ... ]

> @@ -5002,7 +5055,7 @@ static void rtl8169_down(struct rtl8169_private *tp)
>  	bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
>  
>  	/* Reset SerDes PHY to bring down fiber link */
> -	if (tp->sfp_mode)
> +	if (tp->sfp_mode == RTL_SFP_8127_ATF)
>  		rtl_sfp_reset(tp);
>  
>  	rtl8169_update_counters(tp);

[Severity: Medium]
Should the PM paths also quiesce phylink here?

rtl8169_down() masks interrupts, runs rtl8169_cleanup(), pci_clear_master()
and rtl_prepare_power_down(), but nothing calls phylink_stop() or
phylink_suspend() on this path.  phylink_stop() is only reached from
rtl8169_close(), while rtl8169_suspend(), rtl8169_runtime_suspend() and
rtl_shutdown() all reach rtl8169_down() through rtl8169_net_suspend():

rtl8169_net_suspend()
    netif_device_detach(tp->dev);
    if (netif_running(tp->dev))
        rtl8169_down(tp);

Since pl->phylink_disable_state is only set by phylink_stop() and
phylink_suspend(), phylink_run_resolve() is still free to queue
phylink_resolve() on system_power_efficient_wq, including a resolve queued
from the rtl8169_interrupt() -> phylink_mac_change() call added above.  The
suspend callbacks drop rtnl_lock before the PCI core moves the device to
D3hot, so RTNL does not exclude it.

Can that resolve then run rtl8169_pcs_get_state() -> rtl8169_sds_read()
MMIO/OCP reads, or rtl_mac_link_up() -> rtl_link_chg_patch() ERI/MMIO
writes, against a device that is already powered down?

> @@ -5024,9 +5077,9 @@ static void rtl8169_up(struct rtl8169_private *tp)
>  		rtl8168_driver_start(tp);
>  
>  	pci_set_master(tp->pci_dev);
> -	phy_init_hw(tp->phydev);
> -	phy_resume(tp->phydev);
> -	rtl8169_init_phy(tp);
> +	if (tp->phydev)
> +		rtl8169_init_phy(tp);
> +
>  	napi_enable(&tp->napi);
>  	enable_work(&tp->wk.work);
>  	rtl_reset_work(tp);

[Severity: Medium]
Same question from the resume side: rtl8169_up() is the counterpart of
rtl8169_down(), and neither phylink_resume() nor phylink_start() is called
from rtl8169_resume() or rtl8169_runtime_resume().  Is the start/stop
pairing intentionally asymmetric, with phylink_start()/phylink_stop() only
in rtl_open()/rtl8169_close()?  For the copper case, phy_init_hw() and
phy_resume() are also re-run from rtl8169_init_phy() without phylink
knowing about it.

[ ... ]

> @@ -5628,6 +5692,53 @@ static void rtl_mac_config(struct phylink_config *config, unsigned int mode,
>  {
>  }
>  
> +static u16 rtl8169_sds_read(struct rtl8169_private *tp, u16 sds_reg)
> +{
> +	unsigned long flags;
> +	u16 val = 0;
> +
> +	raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
> +	__r8168_mac_ocp_write(tp, OCP_SDS_ADDR_REG, sds_reg);
> +	__r8168_mac_ocp_write(tp, OCP_SDS_CMD_REG, SDS_CMD_READ);
> +	val = __r8168_mac_ocp_read(tp, OCP_SDS_DATA_REG);
> +	raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
> +
> +	return val;
> +}
> +
> +static void rtl8169_pcs_get_state(struct phylink_pcs *pcs,
> +				  unsigned int neg_mode,
> +				  struct phylink_link_state *state)
> +{
> +	struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private,
> +						  pcs);
> +	u16 bmsr, lpa;
> +
> +	bmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR);
> +	lpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA);
> +
> +	phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
> +}

[Severity: Medium]
Does this need a runtime PM guard before touching the SerDes registers?

For RTL_SFP_8168_AF there is no phydev, so phylink's mode is MLO_AN_INBAND
with pl->phydev == NULL, and phylink_ethtool_ksettings_get() takes the
unconditional PCS read path in that case:

	case MLO_AN_INBAND:
		if (pl->phydev)
			break;

		phylink_mac_pcs_get_state(pl, &link_state);

rtl8169_get_link_ksettings() is a bare wrapper around
phylink_ethtool_ksettings_get() with no pm_runtime_get*/pm_runtime_active()
check, unlike rtl8169_get_stats64() which brackets its hardware access.
phylink_mii_ioctl() with SIOCGMIIREG reaches the same code.

If a plain "ethtool ethX" runs while the device is runtime suspended (after
rtl8169_close(), or after rtl_mac_link_down() -> pm_runtime_idle() and
rtl8169_runtime_idle() -> pm_schedule_suspend()), the reads return 0xffff,
so bmsr has BMSR_LSTATUS and BMSR_ANEGCOMPLETE set and
phylink_mii_c22_pcs_decode_state() reports a bogus 1000/Full link.  On
platforms that do not decode MMIO in D3hot the access can raise an
unsupported-request instead.  Should this path take a runtime PM reference,
or bail out when the device is not active?

> +
> +static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
> +			      phy_interface_t interface,
> +			      const unsigned long *advertising,
> +			      bool permit_pause_to_mac)
> +{
> +	return 0;
> +}
> +
> +static int rtl8169_pcs_validate(struct phylink_pcs *pcs,
> +				unsigned long *supported,
> +				const struct phylink_link_state *state)
> +{
> +	return 0;
> +}
> +
> +static void rtl8169_pcs_an_restart(struct phylink_pcs *pcs)
> +{
> +}

[Severity: Medium]
These two callbacks are registered for a mode that declares in-band
1000BASE-X autonegotiation, but neither of them touches the hardware.

include/linux/phylink.h documents the contract:

 * For 1000BASE-X, the advertisement should be programmed into the PCS.
 ...
 * When an autonegotiation restart is required for 802.3z modes,
 * .pcs_config() should return a positive non-zero integer (e.g. 1)

rtl8169_pcs_config() discards neg_mode, interface, advertising and
permit_pause_to_mac and returns 0, rtl8169_pcs_an_restart() is empty, and
rtl8169_sds_read() is the only SerDes accessor added, so there is no write
path at all.

Does this mean ethtool -s advertise=..., rtl8169_set_pauseparam() ->
phylink_ethtool_set_pauseparam() and rtl8169_nway_reset() ->
phylink_ethtool_nway_reset() all return success while the SerDes keeps
advertising whatever reset or firmware left there?  Since
phylink_resolve_an_pause() uses phylink's software advertisement, the
resolved pause can also differ from what the peer actually sees.

If autonegotiation really is fixed or firmware-managed on this part, would
it be clearer to express that through pcs_inband_caps or by rejecting the
unsupported configuration, rather than acknowledging the request?

> +
>  static void rtl_mac_disable_tx_lpi(struct phylink_config *config)
>  {
>  	struct rtl8169_private *tp = container_of(config,

[ ... ]

> @@ -5692,10 +5810,18 @@ static int rtl_init_phylink(struct rtl8169_private *tp)
>  	tp->phylink_config.lpi_capabilities = rtl8169_get_lpi_caps(tp);
>  	tp->phylink_config.mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
>  
> -	if (tp->sfp_mode) {
> +	switch (tp->sfp_mode) {
> +	case RTL_SFP_8168_AF:
> +		tp->pcs.ops = &r8169_pcs_ops;
> +		tp->phylink_config.default_an_inband = true;
> +		phy_mode = PHY_INTERFACE_MODE_1000BASEX;
> +		tp->phylink_config.mac_capabilities |= MAC_1000FD;
> +		break;

[Severity: Low]
This isn't a functional bug, but should RTL_SFP_8168_AF be excluded from
rtl8169_get_lpi_caps() as well?

rtl8169_get_lpi_caps() only gates on rtl_supports_eee() and
tp->sfp_mode == RTL_SFP_8127_ATF:

	if (!rtl_supports_eee(tp) || tp->sfp_mode == RTL_SFP_8127_ATF)
		return 0;

	caps |= MAC_100FD | MAC_1000FD;

RTL_GIGA_MAC_VER_52 passes rtl_supports_eee(), so lpi_capabilities ends up
as MAC_100FD | MAC_1000FD and PHY_INTERFACE_MODE_1000BASEX is added to
lpi_interfaces further down, even though mac_capabilities for this mode is
only MAC_1000FD and there is no phydev.  Nothing can act on it, since
phylink_activate_lpi() is only reached when pl->phy_enable_tx_lpi is set
from a connected PHY and phylink_ethtool_get_eee()/set_eee() return
-EOPNOTSUPP without pl->phydev, but the advertised mask still lists a speed
this interface cannot run at.

> +	case RTL_SFP_8127_ATF:
>  		phy_mode = PHY_INTERFACE_MODE_INTERNAL;
>  		tp->phylink_config.mac_capabilities |= MAC_10000FD;
> -	} else {
> +		break;
> +	default:
>  		tp->phylink_config.mac_capabilities |= MAC_10 | MAC_100;
>  
>  		if (tp->mac_version == RTL_GIGA_MAC_VER_80)

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831053745.1197-1-javen_xu%40realsil.com.cn

  parent reply	other threads:[~2026-09-04 22:25 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31  5:37 [PATCH net-next v9 0/7] r8169: add support for phylink javen
2026-08-31  5:37 ` [PATCH net-next v9 1/7] r8169: add speed in private struct javen
2026-09-04 22:25   ` netdev-bot+sashiko
2026-08-31  5:37 ` [PATCH net-next v9 2/7] net: phy: phylink: add helper to modify pause javen
2026-09-04 22:25   ` netdev-bot+sashiko
2026-08-31  5:37 ` [PATCH net-next v9 3/7] r8169: add support for phylink javen
2026-09-02 14:31   ` Andrew Lunn
2026-09-04 22:25   ` netdev-bot+sashiko
2026-08-31  5:37 ` [PATCH net-next v9 4/7] r8169: add support for RTL8116af javen
2026-09-02 14:38   ` Andrew Lunn
2026-09-04 22:25   ` netdev-bot+sashiko [this message]
2026-08-31  5:37 ` [PATCH net-next v9 5/7] r8169: add support for RTL8127atf javen
2026-09-02 14:41   ` Andrew Lunn
2026-09-04 22:25   ` netdev-bot+sashiko
2026-08-31  5:37 ` [PATCH net-next v9 6/7] r8169: add ltr support for RTL8117 series javen
2026-09-02 14:42   ` Andrew Lunn
2026-09-04 22:25   ` netdev-bot+sashiko
2026-08-31  5:37 ` [PATCH net-next v9 7/7] r8169: fix RTL8116af can not enter s0idle and c10 javen
2026-09-02 14:42   ` Andrew Lunn
2026-09-04 22:25   ` netdev-bot+sashiko
2026-09-02 14:28 ` [PATCH net-next v9 0/7] r8169: add support for phylink Andrew Lunn
2026-09-04 21:50 ` patchwork-bot+netdevbpf

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=178856071965.219967.14695801109001005732@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=daniel@makrotopia.org \
    --cc=daniel@thingy.jp \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=enelsonmoore@gmail.com \
    --cc=hkallweit1@gmail.com \
    --cc=horms@kernel.org \
    --cc=javen_xu@realsil.com.cn \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=maxime.chevallier@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=nic_swsd@realtek.com \
    --cc=pabeni@redhat.com \
    /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.