From: Jakub Kicinski <kuba@kernel.org>
To: jensemil.schulzostergaard@microchip.com
Cc: Jakub Kicinski <kuba@kernel.org>,
UNGLinuxDriver@microchip.com, andrew@lunn.ch, olteanv@gmail.com,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, robh@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org, woojung.huh@microchip.com,
linux@armlinux.org.uk, Steen.Hegelund@microchip.com,
daniel.machon@microchip.com, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH net-next v4 4/9] net: dsa: lan9645x: add basic dsa driver for LAN9645X
Date: Tue, 5 May 2026 18:45:55 -0700 [thread overview]
Message-ID: <20260506014555.1616575-1-kuba@kernel.org> (raw)
In-Reply-To: <20260430-dsa_lan9645x_switch_driver_base-v4-4-f1b6005fa8b7@microchip.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net: dsa: lan9645x: add basic dsa driver for LAN9645X
This patch introduces a new DSA driver for the Microchip LAN9645X switch
family, covering probe/setup/teardown, NPI CPU port wiring, per-port
initialisation, and phylink MAC integration. A few questions inline.
> diff --git a/drivers/net/dsa/microchip/lan9645x/Kconfig b/drivers/net/dsa/microchip/lan9645x/Kconfig
> new file mode 100644
> index 000000000000..4d9fdf34104e
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/lan9645x/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config NET_DSA_MICROCHIP_LAN9645X
> + tristate "Microchip Lan9645x switch support"
> + depends on NET_DSA
> + select NET_DSA_TAG_LAN9645X
> + help
> + This driver adds DSA support for Microchip Lan9645x switch chips.
The driver is non-functional without a parent MFD that registers the named
regmaps ("gcb", "qs", "chip_top", "rew", "sys", "hsio", "dev", "dev1" ..
"dev8", "qsys", "afi", "ana") consumed by lan9645x_request_target_regmaps().
Should this Kconfig depend on the parent provider symbol so that selecting
this option without the parent driver does not produce a module whose probe
always fails?
Is there a companion parent-driver patch this patch depends on? If so,
would it be worth naming it in the commit message and documenting the
ordering?
> diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
> new file mode 100644
> index 000000000000..6fd66ea67cfd
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
> @@ -0,0 +1,423 @@
[ ... ]
> +static const char *lan9645x_resource_names[NUM_TARGETS + 1] = {
> + [TARGET_GCB] = "gcb",
> + [TARGET_QS] = "qs",
> + [TARGET_CHIP_TOP] = "chip_top",
> + [TARGET_REW] = "rew",
> + [TARGET_SYS] = "sys",
> + [TARGET_HSIO] = "hsio",
> + [TARGET_DEV] = "dev",
> + [TARGET_DEV + 1] = "dev1",
> + [TARGET_DEV + 2] = "dev2",
> + [TARGET_DEV + 3] = "dev3",
> + [TARGET_DEV + 4] = "dev4",
> + [TARGET_DEV + 5] = "dev5",
> + [TARGET_DEV + 6] = "dev6",
> + [TARGET_DEV + 7] = "dev7",
> + [TARGET_DEV + 8] = "dev8",
The first DEV instance is named "dev", while the rest are "dev1" through
"dev8". Is this asymmetry intentional, or should the first be "dev0" to
match the natural per-port numbering? Without the parent driver available
in this series, it is hard to tell which naming scheme the parent actually
registers.
If the parent registers "dev0".."dev8" then dev_get_regmap(parent, "dev")
returns NULL and probe fails with -ENODEV.
[ ... ]
> +static void lan9645x_set_feat_dis(struct lan9645x *lan9645x)
> +{
> + u32 feat_dis;
> +
> + /* The features which can be physically disabled on some SKUs are:
> + * 1) Number of ports can be 5, 7 or 9. Any ports can be used, the chip
> + * tracks how many are active.
> + * 2) HSR/PRP. The duplicate discard table can be disabled.
> + * 3) TAS, frame preemption and PSFP can be disabled.
> + */
> + feat_dis = lan_rd(lan9645x, GCB_FEAT_DISABLE);
> +
> + lan9645x->num_port_dis =
> + GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(feat_dis);
> + lan9645x->dd_dis = GCB_FEAT_DISABLE_FEAT_DD_DIS_GET(feat_dis);
> + lan9645x->tsn_dis = GCB_FEAT_DISABLE_FEAT_TSN_DIS_GET(feat_dis);
> +}
Where are num_port_dis, dd_dis and tsn_dis consulted after this read?
ds->num_ports is hardcoded to NUM_PHYS_PORTS (9) in lan9645x_probe(), and
there does not appear to be any rejection of TSN or HSR/PRP configuration
on SKUs where tsn_dis=1 or dd_dis=1 in this patch. On a 5-port SKU
(num_port_dis=4), would the driver still register 9 DSA ports and allow
DT to bring up a fused-off port?
> +static int lan9645x_setup(struct dsa_switch *ds)
> +{
[ ... ]
> + dev_info(lan9645x->dev,
> + "SKU features: tsn_dis=%d hsr_dis=%d max_ports=%d\n",
> + lan9645x->tsn_dis, lan9645x->dd_dis,
> + lan9645x->num_phys_ports - lan9645x->num_port_dis);
The log prints the field called dd_dis in struct lan9645x under the name
hsr_dis. Should the label in the format string match the struct field
name, or should the field be renamed?
[ ... ]
> diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c
> new file mode 100644
> index 000000000000..9eac32ca342c
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c
> @@ -0,0 +1,383 @@
[ ... ]
> +/* Port 4 or 7 is RGMII_0 and port 8 is RGMII_1 */
> +#define RGMII_IDX(port) ((port) == 8 ? 1 : 0)
> +
> +void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,
> + struct phylink_config *c)
> +{
> + c->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 |
> + MAC_100 | MAC_1000FD | MAC_2500FD;
> +
> + switch (port) {
> + case 0 ... 3:
> + __set_bit(PHY_INTERFACE_MODE_GMII, c->supported_interfaces);
> + break;
> + case 4:
> + __set_bit(PHY_INTERFACE_MODE_GMII, c->supported_interfaces);
> + phy_interface_set_rgmii(c->supported_interfaces);
> + break;
> + case 5 ... 6:
> + /* SerDes ports: QSGMII/SGMII/1000BASEX/2500BASEX modes
> + * require PCS support which is not yet implemented.
> + */
> + break;
> + case 7 ... 8:
> + /* QSGMII mode on ports 7-8 requires SerDes PCS support,
> + * which is not yet implemented.
> + */
> + phy_interface_set_rgmii(c->supported_interfaces);
> + break;
> + default:
> + break;
> + }
> +}
mac_capabilities advertises MAC_2500FD for every port, but none of the
supported_interfaces entries allow negotiating 2.5 Gb/s. GMII and RGMII
do not carry 2.5 Gb/s, and ports 5-6 have an empty supported_interfaces
bitmap. Should MAC_2500FD be dropped until a PCS-capable interface is
added, or should it be set only on ports that will actually support it?
For ports 5 and 6, supported_interfaces is left empty. Will phylink_create()
succeed for those ports given no interface mode is permitted, or will they
be silently unusable?
The commit message states:
The lan9645x switch is a multi-port Gigabit AVB/TSN Ethernet Switch
with five integrated 10/100/1000Base-T PHYs. In addition to the
integrated PHYs, it supports up to 2 RGMII/RMII, up to 2
BASE-X/SERDES/2.5GBASE-X and one Quad-SGMII/Quad-USGMII interfaces.
Given ports 5-6 have no supported_interfaces and ports 7-8 expose only
RGMII in this patch, would it help to note in the commit message that
SerDes, QSGMII/USGMII and 2.5GBASE-X are not wired up yet?
[ ... ]
> +static int lan9645x_phylink_mac_prepare(struct phylink_config *config,
> + unsigned int mode,
> + phy_interface_t iface)
> +{
> + struct lan9645x_port *p = lan9645x_phylink_config_to_port(config);
> + struct lan9645x *lan9645x = p->lan9645x;
> + int port = p->chip_port;
> + bool is_rgmii;
> + u32 mask;
> +
> + if (port == 5 || port == 6 || port > 8)
> + return -EINVAL;
> +
> + mask = HSIO_HW_CFG_GMII_ENA_SET(BIT(port));
> + lan_rmw(mask, mask, lan9645x, HSIO_HW_CFG);
> +
> + is_rgmii = phy_interface_mode_is_rgmii(iface);
> + if (port == 4)
> + lan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(is_rgmii),
> + HSIO_HW_CFG_RGMII_0_CFG,
> + lan9645x, HSIO_HW_CFG);
> +
> + return 0;
> +}
The HSIO_HW_CFG_RGMII_0_CFG bit is only written when port == 4, but the
comment above RGMII_IDX() states:
/* Port 4 or 7 is RGMII_0 and port 8 is RGMII_1 */
#define RGMII_IDX(port) ((port) == 8 ? 1 : 0)
Port 7 also maps to RGMII_0. If port 7 is configured for RGMII, does the
RGMII_0 mux ever get routed to port 7? And if port 4 is later configured
in GMII mode, the write HSIO_HW_CFG_RGMII_0_CFG_SET(0) would run and
appear to reroute RGMII_0 away from port 7.
Is there meant to be mutual-exclusion between port 4 and port 7 in RGMII
mode, and a write path for port 7 as well?
> +static void lan9645x_rgmii_dll_config(struct lan9645x_port *p)
> +{
> + u32 rx_idx, tx_idx;
> +
> + /* DLL register layout:
> + * (N*2): RGMII_N_RX
> + * (N*2)+1: RGMII_N_TX
> + */
> + rx_idx = RGMII_IDX(p->chip_port) * 2;
> + tx_idx = RGMII_IDX(p->chip_port) * 2 + 1;
> +
> + /* Enable DLL in RGMII clock paths, deassert DLL reset, and start the
> + * delay tune FSM.
> + */
> + lan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |
> + HSIO_DLL_CFG_DLL_RST_SET(0) |
> + HSIO_DLL_CFG_DLL_ENA_SET(p->rx_internal_delay) |
> + HSIO_DLL_CFG_DELAY_ENA_SET(p->rx_internal_delay),
> + HSIO_DLL_CFG_DLL_CLK_ENA |
> + HSIO_DLL_CFG_DLL_RST |
> + HSIO_DLL_CFG_DLL_ENA |
> + HSIO_DLL_CFG_DELAY_ENA,
> + p->lan9645x, HSIO_DLL_CFG(rx_idx));
> +
> + lan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |
> + HSIO_DLL_CFG_DLL_RST_SET(0) |
> + HSIO_DLL_CFG_DLL_ENA_SET(p->tx_internal_delay) |
> + HSIO_DLL_CFG_DELAY_ENA_SET(p->tx_internal_delay),
> + HSIO_DLL_CFG_DLL_CLK_ENA |
> + HSIO_DLL_CFG_DLL_RST |
> + HSIO_DLL_CFG_DLL_ENA |
> + HSIO_DLL_CFG_DELAY_ENA,
> + p->lan9645x, HSIO_DLL_CFG(tx_idx));
> +}
This function consults only p->rx_internal_delay and p->tx_internal_delay
and never looks at the phy_interface_t. Phylink expects the MAC to apply
internal delay only when the interface is RGMII_ID, RGMII_TXID or
RGMII_RXID, and not when the interface is plain PHY_INTERFACE_MODE_RGMII
(where the PHY provides delay).
With a DT that specifies phy-mode = "rgmii" and nonzero
rx-internal-delay-ps, will both the PHY and the MAC add delay?
And with phy-mode = "rgmii-id" but no {rx,tx}-internal-delay-ps property
in DT, will the MAC fail to add delay on either side?
> diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
> new file mode 100644
> index 000000000000..394a20ee678f
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
[ ... ]
> +int lan9645x_port_setup(struct dsa_switch *ds, int port)
> +{
> + struct dsa_port *dp = dsa_to_port(ds, port);
> + struct lan9645x *lan9645x = ds->priv;
> + struct lan9645x_port *p;
> +
> + p = lan9645x_to_port(lan9645x, port);
> +
> + if (dp->dn) {
> + u32 val;
> +
> + if (!of_property_read_u32(dp->dn, "rx-internal-delay-ps", &val))
> + p->rx_internal_delay = val > 0;
> +
> + if (!of_property_read_u32(dp->dn, "tx-internal-delay-ps", &val))
> + p->tx_internal_delay = val > 0;
> + }
The u32 picosecond value from DT is collapsed to a boolean via "val > 0",
discarding the tap selection. Is the discarded precision intentional, and
if so, why read the value as u32 in the first place rather than using
of_property_read_bool() on a differently-named property?
next prev parent reply other threads:[~2026-05-06 1:45 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-30 9:34 [PATCH net-next v4 0/9] net: dsa: add DSA support for the LAN9645x switch chip family Jens Emil Schulz Østergaard
2026-04-30 9:34 ` [PATCH net-next v4 1/9] net: dsa: add tag driver for LAN9645X Jens Emil Schulz Østergaard
2026-05-06 1:45 ` Jakub Kicinski
2026-04-30 9:34 ` [PATCH net-next v4 2/9] dt-bindings: net: lan9645x: add LAN9645X switch bindings Jens Emil Schulz Østergaard
2026-04-30 9:34 ` [PATCH net-next v4 3/9] net: dsa: lan9645x: add autogenerated register macros Jens Emil Schulz Østergaard
2026-04-30 9:34 ` [PATCH net-next v4 4/9] net: dsa: lan9645x: add basic dsa driver for LAN9645X Jens Emil Schulz Østergaard
2026-05-06 1:45 ` Jakub Kicinski [this message]
2026-04-30 9:34 ` [PATCH net-next v4 5/9] net: dsa: lan9645x: add bridge support Jens Emil Schulz Østergaard
2026-05-06 1:46 ` Jakub Kicinski
2026-04-30 9:34 ` [PATCH net-next v4 6/9] net: dsa: lan9645x: add vlan support Jens Emil Schulz Østergaard
2026-05-06 1:46 ` Jakub Kicinski
2026-04-30 9:34 ` [PATCH net-next v4 7/9] net: dsa: lan9645x: add mac table integration Jens Emil Schulz Østergaard
2026-05-06 1:46 ` Jakub Kicinski
2026-04-30 9:34 ` [PATCH net-next v4 8/9] net: dsa: lan9645x: add mdb management Jens Emil Schulz Østergaard
2026-05-06 1:46 ` Jakub Kicinski
2026-04-30 9:34 ` [PATCH net-next v4 9/9] net: dsa: lan9645x: add port statistics Jens Emil Schulz Østergaard
2026-05-06 1:46 ` Jakub Kicinski
2026-05-06 1:48 ` Jakub Kicinski
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=20260506014555.1616575-1-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=Steen.Hegelund@microchip.com \
--cc=UNGLinuxDriver@microchip.com \
--cc=andrew@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=daniel.machon@microchip.com \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jensemil.schulzostergaard@microchip.com \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
--cc=woojung.huh@microchip.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox