* [PATCH net-next 00/13] Introduce an ethernet port representation
@ 2025-02-07 22:36 Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 01/13] net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values Maxime Chevallier
` (14 more replies)
0 siblings, 15 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Hello everyone,
This series follows the 2 RFC that were sent a few weeks ago :
RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
The goal of this series is to introduce an internal way of representing
the "outputs" of ethernet devices, for now only focusing on PHYs.
This allows laying the groundwork for multi-port devices support (both 1
PHY 2 ports, or more exotic setups with 2 PHYs in parallel, or MII
multiplexers).
Compared to the RFCs, this series tries to properly support SFP,
especially PHY-driven SFPs through special phy_ports named "serdes"
ports. They have the particularity of outputing a generic interface,
that feeds into another component (usually, an SFP cage and therefore an
SFP module).
This allows getting a fairly generic PHY-driven SFP support (MAC-driven
SFP is handled by phylink).
This series doesn't address PHY-less interfaces (bare MAC devices, MACs
with embedded PHYs not driven by phylink, or MAC connected to optical
SFPs) to stay within the 15 patches limit, nor does it include the uAPI
part that exposes these ports to userspace.
I've kept the cover short, much more details can be found in the RFC
covers.
Thanks everyone,
Maxime
Maxime Chevallier (13):
net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values
net: ethtool: Export the link_mode_params definitions
net: phy: Introduce PHY ports representation
net: phy: dp83822: Add support for phy_port representation
net: phy: Create a phy_port for PHY-driven SFPs
net: phy: Intrduce generic SFP handling for PHY drivers
net: phy: marvell-88x2222: Support SFP through phy_port interface
net: phy: marvell: Support SFP through phy_port interface
net: phy: marvell10g: Support SFP through phy_port
net: phy: at803x: Support SFP through phy_port interface
net: phy: Only rely on phy_port for PHY-driven SFP
net: phy: dp83822: Add SFP support through the phy_port interface
dt-bindings: net: Introduce the phy-port description
.../devicetree/bindings/net/ethernet-phy.yaml | 18 +
.../bindings/net/ethernet-port.yaml | 47 +++
drivers/net/phy/Makefile | 2 +-
drivers/net/phy/dp83822.c | 71 ++--
drivers/net/phy/marvell-88x2222.c | 96 +++---
drivers/net/phy/marvell.c | 100 +++---
drivers/net/phy/marvell10g.c | 37 +--
drivers/net/phy/phy_device.c | 307 +++++++++++++++++-
drivers/net/phy/phy_port.c | 176 ++++++++++
drivers/net/phy/phylink.c | 32 ++
drivers/net/phy/qcom/at803x.c | 64 +---
include/linux/ethtool.h | 73 +++++
include/linux/phy.h | 39 ++-
include/linux/phy_port.h | 92 ++++++
include/linux/phylink.h | 2 +
net/ethtool/common.c | 231 ++++++-------
net/ethtool/common.h | 7 -
17 files changed, 1048 insertions(+), 346 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/ethernet-port.yaml
create mode 100644 drivers/net/phy/phy_port.c
create mode 100644 include/linux/phy_port.h
--
2.48.1
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH net-next 01/13] net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 02/13] net: ethtool: Export the link_mode_params definitions Maxime Chevallier
` (13 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
In an effort to have a better representation of Ethernet ports,
introduce enumeration values representing the various ethernet Mediums.
This is part of the 802.3 naming convention, for example :
1000 Base T 4
| | | |
| | | \_ lanes (4)
| | \___ Medium (T == Twisted Copper Pairs)
| \_______ Baseband transmission
\____________ Speed
Other example :
10000 Base K X 4
| | \_ lanes (4)
| \___ encoding (BaseX is 8b/10b while BaseR is 66b/64b)
\_____ Medium (K is backplane ethernet)
In the case of representing a physical port, only the medium and number
of lanes should be relevant. One exception would be 1000BaseX, which is
currently also used as a medium in what appears to be any of
1000BaseSX, 1000BaseFX, 1000BaseCX and 1000BaseLX.
These mediums are set in the net/ethtool/common.c lookup table that
maintains a list of all linkmodes with their number of lanes, medium,
encoding, speed and duplex.
One notable exception to this is 100M BaseT Ethernet. 100BaseTX is a 2-lanes
protocol but it will also work on 4-lanes cables, so the lookup table
contains 2 sets of lane numbers, indicating the min number of lanes for
a protocol to work and the "nominal" number of lanes as well.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
include/linux/ethtool.h | 48 +++++++++
net/ethtool/common.c | 230 +++++++++++++++++++++-------------------
net/ethtool/common.h | 2 +
3 files changed, 171 insertions(+), 109 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 870994cc3ef7..62b5a9d7efd5 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -210,6 +210,54 @@ static inline u8 *ethtool_rxfh_context_key(struct ethtool_rxfh_context *ctx)
void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id);
+enum ethtool_link_medium {
+ ETHTOOL_LINK_MEDIUM_BASET = 0,
+ ETHTOOL_LINK_MEDIUM_BASEK,
+ ETHTOOL_LINK_MEDIUM_BASES,
+ ETHTOOL_LINK_MEDIUM_BASEC,
+ ETHTOOL_LINK_MEDIUM_BASEL,
+ ETHTOOL_LINK_MEDIUM_BASED,
+ ETHTOOL_LINK_MEDIUM_BASEE,
+ ETHTOOL_LINK_MEDIUM_BASEF,
+ ETHTOOL_LINK_MEDIUM_BASEV,
+ ETHTOOL_LINK_MEDIUM_BASEMLD, /* I don't know what that is */
+ ETHTOOL_LINK_MEDIUM_BASEX, /* Not a true medium, but abused... */
+ ETHTOOL_LINK_MEDIUM_NONE,
+
+ __ETHTOOL_LINK_MEDIUM_LAST,
+};
+
+static inline const char *phy_mediums(enum ethtool_link_medium medium)
+{
+ switch (medium) {
+ case ETHTOOL_LINK_MEDIUM_BASET:
+ return "BaseT";
+ case ETHTOOL_LINK_MEDIUM_BASEK:
+ return "BaseK";
+ case ETHTOOL_LINK_MEDIUM_BASES:
+ return "BaseS";
+ case ETHTOOL_LINK_MEDIUM_BASEC:
+ return "BaseC";
+ case ETHTOOL_LINK_MEDIUM_BASEL:
+ return "BaseL";
+ case ETHTOOL_LINK_MEDIUM_BASED:
+ return "BaseD";
+ case ETHTOOL_LINK_MEDIUM_BASEE:
+ return "BaseE";
+ case ETHTOOL_LINK_MEDIUM_BASEF:
+ return "BaseF";
+ case ETHTOOL_LINK_MEDIUM_BASEV:
+ return "BaseV";
+ case ETHTOOL_LINK_MEDIUM_BASEMLD:
+ return "BaseMLD";
+ case ETHTOOL_LINK_MEDIUM_BASEX:
+ return "BaseX";
+ case ETHTOOL_LINK_MEDIUM_NONE:
+ return "None";
+ default: return "unknown";
+ }
+}
+
/* declare a link mode bitmap */
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 5489d0c9d13f..8798ff1abed3 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -279,11 +279,22 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
#define __LINK_MODE_LANES_DR8_2 8
#define __LINK_MODE_LANES_T1BRR 1
-#define __DEFINE_LINK_MODE_PARAMS(_speed, _type, _duplex) \
+#define __DEFINE_LINK_MODE_PARAMS_LANES(_speed, _type, _min_lanes, _lanes, _duplex, _medium) \
[ETHTOOL_LINK_MODE(_speed, _type, _duplex)] = { \
.speed = SPEED_ ## _speed, \
+ .min_lanes = _min_lanes, \
+ .lanes = _lanes, \
+ .duplex = __DUPLEX_ ## _duplex, \
+ .medium = ETHTOOL_LINK_MEDIUM_BASE ## _medium \
+ }
+
+#define __DEFINE_LINK_MODE_PARAMS(_speed, _type, _duplex, _medium) \
+ [ETHTOOL_LINK_MODE(_speed, _type, _duplex)] = { \
+ .speed = SPEED_ ## _speed, \
+ .min_lanes = __LINK_MODE_LANES_ ## _type, \
.lanes = __LINK_MODE_LANES_ ## _type, \
- .duplex = __DUPLEX_ ## _duplex \
+ .duplex = __DUPLEX_ ## _duplex, \
+ .medium = ETHTOOL_LINK_MEDIUM_BASE ## _medium \
}
#define __DUPLEX_Half DUPLEX_HALF
#define __DUPLEX_Full DUPLEX_FULL
@@ -292,134 +303,135 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
.speed = SPEED_UNKNOWN, \
.lanes = 0, \
.duplex = DUPLEX_UNKNOWN, \
+ .medium = ETHTOOL_LINK_MEDIUM_NONE, \
}
const struct link_mode_info link_mode_params[] = {
- __DEFINE_LINK_MODE_PARAMS(10, T, Half),
- __DEFINE_LINK_MODE_PARAMS(10, T, Full),
- __DEFINE_LINK_MODE_PARAMS(100, T, Half),
- __DEFINE_LINK_MODE_PARAMS(100, T, Full),
- __DEFINE_LINK_MODE_PARAMS(1000, T, Half),
- __DEFINE_LINK_MODE_PARAMS(1000, T, Full),
+ __DEFINE_LINK_MODE_PARAMS_LANES(10, T, 2, 4, Half, T),
+ __DEFINE_LINK_MODE_PARAMS_LANES(10, T, 2, 4, Full, T),
+ __DEFINE_LINK_MODE_PARAMS_LANES(100, T, 2, 4, Half, T),
+ __DEFINE_LINK_MODE_PARAMS_LANES(100, T, 2, 4, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(1000, T, Half, T),
+ __DEFINE_LINK_MODE_PARAMS(1000, T, Full, T),
__DEFINE_SPECIAL_MODE_PARAMS(Autoneg),
__DEFINE_SPECIAL_MODE_PARAMS(TP),
__DEFINE_SPECIAL_MODE_PARAMS(AUI),
__DEFINE_SPECIAL_MODE_PARAMS(MII),
__DEFINE_SPECIAL_MODE_PARAMS(FIBRE),
__DEFINE_SPECIAL_MODE_PARAMS(BNC),
- __DEFINE_LINK_MODE_PARAMS(10000, T, Full),
+ __DEFINE_LINK_MODE_PARAMS(10000, T, Full, T),
__DEFINE_SPECIAL_MODE_PARAMS(Pause),
__DEFINE_SPECIAL_MODE_PARAMS(Asym_Pause),
- __DEFINE_LINK_MODE_PARAMS(2500, X, Full),
+ __DEFINE_LINK_MODE_PARAMS(2500, X, Full, X),
__DEFINE_SPECIAL_MODE_PARAMS(Backplane),
- __DEFINE_LINK_MODE_PARAMS(1000, KX, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, KX4, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, KR, Full),
+ __DEFINE_LINK_MODE_PARAMS(1000, KX, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(10000, KX4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(10000, KR, Full, K),
[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = {
.speed = SPEED_10000,
.lanes = 1,
.duplex = DUPLEX_FULL,
},
- __DEFINE_LINK_MODE_PARAMS(20000, MLD2, Full),
- __DEFINE_LINK_MODE_PARAMS(20000, KR2, Full),
- __DEFINE_LINK_MODE_PARAMS(40000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(40000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(40000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(40000, LR4, Full),
- __DEFINE_LINK_MODE_PARAMS(56000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(56000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(56000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(56000, LR4, Full),
- __DEFINE_LINK_MODE_PARAMS(25000, CR, Full),
- __DEFINE_LINK_MODE_PARAMS(25000, KR, Full),
- __DEFINE_LINK_MODE_PARAMS(25000, SR, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, CR2, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, KR2, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, LR4_ER4, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, SR2, Full),
- __DEFINE_LINK_MODE_PARAMS(1000, X, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, CR, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, SR, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, LR, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, LRM, Full),
- __DEFINE_LINK_MODE_PARAMS(10000, ER, Full),
- __DEFINE_LINK_MODE_PARAMS(2500, T, Full),
- __DEFINE_LINK_MODE_PARAMS(5000, T, Full),
+ __DEFINE_LINK_MODE_PARAMS(20000, MLD2, Full, MLD),
+ __DEFINE_LINK_MODE_PARAMS(20000, KR2, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(40000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(40000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(40000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(40000, LR4, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(56000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(56000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(56000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(56000, LR4, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(25000, CR, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(25000, KR, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(25000, SR, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(50000, CR2, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(50000, KR2, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(100000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(100000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(100000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(100000, LR4_ER4, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(50000, SR2, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(1000, X, Full, X), /* :( */
+ __DEFINE_LINK_MODE_PARAMS(10000, CR, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(10000, SR, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(10000, LR, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(10000, LRM, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(10000, ER, Full, E),
+ __DEFINE_LINK_MODE_PARAMS(2500, T, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(5000, T, Full, T),
__DEFINE_SPECIAL_MODE_PARAMS(FEC_NONE),
__DEFINE_SPECIAL_MODE_PARAMS(FEC_RS),
__DEFINE_SPECIAL_MODE_PARAMS(FEC_BASER),
- __DEFINE_LINK_MODE_PARAMS(50000, KR, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, SR, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, CR, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, LR_ER_FR, Full),
- __DEFINE_LINK_MODE_PARAMS(50000, DR, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, KR2, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, SR2, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, CR2, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, LR2_ER2_FR2, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, DR2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, LR4_ER4_FR4, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, DR4, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(100, T1, Full),
- __DEFINE_LINK_MODE_PARAMS(1000, T1, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, KR8, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, SR8, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, LR8_ER8_FR8, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, DR8, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, CR8, Full),
+ __DEFINE_LINK_MODE_PARAMS(50000, KR, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(50000, SR, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(50000, CR, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(50000, LR_ER_FR, Full, L), /* I guess ? */
+ __DEFINE_LINK_MODE_PARAMS(50000, DR, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(100000, KR2, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(100000, SR2, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(100000, CR2, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(100000, LR2_ER2_FR2, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(100000, DR2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(200000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(200000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(200000, LR4_ER4_FR4, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(200000, DR4, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(200000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(100, T1, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(1000, T1, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(400000, KR8, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(400000, SR8, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(400000, LR8_ER8_FR8, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(400000, DR8, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(400000, CR8, Full, C),
__DEFINE_SPECIAL_MODE_PARAMS(FEC_LLRS),
- __DEFINE_LINK_MODE_PARAMS(100000, KR, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, SR, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, LR_ER_FR, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, DR, Full),
- __DEFINE_LINK_MODE_PARAMS(100000, CR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, KR2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, SR2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, LR2_ER2_FR2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, DR2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, CR2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, LR4_ER4_FR4, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, DR4, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(100, FX, Half),
- __DEFINE_LINK_MODE_PARAMS(100, FX, Full),
- __DEFINE_LINK_MODE_PARAMS(10, T1L, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, CR8, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, KR8, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, DR8, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, DR8_2, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, SR8, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, VR8, Full),
- __DEFINE_LINK_MODE_PARAMS(10, T1S, Full),
- __DEFINE_LINK_MODE_PARAMS(10, T1S, Half),
- __DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half),
- __DEFINE_LINK_MODE_PARAMS(10, T1BRR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, CR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, KR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, DR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, DR_2, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, SR, Full),
- __DEFINE_LINK_MODE_PARAMS(200000, VR, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, CR2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, KR2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, DR2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, DR2_2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, SR2, Full),
- __DEFINE_LINK_MODE_PARAMS(400000, VR2, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, CR4, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, KR4, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, DR4, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, DR4_2, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, SR4, Full),
- __DEFINE_LINK_MODE_PARAMS(800000, VR4, Full),
+ __DEFINE_LINK_MODE_PARAMS(100000, KR, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(100000, SR, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(100000, LR_ER_FR, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(100000, DR, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(100000, CR, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(200000, KR2, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(200000, SR2, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(200000, LR2_ER2_FR2, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(200000, DR2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(200000, CR2, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(400000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(400000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(400000, LR4_ER4_FR4, Full, L),
+ __DEFINE_LINK_MODE_PARAMS(400000, DR4, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(400000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(100, FX, Half, F),
+ __DEFINE_LINK_MODE_PARAMS(100, FX, Full, F),
+ __DEFINE_LINK_MODE_PARAMS(10, T1L, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(800000, CR8, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(800000, KR8, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(800000, DR8, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(800000, DR8_2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(800000, SR8, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(800000, VR8, Full, V),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S, Half, T),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half, T),
+ __DEFINE_LINK_MODE_PARAMS(10, T1BRR, Full, T),
+ __DEFINE_LINK_MODE_PARAMS(200000, CR, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(200000, KR, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(200000, DR, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(200000, DR_2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(200000, SR, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(200000, VR, Full, V),
+ __DEFINE_LINK_MODE_PARAMS(400000, CR2, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(400000, KR2, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(400000, DR2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(400000, DR2_2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(400000, SR2, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(400000, VR2, Full, V),
+ __DEFINE_LINK_MODE_PARAMS(800000, CR4, Full, C),
+ __DEFINE_LINK_MODE_PARAMS(800000, KR4, Full, K),
+ __DEFINE_LINK_MODE_PARAMS(800000, DR4, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(800000, DR4_2, Full, D),
+ __DEFINE_LINK_MODE_PARAMS(800000, SR4, Full, S),
+ __DEFINE_LINK_MODE_PARAMS(800000, VR4, Full, V),
};
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 850eadde4bfc..b25011a05fea 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -16,8 +16,10 @@
struct link_mode_info {
int speed;
+ u8 min_lanes;
u8 lanes;
u8 duplex;
+ enum ethtool_link_medium medium;
};
struct genl_info;
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 02/13] net: ethtool: Export the link_mode_params definitions
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 01/13] net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 03/13] net: phy: Introduce PHY ports representation Maxime Chevallier
` (12 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
link_mode_params contains a lookup table of all 802.3 link modes that
are currently supported with structured data about each mode's speed,
duplex, number of lanes and mediums.
As a preparation for a port representation, export that table for the
rest of the net stack to use.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
include/linux/ethtool.h | 10 ++++++++++
net/ethtool/common.c | 1 +
net/ethtool/common.h | 9 ---------
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 62b5a9d7efd5..519a90ce24d3 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -258,6 +258,16 @@ static inline const char *phy_mediums(enum ethtool_link_medium medium)
}
}
+struct link_mode_info {
+ int speed;
+ u8 min_lanes;
+ u8 lanes;
+ u8 duplex;
+ enum ethtool_link_medium medium;
+};
+
+extern const struct link_mode_info link_mode_params[];
+
/* declare a link mode bitmap */
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 8798ff1abed3..7b43ae04d731 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -434,6 +434,7 @@ const struct link_mode_info link_mode_params[] = {
__DEFINE_LINK_MODE_PARAMS(800000, VR4, Full, V),
};
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);
+EXPORT_SYMBOL_GPL(link_mode_params);
const char netif_msg_class_names[][ETH_GSTRING_LEN] = {
[NETIF_MSG_DRV_BIT] = "drv",
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index b25011a05fea..ee250a5c5364 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -14,14 +14,6 @@
#define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
-struct link_mode_info {
- int speed;
- u8 min_lanes;
- u8 lanes;
- u8 duplex;
- enum ethtool_link_medium medium;
-};
-
struct genl_info;
struct hwtstamp_provider_desc;
@@ -34,7 +26,6 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
extern const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
extern const char link_mode_names[][ETH_GSTRING_LEN];
-extern const struct link_mode_info link_mode_params[];
extern const char netif_msg_class_names[][ETH_GSTRING_LEN];
extern const char wol_mode_names[][ETH_GSTRING_LEN];
extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 01/13] net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 02/13] net: ethtool: Export the link_mode_params definitions Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-11 13:32 ` Kory Maincent
2025-02-07 22:36 ` [PATCH net-next 04/13] net: phy: dp83822: Add support for phy_port representation Maxime Chevallier
` (11 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Ethernet provides a wide variety of layer 1 protocols and standards for
data transmission. The front-facing ports of an interface have their own
complexity and configurability.
Introduce a representation of these front-facing ports. The current code
is minimalistic and only support ports controlled by PHY devices, but
the plan is to extend that to SFP as well as raw Ethernet MACs that
don't use PHY devices.
This minimal port representation allows describing the media and number
of lanes of a port. From that information, we can derive the linkmodes
usable on the port, which can be used to limit the capabilities of an
interface.
For now, the port lanes and medium is derived from devicetree, defined
by the PHY driver, or populated with default values (as we assume that
all PHYs expose at least one port).
The typical example is 100M ethernet. 100BaseT can work using only 2
lanes on a Cat 5 cables. However, in the situation where a 10/100/1000
capable PHY is wired to its RJ45 port through 2 lanes only, we have no
way of detecting that. The "max-speed" DT property can be used, but a
more accurate representation can be used :
mdi {
port@0 {
media = "BaseT";
lanes = <2>;
};
};
From that information, we can derive the max speed reachable on the
port.
Another benefit of having that is to avoid vendor-specific DT properties
(micrel,fiber-mode or ti,fiber-mode).
This basic representation is meant to be expanded, by the introduction
of port ops, userspace listing of ports, and support for multi-port
devices.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/Makefile | 2 +-
drivers/net/phy/phy_device.c | 168 +++++++++++++++++++++++++++++++++++
drivers/net/phy/phy_port.c | 166 ++++++++++++++++++++++++++++++++++
include/linux/ethtool.h | 15 ++++
include/linux/phy.h | 31 +++++++
include/linux/phy_port.h | 92 +++++++++++++++++++
6 files changed, 473 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/phy/phy_port.c
create mode 100644 include/linux/phy_port.h
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index c8dac6e92278..de1415a46629 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -2,7 +2,7 @@
# Makefile for Linux PHY drivers
libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \
- linkmode.o phy_link_topology.o
+ linkmode.o phy_link_topology.o phy_port.o
mdio-bus-y += mdio_bus.o mdio_device.o
ifdef CONFIG_MDIO_DEVICE
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 46713d27412b..df016d344c55 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -30,6 +30,7 @@
#include <linux/phylib_stubs.h>
#include <linux/phy_led_triggers.h>
#include <linux/phy_link_topology.h>
+#include <linux/phy_port.h>
#include <linux/pse-pd/pse.h>
#include <linux/property.h>
#include <linux/ptp_clock_kernel.h>
@@ -656,6 +657,13 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
dev->state = PHY_DOWN;
INIT_LIST_HEAD(&dev->leds);
+ INIT_LIST_HEAD(&dev->ports);
+
+ /* The driver's probe function must change that to the real number
+ * of ports possible on the PHY. We assume by default we are dealing
+ * with a single-port PHY
+ */
+ dev->max_n_ports = 1;
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
@@ -1412,6 +1420,46 @@ void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
}
EXPORT_SYMBOL(phy_sfp_detach);
+static int phy_add_port(struct phy_device *phydev, struct phy_port *port)
+{
+ int ret = 0;
+
+ if (phydev->n_ports == phydev->max_n_ports)
+ return -EBUSY;
+
+ /* We set all ports as active by default, PHY drivers may deactivate
+ * them (when unused)
+ */
+ port->active = true;
+
+ if (phydev->drv && phydev->drv->attach_port)
+ ret = phydev->drv->attach_port(phydev, port);
+
+ if (ret)
+ return ret;
+
+ /* The PHY driver might have added, removed or set medium/lanes info,
+ * so update the port supported accordingly.
+ */
+ phy_port_update_supported(port);
+
+ list_add(&port->head, &phydev->ports);
+
+ phydev->n_ports++;
+
+ return 0;
+}
+
+static void phy_del_port(struct phy_device *phydev, struct phy_port *port)
+{
+ if (!phydev->n_ports)
+ return;
+
+ list_del(&port->head);
+
+ phydev->n_ports--;
+}
+
/**
* phy_sfp_probe - probe for a SFP cage attached to this PHY device
* @phydev: Pointer to phy_device
@@ -3405,6 +3453,119 @@ static int of_phy_leds(struct phy_device *phydev)
return 0;
}
+static void phy_cleanup_ports(struct phy_device *phydev)
+{
+ struct phy_port *tmp, *port;
+
+ list_for_each_entry_safe(port, tmp, &phydev->ports, head) {
+ phy_del_port(phydev, port);
+ phy_port_destroy(port);
+ }
+}
+
+static int phy_default_setup_single_port(struct phy_device *phydev)
+{
+ struct phy_port *port = phy_port_alloc();
+
+ if (!port)
+ return -ENOMEM;
+
+ port->parent_type = PHY_PORT_PHY;
+ port->phy = phydev;
+ linkmode_copy(port->supported, phydev->supported);
+
+ phy_add_port(phydev, port);
+
+ /* default medium is copper */
+ if (!port->mediums)
+ port->mediums |= BIT(ETHTOOL_LINK_MEDIUM_BASET);
+
+ return 0;
+}
+
+static int of_phy_ports(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *mdi;
+ struct phy_port *port;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
+ return 0;
+
+ if (!node)
+ return 0;
+
+ mdi = of_get_child_by_name(node, "mdi");
+ if (!mdi)
+ return 0;
+
+ for_each_available_child_of_node_scoped(mdi, port_node) {
+ port = phy_of_parse_port(port_node);
+ if (IS_ERR(port)) {
+ err = PTR_ERR(port);
+ goto out_err;
+ }
+
+ port->parent_type = PHY_PORT_PHY;
+ port->phy = phydev;
+ err = phy_add_port(phydev, port);
+ if (err)
+ goto out_err;
+ }
+ of_node_put(mdi);
+
+ return 0;
+
+out_err:
+ phy_cleanup_ports(phydev);
+ of_node_put(mdi);
+ return err;
+}
+
+static int phy_setup_ports(struct phy_device *phydev)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(ports_supported);
+ struct phy_port *port;
+ int ret;
+
+ ret = of_phy_ports(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->n_ports < phydev->max_n_ports) {
+ ret = phy_default_setup_single_port(phydev);
+ if (ret)
+ goto out;
+ }
+
+ linkmode_zero(ports_supported);
+
+ /* Aggregate the supported modes, which are made-up of :
+ * - What the PHY itself supports
+ * - What the sum of all ports support
+ */
+ list_for_each_entry(port, &phydev->ports, head)
+ if (port->active)
+ linkmode_or(ports_supported, ports_supported,
+ port->supported);
+
+ if (!linkmode_empty(ports_supported))
+ linkmode_and(phydev->supported, phydev->supported,
+ ports_supported);
+
+ /* For now, the phy->port field is set as the first active port's type */
+ list_for_each_entry(port, &phydev->ports, head)
+ if (port->active)
+ phydev->port = phy_port_get_type(port);
+
+ return 0;
+
+out:
+ phy_cleanup_ports(phydev);
+ return ret;
+}
+
/**
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
* @fwnode: pointer to the mdio_device's fwnode
@@ -3554,6 +3715,11 @@ static int phy_probe(struct device *dev)
phydev->is_gigabit_capable = 1;
of_set_phy_supported(phydev);
+
+ err = phy_setup_ports(phydev);
+ if (err)
+ goto out;
+
phy_advertise_supported(phydev);
/* Get PHY default EEE advertising modes and handle them as potentially
@@ -3630,6 +3796,8 @@ static int phy_remove(struct device *dev)
phydev->state = PHY_DOWN;
+ phy_cleanup_ports(phydev);
+
sfp_bus_del_upstream(phydev->sfp_bus);
phydev->sfp_bus = NULL;
diff --git a/drivers/net/phy/phy_port.c b/drivers/net/phy/phy_port.c
new file mode 100644
index 000000000000..3a7bdc44b556
--- /dev/null
+++ b/drivers/net/phy/phy_port.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Framework to drive Ethernet ports
+ *
+ * Copyright (c) 2024 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+
+#include <linux/linkmode.h>
+#include <linux/of.h>
+#include <linux/phy_port.h>
+
+/**
+ * phy_port_alloc: Allocate a new phy_port
+ *
+ * Returns a newly allocated struct phy_port, or NULL.
+ */
+struct phy_port *phy_port_alloc(void)
+{
+ struct phy_port *port;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return NULL;
+
+ linkmode_zero(port->supported);
+ INIT_LIST_HEAD(&port->head);
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(phy_port_alloc);
+
+/**
+ * phy_port_destroy: Free a struct phy_port
+ */
+void phy_port_destroy(struct phy_port *port)
+{
+ kfree(port);
+}
+EXPORT_SYMBOL_GPL(phy_port_destroy);
+
+static void ethtool_medium_get_supported(unsigned long *supported,
+ enum ethtool_link_medium medium,
+ int lanes)
+{
+ int i;
+
+ for (i = 0; i < __ETHTOOL_LINK_MODE_MASK_NBITS; i++) {
+ /* Special bits such as Autoneg, Pause, Asym_pause, etc. are
+ * set and will be masked away by the port parent.
+ */
+ if (link_mode_params[i].medium == ETHTOOL_LINK_MEDIUM_NONE) {
+ linkmode_set_bit(i, supported);
+ continue;
+ }
+
+ /* For most cases, min_lanes == lanes, except for 10/100BaseT that work
+ * on 2 lanes but are compatible with 4 lanes mediums
+ */
+ if (link_mode_params[i].medium == medium &&
+ link_mode_params[i].lanes >= lanes &&
+ link_mode_params[i].min_lanes <= lanes) {
+ linkmode_set_bit(i, supported);
+ }
+ }
+}
+
+static enum ethtool_link_medium ethtool_str_to_medium(const char *str)
+{
+ int i;
+
+ for (i = 0; i < __ETHTOOL_LINK_MEDIUM_LAST; i++)
+ if (!strcmp(phy_mediums(i), str))
+ return i;
+
+ return ETHTOOL_LINK_MEDIUM_NONE;
+}
+
+/**
+ * phy_of_parse_port: Create a phy_port from a firmware representation
+ *
+ * Returns a newly allocated and initialized phy_port pointer, or an ERR_PTR.
+ */
+struct phy_port *phy_of_parse_port(struct device_node *dn)
+{
+ struct fwnode_handle *fwnode = of_fwnode_handle(dn);
+ enum ethtool_link_medium medium;
+ struct phy_port *port;
+ struct property *prop;
+ const char *med_str;
+ u32 lanes, mediums = 0;
+ int ret;
+
+ ret = fwnode_property_read_u32(fwnode, "lanes", &lanes);
+ if (ret)
+ lanes = 0;
+
+ ret = fwnode_property_read_string(fwnode, "media", &med_str);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_property_for_each_string(to_of_node(fwnode), "media", prop, med_str) {
+ medium = ethtool_str_to_medium(med_str);
+ if (medium == ETHTOOL_LINK_MEDIUM_NONE)
+ return ERR_PTR(-EINVAL);
+
+ mediums |= BIT(medium);
+ }
+
+ if (!mediums)
+ return ERR_PTR(-EINVAL);
+
+ port = phy_port_alloc();
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
+ port->lanes = lanes;
+ port->mediums = mediums;
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(phy_of_parse_port);
+
+/**
+ * phy_port_update_supported: Setup the port->supported field
+ * port: the port to update
+ *
+ * Once the port's medium list and number of lanes has been configured based
+ * on firmware, straps and vendor-specific properties, this function may be
+ * called to update the port's supported linkmodes list.
+ *
+ * Any mode that was manually set in the port's supported list remains set.
+ */
+void phy_port_update_supported(struct phy_port *port)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+ int i, lanes = 1;
+
+ /* If there's no lanes specified, we grab the default number of
+ * lanes as the max of the default lanes for each medium
+ */
+ if (!port->lanes)
+ for_each_set_bit(i, &port->mediums, __ETHTOOL_LINK_MEDIUM_LAST)
+ lanes = max_t(int, lanes, phy_medium_default_lanes(i));
+
+ for_each_set_bit(i, &port->mediums, __ETHTOOL_LINK_MEDIUM_LAST) {
+ linkmode_zero(supported);
+ ethtool_medium_get_supported(supported, i, port->lanes);
+ linkmode_or(port->supported, port->supported, supported);
+ }
+}
+EXPORT_SYMBOL_GPL(phy_port_update_supported);
+
+/**
+ * phy_port_get_type: get the PORT_* attribut for that port.
+ */
+int phy_port_get_type(struct phy_port *port)
+{
+ if (port->mediums & ETHTOOL_LINK_MEDIUM_BASET)
+ return PORT_TP;
+
+ if (phy_port_is_fiber(port) ||
+ (port->mediums & BIT(ETHTOOL_LINK_MEDIUM_BASEX)))
+ return PORT_FIBRE;
+
+ return PORT_OTHER;
+}
+EXPORT_SYMBOL_GPL(phy_port_get_type);
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 519a90ce24d3..32fe062b715c 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -227,6 +227,10 @@ enum ethtool_link_medium {
__ETHTOOL_LINK_MEDIUM_LAST,
};
+#define ETHTOOL_MEDIUM_FIBER_BITS (BIT(ETHTOOL_LINK_MEDIUM_BASES) | \
+ BIT(ETHTOOL_LINK_MEDIUM_BASEL) | \
+ BIT(ETHTOOL_LINK_MEDIUM_BASEF))
+
static inline const char *phy_mediums(enum ethtool_link_medium medium)
{
switch (medium) {
@@ -258,6 +262,17 @@ static inline const char *phy_mediums(enum ethtool_link_medium medium)
}
}
+static inline int phy_medium_default_lanes(enum ethtool_link_medium medium)
+{
+ /* Let's consider that the default BaseT ethernet is BaseT4, i.e.
+ * Gigabit Ethernet.
+ */
+ if (medium == ETHTOOL_LINK_MEDIUM_BASET)
+ return 4;
+
+ return 1;
+}
+
struct link_mode_info {
int speed;
u8 min_lanes;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 19f076a71f94..17bc287c1866 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -316,6 +316,7 @@ static inline long rgmii_clock(int speed)
struct device;
struct kernel_hwtstamp_config;
struct phylink;
+struct phy_port;
struct sfp_bus;
struct sfp_upstream_ops;
struct sk_buff;
@@ -642,6 +643,9 @@ struct macsec_ops;
* @master_slave_state: Current master/slave configuration
* @mii_ts: Pointer to time stamper callbacks
* @psec: Pointer to Power Sourcing Equipment control struct
+ * @ports: List of PHY ports structures
+ * n_ports: Number of ports currently attached to the PHY
+ * @max_n_ports: Max number of ports this PHY can expose
* @lock: Mutex for serialization access to PHY
* @state_queue: Work queue for state machine
* @link_down_events: Number of times link was lost
@@ -734,6 +738,7 @@ struct phy_device {
/* Host supported PHY interface types. Should be ignored if empty. */
DECLARE_PHY_INTERFACE_MASK(host_interfaces);
+ DECLARE_PHY_INTERFACE_MASK(sfp_bus_interfaces);
#ifdef CONFIG_LED_TRIGGER_PHY
struct phy_led_trigger *phy_led_triggers;
@@ -776,6 +781,10 @@ struct phy_device {
struct mii_timestamper *mii_ts;
struct pse_control *psec;
+ struct list_head ports;
+ int n_ports;
+ int max_n_ports;
+
u8 mdix;
u8 mdix_ctrl;
@@ -1273,6 +1282,27 @@ struct phy_driver {
*/
int (*led_polarity_set)(struct phy_device *dev, int index,
unsigned long modes);
+
+ /**
+ * @attach_port: Indicates to the PHY driver that a port is detected
+ * @dev: PHY device to notify
+ * @port: The port being added
+ *
+ * Called when a port that needs to be driven by the PHY is found. The
+ * number of time this will be called depends on phydev->max_n_ports,
+ * which the driver can change in .probe().
+ *
+ * The port that is being passed may or may not be initialized. If it is
+ * already initialized, it is by the generic port representation from
+ * devicetree, which superseeds any strapping or vendor-specific
+ * properties.
+ *
+ * If the port isn't initialized, the port->mediums and port->lanes
+ * fields must be set, possibly according to stapping information.
+ *
+ * Returns 0, or an error code.
+ */
+ int (*attach_port)(struct phy_device *dev, struct phy_port *port);
};
#define to_phy_driver(d) container_of_const(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
@@ -2083,6 +2113,7 @@ void phy_trigger_machine(struct phy_device *phydev);
void phy_mac_interrupt(struct phy_device *phydev);
void phy_start_machine(struct phy_device *phydev);
void phy_stop_machine(struct phy_device *phydev);
+
void phy_ethtool_ksettings_get(struct phy_device *phydev,
struct ethtool_link_ksettings *cmd);
int phy_ethtool_ksettings_set(struct phy_device *phydev,
diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h
new file mode 100644
index 000000000000..5dfad5157601
--- /dev/null
+++ b/include/linux/phy_port.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __PHY_PORT_H
+#define __PHY_PORT_H
+
+#include <linux/ethtool.h>
+#include <linux/types.h>
+#include <linux/phy.h>
+
+struct phy_port;
+
+/**
+ * enum phy_port_parent - The device this port is attached to
+ *
+ * @PHY_PORT_PHY: Indicates that the port is driven by a PHY device
+ */
+enum phy_port_parent {
+ PHY_PORT_PHY,
+};
+
+struct phy_port_ops {
+ /* Sometimes, the link state can be retrieved from physical,
+ * out-of-band channels such as the LOS signal on SFP. These
+ * callbacks allows notifying the port about state changes
+ */
+ void (*link_up)(struct phy_port *port);
+ void (*link_down)(struct phy_port *port);
+
+ /* If the port acts as a Media Independent Interface (Serdes port),
+ * configures the port with the relevant state and mode. When enable is
+ * not set, interface should be ignored
+ */
+ int (*configure_mii)(struct phy_port *port, bool enable, phy_interface_t interface);
+};
+
+/**
+ * struct phy_port - A representation of a network device physical interface
+ *
+ * @head: Used by the port's parent to list ports
+ * @parent_type: The type of device this port is directly connected to
+ * @phy: If the parent is PHY_PORT_PHYDEV, the PHY controlling that port
+ * @lanes: The number of lanes (diff pairs) this port has, 0 if not applicable
+ * @medium: The physical medium this port provides access to
+ * @supported: The link modes this port can expose, if this port is MDI (not MII)
+ * @interfaces: The MII interfaces this port supports, if this port is MII
+ * @active: Indicates if the port is currently part of the active link.
+ * @is_serdes: Indicates if this port is Serialised MII (Media Independent
+ * Interface), or an MDI (Media Dependent Interface).
+ */
+struct phy_port {
+ struct list_head head;
+ enum phy_port_parent parent_type;
+ union {
+ struct phy_device *phy;
+ };
+
+ const struct phy_port_ops *ops;
+
+ int lanes;
+ unsigned long mediums;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
+
+ unsigned int active:1;
+ unsigned int is_serdes:1;
+};
+
+struct phy_port *phy_port_alloc(void);
+void phy_port_destroy(struct phy_port *port);
+
+static inline struct phy_device *port_phydev(struct phy_port *port)
+{
+ return port->phy;
+}
+
+struct phy_port *phy_of_parse_port(struct device_node *dn);
+
+static inline bool phy_port_is_copper(struct phy_port *port)
+{
+ return port->mediums == BIT(ETHTOOL_LINK_MEDIUM_BASET);
+}
+
+static inline bool phy_port_is_fiber(struct phy_port *port)
+{
+ return !!(port->mediums & ETHTOOL_MEDIUM_FIBER_BITS);
+}
+
+void phy_port_update_supported(struct phy_port *port);
+
+int phy_port_get_type(struct phy_port *port);
+
+#endif
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 04/13] net: phy: dp83822: Add support for phy_port representation
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (2 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 03/13] net: phy: Introduce PHY ports representation Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs Maxime Chevallier
` (10 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
With the phy_port representation intrduced, we can use .attach_port to
populate the port information based on either the straps or the
ti,fiber-mode property. This allows simplifying the probe function and
allow users to override the strapping configuration.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/dp83822.c | 64 ++++++++++++++++++++++++---------------
1 file changed, 40 insertions(+), 24 deletions(-)
diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c
index 6599feca1967..af535b0a3914 100644
--- a/drivers/net/phy/dp83822.c
+++ b/drivers/net/phy/dp83822.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
+#include <linux/phy_port.h>
#include <linux/netdevice.h>
#include <linux/bitfield.h>
@@ -781,17 +782,6 @@ static int dp83822_of_init(struct phy_device *phydev)
struct device *dev = &phydev->mdio.dev;
const char *of_val;
- /* Signal detection for the PHY is only enabled if the FX_EN and the
- * SD_EN pins are strapped. Signal detection can only enabled if FX_EN
- * is strapped otherwise signal detection is disabled for the PHY.
- */
- if (dp83822->fx_enabled && dp83822->fx_sd_enable)
- dp83822->fx_signal_det_low = device_property_present(dev,
- "ti,link-loss-low");
- if (!dp83822->fx_enabled)
- dp83822->fx_enabled = device_property_present(dev,
- "ti,fiber-mode");
-
if (!device_property_read_string(dev, "ti,gpio2-clk-out", &of_val)) {
if (strcmp(of_val, "mac-if") == 0) {
dp83822->gpio2_clk_out = DP83822_CLK_SRC_MAC_IF;
@@ -884,6 +874,43 @@ static int dp83822_read_straps(struct phy_device *phydev)
return 0;
}
+static int dp83822_attach_port(struct phy_device *phydev, struct phy_port *port)
+{
+ struct dp83822_private *dp83822 = phydev->priv;
+ int ret;
+
+ if (port->mediums) {
+ if (phy_port_is_fiber(port) ||
+ port->mediums & BIT(ETHTOOL_LINK_MEDIUM_BASEX))
+ dp83822->fx_enabled = true;
+ } else {
+ ret = dp83822_read_straps(phydev);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_OF_MDIO
+ if (dp83822->fx_enabled && dp83822->fx_sd_enable)
+ dp83822->fx_signal_det_low =
+ device_property_present(dev, "ti,link-loss-low");
+ if (!dp83822->fx_enabled)
+ dp83822->fx_enabled =
+ device_property_present(dev, "ti,fiber-mode");
+#endif
+
+ if (dp83822->fx_enabled) {
+ port->lanes = 1;
+ port->mediums = BIT(ETHTOOL_LINK_MEDIUM_BASEF) |
+ BIT(ETHTOOL_LINK_MEDIUM_BASEX);
+ } else {
+ /* This PHY can only to 100BaseTX max, so on 2 lanes */
+ port->lanes = 2;
+ port->mediums = BIT(ETHTOOL_LINK_MEDIUM_BASET);
+ }
+ }
+
+ return 0;
+}
+
static int dp8382x_probe(struct phy_device *phydev)
{
struct dp83822_private *dp83822;
@@ -900,25 +927,13 @@ static int dp8382x_probe(struct phy_device *phydev)
static int dp83822_probe(struct phy_device *phydev)
{
- struct dp83822_private *dp83822;
int ret;
ret = dp8382x_probe(phydev);
if (ret)
return ret;
- dp83822 = phydev->priv;
-
- ret = dp83822_read_straps(phydev);
- if (ret)
- return ret;
-
- ret = dp83822_of_init(phydev);
- if (ret)
- return ret;
-
- if (dp83822->fx_enabled)
- phydev->port = PORT_FIBRE;
+ dp83822_of_init(phydev);
return 0;
}
@@ -1104,6 +1119,7 @@ static int dp83822_led_hw_control_get(struct phy_device *phydev, u8 index,
.led_hw_is_supported = dp83822_led_hw_is_supported, \
.led_hw_control_set = dp83822_led_hw_control_set, \
.led_hw_control_get = dp83822_led_hw_control_get, \
+ .attach_port = dp83822_attach_port \
}
#define DP83825_PHY_DRIVER(_id, _name) \
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (3 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 04/13] net: phy: dp83822: Add support for phy_port representation Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-12 15:59 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers Maxime Chevallier
` (9 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Some PHY devices may be used as media-converters to drive SFP ports (for
example, to allow using SFP when the SoC can only output RGMII). This is
already supported to some extend by allowing PHY drivers to registers
themselves as being SFP upstream.
However, the logic to drive the SFP can actually be split to a per-port
control logic, allowing support for multi-port PHYs, or PHYs that can
either drive SFPs or Copper.
To that extent, create a phy_port when registering an SFP bus onto a
PHY. This port is considered a "serdes" port, in that it can feed data
to anther entity on the link. The PHY driver needs to specify the
various PHY_INTERFACE_MODE_XXX that this port supports.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 21 +++++++++++++++++++++
drivers/net/phy/phy_port.c | 10 ++++++++++
drivers/net/phy/phylink.c | 32 ++++++++++++++++++++++++++++++++
include/linux/phylink.h | 2 ++
4 files changed, 65 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index df016d344c55..56928c4459c6 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1460,6 +1460,23 @@ static void phy_del_port(struct phy_device *phydev, struct phy_port *port)
phydev->n_ports--;
}
+static int phy_setup_sfp_port(struct phy_device *phydev)
+{
+ struct phy_port *port = phy_port_alloc();
+
+ if (!port)
+ return -ENOMEM;
+
+ port->parent_type = PHY_PORT_PHY;
+ port->phy = phydev;
+
+ port->is_serdes = true;
+
+ phy_add_port(phydev, port);
+
+ return 0;
+}
+
/**
* phy_sfp_probe - probe for a SFP cage attached to this PHY device
* @phydev: Pointer to phy_device
@@ -1481,6 +1498,10 @@ int phy_sfp_probe(struct phy_device *phydev,
ret = sfp_bus_add_upstream(bus, phydev, ops);
sfp_bus_put(bus);
}
+
+ if (phydev->sfp_bus)
+ ret = phy_setup_sfp_port(phydev);
+
return ret;
}
EXPORT_SYMBOL(phy_sfp_probe);
diff --git a/drivers/net/phy/phy_port.c b/drivers/net/phy/phy_port.c
index 3a7bdc44b556..7fba101369cf 100644
--- a/drivers/net/phy/phy_port.c
+++ b/drivers/net/phy/phy_port.c
@@ -7,6 +7,7 @@
#include <linux/linkmode.h>
#include <linux/of.h>
#include <linux/phy_port.h>
+#include <linux/phylink.h>
/**
* phy_port_alloc: Allocate a new phy_port
@@ -146,6 +147,15 @@ void phy_port_update_supported(struct phy_port *port)
ethtool_medium_get_supported(supported, i, port->lanes);
linkmode_or(port->supported, port->supported, supported);
}
+
+ /* Serdes ports supported may through SFP may not have any medium set,
+ * as they will output PHY_INTERFACE_MODE_XXX modes. In that case, derive
+ * the supported list based on these interfaces
+ */
+ if (port->is_serdes && linkmode_empty(supported))
+ phylink_interfaces_to_linkmodes(port->supported,
+ port->interfaces);
+
}
EXPORT_SYMBOL_GPL(phy_port_update_supported);
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 214b62fba991..a49edc012636 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -673,6 +673,38 @@ static void phylink_validate_mask_caps(unsigned long *supported,
linkmode_and(state->advertising, state->advertising, mask);
}
+/**
+ * phylink_interfaces_to_linkmodes() - List all possible linkmodes based on a
+ * set of supported interfaces, assuming no
+ * rate matching.
+ * @linkmodes: the supported linkmodes
+ * @interfaces: Set of interfaces (PHY_INTERFACE_MODE_XXX)
+ *
+ * Compute the exhaustive list of modes that can conceivably be achieved from a
+ * set of MII interfaces. This is derived from the possible speeds and duplex
+ * achievable from these interfaces. This list is likely too exhaustive (there
+ * may not exist any device out there that can convert from an interface to a
+ * linkmode) and it needs further filtering based on real HW capabilities.
+ */
+void phylink_interfaces_to_linkmodes(unsigned long *linkmodes,
+ const unsigned long *interfaces)
+{
+ phy_interface_t interface;
+ unsigned long caps = 0;
+
+ linkmode_zero(linkmodes);
+
+ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+ caps = phylink_get_capabilities(interface,
+ GENMASK(__fls(MAC_400000FD),
+ __fls(MAC_10HD)),
+ RATE_MATCH_NONE);
+
+ phylink_set(linkmodes, Autoneg);
+ phylink_caps_to_linkmodes(linkmodes, caps);
+}
+EXPORT_SYMBOL_GPL(phylink_interfaces_to_linkmodes);
+
static int phylink_validate_mac_and_pcs(struct phylink *pl,
unsigned long *supported,
struct phylink_link_state *state)
diff --git a/include/linux/phylink.h b/include/linux/phylink.h
index 898b00451bbf..ffd8dd32ff3d 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -176,6 +176,8 @@ struct phylink_config {
};
void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed);
+void phylink_interfaces_to_linkmodes(unsigned long *linkmodes,
+ const unsigned long *interfaces);
/**
* struct phylink_mac_ops - MAC operations structure.
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (4 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-08 15:32 ` kernel test robot
2025-02-07 22:36 ` [PATCH net-next 07/13] net: phy: marvell-88x2222: Support SFP through phy_port interface Maxime Chevallier
` (8 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
There are currently 4 PHY drivers that can drive downstream SFPs:
marvell.c, marvell10g.c, at803x.c and marvell-88x2222.c. Most of the
logic is boilerplate, either calling into generic phylib helpers (for
SFP PHY attach, bus attach, etc.) or performing the same tasks with a
bit of validation :
- Getting the module's expected interface mode
- Making sure the PHY supports it
- Optionnaly perform some configuration to make sure the PHY outputs
the right mode
This can be made more generic by leveraging the phy_port, and its
configure_mii() callback which allows setting a port's interfaces when
the port is a serdes.
Introduce a generic PHY SFP support. If a driver doesn't probe the SFP
bus itself, but an SFP phandle is found in devicetree/firmware, then the
generic PHY SFP support will be used, relying on port ops.
PHY driver need to :
- Register a .attach_port() callback
- When a serdes port is registered to the PHY, drivers must set
port->interfaces to the set of PHY_INTERFACE_MODE the port can output
- If the port has limitations regarding speed, duplex and aneg, the
port can also fine-tune the final linkmodes that can be supported
- The port may register a set of ops, including .configure_mii(), that
will be called at module_insert time to adjust the interface based on
the module detected.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 102 +++++++++++++++++++++++++++++++++++
include/linux/phy.h | 2 +
2 files changed, 104 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 56928c4459c6..4aac9644c25c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1420,6 +1420,87 @@ void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
}
EXPORT_SYMBOL(phy_sfp_detach);
+static int phy_sfp_module_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+ struct phy_device *phydev = upstream;
+ struct phy_port *port = phy_get_sfp_port(phydev);
+
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
+ phy_interface_t iface;
+
+ linkmode_zero(sfp_support);
+
+ if (!port)
+ return -EINVAL;
+
+ sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
+
+ if (phydev->n_ports == 1)
+ phydev->port = sfp_parse_port(phydev->sfp_bus, id, sfp_support);
+
+ linkmode_and(sfp_support, port->supported, sfp_support);
+
+ if (linkmode_empty(sfp_support)) {
+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+ return -EINVAL;
+ }
+
+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
+
+ /* Check that this interface is supported */
+ if (!test_bit(iface, port->interfaces)) {
+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+ return -EINVAL;
+ }
+
+ if (port->ops && port->ops->configure_mii)
+ return port->ops->configure_mii(port, true, iface);
+
+ return 0;
+}
+
+static void phy_sfp_module_remove(void *upstream)
+{
+ struct phy_device *phydev = upstream;
+ struct phy_port *port = phy_get_sfp_port(phydev);
+
+ if (port && port->ops && port->ops->configure_mii)
+ port->ops->configure_mii(port, false, PHY_INTERFACE_MODE_NA);
+
+ if (phydev->n_ports == 1)
+ phydev->port = PORT_NONE;
+}
+
+static void phy_sfp_link_up(void *upstream)
+{
+ struct phy_device *phydev = upstream;
+ struct phy_port *port = phy_get_sfp_port(phydev);
+
+ if (port && port->ops && port->ops->link_up)
+ port->ops->link_up(port);
+}
+
+static void phy_sfp_link_down(void *upstream)
+{
+ struct phy_device *phydev = upstream;
+ struct phy_port *port = phy_get_sfp_port(phydev);
+
+ if (port && port->ops && port->ops->link_down)
+ port->ops->link_down(port);
+}
+
+static const struct sfp_upstream_ops sfp_phydev_ops = {
+ .attach = phy_sfp_attach,
+ .detach = phy_sfp_detach,
+ .module_insert = phy_sfp_module_insert,
+ .module_remove = phy_sfp_module_remove,
+ .link_up = phy_sfp_link_up,
+ .link_down = phy_sfp_link_down,
+ .connect_phy = phy_sfp_connect_phy,
+ .disconnect_phy = phy_sfp_disconnect_phy,
+};
+
static int phy_add_port(struct phy_device *phydev, struct phy_port *port)
{
int ret = 0;
@@ -3554,6 +3635,13 @@ static int phy_setup_ports(struct phy_device *phydev)
if (ret)
return ret;
+ /* Use generic SFP probing only if the driver didn't do so already */
+ if (!phydev->sfp_bus) {
+ ret = phy_sfp_probe(phydev, &sfp_phydev_ops);
+ if (ret)
+ goto out;
+ }
+
if (phydev->n_ports < phydev->max_n_ports) {
ret = phy_default_setup_single_port(phydev);
if (ret)
@@ -3587,6 +3675,20 @@ static int phy_setup_ports(struct phy_device *phydev)
return ret;
}
+/**
+ * phy_get_sfp_port() - Returns the first valid SFP port of a PHY
+ */
+struct phy_port *phy_get_sfp_port(struct phy_device *phydev)
+{
+ struct phy_port *port;
+ list_for_each_entry(port, &phydev->ports, head)
+ if (port->active && port->is_serdes)
+ return port;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(phy_get_sfp_port);
+
/**
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
* @fwnode: pointer to the mdio_device's fwnode
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 17bc287c1866..b850af2500e4 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2209,6 +2209,8 @@ int __phy_hwtstamp_set(struct phy_device *phydev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
+struct phy_port *phy_get_sfp_port(struct phy_device *phydev);
+
static inline int phy_package_address(struct phy_device *phydev,
unsigned int addr_offset)
{
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 07/13] net: phy: marvell-88x2222: Support SFP through phy_port interface
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (5 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 08/13] net: phy: marvell: " Maxime Chevallier
` (7 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
The 88x2222 PHY from Marvell only supports serialised modes as its
line-facing interfaces. Convert that driver to the generic phylib SFP
handling.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/marvell-88x2222.c | 96 +++++++++++++------------------
1 file changed, 39 insertions(+), 57 deletions(-)
diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c
index fad2f54c1eac..3dba7b33a873 100644
--- a/drivers/net/phy/marvell-88x2222.c
+++ b/drivers/net/phy/marvell-88x2222.c
@@ -13,7 +13,7 @@
#include <linux/mdio.h>
#include <linux/marvell_phy.h>
#include <linux/of.h>
-#include <linux/sfp.h>
+#include <linux/phy_port.h>
#include <linux/netdevice.h>
/* Port PCS Configuration */
@@ -473,90 +473,71 @@ static int mv2222_config_init(struct phy_device *phydev)
return 0;
}
-static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+static int mv2222_configure_serdes(struct phy_port *port, bool enable,
+ phy_interface_t interface)
{
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- struct phy_device *phydev = upstream;
- phy_interface_t sfp_interface;
+ struct phy_device *phydev = port_phydev(port);
struct mv2222_data *priv;
- struct device *dev;
- int ret;
-
- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, };
+ int ret = 0;
priv = phydev->priv;
- dev = &phydev->mdio.dev;
-
- sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces);
- phydev->port = sfp_parse_port(phydev->sfp_bus, id, sfp_supported);
- sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
-
- dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
+ priv->line_interface = interface;
- if (sfp_interface != PHY_INTERFACE_MODE_10GBASER &&
- sfp_interface != PHY_INTERFACE_MODE_1000BASEX &&
- sfp_interface != PHY_INTERFACE_MODE_SGMII) {
- dev_err(dev, "Incompatible SFP module inserted\n");
+ if (enable) {
+ linkmode_and(priv->supported, phydev->supported, port->supported);
- return -EINVAL;
- }
-
- priv->line_interface = sfp_interface;
- linkmode_and(priv->supported, phydev->supported, sfp_supported);
+ ret = mv2222_config_line(phydev);
+ if (ret < 0)
+ return ret;
- ret = mv2222_config_line(phydev);
- if (ret < 0)
- return ret;
+ if (mutex_trylock(&phydev->lock)) {
+ ret = mv2222_config_aneg(phydev);
+ mutex_unlock(&phydev->lock);
+ }
- if (mutex_trylock(&phydev->lock)) {
- ret = mv2222_config_aneg(phydev);
- mutex_unlock(&phydev->lock);
+ } else {
+ linkmode_zero(priv->supported);
}
return ret;
}
-static void mv2222_sfp_remove(void *upstream)
-{
- struct phy_device *phydev = upstream;
- struct mv2222_data *priv;
-
- priv = phydev->priv;
-
- priv->line_interface = PHY_INTERFACE_MODE_NA;
- linkmode_zero(priv->supported);
- phydev->port = PORT_NONE;
-}
-
-static void mv2222_sfp_link_up(void *upstream)
+static void mv2222_port_link_up(struct phy_port *port)
{
- struct phy_device *phydev = upstream;
+ struct phy_device *phydev = port_phydev(port);
struct mv2222_data *priv;
priv = phydev->priv;
priv->sfp_link = true;
}
-static void mv2222_sfp_link_down(void *upstream)
+static void mv2222_port_link_down(struct phy_port *port)
{
- struct phy_device *phydev = upstream;
+ struct phy_device *phydev = port_phydev(port);
struct mv2222_data *priv;
priv = phydev->priv;
priv->sfp_link = false;
}
-static const struct sfp_upstream_ops sfp_phy_ops = {
- .module_insert = mv2222_sfp_insert,
- .module_remove = mv2222_sfp_remove,
- .link_up = mv2222_sfp_link_up,
- .link_down = mv2222_sfp_link_down,
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .connect_phy = phy_sfp_connect_phy,
- .disconnect_phy = phy_sfp_disconnect_phy,
+static const struct phy_port_ops mv2222_port_ops = {
+ .link_up = mv2222_port_link_up,
+ .link_down = mv2222_port_link_down,
+ .configure_mii = mv2222_configure_serdes,
};
+static int mv2222_attach_port(struct phy_device *phydev, struct phy_port *port)
+{
+ if (!port->is_serdes)
+ return 0;
+
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, port->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, port->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_SGMII, port->interfaces);
+
+ return 0;
+}
+
static int mv2222_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -592,7 +573,7 @@ static int mv2222_probe(struct phy_device *phydev)
priv->line_interface = PHY_INTERFACE_MODE_NA;
phydev->priv = priv;
- return phy_sfp_probe(phydev, &sfp_phy_ops);
+ return 0;
}
static struct phy_driver mv2222_drivers[] = {
@@ -609,6 +590,7 @@ static struct phy_driver mv2222_drivers[] = {
.suspend = mv2222_suspend,
.resume = mv2222_resume,
.read_status = mv2222_read_status,
+ .attach_port = mv2222_attach_port,
},
};
module_phy_driver(mv2222_drivers);
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 08/13] net: phy: marvell: Support SFP through phy_port interface
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (6 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 07/13] net: phy: marvell-88x2222: Support SFP through phy_port interface Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 09/13] net: phy: marvell10g: Support SFP through phy_port Maxime Chevallier
` (6 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Convert the Marvell driver (especially the 88e1512 driver) to use the
phy_port interface to handle SFPs. This means registering a
.attach_port() handler to detect when a serdes line interface is used
(most likely, and SFP module).
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/marvell.c | 100 +++++++++++++++-----------------------
1 file changed, 39 insertions(+), 61 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 44e1927de499..56b8fd1fda0d 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -29,10 +29,10 @@
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/phy.h>
+#include <linux/phy_port.h>
#include <linux/marvell_phy.h>
#include <linux/bitfield.h>
#include <linux/of.h>
-#include <linux/sfp.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -3581,42 +3581,38 @@ static int marvell_probe(struct phy_device *phydev)
return marvell_hwmon_probe(phydev);
}
-static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+static int mv88e1510_port_configure_serdes(struct phy_port *port, bool enable,
+ phy_interface_t interface)
{
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- struct phy_device *phydev = upstream;
- phy_interface_t interface;
+ struct phy_device *phydev = port_phydev(port);
struct device *dev;
int oldpage;
int ret = 0;
u16 mode;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
-
dev = &phydev->mdio.dev;
- sfp_parse_support(phydev->sfp_bus, id, supported, interfaces);
- interface = sfp_select_interface(phydev->sfp_bus, supported);
-
- dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));
-
- switch (interface) {
- case PHY_INTERFACE_MODE_1000BASEX:
- mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X;
+ if (enable) {
+ switch (interface) {
+ case PHY_INTERFACE_MODE_1000BASEX:
+ mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X;
- break;
- case PHY_INTERFACE_MODE_100BASEX:
- mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX;
+ break;
+ case PHY_INTERFACE_MODE_100BASEX:
+ mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX;
- break;
- case PHY_INTERFACE_MODE_SGMII:
- mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII;
- break;
- default:
- dev_err(dev, "Incompatible SFP module inserted\n");
+ break;
+ default:
+ dev_err(dev, "Incompatible SFP module inserted\n");
- return -EINVAL;
+ return -EINVAL;
+ }
+ } else {
+ mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII;
}
oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);
@@ -3633,49 +3629,30 @@ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
error:
return phy_restore_page(phydev, oldpage, ret);
-}
-
-static void m88e1510_sfp_remove(void *upstream)
-{
- struct phy_device *phydev = upstream;
- int oldpage;
- int ret = 0;
-
- oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);
- if (oldpage < 0)
- goto error;
-
- ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
- MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
- MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII);
- if (ret < 0)
- goto error;
- ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,
- MII_88E1510_GEN_CTRL_REG_1_RESET);
-
-error:
- phy_restore_page(phydev, oldpage, ret);
+ return 0;
}
-static const struct sfp_upstream_ops m88e1510_sfp_ops = {
- .module_insert = m88e1510_sfp_insert,
- .module_remove = m88e1510_sfp_remove,
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .connect_phy = phy_sfp_connect_phy,
- .disconnect_phy = phy_sfp_disconnect_phy,
+static const struct phy_port_ops mv88e1510_serdes_port_ops = {
+ .configure_mii = mv88e1510_port_configure_serdes,
};
-static int m88e1510_probe(struct phy_device *phydev)
+static int m88e1510_attach_port(struct phy_device *phy_device,
+ struct phy_port *port)
{
- int err;
+ /* For classic Copper operation, we don't have any port-specific
+ * control to do.
+ */
+ if (!port->is_serdes)
+ return 0;
- err = marvell_probe(phydev);
- if (err)
- return err;
+ port->ops = &mv88e1510_serdes_port_ops;
+
+ __set_bit(PHY_INTERFACE_MODE_SGMII, port->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, port->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_100BASEX, port->interfaces);
- return phy_sfp_probe(phydev, &m88e1510_sfp_ops);
+ return 0;
}
static struct phy_driver marvell_drivers[] = {
@@ -3935,7 +3912,7 @@ static struct phy_driver marvell_drivers[] = {
.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
.features = PHY_GBIT_FIBRE_FEATURES,
.flags = PHY_POLL_CABLE_TEST,
- .probe = m88e1510_probe,
+ .probe = marvell_probe,
.config_init = m88e1510_config_init,
.config_aneg = m88e1510_config_aneg,
.read_status = marvell_read_status,
@@ -3961,6 +3938,7 @@ static struct phy_driver marvell_drivers[] = {
.led_hw_is_supported = m88e1318_led_hw_is_supported,
.led_hw_control_set = m88e1318_led_hw_control_set,
.led_hw_control_get = m88e1318_led_hw_control_get,
+ .attach_port = m88e1510_attach_port,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 09/13] net: phy: marvell10g: Support SFP through phy_port
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (7 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 08/13] net: phy: marvell: " Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 10/13] net: phy: at803x: Support SFP through phy_port interface Maxime Chevallier
` (5 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Convert the Marvell10G driver to use the generic SFP handling, through a
dedicated .attach_port() handler to populate the port's supported
interfaces. As there's no logic to setup the interface for now (as only
10GBaseR is supported for serdes line interfaces), no extra logic is
required.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/marvell10g.c | 37 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 623bdb8466b8..4a66694e49bb 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -28,7 +28,7 @@
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
#include <linux/phy.h>
-#include <linux/sfp.h>
+#include <linux/phy_port.h>
#include <linux/netdevice.h>
#define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
@@ -483,36 +483,23 @@ static int mv3310_set_edpd(struct phy_device *phydev, u16 edpd)
return err;
}
-static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+static int mv3310_attach_port(struct phy_device *phydev, struct phy_port *port)
{
- struct phy_device *phydev = upstream;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- phy_interface_t iface;
+ /* Nothing special to do to handle non-serdes ports */
+ if (!port->is_serdes)
+ return 0;
- sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
- iface = sfp_select_interface(phydev->sfp_bus, support);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, port->interfaces);
- if (iface != PHY_INTERFACE_MODE_10GBASER) {
- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
- return -EINVAL;
- }
return 0;
}
-static const struct sfp_upstream_ops mv3310_sfp_ops = {
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .connect_phy = phy_sfp_connect_phy,
- .disconnect_phy = phy_sfp_disconnect_phy,
- .module_insert = mv3310_sfp_insert,
-};
-
static int mv3310_probe(struct phy_device *phydev)
{
const struct mv3310_chip *chip = to_mv3310_chip(phydev);
struct mv3310_priv *priv;
u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
int ret;
if (!phydev->is_c45 ||
@@ -563,9 +550,13 @@ static int mv3310_probe(struct phy_device *phydev)
if (ret)
return ret;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+
chip->init_supported_interfaces(priv->supported_interfaces);
- return phy_sfp_probe(phydev, &mv3310_sfp_ops);
+ phydev->max_n_ports = 2;
+
+ return 0;
}
static void mv3310_remove(struct phy_device *phydev)
@@ -1422,6 +1413,7 @@ static struct phy_driver mv3310_drivers[] = {
.set_loopback = genphy_c45_loopback,
.get_wol = mv3110_get_wol,
.set_wol = mv3110_set_wol,
+ .attach_port = mv3310_attach_port,
},
{
.phy_id = MARVELL_PHY_ID_88X3310,
@@ -1441,6 +1433,7 @@ static struct phy_driver mv3310_drivers[] = {
.set_tunable = mv3310_set_tunable,
.remove = mv3310_remove,
.set_loopback = genphy_c45_loopback,
+ .attach_port = mv3310_attach_port,
},
{
.phy_id = MARVELL_PHY_ID_88E2110,
@@ -1461,6 +1454,7 @@ static struct phy_driver mv3310_drivers[] = {
.set_loopback = genphy_c45_loopback,
.get_wol = mv3110_get_wol,
.set_wol = mv3110_set_wol,
+ .attach_port = mv3310_attach_port,
},
{
.phy_id = MARVELL_PHY_ID_88E2110,
@@ -1479,6 +1473,7 @@ static struct phy_driver mv3310_drivers[] = {
.set_tunable = mv3310_set_tunable,
.remove = mv3310_remove,
.set_loopback = genphy_c45_loopback,
+ .attach_port = mv3310_attach_port,
},
};
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 10/13] net: phy: at803x: Support SFP through phy_port interface
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (8 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 09/13] net: phy: marvell10g: Support SFP through phy_port Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP Maxime Chevallier
` (4 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Convert the at803x driver to use the generic phylib SFP handling, via a
dedicated .attach_port() callback, populating the supported interfaces.
As these devices are limited to 1000BaseX, a workaround is used to also
support, in a very limited way, copper modules. This is done by
supporting SGMII but limiting it to 1G full duplex (in which case it's
somwhat compatible with 1000BaseX).
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/qcom/at803x.c | 64 ++++++++++-------------------------
1 file changed, 17 insertions(+), 47 deletions(-)
diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c
index 26350b962890..87145c4b4cbd 100644
--- a/drivers/net/phy/qcom/at803x.c
+++ b/drivers/net/phy/qcom/at803x.c
@@ -19,7 +19,7 @@
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/phylink.h>
-#include <linux/sfp.h>
+#include <linux/phy_port.h>
#include <dt-bindings/net/qca-ar803x.h>
#include "qcom.h"
@@ -722,58 +722,28 @@ static int at8031_register_regulators(struct phy_device *phydev)
return 0;
}
-static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+static int at8031_attach_port(struct phy_device *phydev, struct phy_port *port)
{
- struct phy_device *phydev = upstream;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- phy_interface_t iface;
-
- linkmode_zero(phy_support);
- phylink_set(phy_support, 1000baseX_Full);
- phylink_set(phy_support, 1000baseT_Full);
- phylink_set(phy_support, Autoneg);
- phylink_set(phy_support, Pause);
- phylink_set(phy_support, Asym_Pause);
-
- linkmode_zero(sfp_support);
- sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
- /* Some modules support 10G modes as well as others we support.
- * Mask out non-supported modes so the correct interface is picked.
- */
- linkmode_and(sfp_support, phy_support, sfp_support);
-
- if (linkmode_empty(sfp_support)) {
- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
- return -EINVAL;
- }
+ if (!port->is_serdes)
+ return 0;
- iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
+ linkmode_zero(port->supported);
+ phylink_set(port->supported, 1000baseX_Full);
+ phylink_set(port->supported, 1000baseT_Full);
+ phylink_set(port->supported, Autoneg);
+ phylink_set(port->supported, Pause);
+ phylink_set(port->supported, Asym_Pause);
- /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
- * interface for use with SFP modules.
- * However, some copper modules detected as having a preferred SGMII
- * interface do default to and function in 1000Base-X mode, so just
- * print a warning and allow such modules, as they may have some chance
- * of working.
+ /* This device doesn't really support SGMII. However, do our best
+ * to be compatible with copper modules (that usually require SGMII),
+ * in a degraded mode as we only allow 1000BaseT Full
*/
- if (iface == PHY_INTERFACE_MODE_SGMII)
- dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
- else if (iface != PHY_INTERFACE_MODE_1000BASEX)
- return -EINVAL;
+ __set_bit(PHY_INTERFACE_MODE_SGMII, port->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, port->interfaces);
return 0;
}
-static const struct sfp_upstream_ops at8031_sfp_ops = {
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .module_insert = at8031_sfp_insert,
- .connect_phy = phy_sfp_connect_phy,
- .disconnect_phy = phy_sfp_disconnect_phy,
-};
-
static int at8031_parse_dt(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
@@ -794,8 +764,7 @@ static int at8031_parse_dt(struct phy_device *phydev)
return ret;
}
- /* Only AR8031/8033 support 1000Base-X for SFP modules */
- return phy_sfp_probe(phydev, &at8031_sfp_ops);
+ return 0;
}
static int at8031_probe(struct phy_device *phydev)
@@ -1047,6 +1016,7 @@ static struct phy_driver at803x_driver[] = {
.set_tunable = at803x_set_tunable,
.cable_test_start = at8031_cable_test_start,
.cable_test_get_status = at8031_cable_test_get_status,
+ .attach_port = at8031_attach_port,
}, {
/* Qualcomm Atheros AR8032 */
PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (9 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 10/13] net: phy: at803x: Support SFP through phy_port interface Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-08 16:04 ` kernel test robot
2025-02-07 22:36 ` [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface Maxime Chevallier
` (3 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Now that all PHY drivers that support downstream SFP have been converted
to phy_port serdes handling, we can make the generic PHY SFP handling
mandatory, thus making all phylib sfp helpers static.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 28 +++++++++-------------------
include/linux/phy.h | 6 ------
2 files changed, 9 insertions(+), 25 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 4aac9644c25c..9ae9607e0cd4 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1354,7 +1354,7 @@ static DEVICE_ATTR_RO(phy_standalone);
*
* Return: 0 on success, otherwise a negative error code.
*/
-int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
+static int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
{
struct phy_device *phydev = upstream;
struct net_device *dev = phydev->attached_dev;
@@ -1364,7 +1364,6 @@ int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
return 0;
}
-EXPORT_SYMBOL(phy_sfp_connect_phy);
/**
* phy_sfp_disconnect_phy - Disconnect the SFP module's PHY from the upstream PHY
@@ -1376,7 +1375,7 @@ EXPORT_SYMBOL(phy_sfp_connect_phy);
* will be destroyed, re-inserting the same module will add a new phy with a
* new index.
*/
-void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
+static void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
{
struct phy_device *phydev = upstream;
struct net_device *dev = phydev->attached_dev;
@@ -1384,7 +1383,6 @@ void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
if (dev)
phy_link_topo_del_phy(dev, phy);
}
-EXPORT_SYMBOL(phy_sfp_disconnect_phy);
/**
* phy_sfp_attach - attach the SFP bus to the PHY upstream network device
@@ -1393,7 +1391,7 @@ EXPORT_SYMBOL(phy_sfp_disconnect_phy);
*
* This is used to fill in the sfp_upstream_ops .attach member.
*/
-void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
+static void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
{
struct phy_device *phydev = upstream;
@@ -1401,7 +1399,6 @@ void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
phydev->attached_dev->sfp_bus = bus;
phydev->sfp_bus_attached = true;
}
-EXPORT_SYMBOL(phy_sfp_attach);
/**
* phy_sfp_detach - detach the SFP bus from the PHY upstream network device
@@ -1410,7 +1407,7 @@ EXPORT_SYMBOL(phy_sfp_attach);
*
* This is used to fill in the sfp_upstream_ops .detach member.
*/
-void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
+static void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
{
struct phy_device *phydev = upstream;
@@ -1418,7 +1415,6 @@ void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
phydev->attached_dev->sfp_bus = NULL;
phydev->sfp_bus_attached = false;
}
-EXPORT_SYMBOL(phy_sfp_detach);
static int phy_sfp_module_insert(void *upstream, const struct sfp_eeprom_id *id)
{
@@ -1561,10 +1557,8 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
/**
* phy_sfp_probe - probe for a SFP cage attached to this PHY device
* @phydev: Pointer to phy_device
- * @ops: SFP's upstream operations
*/
-int phy_sfp_probe(struct phy_device *phydev,
- const struct sfp_upstream_ops *ops)
+static int phy_sfp_probe(struct phy_device *phydev)
{
struct sfp_bus *bus;
int ret = 0;
@@ -1576,7 +1570,7 @@ int phy_sfp_probe(struct phy_device *phydev,
phydev->sfp_bus = bus;
- ret = sfp_bus_add_upstream(bus, phydev, ops);
+ ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
sfp_bus_put(bus);
}
@@ -1585,7 +1579,6 @@ int phy_sfp_probe(struct phy_device *phydev,
return ret;
}
-EXPORT_SYMBOL(phy_sfp_probe);
static bool phy_drv_supports_irq(const struct phy_driver *phydrv)
{
@@ -3635,12 +3628,9 @@ static int phy_setup_ports(struct phy_device *phydev)
if (ret)
return ret;
- /* Use generic SFP probing only if the driver didn't do so already */
- if (!phydev->sfp_bus) {
- ret = phy_sfp_probe(phydev, &sfp_phydev_ops);
- if (ret)
- goto out;
- }
+ ret = phy_sfp_probe(phydev);
+ if (ret)
+ goto out;
if (phydev->n_ports < phydev->max_n_ports) {
ret = phy_default_setup_single_port(phydev);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index b850af2500e4..12cf2d81567c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1909,12 +1909,6 @@ int phy_suspend(struct phy_device *phydev);
int phy_resume(struct phy_device *phydev);
int __phy_resume(struct phy_device *phydev);
int phy_loopback(struct phy_device *phydev, bool enable);
-int phy_sfp_connect_phy(void *upstream, struct phy_device *phy);
-void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy);
-void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
-void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
-int phy_sfp_probe(struct phy_device *phydev,
- const struct sfp_upstream_ops *ops);
struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
phy_interface_t interface);
struct phy_device *phy_find_first(struct mii_bus *bus);
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (10 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-08 16:15 ` kernel test robot
2025-02-07 22:36 ` [PATCH net-next 13/13] dt-bindings: net: Introduce the phy-port description Maxime Chevallier
` (2 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
The DP83822 can support 100BaseFX. This mode was only accessible through
custom DT properties, but there also exist SFP modules that support
these modes. As this only requires setting the relevant supported
interface in the driver, expose the port capability with the new
phy_port API, allowing SFP support.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/dp83822.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c
index af535b0a3914..873ba467cd57 100644
--- a/drivers/net/phy/dp83822.c
+++ b/drivers/net/phy/dp83822.c
@@ -908,6 +908,13 @@ static int dp83822_attach_port(struct phy_device *phydev, struct phy_port *port)
}
}
+ /* If attached from SFP, is_serdes is set, but not the mediums. */
+ if (port->is_serdes)
+ dp83822->fx_enabled = true;
+
+ if (dp83822->fx_enabled)
+ __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
+
return 0;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 13/13] dt-bindings: net: Introduce the phy-port description
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (11 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface Maxime Chevallier
@ 2025-02-07 22:36 ` Maxime Chevallier
2025-02-08 2:14 ` [PATCH net-next 00/13] Introduce an ethernet port representation Sean Anderson
2025-02-12 19:48 ` Rob Herring
14 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-07 22:36 UTC (permalink / raw)
To: davem
Cc: Maxime Chevallier, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
The ability to describe the physical ports of Ethernet devices is useful
to describe multi-port devices, as well as to remove any ambiguity with
regard to the nature of the port.
Moreover, describing ports allows for a better description of features
that are tied to connectors, such as PoE through the PSE-PD devices.
Introduce a binding to allow describing the ports, for now with 2
attributes :
- The number of lanes, which is a quite generic property that allows
differentating between multiple similar technologies such as BaseT1
and "regular" BaseT (which usually means BaseT4).
- The media that can be used on that port, such as BaseT for Twisted
Copper, BaseC for coax copper, BaseS/L for Fiber, BaseK for backplane
ethernet, etc. This allows defining the nature of the port, and
therefore avoids the need for vendor-specific properties such as
"micrel,fiber-mode" or "ti,fiber-mode".
The port description lives in its own file, as it is intended in the
future to allow describing the ports for phy-less devices.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
.../devicetree/bindings/net/ethernet-phy.yaml | 18 +++++++
.../bindings/net/ethernet-port.yaml | 47 +++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/ethernet-port.yaml
diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
index 2c71454ae8e3..950fdacfd27d 100644
--- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
@@ -261,6 +261,17 @@ properties:
additionalProperties: false
+ mdi:
+ type: object
+
+ patternProperties:
+ '^port-[a-f0-9]+$':
+ $ref: /schemas/net/ethernet-port.yaml#
+
+ unevaluatedProperties: false
+
+ additionalProperties: false
+
required:
- reg
@@ -297,5 +308,12 @@ examples:
default-state = "keep";
};
};
+
+ mdi {
+ port-0 {
+ lanes = <2>;
+ media = "BaseT";
+ };
+ };
};
};
diff --git a/Documentation/devicetree/bindings/net/ethernet-port.yaml b/Documentation/devicetree/bindings/net/ethernet-port.yaml
new file mode 100644
index 000000000000..bf0f64f1b0aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ethernet-port.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/ethernet-port.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic Ethernet Port
+
+maintainers:
+ - Maxime Chevallier <maxime.chevallier@bootlin.com>
+
+description:
+ An Ethernet port represents an output, such as a connector, of a network
+ component such as a PHY, an Ethernet controller with no PHY, or an SFP module.
+
+properties:
+
+ lanes:
+ description:
+ Defines the number of lanes on the port, that is the number of physical
+ channels used to convey the data with the link partner.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ media:
+ description:
+ The mediums, as defined in 802.3, that can be used on the port.
+ items:
+ enum:
+ - BaseT
+ - BaseK
+ - BaseS
+ - BaseC
+ - BaseL
+ - BaseD
+ - BaseE
+ - BaseF
+ - BaseV
+ - BaseMLD
+ - BaseX
+
+required:
+ - lanes
+ - media
+
+additionalProperties: true
+
+...
--
2.48.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (12 preceding siblings ...)
2025-02-07 22:36 ` [PATCH net-next 13/13] dt-bindings: net: Introduce the phy-port description Maxime Chevallier
@ 2025-02-08 2:14 ` Sean Anderson
2025-02-10 8:55 ` Maxime Chevallier
2025-02-12 19:48 ` Rob Herring
14 siblings, 1 reply; 30+ messages in thread
From: Sean Anderson @ 2025-02-08 2:14 UTC (permalink / raw)
To: Maxime Chevallier, davem
Cc: netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Hi Maxime,
On 2/7/25 17:36, Maxime Chevallier wrote:
> Hello everyone,
>
> This series follows the 2 RFC that were sent a few weeks ago :
> RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
> RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
>
> The goal of this series is to introduce an internal way of representing
> the "outputs" of ethernet devices, for now only focusing on PHYs.
>
> This allows laying the groundwork for multi-port devices support (both 1
> PHY 2 ports, or more exotic setups with 2 PHYs in parallel, or MII
> multiplexers).
>
> Compared to the RFCs, this series tries to properly support SFP,
> especially PHY-driven SFPs through special phy_ports named "serdes"
> ports. They have the particularity of outputing a generic interface,
> that feeds into another component (usually, an SFP cage and therefore an
> SFP module).
>
> This allows getting a fairly generic PHY-driven SFP support (MAC-driven
> SFP is handled by phylink).
>
> This series doesn't address PHY-less interfaces (bare MAC devices, MACs
> with embedded PHYs not driven by phylink, or MAC connected to optical
> SFPs) to stay within the 15 patches limit, nor does it include the uAPI
> part that exposes these ports to userspace.
>
> I've kept the cover short, much more details can be found in the RFC
> covers.
>
> Thanks everyone,
>
> Maxime
Forgive me for my ignorance, but why have a new ethtool interface instead of
extending ethtool_link_settings.port? It's a rather ancient interface, but it
seems to be tackling the exact same problem as you are trying to address. Older
NICs used to have several physical connectors (e.g. BNC, MII, twisted-pair) but
only one could be used at once. This seems directly analogous to a PHY that
supports multiple "port"s but not all at once. In fact, the only missing
connector type seems to be PORT_BACKPLANE.
I can think of a few reasons why you wouldn't use PORT_*:
- It describes the NIC and not the PHY, and perhaps there is too much impedance
mismatch?
- There is too much legacy in userspace (or in the kernel) to use that API in
this way?
- You need more flexibility?
At the very least, I think some discussion in one of the commits would be
warranted. Perhaps there was some on the RFC that I missed?
--Sean
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers
2025-02-07 22:36 ` [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers Maxime Chevallier
@ 2025-02-08 15:32 ` kernel test robot
0 siblings, 0 replies; 30+ messages in thread
From: kernel test robot @ 2025-02-08 15:32 UTC (permalink / raw)
To: Maxime Chevallier, davem
Cc: llvm, oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
linux-arm-msm, thomas.petazzoni, Andrew Lunn, Jakub Kicinski,
Eric Dumazet, Paolo Abeni, Russell King, linux-arm-kernel,
Christophe Leroy, Herve Codina, Florian Fainelli, Heiner Kallweit,
Vladimir Oltean, Köry Maincent, Marek Behún,
Oleksij Rempel, Nicolò Veronese, Simon Horman, mwojtas,
Antoine Tenart, devicetree, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, Romain Gantois
Hi Maxime,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-ethtool-Introduce-ETHTOOL_LINK_MEDIUM_-values/20250208-064223
base: net-next/main
patch link: https://lore.kernel.org/r/20250207223634.600218-7-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers
config: i386-buildonly-randconfig-004-20250208 (https://download.01.org/0day-ci/archive/20250208/202502082328.PaOrs2Uu-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250208/202502082328.PaOrs2Uu-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502082328.PaOrs2Uu-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/net/phy/phy_device.c:3682: warning: Function parameter or struct member 'phydev' not described in 'phy_get_sfp_port'
vim +3682 drivers/net/phy/phy_device.c
3677
3678 /**
3679 * phy_get_sfp_port() - Returns the first valid SFP port of a PHY
3680 */
3681 struct phy_port *phy_get_sfp_port(struct phy_device *phydev)
> 3682 {
3683 struct phy_port *port;
3684 list_for_each_entry(port, &phydev->ports, head)
3685 if (port->active && port->is_serdes)
3686 return port;
3687
3688 return NULL;
3689 }
3690 EXPORT_SYMBOL_GPL(phy_get_sfp_port);
3691
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP
2025-02-07 22:36 ` [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP Maxime Chevallier
@ 2025-02-08 16:04 ` kernel test robot
2025-02-11 9:17 ` Maxime Chevallier
0 siblings, 1 reply; 30+ messages in thread
From: kernel test robot @ 2025-02-08 16:04 UTC (permalink / raw)
To: Maxime Chevallier, davem
Cc: llvm, oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
linux-arm-msm, thomas.petazzoni, Andrew Lunn, Jakub Kicinski,
Eric Dumazet, Paolo Abeni, Russell King, linux-arm-kernel,
Christophe Leroy, Herve Codina, Florian Fainelli, Heiner Kallweit,
Vladimir Oltean, Köry Maincent, Marek Behún,
Oleksij Rempel, Nicolò Veronese, Simon Horman, mwojtas,
Antoine Tenart, devicetree, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, Romain Gantois
Hi Maxime,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-ethtool-Introduce-ETHTOOL_LINK_MEDIUM_-values/20250208-064223
base: net-next/main
patch link: https://lore.kernel.org/r/20250207223634.600218-12-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP
config: i386-buildonly-randconfig-005-20250208 (https://download.01.org/0day-ci/archive/20250208/202502082347.tFufJ529-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250208/202502082347.tFufJ529-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502082347.tFufJ529-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/phy/qcom/qca807x.c:698:12: error: use of undeclared identifier 'phy_sfp_attach'; did you mean 'phy_attach'?
698 | .attach = phy_sfp_attach,
| ^~~~~~~~~~~~~~
| phy_attach
include/linux/phy.h:1912:20: note: 'phy_attach' declared here
1912 | struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
| ^
>> drivers/net/phy/qcom/qca807x.c:699:12: error: use of undeclared identifier 'phy_sfp_detach'; did you mean 'phy_detach'?
699 | .detach = phy_sfp_detach,
| ^~~~~~~~~~~~~~
| phy_detach
include/linux/phy.h:1924:6: note: 'phy_detach' declared here
1924 | void phy_detach(struct phy_device *phydev);
| ^
>> drivers/net/phy/qcom/qca807x.c:702:17: error: use of undeclared identifier 'phy_sfp_connect_phy'
702 | .connect_phy = phy_sfp_connect_phy,
| ^
>> drivers/net/phy/qcom/qca807x.c:703:20: error: use of undeclared identifier 'phy_sfp_disconnect_phy'
703 | .disconnect_phy = phy_sfp_disconnect_phy,
| ^
>> drivers/net/phy/qcom/qca807x.c:748:9: error: call to undeclared function 'phy_sfp_probe'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
748 | ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
| ^
5 errors generated.
vim +698 drivers/net/phy/qcom/qca807x.c
d1cb613efbd3cd Robert Marko 2024-02-06 696
d1cb613efbd3cd Robert Marko 2024-02-06 697 static const struct sfp_upstream_ops qca807x_sfp_ops = {
d1cb613efbd3cd Robert Marko 2024-02-06 @698 .attach = phy_sfp_attach,
d1cb613efbd3cd Robert Marko 2024-02-06 @699 .detach = phy_sfp_detach,
d1cb613efbd3cd Robert Marko 2024-02-06 700 .module_insert = qca807x_sfp_insert,
d1cb613efbd3cd Robert Marko 2024-02-06 701 .module_remove = qca807x_sfp_remove,
b2db6f4ace72e7 Maxime Chevallier 2024-08-21 @702 .connect_phy = phy_sfp_connect_phy,
b2db6f4ace72e7 Maxime Chevallier 2024-08-21 @703 .disconnect_phy = phy_sfp_disconnect_phy,
d1cb613efbd3cd Robert Marko 2024-02-06 704 };
d1cb613efbd3cd Robert Marko 2024-02-06 705
d1cb613efbd3cd Robert Marko 2024-02-06 706 static int qca807x_probe(struct phy_device *phydev)
d1cb613efbd3cd Robert Marko 2024-02-06 707 {
d1cb613efbd3cd Robert Marko 2024-02-06 708 struct device_node *node = phydev->mdio.dev.of_node;
d1cb613efbd3cd Robert Marko 2024-02-06 709 struct qca807x_shared_priv *shared_priv;
d1cb613efbd3cd Robert Marko 2024-02-06 710 struct device *dev = &phydev->mdio.dev;
d1cb613efbd3cd Robert Marko 2024-02-06 711 struct phy_package_shared *shared;
d1cb613efbd3cd Robert Marko 2024-02-06 712 struct qca807x_priv *priv;
d1cb613efbd3cd Robert Marko 2024-02-06 713 int ret;
d1cb613efbd3cd Robert Marko 2024-02-06 714
d1cb613efbd3cd Robert Marko 2024-02-06 715 ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));
d1cb613efbd3cd Robert Marko 2024-02-06 716 if (ret)
d1cb613efbd3cd Robert Marko 2024-02-06 717 return ret;
d1cb613efbd3cd Robert Marko 2024-02-06 718
d1cb613efbd3cd Robert Marko 2024-02-06 719 if (phy_package_probe_once(phydev)) {
d1cb613efbd3cd Robert Marko 2024-02-06 720 ret = qca807x_phy_package_probe_once(phydev);
d1cb613efbd3cd Robert Marko 2024-02-06 721 if (ret)
d1cb613efbd3cd Robert Marko 2024-02-06 722 return ret;
d1cb613efbd3cd Robert Marko 2024-02-06 723 }
d1cb613efbd3cd Robert Marko 2024-02-06 724
d1cb613efbd3cd Robert Marko 2024-02-06 725 shared = phydev->shared;
d1cb613efbd3cd Robert Marko 2024-02-06 726 shared_priv = shared->priv;
d1cb613efbd3cd Robert Marko 2024-02-06 727
d1cb613efbd3cd Robert Marko 2024-02-06 728 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
d1cb613efbd3cd Robert Marko 2024-02-06 729 if (!priv)
d1cb613efbd3cd Robert Marko 2024-02-06 730 return -ENOMEM;
d1cb613efbd3cd Robert Marko 2024-02-06 731
d1cb613efbd3cd Robert Marko 2024-02-06 732 priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude");
d1cb613efbd3cd Robert Marko 2024-02-06 733 priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current");
d1cb613efbd3cd Robert Marko 2024-02-06 734 priv->dac_disable_bias_current_tweak = of_property_read_bool(node,
d1cb613efbd3cd Robert Marko 2024-02-06 735 "qcom,dac-disable-bias-current-tweak");
d1cb613efbd3cd Robert Marko 2024-02-06 736
1677293ed89166 Robert Marko 2024-03-05 737 #if IS_ENABLED(CONFIG_GPIOLIB)
d1cb613efbd3cd Robert Marko 2024-02-06 738 /* Do not register a GPIO controller unless flagged for it */
d1cb613efbd3cd Robert Marko 2024-02-06 739 if (of_property_read_bool(node, "gpio-controller")) {
d1cb613efbd3cd Robert Marko 2024-02-06 740 ret = qca807x_gpio(phydev);
d1cb613efbd3cd Robert Marko 2024-02-06 741 if (ret)
d1cb613efbd3cd Robert Marko 2024-02-06 742 return ret;
d1cb613efbd3cd Robert Marko 2024-02-06 743 }
1677293ed89166 Robert Marko 2024-03-05 744 #endif
d1cb613efbd3cd Robert Marko 2024-02-06 745
d1cb613efbd3cd Robert Marko 2024-02-06 746 /* Attach SFP bus on combo port*/
d1cb613efbd3cd Robert Marko 2024-02-06 747 if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
d1cb613efbd3cd Robert Marko 2024-02-06 @748 ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
d1cb613efbd3cd Robert Marko 2024-02-06 749 if (ret)
d1cb613efbd3cd Robert Marko 2024-02-06 750 return ret;
d1cb613efbd3cd Robert Marko 2024-02-06 751 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
d1cb613efbd3cd Robert Marko 2024-02-06 752 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
d1cb613efbd3cd Robert Marko 2024-02-06 753 }
d1cb613efbd3cd Robert Marko 2024-02-06 754
d1cb613efbd3cd Robert Marko 2024-02-06 755 phydev->priv = priv;
d1cb613efbd3cd Robert Marko 2024-02-06 756
d1cb613efbd3cd Robert Marko 2024-02-06 757 return 0;
d1cb613efbd3cd Robert Marko 2024-02-06 758 }
d1cb613efbd3cd Robert Marko 2024-02-06 759
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface
2025-02-07 22:36 ` [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface Maxime Chevallier
@ 2025-02-08 16:15 ` kernel test robot
0 siblings, 0 replies; 30+ messages in thread
From: kernel test robot @ 2025-02-08 16:15 UTC (permalink / raw)
To: Maxime Chevallier, davem
Cc: llvm, oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
linux-arm-msm, thomas.petazzoni, Andrew Lunn, Jakub Kicinski,
Eric Dumazet, Paolo Abeni, Russell King, linux-arm-kernel,
Christophe Leroy, Herve Codina, Florian Fainelli, Heiner Kallweit,
Vladimir Oltean, Köry Maincent, Marek Behún,
Oleksij Rempel, Nicolò Veronese, Simon Horman, mwojtas,
Antoine Tenart, devicetree, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, Romain Gantois
Hi Maxime,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-ethtool-Introduce-ETHTOOL_LINK_MEDIUM_-values/20250208-064223
base: net-next/main
patch link: https://lore.kernel.org/r/20250207223634.600218-13-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface
config: i386-buildonly-randconfig-004-20250208 (https://download.01.org/0day-ci/archive/20250209/202502090056.jTCOvIPk-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250209/202502090056.jTCOvIPk-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502090056.jTCOvIPk-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/phy/dp83822.c:916:43: error: use of undeclared identifier 'interfaces'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
>> drivers/net/phy/dp83822.c:916:13: error: use of undeclared identifier 'PHY_INTERFACE_MODE_100BASEFX'; did you mean 'PHY_INTERFACE_MODE_100BASEX'?
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| PHY_INTERFACE_MODE_100BASEX
include/linux/bitops.h:54:48: note: expanded from macro '__set_bit'
54 | #define __set_bit(nr, addr) bitop(___set_bit, nr, addr)
| ^
include/linux/bitops.h:44:25: note: expanded from macro 'bitop'
44 | ((__builtin_constant_p(nr) && \
| ^
include/linux/phy.h:140:2: note: 'PHY_INTERFACE_MODE_100BASEX' declared here
140 | PHY_INTERFACE_MODE_100BASEX,
| ^
>> drivers/net/phy/dp83822.c:916:43: error: use of undeclared identifier 'interfaces'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
>> drivers/net/phy/dp83822.c:916:43: error: use of undeclared identifier 'interfaces'
drivers/net/phy/dp83822.c:916:13: error: use of undeclared identifier 'PHY_INTERFACE_MODE_100BASEFX'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
>> drivers/net/phy/dp83822.c:916:43: error: use of undeclared identifier 'interfaces'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
drivers/net/phy/dp83822.c:916:13: error: use of undeclared identifier 'PHY_INTERFACE_MODE_100BASEFX'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
>> drivers/net/phy/dp83822.c:916:43: error: use of undeclared identifier 'interfaces'
916 | __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
| ^
8 errors generated.
vim +/interfaces +916 drivers/net/phy/dp83822.c
899
900 if (dp83822->fx_enabled) {
901 port->lanes = 1;
902 port->mediums = BIT(ETHTOOL_LINK_MEDIUM_BASEF) |
903 BIT(ETHTOOL_LINK_MEDIUM_BASEX);
904 } else {
905 /* This PHY can only to 100BaseTX max, so on 2 lanes */
906 port->lanes = 2;
907 port->mediums = BIT(ETHTOOL_LINK_MEDIUM_BASET);
908 }
909 }
910
911 /* If attached from SFP, is_serdes is set, but not the mediums. */
912 if (port->is_serdes)
913 dp83822->fx_enabled = true;
914
915 if (dp83822->fx_enabled)
> 916 __set_bit(PHY_INTERFACE_MODE_100BASEFX, interfaces);
917
918 return 0;
919 }
920
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-08 2:14 ` [PATCH net-next 00/13] Introduce an ethernet port representation Sean Anderson
@ 2025-02-10 8:55 ` Maxime Chevallier
2025-02-12 15:39 ` Sean Anderson
0 siblings, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-10 8:55 UTC (permalink / raw)
To: Sean Anderson
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Hi Sean,
On Fri, 7 Feb 2025 21:14:32 -0500
Sean Anderson <seanga2@gmail.com> wrote:
> Hi Maxime,
>
> On 2/7/25 17:36, Maxime Chevallier wrote:
> > Hello everyone,
> >
> > This series follows the 2 RFC that were sent a few weeks ago :
> > RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
> > RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
> >
> > The goal of this series is to introduce an internal way of representing
> > the "outputs" of ethernet devices, for now only focusing on PHYs.
> >
> > This allows laying the groundwork for multi-port devices support (both 1
> > PHY 2 ports, or more exotic setups with 2 PHYs in parallel, or MII
> > multiplexers).
> >
> > Compared to the RFCs, this series tries to properly support SFP,
> > especially PHY-driven SFPs through special phy_ports named "serdes"
> > ports. They have the particularity of outputing a generic interface,
> > that feeds into another component (usually, an SFP cage and therefore an
> > SFP module).
> >
> > This allows getting a fairly generic PHY-driven SFP support (MAC-driven
> > SFP is handled by phylink).
> >
> > This series doesn't address PHY-less interfaces (bare MAC devices, MACs
> > with embedded PHYs not driven by phylink, or MAC connected to optical
> > SFPs) to stay within the 15 patches limit, nor does it include the uAPI
> > part that exposes these ports to userspace.
> >
> > I've kept the cover short, much more details can be found in the RFC
> > covers.
> >
> > Thanks everyone,
> >
> > Maxime
>
> Forgive me for my ignorance, but why have a new ethtool interface instead of
> extending ethtool_link_settings.port? It's a rather ancient interface, but it
> seems to be tackling the exact same problem as you are trying to address. Older
> NICs used to have several physical connectors (e.g. BNC, MII, twisted-pair) but
> only one could be used at once. This seems directly analogous to a PHY that
> supports multiple "port"s but not all at once. In fact, the only missing
> connector type seems to be PORT_BACKPLANE.
>
> I can think of a few reasons why you wouldn't use PORT_*:
>
> - It describes the NIC and not the PHY, and perhaps there is too much impedance
> mismatch?
> - There is too much legacy in userspace (or in the kernel) to use that API in
> this way?
> - You need more flexibility?
So there are multiple reasons that make the PORT_* field limited :
- We can't gracefully handle multi-port PHYs for complex scenarios
where we could say "I'm currently using the Copper port, but does the
Fiber port has link ?"
- As you mention in your first argument, what I'd like to try to do is
come-up with a "generic" representation of outgoing NIC interfaces. The
final use-cases I'd like to cover are multi-port NICs, allowing
userspace to control which physical interfaces are available, and which
t use. Looking at the hardware, this can be implemented in multiple
ways :
___ Copper
/
MAC - PHY
\__ SFP
Here, a single PHY has 2 media-side interfaces, and we'd like to select
the one to use. That's fairly common now, there are quite a number of
PHYs that support this : mv33x3310, VSC8552, mv88x2222 only to name a
few. But there are other, more uncommon topologies that exist :
____ SGMII PHY -- Copper
/
MAC - SGMII/1000BaseX MUX
\____ SFP
Here, we also have 2 media-side ports, but they are driver through
different entities : The Copper port sits behind a single-port PHY,
that is itself behind a *MII MUX, that's also connected to an SFP. Here
the port selection is done at the MUX level
Finally, I've been working on supporting devices whith another topology
(actually, what started this whole work) :
___ PHY
/
MAC --MUX |
\__ PHY
Here both PHYs are on the same *MII bus, with some physical,
gpio-driven MUX, and we have 2 PORT_TP on the same NIC. That design is
used for link redundancy, if one PHY loses the link, we switch to the
other one (that hopefully has link).
All these cases have different drivers involved in the MUX'ing (phy
driver itself, intermediate MUX in-between...), so the end-goal would
be to expose to userspace info about the media interfaces themselves.
This phy_port object would be what we expose to userspace. One missing
step in this series is adding control on the ports (netlink API,
enabling/disabling logic for ports) but that far exceeds the 15 patches
limitation :)
Sorry if all of that was blurry, I did make so good of a job linking to
all previous discussions on the topic, I'll address that for the next
round.
Thanks,
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP
2025-02-08 16:04 ` kernel test robot
@ 2025-02-11 9:17 ` Maxime Chevallier
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-11 9:17 UTC (permalink / raw)
To: kernel test robot
Cc: davem, llvm, oe-kbuild-all, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Russell King, linux-arm-kernel, Christophe Leroy,
Herve Codina, Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois, Robert Marko
Hi,
On Sun, 9 Feb 2025 00:04:55 +0800
kernel test robot <lkp@intel.com> wrote:
> Hi Maxime,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on net-next/main]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-ethtool-Introduce-ETHTOOL_LINK_MEDIUM_-values/20250208-064223
> base: net-next/main
> patch link: https://lore.kernel.org/r/20250207223634.600218-12-maxime.chevallier%40bootlin.com
> patch subject: [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP
> config: i386-buildonly-randconfig-005-20250208 (https://download.01.org/0day-ci/archive/20250208/202502082347.tFufJ529-lkp@intel.com/config)
> compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250208/202502082347.tFufJ529-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202502082347.tFufJ529-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> >> drivers/net/phy/qcom/qca807x.c:698:12: error: use of undeclared identifier 'phy_sfp_attach'; did you mean 'phy_attach'?
> 698 | .attach = phy_sfp_attach,
> | ^~~~~~~~~~~~~~
> | phy_attach
> include/linux/phy.h:1912:20: note: 'phy_attach' declared here
> 1912 | struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
> | ^
> >> drivers/net/phy/qcom/qca807x.c:699:12: error: use of undeclared identifier 'phy_sfp_detach'; did you mean 'phy_detach'?
> 699 | .detach = phy_sfp_detach,
> | ^~~~~~~~~~~~~~
> | phy_detach
> include/linux/phy.h:1924:6: note: 'phy_detach' declared here
> 1924 | void phy_detach(struct phy_device *phydev);
> | ^
> >> drivers/net/phy/qcom/qca807x.c:702:17: error: use of undeclared identifier 'phy_sfp_connect_phy'
> 702 | .connect_phy = phy_sfp_connect_phy,
> | ^
> >> drivers/net/phy/qcom/qca807x.c:703:20: error: use of undeclared identifier 'phy_sfp_disconnect_phy'
> 703 | .disconnect_phy = phy_sfp_disconnect_phy,
> | ^
> >> drivers/net/phy/qcom/qca807x.c:748:9: error: call to undeclared function 'phy_sfp_probe'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> 748 | ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
> | ^
> 5 errors generated.
Ah damned, I missed that qca807x now also supports SFP. I'll include a
conversion fr that driver too in V2 (and add Robert in CC:)
Thanks,
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-07 22:36 ` [PATCH net-next 03/13] net: phy: Introduce PHY ports representation Maxime Chevallier
@ 2025-02-11 13:32 ` Kory Maincent
2025-02-11 13:42 ` Maxime Chevallier
2025-02-11 14:04 ` Andrew Lunn
0 siblings, 2 replies; 30+ messages in thread
From: Kory Maincent @ 2025-02-11 13:32 UTC (permalink / raw)
To: Maxime Chevallier
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Marek Behún, Oleksij Rempel, Nicolò Veronese,
Simon Horman, mwojtas, Antoine Tenart, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring, Romain Gantois
On Fri, 7 Feb 2025 23:36:22 +0100
Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
> Ethernet provides a wide variety of layer 1 protocols and standards for
> data transmission. The front-facing ports of an interface have their own
> complexity and configurability.
>
> Introduce a representation of these front-facing ports. The current code
> is minimalistic and only support ports controlled by PHY devices, but
> the plan is to extend that to SFP as well as raw Ethernet MACs that
> don't use PHY devices.
>
> This minimal port representation allows describing the media and number
> of lanes of a port. From that information, we can derive the linkmodes
> usable on the port, which can be used to limit the capabilities of an
> interface.
>
> For now, the port lanes and medium is derived from devicetree, defined
> by the PHY driver, or populated with default values (as we assume that
> all PHYs expose at least one port).
>
> The typical example is 100M ethernet. 100BaseT can work using only 2
> lanes on a Cat 5 cables. However, in the situation where a 10/100/1000
> capable PHY is wired to its RJ45 port through 2 lanes only, we have no
> way of detecting that. The "max-speed" DT property can be used, but a
> more accurate representation can be used :
>
> mdi {
> port@0 {
> media = "BaseT";
> lanes = <2>;
> };
> };
>
> From that information, we can derive the max speed reachable on the
> port.
>
> Another benefit of having that is to avoid vendor-specific DT properties
> (micrel,fiber-mode or ti,fiber-mode).
>
> This basic representation is meant to be expanded, by the introduction
> of port ops, userspace listing of ports, and support for multi-port
> devices.
This patch is tackling the support of ports only for the PHY API. Keeping in
mind that this port abstraction support will also be of interest to the NICs.
Isn't it preferable to handle port in a standalone API?
With net drivers having PHY managed by the firmware or DSA, there is no linux
description of their PHYs. On that case, if we want to use port abstraction,
what is the best? Register a virtual phy_device to use the abstraction port or
use the port abstraction API directly which meant that it is not related to any
PHY?
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-11 13:32 ` Kory Maincent
@ 2025-02-11 13:42 ` Maxime Chevallier
2025-02-11 13:52 ` Kory Maincent
2025-02-11 14:04 ` Andrew Lunn
1 sibling, 1 reply; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-11 13:42 UTC (permalink / raw)
To: Kory Maincent
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Marek Behún, Oleksij Rempel, Nicolò Veronese,
Simon Horman, mwojtas, Antoine Tenart, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring, Romain Gantois
Hi Köry,
On Tue, 11 Feb 2025 14:32:09 +0100
Kory Maincent <kory.maincent@bootlin.com> wrote:
> On Fri, 7 Feb 2025 23:36:22 +0100
> Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
>
> > Ethernet provides a wide variety of layer 1 protocols and standards for
> > data transmission. The front-facing ports of an interface have their own
> > complexity and configurability.
> >
> > Introduce a representation of these front-facing ports. The current code
> > is minimalistic and only support ports controlled by PHY devices, but
> > the plan is to extend that to SFP as well as raw Ethernet MACs that
> > don't use PHY devices.
> >
> > This minimal port representation allows describing the media and number
> > of lanes of a port. From that information, we can derive the linkmodes
> > usable on the port, which can be used to limit the capabilities of an
> > interface.
> >
> > For now, the port lanes and medium is derived from devicetree, defined
> > by the PHY driver, or populated with default values (as we assume that
> > all PHYs expose at least one port).
> >
> > The typical example is 100M ethernet. 100BaseT can work using only 2
> > lanes on a Cat 5 cables. However, in the situation where a 10/100/1000
> > capable PHY is wired to its RJ45 port through 2 lanes only, we have no
> > way of detecting that. The "max-speed" DT property can be used, but a
> > more accurate representation can be used :
> >
> > mdi {
> > port@0 {
> > media = "BaseT";
> > lanes = <2>;
> > };
> > };
> >
> > From that information, we can derive the max speed reachable on the
> > port.
> >
> > Another benefit of having that is to avoid vendor-specific DT properties
> > (micrel,fiber-mode or ti,fiber-mode).
> >
> > This basic representation is meant to be expanded, by the introduction
> > of port ops, userspace listing of ports, and support for multi-port
> > devices.
>
> This patch is tackling the support of ports only for the PHY API. Keeping in
> mind that this port abstraction support will also be of interest to the NICs.
> Isn't it preferable to handle port in a standalone API?
The way I see it, nothing prevents from using the port definition in
ethernet-port.yml in DSA/raw nics.
> With net drivers having PHY managed by the firmware or DSA, there is no linux
> description of their PHYs. On that case, if we want to use port abstraction,
> what is the best? Register a virtual phy_device to use the abstraction port or
> use the port abstraction API directly which meant that it is not related to any
> PHY?
I think the next steps will be to have net_device have a list of ports
(maintained in the phy_link_topology) that aggregates ports from all
its PHYs/SFPs/raw interfaces. in that case net_device will be the
direct parent. I haven't worked on the bindings for that though,
especially for DSA :'(
I don't think the virtual phydev is going to be helpful. I'm hitting
the 15 patches limit, but a possible extension is to make so that
phylink also creates a port when it finds an SFP (hence, when upstream
is a MAC).
This is why phy_port has these fields :
enum phy_port_parent {
PHY_PORT_PHY,
};
struct phy_port {
...
enum phy_port_parent parent_type;
union {
struct phy_device *phy;
};
};
The parent type may (will) be extended with PORT_PHY_MAC, and that's
also why the parent pointer is in a union :)
I'm trying hard to make so that phy_port doesn't depend on phylib
(altough, phylib depends on phy_port). There's a dependency on some
core stuff (converting from medium => linkmodes) and phylink
(converting the interfaces list to linkmodes), but we can extract these
fairly easily.
You're correct in that for now, the integration is with phylib only
though, but let's make sure this will also work for phy-less devices.
Thanks a lot for your input,
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-11 13:42 ` Maxime Chevallier
@ 2025-02-11 13:52 ` Kory Maincent
0 siblings, 0 replies; 30+ messages in thread
From: Kory Maincent @ 2025-02-11 13:52 UTC (permalink / raw)
To: Maxime Chevallier
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Marek Behún, Oleksij Rempel, Nicolò Veronese,
Simon Horman, mwojtas, Antoine Tenart, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring, Romain Gantois
On Tue, 11 Feb 2025 14:42:43 +0100
Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
> Hi Köry,
>
> On Tue, 11 Feb 2025 14:32:09 +0100
> Kory Maincent <kory.maincent@bootlin.com> wrote:
>
> > On Fri, 7 Feb 2025 23:36:22 +0100
> > Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
> >
> > > Ethernet provides a wide variety of layer 1 protocols and standards for
> > > data transmission. The front-facing ports of an interface have their own
> > > complexity and configurability.
> > >
> > > Introduce a representation of these front-facing ports. The current code
> > > is minimalistic and only support ports controlled by PHY devices, but
> > > the plan is to extend that to SFP as well as raw Ethernet MACs that
> > > don't use PHY devices.
> > >
> > > This minimal port representation allows describing the media and number
> > > of lanes of a port. From that information, we can derive the linkmodes
> > > usable on the port, which can be used to limit the capabilities of an
> > > interface.
> > >
> > > For now, the port lanes and medium is derived from devicetree, defined
> > > by the PHY driver, or populated with default values (as we assume that
> > > all PHYs expose at least one port).
> > >
> > > The typical example is 100M ethernet. 100BaseT can work using only 2
> > > lanes on a Cat 5 cables. However, in the situation where a 10/100/1000
> > > capable PHY is wired to its RJ45 port through 2 lanes only, we have no
> > > way of detecting that. The "max-speed" DT property can be used, but a
> > > more accurate representation can be used :
> > >
> > > mdi {
> > > port@0 {
> > > media = "BaseT";
> > > lanes = <2>;
> > > };
> > > };
> > >
> > > From that information, we can derive the max speed reachable on the
> > > port.
> > >
> > > Another benefit of having that is to avoid vendor-specific DT properties
> > > (micrel,fiber-mode or ti,fiber-mode).
> > >
> > > This basic representation is meant to be expanded, by the introduction
> > > of port ops, userspace listing of ports, and support for multi-port
> > > devices.
> >
> > This patch is tackling the support of ports only for the PHY API. Keeping in
> > mind that this port abstraction support will also be of interest to the
> > NICs. Isn't it preferable to handle port in a standalone API?
>
> The way I see it, nothing prevents from using the port definition in
> ethernet-port.yml in DSA/raw nics.
>
> > With net drivers having PHY managed by the firmware or DSA, there is no
> > linux description of their PHYs. On that case, if we want to use port
> > abstraction, what is the best? Register a virtual phy_device to use the
> > abstraction port or use the port abstraction API directly which meant that
> > it is not related to any PHY?
>
> I think the next steps will be to have net_device have a list of ports
> (maintained in the phy_link_topology) that aggregates ports from all
> its PHYs/SFPs/raw interfaces. in that case net_device will be the
> direct parent. I haven't worked on the bindings for that though,
> especially for DSA :'(
Having it under phy_link_topology is a great idea!
> I don't think the virtual phydev is going to be helpful. I'm hitting
> the 15 patches limit, but a possible extension is to make so that
> phylink also creates a port when it finds an SFP (hence, when upstream
> is a MAC).
I would say not only for SFP but phylink should create a port when it can find
a mdi description in the devicetree. Port with PoE, leds or whatever future
supported features should be created by phylink.
> This is why phy_port has these fields :
>
>
> enum phy_port_parent {
> PHY_PORT_PHY,
> };
>
> struct phy_port {
> ...
> enum phy_port_parent parent_type;
> union {
> struct phy_device *phy;
> };
>
> };
>
> The parent type may (will) be extended with PORT_PHY_MAC, and that's
> also why the parent pointer is in a union :)
Ok for me!
> I'm trying hard to make so that phy_port doesn't depend on phylib
> (altough, phylib depends on phy_port). There's a dependency on some
> core stuff (converting from medium => linkmodes) and phylink
> (converting the interfaces list to linkmodes), but we can extract these
> fairly easily.
>
> You're correct in that for now, the integration is with phylib only
> though, but let's make sure this will also work for phy-less devices.
>
> Thanks a lot for your input,
Thanks for your work, it will be really helpful to add support for PoE in DSA.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-11 13:32 ` Kory Maincent
2025-02-11 13:42 ` Maxime Chevallier
@ 2025-02-11 14:04 ` Andrew Lunn
2025-02-11 14:17 ` Maxime Chevallier
1 sibling, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2025-02-11 14:04 UTC (permalink / raw)
To: Kory Maincent
Cc: Maxime Chevallier, davem, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Marek Behún, Oleksij Rempel, Nicolò Veronese,
Simon Horman, mwojtas, Antoine Tenart, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring, Romain Gantois
> With net drivers having PHY managed by the firmware or DSA, there is no linux
> description of their PHYs.
DSA should not be special, Linux is driving the PHY so it has to exist
as a linux device.
Firmware is a different case. If the firmware has decided to hide the
PHY, the MAC driver is using a higher level API, generally just
ksetting_set etc. It would be up to the MAC driver to export its PHY
topology and provide whatever other firmware calls are needed. We
should keep this in mind when designing the kAPI, but don't need to
actually implement it. The kAPI should not directly reference a
phydev/phylink instance, but an abstract object which represents a
PHY.
Andrew
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/13] net: phy: Introduce PHY ports representation
2025-02-11 14:04 ` Andrew Lunn
@ 2025-02-11 14:17 ` Maxime Chevallier
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-11 14:17 UTC (permalink / raw)
To: Andrew Lunn
Cc: Kory Maincent, davem, netdev, linux-kernel, linux-arm-msm,
thomas.petazzoni, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Marek Behún, Oleksij Rempel, Nicolò Veronese,
Simon Horman, mwojtas, Antoine Tenart, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring, Romain Gantois
On Tue, 11 Feb 2025 15:04:27 +0100
Andrew Lunn <andrew@lunn.ch> wrote:
> > With net drivers having PHY managed by the firmware or DSA, there is no linux
> > description of their PHYs.
>
> DSA should not be special, Linux is driving the PHY so it has to exist
> as a linux device.
>
> Firmware is a different case. If the firmware has decided to hide the
> PHY, the MAC driver is using a higher level API, generally just
> ksetting_set etc. It would be up to the MAC driver to export its PHY
> topology and provide whatever other firmware calls are needed. We
> should keep this in mind when designing the kAPI, but don't need to
> actually implement it. The kAPI should not directly reference a
> phydev/phylink instance, but an abstract object which represents a
> PHY.
That's fine by me for the port representation, and I'm on the same page
here. In the end, the ways for a NIC to register its interfaces would
be :
- phylib, as done in this series. The port is controlled by the PHY,
the phy_port_ops are implemented in the PHY driver + phylib, we
discover the ports based on what the PHY reports, the new port binding
and the presence of an SFP phandle under the PHY.
- phylink, and what I mean by phylink is actually SFP (phylink is the
SFP upstream in PHY-less SFP setups, so it would create the phy_port,
nothing more). what we cover here are MACs that are connected directly
to an SFP cage. This is simply because phylink parses the sfp phandle,
so it's an easy spot to make sure we create the NIC's port without
rewriting all drivers.
- NIC drivers themselves, for drivers that don't use phylink/phylib.
For now this series only has the "phy_add_port" kAPI, which only really
covers case 1. But netdev_add_port() can clearly be implemented as well.
I'm having a hard time splitting that work in digestable chunks :(
I've focused on PHY as a reference use for ports, but the end-goal
clearly is a generic way to expose what interfaces a netdev has, either
through PHY, SFP or firmware.
Thanks,
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-10 8:55 ` Maxime Chevallier
@ 2025-02-12 15:39 ` Sean Anderson
2025-02-12 15:44 ` Maxime Chevallier
0 siblings, 1 reply; 30+ messages in thread
From: Sean Anderson @ 2025-02-12 15:39 UTC (permalink / raw)
To: Maxime Chevallier
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Hi Maxime,
On 2/10/25 03:55, Maxime Chevallier wrote:
> Hi Sean,
>
> On Fri, 7 Feb 2025 21:14:32 -0500
> Sean Anderson <seanga2@gmail.com> wrote:
>
>> Hi Maxime,
>>
>> On 2/7/25 17:36, Maxime Chevallier wrote:
>>> Hello everyone,
>>>
>>> This series follows the 2 RFC that were sent a few weeks ago :
>>> RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
>>> RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
>>>
>>> The goal of this series is to introduce an internal way of representing
>>> the "outputs" of ethernet devices, for now only focusing on PHYs.
>>>
>>> This allows laying the groundwork for multi-port devices support (both 1
>>> PHY 2 ports, or more exotic setups with 2 PHYs in parallel, or MII
>>> multiplexers).
>>>
>>> Compared to the RFCs, this series tries to properly support SFP,
>>> especially PHY-driven SFPs through special phy_ports named "serdes"
>>> ports. They have the particularity of outputing a generic interface,
>>> that feeds into another component (usually, an SFP cage and therefore an
>>> SFP module).
>>>
>>> This allows getting a fairly generic PHY-driven SFP support (MAC-driven
>>> SFP is handled by phylink).
>>>
>>> This series doesn't address PHY-less interfaces (bare MAC devices, MACs
>>> with embedded PHYs not driven by phylink, or MAC connected to optical
>>> SFPs) to stay within the 15 patches limit, nor does it include the uAPI
>>> part that exposes these ports to userspace.
>>>
>>> I've kept the cover short, much more details can be found in the RFC
>>> covers.
>>>
>>> Thanks everyone,
>>>
>>> Maxime
>>
>> Forgive me for my ignorance, but why have a new ethtool interface instead of
>> extending ethtool_link_settings.port? It's a rather ancient interface, but it
>> seems to be tackling the exact same problem as you are trying to address. Older
>> NICs used to have several physical connectors (e.g. BNC, MII, twisted-pair) but
>> only one could be used at once. This seems directly analogous to a PHY that
>> supports multiple "port"s but not all at once. In fact, the only missing
>> connector type seems to be PORT_BACKPLANE.
>>
>> I can think of a few reasons why you wouldn't use PORT_*:
>>
>> - It describes the NIC and not the PHY, and perhaps there is too much impedance
>> mismatch?
>> - There is too much legacy in userspace (or in the kernel) to use that API in
>> this way?
>> - You need more flexibility?
>
> So there are multiple reasons that make the PORT_* field limited :
>
> - We can't gracefully handle multi-port PHYs for complex scenarios
> where we could say "I'm currently using the Copper port, but does the
> Fiber port has link ?"
>
> - As you mention in your first argument, what I'd like to try to do is
> come-up with a "generic" representation of outgoing NIC interfaces. The
> final use-cases I'd like to cover are multi-port NICs, allowing
> userspace to control which physical interfaces are available, and which
> t use. Looking at the hardware, this can be implemented in multiple
> ways :
>
> ___ Copper
> /
> MAC - PHY
> \__ SFP
>
> Here, a single PHY has 2 media-side interfaces, and we'd like to select
> the one to use. That's fairly common now, there are quite a number of
> PHYs that support this : mv33x3310, VSC8552, mv88x2222 only to name a
> few. But there are other, more uncommon topologies that exist :
>
> ____ SGMII PHY -- Copper
> /
> MAC - SGMII/1000BaseX MUX
> \____ SFP
>
> Here, we also have 2 media-side ports, but they are driver through
> different entities : The Copper port sits behind a single-port PHY,
> that is itself behind a *MII MUX, that's also connected to an SFP. Here
> the port selection is done at the MUX level
>
> Finally, I've been working on supporting devices whith another topology
> (actually, what started this whole work) :
>
> ___ PHY
> /
> MAC --MUX |
> \__ PHY
>
> Here both PHYs are on the same *MII bus, with some physical,
> gpio-driven MUX, and we have 2 PORT_TP on the same NIC. That design is
> used for link redundancy, if one PHY loses the link, we switch to the
> other one (that hopefully has link).
>
> All these cases have different drivers involved in the MUX'ing (phy
> driver itself, intermediate MUX in-between...), so the end-goal would
> be to expose to userspace info about the media interfaces themselves.
>
> This phy_port object would be what we expose to userspace. One missing
> step in this series is adding control on the ports (netlink API,
> enabling/disabling logic for ports) but that far exceeds the 15 patches
> limitation :)
>
> Sorry if all of that was blurry, I did make so good of a job linking to
> all previous discussions on the topic, I'll address that for the next
> round.
Thanks for the detailed explanation, especially regarding PHY redundancy.
Could you add it to a commit message (or even better to Documentation/)?
--Sean
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-12 15:39 ` Sean Anderson
@ 2025-02-12 15:44 ` Maxime Chevallier
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-12 15:44 UTC (permalink / raw)
To: Sean Anderson
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
Hello Sean,
On Wed, 12 Feb 2025 10:39:48 -0500
Sean Anderson <seanga2@gmail.com> wrote:
> > Sorry if all of that was blurry, I did make so good of a job linking to
> > all previous discussions on the topic, I'll address that for the next
> > round.
>
> Thanks for the detailed explanation, especially regarding PHY redundancy.
> Could you add it to a commit message (or even better to Documentation/)?
Sure thing :)
Thanks,
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs
2025-02-07 22:36 ` [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs Maxime Chevallier
@ 2025-02-12 15:59 ` Maxime Chevallier
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-12 15:59 UTC (permalink / raw)
To: davem
Cc: netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Romain Gantois
On Fri, 7 Feb 2025 23:36:24 +0100
Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
> Some PHY devices may be used as media-converters to drive SFP ports (for
> example, to allow using SFP when the SoC can only output RGMII). This is
> already supported to some extend by allowing PHY drivers to registers
> themselves as being SFP upstream.
>
> However, the logic to drive the SFP can actually be split to a per-port
> control logic, allowing support for multi-port PHYs, or PHYs that can
> either drive SFPs or Copper.
>
> To that extent, create a phy_port when registering an SFP bus onto a
> PHY. This port is considered a "serdes" port, in that it can feed data
> to anther entity on the link. The PHY driver needs to specify the
> various PHY_INTERFACE_MODE_XXX that this port supports.
>
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
[...]
>
> +/**
> + * phylink_interfaces_to_linkmodes() - List all possible linkmodes based on a
> + * set of supported interfaces, assuming no
> + * rate matching.
> + * @linkmodes: the supported linkmodes
> + * @interfaces: Set of interfaces (PHY_INTERFACE_MODE_XXX)
> + *
> + * Compute the exhaustive list of modes that can conceivably be achieved from a
> + * set of MII interfaces. This is derived from the possible speeds and duplex
> + * achievable from these interfaces. This list is likely too exhaustive (there
> + * may not exist any device out there that can convert from an interface to a
> + * linkmode) and it needs further filtering based on real HW capabilities.
> + */
> +void phylink_interfaces_to_linkmodes(unsigned long *linkmodes,
> + const unsigned long *interfaces)
> +{
> + phy_interface_t interface;
> + unsigned long caps = 0;
> +
> + linkmode_zero(linkmodes);
> +
> + for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
> + caps = phylink_get_capabilities(interface,
> + GENMASK(__fls(MAC_400000FD),
> + __fls(MAC_10HD)),
> + RATE_MATCH_NONE);
Shoule be :
caps |= phylink_get_capabilities(...);
I'll address that in V2, my bad...
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
` (13 preceding siblings ...)
2025-02-08 2:14 ` [PATCH net-next 00/13] Introduce an ethernet port representation Sean Anderson
@ 2025-02-12 19:48 ` Rob Herring
2025-02-13 9:57 ` Maxime Chevallier
14 siblings, 1 reply; 30+ messages in thread
From: Rob Herring @ 2025-02-12 19:48 UTC (permalink / raw)
To: Maxime Chevallier
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Romain Gantois
On Fri, Feb 07, 2025 at 11:36:19PM +0100, Maxime Chevallier wrote:
> Hello everyone,
>
> This series follows the 2 RFC that were sent a few weeks ago :
> RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
> RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
That makes this series v3. RFC is not a version, but a condition the
patches are in (not ready to merge).
Rob
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 00/13] Introduce an ethernet port representation
2025-02-12 19:48 ` Rob Herring
@ 2025-02-13 9:57 ` Maxime Chevallier
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Chevallier @ 2025-02-13 9:57 UTC (permalink / raw)
To: Rob Herring
Cc: davem, netdev, linux-kernel, linux-arm-msm, thomas.petazzoni,
Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, linux-arm-kernel, Christophe Leroy, Herve Codina,
Florian Fainelli, Heiner Kallweit, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Antoine Tenart,
devicetree, Conor Dooley, Krzysztof Kozlowski, Romain Gantois
Hello Rob,
On Wed, 12 Feb 2025 13:48:08 -0600
Rob Herring <robh@kernel.org> wrote:
> On Fri, Feb 07, 2025 at 11:36:19PM +0100, Maxime Chevallier wrote:
> > Hello everyone,
> >
> > This series follows the 2 RFC that were sent a few weeks ago :
> > RFC V2: https://lore.kernel.org/netdev/20250122174252.82730-1-maxime.chevallier@bootlin.com/
> > RFC V1: https://lore.kernel.org/netdev/20241220201506.2791940-1-maxime.chevallier@bootlin.com/
>
> That makes this series v3. RFC is not a version, but a condition the
> patches are in (not ready to merge).
Fair enough, next iteration will be V4 then :)
Thanks,
Maxime
> Rob
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2025-02-13 11:11 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-07 22:36 [PATCH net-next 00/13] Introduce an ethernet port representation Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 01/13] net: ethtool: Introduce ETHTOOL_LINK_MEDIUM_* values Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 02/13] net: ethtool: Export the link_mode_params definitions Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 03/13] net: phy: Introduce PHY ports representation Maxime Chevallier
2025-02-11 13:32 ` Kory Maincent
2025-02-11 13:42 ` Maxime Chevallier
2025-02-11 13:52 ` Kory Maincent
2025-02-11 14:04 ` Andrew Lunn
2025-02-11 14:17 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 04/13] net: phy: dp83822: Add support for phy_port representation Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 05/13] net: phy: Create a phy_port for PHY-driven SFPs Maxime Chevallier
2025-02-12 15:59 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 06/13] net: phy: Intrduce generic SFP handling for PHY drivers Maxime Chevallier
2025-02-08 15:32 ` kernel test robot
2025-02-07 22:36 ` [PATCH net-next 07/13] net: phy: marvell-88x2222: Support SFP through phy_port interface Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 08/13] net: phy: marvell: " Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 09/13] net: phy: marvell10g: Support SFP through phy_port Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 10/13] net: phy: at803x: Support SFP through phy_port interface Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 11/13] net: phy: Only rely on phy_port for PHY-driven SFP Maxime Chevallier
2025-02-08 16:04 ` kernel test robot
2025-02-11 9:17 ` Maxime Chevallier
2025-02-07 22:36 ` [PATCH net-next 12/13] net: phy: dp83822: Add SFP support through the phy_port interface Maxime Chevallier
2025-02-08 16:15 ` kernel test robot
2025-02-07 22:36 ` [PATCH net-next 13/13] dt-bindings: net: Introduce the phy-port description Maxime Chevallier
2025-02-08 2:14 ` [PATCH net-next 00/13] Introduce an ethernet port representation Sean Anderson
2025-02-10 8:55 ` Maxime Chevallier
2025-02-12 15:39 ` Sean Anderson
2025-02-12 15:44 ` Maxime Chevallier
2025-02-12 19:48 ` Rob Herring
2025-02-13 9:57 ` Maxime Chevallier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).