linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs
@ 2025-05-15 11:27 Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 1/7] net: phy: pass PHY driver to .match_phy_device OP Christian Marangi
                   ` (6 more replies)
  0 siblings, 7 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

Add support for new Aeonsemi 10G C45 PHYs. These PHYs intergate an IPC
to setup some configuration and require special handling to sync with
the parity bit. The parity bit is a way the IPC use to follow correct
order of command sent.

Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
AS21210PB1 that all register with the PHY ID 0x7500 0x7500
before the firmware is loaded.

The big special thing about this PHY is that it does provide
a generic PHY ID in C45 register that change to the correct one
one the firmware is loaded.

In practice:
- MMD 0x7 ID 0x7500 0x9410 -> FW LOAD -> ID 0x7500 0x9422

To handle this, we operate on .match_phy_device where
we check the PHY ID, if the ID match the generic one,
we load the firmware and we return 0 (PHY driver doesn't
match). Then PHY core will try the next PHY driver in the list
and this time the PHY is correctly filled in and we register
for it.

To help in the matching and not modify part of the PHY device
struct, .match_phy_device is extended to provide also the
current phy_driver is trying to match for. This add the
extra benefits that some other PHY can simplify their
.match_phy_device OP.

Changes v10:
- Add rust patch
Changes v9:
- Reorder AS21XXX_PHY kconfig before Airoha
- Add Reviewed-by tag from Andrew
Changes v8:
- Move IPC ready condition to dedicated function for poll
  timeout
- Fix typo aeon_ipcs_wait_cmd -> aeon_ipc_wait_cmd
- Merge aeon_ipc_send_msg and aeon_ipc_rcv_msg to
  correctly handle locking
- Fix AEON_MAX_LDES typo
Changes v7:
- Make sure fw_version is NULL terminated
- Better describe logic for .match_phy_device
Changes v6:
- Out of RFC
- Add Reviewed-by tag from Russell
Changes v5:
- Add Reviewed-by tag from Rob
- Fix subject in DT patch
- Fix wrong Suggested-by tag in patch 1
- Rework nxp patch to 80 column
Changes v4:
- Add Reviewed-by tag
- Better handle PHY ID scan in as21xxx
- Also simplify nxp driver and fix .match_phy_device
Changes v3:
- Correct typo intergate->integrate
- Try to reduce to 80 column (where possible... define become
  unreasable if split)
- Rework to new .match_phy_device implementation
- Init active_low_led and fix other minor smatch war
- Drop inline tag (kbot doesn't like it but not reported by checkpatch???)
Changes v2:
- Move to RFC as net-next closed :(
- Add lock for IPC command
- Better check size values from IPC
- Add PHY ID for all supported PHYs
- Drop .get_feature (correct values are exported by standard
  regs)
- Rework LED event to enum
- Update .yaml with changes requested (firmware-name required
  for generic PHY ID)
- Better document C22 in C45
- Document PHY name logic
- Introduce patch to load PHY 2 times

Christian Marangi (7):
  net: phy: pass PHY driver to .match_phy_device OP
  net: phy: bcm87xx: simplify .match_phy_device OP
  net: phy: nxp-c45-tja11xx: simplify .match_phy_device OP
  net: phy: introduce genphy_match_phy_device()
  net: phy: Add support for Aeonsemi AS21xxx PHYs
  dt-bindings: net: Document support for Aeonsemi PHYs
  rust: net::phy sync with match_phy_device C changes

 .../bindings/net/aeonsemi,as21xxx.yaml        |  122 ++
 MAINTAINERS                                   |    7 +
 drivers/net/phy/Kconfig                       |   12 +
 drivers/net/phy/Makefile                      |    1 +
 drivers/net/phy/as21xxx.c                     | 1087 +++++++++++++++++
 drivers/net/phy/bcm87xx.c                     |   14 +-
 drivers/net/phy/icplus.c                      |    6 +-
 drivers/net/phy/marvell10g.c                  |   12 +-
 drivers/net/phy/micrel.c                      |    6 +-
 drivers/net/phy/nxp-c45-tja11xx.c             |   41 +-
 drivers/net/phy/nxp-tja11xx.c                 |    6 +-
 drivers/net/phy/phy_device.c                  |   52 +-
 drivers/net/phy/realtek/realtek_main.c        |   27 +-
 drivers/net/phy/teranetics.c                  |    3 +-
 include/linux/phy.h                           |    6 +-
 rust/kernel/net/phy.rs                        |   26 +-
 16 files changed, 1359 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml
 create mode 100644 drivers/net/phy/as21xxx.c

-- 
2.48.1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 1/7] net: phy: pass PHY driver to .match_phy_device OP
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 2/7] net: phy: bcm87xx: simplify " Christian Marangi
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux
  Cc: Russell King (Oracle)

Pass PHY driver pointer to .match_phy_device OP in addition to phydev.
Having access to the PHY driver struct might be useful to check the
PHY ID of the driver is being matched for in case the PHY ID scanned in
the phydev is not consistent.

A scenario for this is a PHY that change PHY ID after a firmware is
loaded, in such case, the PHY ID stored in PHY device struct is not
valid anymore and PHY will manually scan the ID in the match_phy_device
function.

Having the PHY driver info is also useful for those PHY driver that
implement multiple simple .match_phy_device OP to match specific MMD PHY
ID. With this extra info if the parsing logic is the same, the matching
function can be generalized by using the phy_id in the PHY driver
instead of hardcoding.

Suggested-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/bcm87xx.c              |  6 ++++--
 drivers/net/phy/icplus.c               |  6 ++++--
 drivers/net/phy/marvell10g.c           | 12 ++++++++----
 drivers/net/phy/micrel.c               |  6 ++++--
 drivers/net/phy/nxp-c45-tja11xx.c      | 12 ++++++++----
 drivers/net/phy/nxp-tja11xx.c          |  6 ++++--
 drivers/net/phy/phy_device.c           |  2 +-
 drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++---------
 drivers/net/phy/teranetics.c           |  3 ++-
 include/linux/phy.h                    |  3 ++-
 10 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index e81404bf8994..1e1e2259fc2b 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -185,12 +185,14 @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev)
 	return IRQ_HANDLED;
 }
 
-static int bcm8706_match_phy_device(struct phy_device *phydev)
+static int bcm8706_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706;
 }
 
-static int bcm8727_match_phy_device(struct phy_device *phydev)
+static int bcm8727_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727;
 }
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index bbcc7d2b54cd..c0c4f19cfb6a 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -520,12 +520,14 @@ static int ip101a_g_match_phy_device(struct phy_device *phydev, bool ip101a)
 	return ip101a == !ret;
 }
 
-static int ip101a_match_phy_device(struct phy_device *phydev)
+static int ip101a_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	return ip101a_g_match_phy_device(phydev, true);
 }
 
-static int ip101g_match_phy_device(struct phy_device *phydev)
+static int ip101g_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	return ip101a_g_match_phy_device(phydev, false);
 }
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 5354c8895163..13e81dff42c1 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -1264,7 +1264,8 @@ static int mv3310_get_number_of_ports(struct phy_device *phydev)
 	return ret + 1;
 }
 
-static int mv3310_match_phy_device(struct phy_device *phydev)
+static int mv3310_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] &
 	     MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310)
@@ -1273,7 +1274,8 @@ static int mv3310_match_phy_device(struct phy_device *phydev)
 	return mv3310_get_number_of_ports(phydev) == 1;
 }
 
-static int mv3340_match_phy_device(struct phy_device *phydev)
+static int mv3340_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] &
 	     MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310)
@@ -1297,12 +1299,14 @@ static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g)
 	return !!(val & MDIO_PCS_SPEED_5G) == has_5g;
 }
 
-static int mv2110_match_phy_device(struct phy_device *phydev)
+static int mv2110_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	return mv211x_match_phy_device(phydev, true);
 }
 
-static int mv2111_match_phy_device(struct phy_device *phydev)
+static int mv2111_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	return mv211x_match_phy_device(phydev, false);
 }
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 71fb4410c31b..4d8460c93078 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -768,7 +768,8 @@ static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev,
 		return !ret;
 }
 
-static int ksz8051_match_phy_device(struct phy_device *phydev)
+static int ksz8051_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return ksz8051_ksz8795_match_phy_device(phydev, true);
 }
@@ -888,7 +889,8 @@ static int ksz8061_config_init(struct phy_device *phydev)
 	return kszphy_config_init(phydev);
 }
 
-static int ksz8795_match_phy_device(struct phy_device *phydev)
+static int ksz8795_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return ksz8051_ksz8795_match_phy_device(phydev, false);
 }
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index f11dd32494c3..22921b192a8b 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -1966,25 +1966,29 @@ static int nxp_c45_macsec_ability(struct phy_device *phydev)
 	return macsec_ability;
 }
 
-static int tja1103_match_phy_device(struct phy_device *phydev)
+static int tja1103_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
 	       !nxp_c45_macsec_ability(phydev);
 }
 
-static int tja1104_match_phy_device(struct phy_device *phydev)
+static int tja1104_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
 	       nxp_c45_macsec_ability(phydev);
 }
 
-static int tja1120_match_phy_device(struct phy_device *phydev)
+static int tja1120_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) &&
 	       !nxp_c45_macsec_ability(phydev);
 }
 
-static int tja1121_match_phy_device(struct phy_device *phydev)
+static int tja1121_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) &&
 	       nxp_c45_macsec_ability(phydev);
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index 07e94a2478ac..3c38a8ddae2f 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -651,12 +651,14 @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
 	return !ret;
 }
 
-static int tja1102_p0_match_phy_device(struct phy_device *phydev)
+static int tja1102_p0_match_phy_device(struct phy_device *phydev,
+				       const struct phy_driver *phydrv)
 {
 	return tja1102_match_phy_device(phydev, true);
 }
 
-static int tja1102_p1_match_phy_device(struct phy_device *phydev)
+static int tja1102_p1_match_phy_device(struct phy_device *phydev,
+				       const struct phy_driver *phydrv)
 {
 	return tja1102_match_phy_device(phydev, false);
 }
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 2eb735e68dd8..96a96c0334a7 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -554,7 +554,7 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv)
 		return 0;
 
 	if (phydrv->match_phy_device)
-		return phydrv->match_phy_device(phydev);
+		return phydrv->match_phy_device(phydev, phydrv);
 
 	if (phydev->is_c45) {
 		for (i = 1; i < num_ids; i++) {
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index 301fbe141b9b..6b655d3c7e1c 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1314,13 +1314,15 @@ static bool rtlgen_supports_mmd(struct phy_device *phydev)
 	return val > 0;
 }
 
-static int rtlgen_match_phy_device(struct phy_device *phydev)
+static int rtlgen_match_phy_device(struct phy_device *phydev,
+				   const struct phy_driver *phydrv)
 {
 	return phydev->phy_id == RTL_GENERIC_PHYID &&
 	       !rtlgen_supports_2_5gbps(phydev);
 }
 
-static int rtl8226_match_phy_device(struct phy_device *phydev)
+static int rtl8226_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
 {
 	return phydev->phy_id == RTL_GENERIC_PHYID &&
 	       rtlgen_supports_2_5gbps(phydev) &&
@@ -1336,32 +1338,38 @@ static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
 		return !is_c45 && (id == phydev->phy_id);
 }
 
-static int rtl8221b_match_phy_device(struct phy_device *phydev)
+static int rtl8221b_match_phy_device(struct phy_device *phydev,
+				     const struct phy_driver *phydrv)
 {
 	return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev);
 }
 
-static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev,
+					       const struct phy_driver *phydrv)
 {
 	return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
 }
 
-static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev,
+					       const struct phy_driver *phydrv)
 {
 	return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
 }
 
-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev,
+					       const struct phy_driver *phydrv)
 {
 	return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
 }
 
-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev,
+					       const struct phy_driver *phydrv)
 {
 	return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
 }
 
-static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
+						const struct phy_driver *phydrv)
 {
 	if (phydev->is_c45)
 		return false;
@@ -1379,7 +1387,8 @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
 	return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev);
 }
 
-static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
+static int rtl8251b_c45_match_phy_device(struct phy_device *phydev,
+					 const struct phy_driver *phydrv)
 {
 	return rtlgen_is_c45_match(phydev, RTL_8251B, true);
 }
diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c
index 752d4bf7bb99..46c5ff7d7b56 100644
--- a/drivers/net/phy/teranetics.c
+++ b/drivers/net/phy/teranetics.c
@@ -67,7 +67,8 @@ static int teranetics_read_status(struct phy_device *phydev)
 	return 0;
 }
 
-static int teranetics_match_phy_device(struct phy_device *phydev)
+static int teranetics_match_phy_device(struct phy_device *phydev,
+				       const struct phy_driver *phydrv)
 {
 	return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020;
 }
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7c29d346d4b3..34ed85686b83 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -990,7 +990,8 @@ struct phy_driver {
 	 * driver for the given phydev.	 If NULL, matching is based on
 	 * phy_id and phy_id_mask.
 	 */
-	int (*match_phy_device)(struct phy_device *phydev);
+	int (*match_phy_device)(struct phy_device *phydev,
+				const struct phy_driver *phydrv);
 
 	/**
 	 * @set_wol: Some devices (e.g. qnap TS-119P II) require PHY
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 2/7] net: phy: bcm87xx: simplify .match_phy_device OP
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 1/7] net: phy: pass PHY driver to .match_phy_device OP Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 3/7] net: phy: nxp-c45-tja11xx: " Christian Marangi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux
  Cc: Russell King (Oracle)

Simplify .match_phy_device OP by using a generic function and using the
new phy_id PHY driver info instead of hardcoding the matching PHY ID.

Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/bcm87xx.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index 1e1e2259fc2b..299f9a8f30f4 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -185,16 +185,10 @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev)
 	return IRQ_HANDLED;
 }
 
-static int bcm8706_match_phy_device(struct phy_device *phydev,
+static int bcm87xx_match_phy_device(struct phy_device *phydev,
 				    const struct phy_driver *phydrv)
 {
-	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706;
-}
-
-static int bcm8727_match_phy_device(struct phy_device *phydev,
-				    const struct phy_driver *phydrv)
-{
-	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727;
+	return phydev->c45_ids.device_ids[4] == phydrv->phy_id;
 }
 
 static struct phy_driver bcm87xx_driver[] = {
@@ -208,7 +202,7 @@ static struct phy_driver bcm87xx_driver[] = {
 	.read_status	= bcm87xx_read_status,
 	.config_intr	= bcm87xx_config_intr,
 	.handle_interrupt = bcm87xx_handle_interrupt,
-	.match_phy_device = bcm8706_match_phy_device,
+	.match_phy_device = bcm87xx_match_phy_device,
 }, {
 	.phy_id		= PHY_ID_BCM8727,
 	.phy_id_mask	= 0xffffffff,
@@ -219,7 +213,7 @@ static struct phy_driver bcm87xx_driver[] = {
 	.read_status	= bcm87xx_read_status,
 	.config_intr	= bcm87xx_config_intr,
 	.handle_interrupt = bcm87xx_handle_interrupt,
-	.match_phy_device = bcm8727_match_phy_device,
+	.match_phy_device = bcm87xx_match_phy_device,
 } };
 
 module_phy_driver(bcm87xx_driver);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 3/7] net: phy: nxp-c45-tja11xx: simplify .match_phy_device OP
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 1/7] net: phy: pass PHY driver to .match_phy_device OP Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 2/7] net: phy: bcm87xx: simplify " Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 4/7] net: phy: introduce genphy_match_phy_device() Christian Marangi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux
  Cc: Russell King (Oracle)

Simplify .match_phy_device OP by using a generic function and using the
new phy_id PHY driver info instead of hardcoding the matching PHY ID
with new variant for macsec and no_macsec PHYs.

Also make use of PHY_ID_MATCH_MODEL macro and drop PHY_ID_MASK define to
introduce phy_id and phy_id_mask again in phy_driver struct.

Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/nxp-c45-tja11xx.c | 45 ++++++++++++++-----------------
 1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 22921b192a8b..4c6d905f0a9f 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -19,7 +19,6 @@
 
 #include "nxp-c45-tja11xx.h"
 
-#define PHY_ID_MASK			GENMASK(31, 4)
 /* Same id: TJA1103, TJA1104 */
 #define PHY_ID_TJA_1103			0x001BB010
 /* Same id: TJA1120, TJA1121 */
@@ -1966,32 +1965,24 @@ static int nxp_c45_macsec_ability(struct phy_device *phydev)
 	return macsec_ability;
 }
 
-static int tja1103_match_phy_device(struct phy_device *phydev,
-				    const struct phy_driver *phydrv)
+static int tja11xx_no_macsec_match_phy_device(struct phy_device *phydev,
+					      const struct phy_driver *phydrv)
 {
-	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
-	       !nxp_c45_macsec_ability(phydev);
-}
+	if (!phy_id_compare(phydev->phy_id, phydrv->phy_id,
+			    phydrv->phy_id_mask))
+		return 0;
 
-static int tja1104_match_phy_device(struct phy_device *phydev,
-				    const struct phy_driver *phydrv)
-{
-	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
-	       nxp_c45_macsec_ability(phydev);
+	return !nxp_c45_macsec_ability(phydev);
 }
 
-static int tja1120_match_phy_device(struct phy_device *phydev,
-				    const struct phy_driver *phydrv)
+static int tja11xx_macsec_match_phy_device(struct phy_device *phydev,
+					   const struct phy_driver *phydrv)
 {
-	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) &&
-	       !nxp_c45_macsec_ability(phydev);
-}
+	if (!phy_id_compare(phydev->phy_id, phydrv->phy_id,
+			    phydrv->phy_id_mask))
+		return 0;
 
-static int tja1121_match_phy_device(struct phy_device *phydev,
-				    const struct phy_driver *phydrv)
-{
-	return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) &&
-	       nxp_c45_macsec_ability(phydev);
+	return nxp_c45_macsec_ability(phydev);
 }
 
 static const struct nxp_c45_regmap tja1120_regmap = {
@@ -2064,6 +2055,7 @@ static const struct nxp_c45_phy_data tja1120_phy_data = {
 
 static struct phy_driver nxp_c45_driver[] = {
 	{
+		PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103),
 		.name			= "NXP C45 TJA1103",
 		.get_features		= nxp_c45_get_features,
 		.driver_data		= &tja1103_phy_data,
@@ -2085,9 +2077,10 @@ static struct phy_driver nxp_c45_driver[] = {
 		.get_sqi		= nxp_c45_get_sqi,
 		.get_sqi_max		= nxp_c45_get_sqi_max,
 		.remove			= nxp_c45_remove,
-		.match_phy_device	= tja1103_match_phy_device,
+		.match_phy_device	= tja11xx_no_macsec_match_phy_device,
 	},
 	{
+		PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103),
 		.name			= "NXP C45 TJA1104",
 		.get_features		= nxp_c45_get_features,
 		.driver_data		= &tja1103_phy_data,
@@ -2109,9 +2102,10 @@ static struct phy_driver nxp_c45_driver[] = {
 		.get_sqi		= nxp_c45_get_sqi,
 		.get_sqi_max		= nxp_c45_get_sqi_max,
 		.remove			= nxp_c45_remove,
-		.match_phy_device	= tja1104_match_phy_device,
+		.match_phy_device	= tja11xx_macsec_match_phy_device,
 	},
 	{
+		PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120),
 		.name			= "NXP C45 TJA1120",
 		.get_features		= nxp_c45_get_features,
 		.driver_data		= &tja1120_phy_data,
@@ -2134,9 +2128,10 @@ static struct phy_driver nxp_c45_driver[] = {
 		.get_sqi		= nxp_c45_get_sqi,
 		.get_sqi_max		= nxp_c45_get_sqi_max,
 		.remove			= nxp_c45_remove,
-		.match_phy_device	= tja1120_match_phy_device,
+		.match_phy_device	= tja11xx_no_macsec_match_phy_device,
 	},
 	{
+		PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120),
 		.name			= "NXP C45 TJA1121",
 		.get_features		= nxp_c45_get_features,
 		.driver_data		= &tja1120_phy_data,
@@ -2159,7 +2154,7 @@ static struct phy_driver nxp_c45_driver[] = {
 		.get_sqi		= nxp_c45_get_sqi,
 		.get_sqi_max		= nxp_c45_get_sqi_max,
 		.remove			= nxp_c45_remove,
-		.match_phy_device	= tja1121_match_phy_device,
+		.match_phy_device	= tja11xx_macsec_match_phy_device,
 	},
 };
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 4/7] net: phy: introduce genphy_match_phy_device()
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
                   ` (2 preceding siblings ...)
  2025-05-15 11:27 ` [net-next PATCH v10 3/7] net: phy: nxp-c45-tja11xx: " Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 5/7] net: phy: Add support for Aeonsemi AS21xxx PHYs Christian Marangi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux
  Cc: Russell King (Oracle)

Introduce new API, genphy_match_phy_device(), to provide a way to check
to match a PHY driver for a PHY device based on the info stored in the
PHY device struct.

The function generalize the logic used in phy_bus_match() to check the
PHY ID whether if C45 or C22 ID should be used for matching.

This is useful for custom .match_phy_device function that wants to use
the generic logic under some condition. (example a PHY is already setup
and provide the correct PHY ID)

Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++-----------
 include/linux/phy.h          |  3 +++
 2 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 96a96c0334a7..9282de0d591e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -543,20 +543,26 @@ static int phy_scan_fixups(struct phy_device *phydev)
 	return 0;
 }
 
-static int phy_bus_match(struct device *dev, const struct device_driver *drv)
+/**
+ * genphy_match_phy_device - match a PHY device with a PHY driver
+ * @phydev: target phy_device struct
+ * @phydrv: target phy_driver struct
+ *
+ * Description: Checks whether the given PHY device matches the specified
+ * PHY driver. For Clause 45 PHYs, iterates over the available device
+ * identifiers and compares them against the driver's expected PHY ID,
+ * applying the provided mask. For Clause 22 PHYs, a direct ID comparison
+ * is performed.
+ *
+ * Return: 1 if the PHY device matches the driver, 0 otherwise.
+ */
+int genphy_match_phy_device(struct phy_device *phydev,
+			    const struct phy_driver *phydrv)
 {
-	struct phy_device *phydev = to_phy_device(dev);
-	const struct phy_driver *phydrv = to_phy_driver(drv);
-	const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
-	int i;
-
-	if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY))
-		return 0;
-
-	if (phydrv->match_phy_device)
-		return phydrv->match_phy_device(phydev, phydrv);
-
 	if (phydev->is_c45) {
+		const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
+		int i;
+
 		for (i = 1; i < num_ids; i++) {
 			if (phydev->c45_ids.device_ids[i] == 0xffffffff)
 				continue;
@@ -565,11 +571,27 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv)
 					   phydrv->phy_id, phydrv->phy_id_mask))
 				return 1;
 		}
+
 		return 0;
-	} else {
-		return phy_id_compare(phydev->phy_id, phydrv->phy_id,
-				      phydrv->phy_id_mask);
 	}
+
+	return phy_id_compare(phydev->phy_id, phydrv->phy_id,
+			      phydrv->phy_id_mask);
+}
+EXPORT_SYMBOL_GPL(genphy_match_phy_device);
+
+static int phy_bus_match(struct device *dev, const struct device_driver *drv)
+{
+	struct phy_device *phydev = to_phy_device(dev);
+	const struct phy_driver *phydrv = to_phy_driver(drv);
+
+	if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY))
+		return 0;
+
+	if (phydrv->match_phy_device)
+		return phydrv->match_phy_device(phydev, phydrv);
+
+	return genphy_match_phy_device(phydev, phydrv);
 }
 
 static ssize_t
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 34ed85686b83..48e80f089b17 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1868,6 +1868,9 @@ char *phy_attached_info_irq(struct phy_device *phydev)
 	__malloc;
 void phy_attached_info(struct phy_device *phydev);
 
+int genphy_match_phy_device(struct phy_device *phydev,
+			    const struct phy_driver *phydrv);
+
 /* Clause 22 PHY */
 int genphy_read_abilities(struct phy_device *phydev);
 int genphy_setup_forced(struct phy_device *phydev);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 5/7] net: phy: Add support for Aeonsemi AS21xxx PHYs
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
                   ` (3 preceding siblings ...)
  2025-05-15 11:27 ` [net-next PATCH v10 4/7] net: phy: introduce genphy_match_phy_device() Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 6/7] dt-bindings: net: Document support for Aeonsemi PHYs Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes Christian Marangi
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux
  Cc: Andrew Lunn

Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs integrate
an IPC to setup some configuration and require special handling to
sync with the parity bit. The parity bit is a way the IPC use to
follow correct order of command sent.

Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
AS21210PB1 that all register with the PHY ID 0x7500 0x7510
before the firmware is loaded.

They all support up to 5 LEDs with various HW mode supported.

While implementing it was found some strange coincidence with using the
same logic for implementing C22 in MMD regs in Broadcom PHYs.

For reference here the AS21xxx PHY name logic:

AS21x1xxB1
    ^ ^^
    | |J: Supports SyncE/PTP
    | |P: No SyncE/PTP support
    | 1: Supports 2nd Serdes
    | 2: Not 2nd Serdes support
    0: 10G, 5G, 2.5G
    5: 5G, 2.5G
    2: 2.5G

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 MAINTAINERS               |    6 +
 drivers/net/phy/Kconfig   |   12 +
 drivers/net/phy/Makefile  |    1 +
 drivers/net/phy/as21xxx.c | 1087 +++++++++++++++++++++++++++++++++++++
 4 files changed, 1106 insertions(+)
 create mode 100644 drivers/net/phy/as21xxx.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 800d23264c94..6cc52e99c1f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -646,6 +646,12 @@ F:	drivers/iio/accel/adxl380.h
 F:	drivers/iio/accel/adxl380_i2c.c
 F:	drivers/iio/accel/adxl380_spi.c
 
+AEONSEMI PHY DRIVER
+M:	Christian Marangi <ansuelsmth@gmail.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/phy/as21xxx.c
+
 AF8133J THREE-AXIS MAGNETOMETER DRIVER
 M:	Ondřej Jirman <megi@xff.cz>
 S:	Maintained
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 677d56e06539..895f92ccfe1f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -76,6 +76,18 @@ config SFP
 
 comment "MII PHY device drivers"
 
+config AS21XXX_PHY
+	tristate "Aeonsemi AS21xxx PHYs"
+	help
+	  Currently supports the Aeonsemi AS21xxx PHY.
+
+	  These are C45 PHYs 10G that require all a generic firmware.
+
+	  Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
+	  AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
+	  AS21210PB1 that all register with the PHY ID 0x7500 0x7500
+	  before the firmware is loaded.
+
 config AIR_EN8811H_PHY
 	tristate "Airoha EN8811H 2.5 Gigabit PHY"
 	help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 59ac3a9a3177..42f215905a29 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_AIR_EN8811H_PHY)   += air_en8811h.o
 obj-$(CONFIG_AMD_PHY)		+= amd.o
 obj-$(CONFIG_AMCC_QT2025_PHY)	+= qt2025.o
 obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia/
+obj-$(CONFIG_AS21XXX_PHY)	+= as21xxx.o
 ifdef CONFIG_AX88796B_RUST_PHY
   obj-$(CONFIG_AX88796B_PHY)	+= ax88796b_rust.o
 else
diff --git a/drivers/net/phy/as21xxx.c b/drivers/net/phy/as21xxx.c
new file mode 100644
index 000000000000..92697f43087d
--- /dev/null
+++ b/drivers/net/phy/as21xxx.c
@@ -0,0 +1,1087 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Aeonsemi AS21XXxX PHY Driver
+ *
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+
+#define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3
+#define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4
+
+#define VEND1_GLB_REG_CPU_CTRL		0xe
+#define   VEND1_GLB_CPU_CTRL_MASK	GENMASK(4, 0)
+#define   VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8)
+#define   VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \
+							 BIT(_n))
+
+#define VEND1_FW_START_ADDR		0x100
+
+#define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101
+#define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102
+
+#define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103
+
+#define VEND1_PTP_CLK			0x142
+#define   VEND1_PTP_CLK_EN		BIT(6)
+
+/* 5 LED at step of 0x20
+ * FE: Fast-Ethernet (10/100)
+ * GE: Gigabit-Ethernet (1000)
+ * NG: New-Generation (2500/5000/10000)
+ */
+#define VEND1_LED_REG(_n)		(0x1800 + ((_n) * 0x10))
+#define   VEND1_LED_REG_A_EVENT		GENMASK(15, 11)
+#define VEND1_LED_CONF			0x1881
+#define   VEND1_LED_CONFG_BLINK		GENMASK(7, 0)
+
+#define VEND1_SPEED_STATUS		0x4002
+#define   VEND1_SPEED_MASK		GENMASK(7, 0)
+#define   VEND1_SPEED_10000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3)
+#define   VEND1_SPEED_5000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5)
+#define   VEND1_SPEED_2500		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9)
+#define   VEND1_SPEED_1000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10)
+#define   VEND1_SPEED_100		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20)
+#define   VEND1_SPEED_10		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0)
+
+#define VEND1_IPC_CMD			0x5801
+#define   AEON_IPC_CMD_PARITY		BIT(15)
+#define   AEON_IPC_CMD_SIZE		GENMASK(10, 6)
+#define   AEON_IPC_CMD_OPCODE		GENMASK(5, 0)
+
+#define IPC_CMD_NOOP			0x0  /* Do nothing */
+#define IPC_CMD_INFO			0x1  /* Get Firmware Version */
+#define IPC_CMD_SYS_CPU			0x2  /* SYS_CPU */
+#define IPC_CMD_BULK_DATA		0xa  /* Pass bulk data in ipc registers. */
+#define IPC_CMD_BULK_WRITE		0xc  /* Write bulk data to memory */
+#define IPC_CMD_CFG_PARAM		0x1a /* Write config parameters to memory */
+#define IPC_CMD_NG_TESTMODE		0x1b /* Set NG test mode and tone */
+#define IPC_CMD_TEMP_MON		0x15 /* Temperature monitoring function */
+#define IPC_CMD_SET_LED			0x23 /* Set led */
+
+#define VEND1_IPC_STS			0x5802
+#define   AEON_IPC_STS_PARITY		BIT(15)
+#define   AEON_IPC_STS_SIZE		GENMASK(14, 10)
+#define   AEON_IPC_STS_OPCODE		GENMASK(9, 4)
+#define   AEON_IPC_STS_STATUS		GENMASK(3, 0)
+#define   AEON_IPC_STS_STATUS_RCVD	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1)
+#define   AEON_IPC_STS_STATUS_PROCESS	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2)
+#define   AEON_IPC_STS_STATUS_SUCCESS	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4)
+#define   AEON_IPC_STS_STATUS_ERROR	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8)
+#define   AEON_IPC_STS_STATUS_BUSY	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe)
+#define   AEON_IPC_STS_STATUS_READY	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf)
+
+#define VEND1_IPC_DATA0			0x5808
+#define VEND1_IPC_DATA1			0x5809
+#define VEND1_IPC_DATA2			0x580a
+#define VEND1_IPC_DATA3			0x580b
+#define VEND1_IPC_DATA4			0x580c
+#define VEND1_IPC_DATA5			0x580d
+#define VEND1_IPC_DATA6			0x580e
+#define VEND1_IPC_DATA7			0x580f
+#define VEND1_IPC_DATA(_n)		(VEND1_IPC_DATA0 + (_n))
+
+/* Sub command of CMD_INFO */
+#define IPC_INFO_VERSION		0x1
+
+/* Sub command of CMD_SYS_CPU */
+#define IPC_SYS_CPU_REBOOT		0x3
+#define IPC_SYS_CPU_IMAGE_OFST		0x4
+#define IPC_SYS_CPU_IMAGE_CHECK		0x5
+#define IPC_SYS_CPU_PHY_ENABLE		0x6
+
+/* Sub command of CMD_CFG_PARAM */
+#define IPC_CFG_PARAM_DIRECT		0x4
+
+/* CFG DIRECT sub command */
+#define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL	0x1
+#define IPC_CFG_PARAM_DIRECT_CU_AN	0x2
+#define IPC_CFG_PARAM_DIRECT_SDS_PCS	0x3
+#define IPC_CFG_PARAM_DIRECT_AUTO_EEE	0x4
+#define IPC_CFG_PARAM_DIRECT_SDS_PMA	0x5
+#define IPC_CFG_PARAM_DIRECT_DPC_RA	0x6
+#define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7
+#define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8
+#define IPC_CFG_PARAM_DIRECT_WDT	0x9
+#define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10
+#define IPC_CFG_PARAM_DIRECT_TEMP_MON	0x11
+#define IPC_CFG_PARAM_DIRECT_WOL	0x12
+
+/* Sub command of CMD_TEMP_MON */
+#define IPC_CMD_TEMP_MON_GET		0x4
+
+#define AS21XXX_MDIO_AN_C22		0xffe0
+
+#define PHY_ID_AS21XXX			0x75009410
+/* AS21xxx ID Legend
+ * AS21x1xxB1
+ *     ^ ^^
+ *     | |J: Supports SyncE/PTP
+ *     | |P: No SyncE/PTP support
+ *     | 1: Supports 2nd Serdes
+ *     | 2: Not 2nd Serdes support
+ *     0: 10G, 5G, 2.5G
+ *     5: 5G, 2.5G
+ *     2: 2.5G
+ */
+#define PHY_ID_AS21011JB1		0x75009402
+#define PHY_ID_AS21011PB1		0x75009412
+#define PHY_ID_AS21010JB1		0x75009422
+#define PHY_ID_AS21010PB1		0x75009432
+#define PHY_ID_AS21511JB1		0x75009442
+#define PHY_ID_AS21511PB1		0x75009452
+#define PHY_ID_AS21510JB1		0x75009462
+#define PHY_ID_AS21510PB1		0x75009472
+#define PHY_ID_AS21210JB1		0x75009482
+#define PHY_ID_AS21210PB1		0x75009492
+#define PHY_VENDOR_AEONSEMI		0x75009400
+
+#define AEON_MAX_LEDS			5
+#define AEON_IPC_DELAY			10000
+#define AEON_IPC_TIMEOUT		(AEON_IPC_DELAY * 100)
+#define AEON_IPC_DATA_NUM_REGISTERS	8
+#define AEON_IPC_DATA_MAX		(AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16))
+
+#define AEON_BOOT_ADDR			0x1000
+#define AEON_CPU_BOOT_ADDR		0x2000
+#define AEON_CPU_CTRL_FW_LOAD		(BIT(4) | BIT(2) | BIT(1) | BIT(0))
+#define AEON_CPU_CTRL_FW_START		BIT(0)
+
+enum as21xxx_led_event {
+	VEND1_LED_REG_A_EVENT_ON_10 = 0x0,
+	VEND1_LED_REG_A_EVENT_ON_100,
+	VEND1_LED_REG_A_EVENT_ON_1000,
+	VEND1_LED_REG_A_EVENT_ON_2500,
+	VEND1_LED_REG_A_EVENT_ON_5000,
+	VEND1_LED_REG_A_EVENT_ON_10000,
+	VEND1_LED_REG_A_EVENT_ON_FE_GE,
+	VEND1_LED_REG_A_EVENT_ON_NG,
+	VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX,
+	VEND1_LED_REG_A_EVENT_ON_COLLISION,
+	VEND1_LED_REG_A_EVENT_BLINK_TX,
+	VEND1_LED_REG_A_EVENT_BLINK_RX,
+	VEND1_LED_REG_A_EVENT_BLINK_ACT,
+	VEND1_LED_REG_A_EVENT_ON_LINK,
+	VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT,
+	VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX,
+	VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT,
+	VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT,
+	VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE,
+	VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION,
+	VEND1_LED_REG_A_EVENT_ON,
+	VEND1_LED_REG_A_EVENT_OFF,
+};
+
+struct as21xxx_led_pattern_info {
+	unsigned int pattern;
+	u16 val;
+};
+
+struct as21xxx_priv {
+	bool parity_status;
+	/* Protect concurrent IPC access */
+	struct mutex ipc_lock;
+};
+
+static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = {
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10),
+		.val = VEND1_LED_REG_A_EVENT_ON_10
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_100),
+		.val = VEND1_LED_REG_A_EVENT_ON_100
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_1000),
+		.val = VEND1_LED_REG_A_EVENT_ON_1000
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_2500),
+		.val = VEND1_LED_REG_A_EVENT_ON_2500
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_5000),
+		.val = VEND1_LED_REG_A_EVENT_ON_5000
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10000),
+		.val = VEND1_LED_REG_A_EVENT_ON_10000
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK),
+		.val = VEND1_LED_REG_A_EVENT_ON_LINK
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
+			   BIT(TRIGGER_NETDEV_LINK_100) |
+			   BIT(TRIGGER_NETDEV_LINK_1000),
+		.val = VEND1_LED_REG_A_EVENT_ON_FE_GE
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
+			   BIT(TRIGGER_NETDEV_LINK_5000) |
+			   BIT(TRIGGER_NETDEV_LINK_10000),
+		.val = VEND1_LED_REG_A_EVENT_ON_NG
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
+		.val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_TX),
+		.val = VEND1_LED_REG_A_EVENT_BLINK_TX
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_BLINK_RX
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_TX) |
+			   BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_BLINK_ACT
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
+			   BIT(TRIGGER_NETDEV_LINK_100) |
+			   BIT(TRIGGER_NETDEV_LINK_1000) |
+			   BIT(TRIGGER_NETDEV_LINK_2500) |
+			   BIT(TRIGGER_NETDEV_LINK_5000) |
+			   BIT(TRIGGER_NETDEV_LINK_10000),
+		.val = VEND1_LED_REG_A_EVENT_ON_LINK
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
+			   BIT(TRIGGER_NETDEV_LINK_100) |
+			   BIT(TRIGGER_NETDEV_LINK_1000) |
+			   BIT(TRIGGER_NETDEV_LINK_2500) |
+			   BIT(TRIGGER_NETDEV_LINK_5000) |
+			   BIT(TRIGGER_NETDEV_LINK_10000) |
+			   BIT(TRIGGER_NETDEV_TX) |
+			   BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
+			   BIT(TRIGGER_NETDEV_LINK_100) |
+			   BIT(TRIGGER_NETDEV_LINK_1000) |
+			   BIT(TRIGGER_NETDEV_LINK_2500) |
+			   BIT(TRIGGER_NETDEV_LINK_5000) |
+			   BIT(TRIGGER_NETDEV_LINK_10000) |
+			   BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
+			   BIT(TRIGGER_NETDEV_LINK_100) |
+			   BIT(TRIGGER_NETDEV_LINK_1000) |
+			   BIT(TRIGGER_NETDEV_TX) |
+			   BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT
+	},
+	{
+		.pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
+			   BIT(TRIGGER_NETDEV_LINK_5000) |
+			   BIT(TRIGGER_NETDEV_LINK_10000) |
+			   BIT(TRIGGER_NETDEV_TX) |
+			   BIT(TRIGGER_NETDEV_RX),
+		.val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT
+	}
+};
+
+static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data,
+			      size_t size)
+{
+	int i, ret;
+	u16 val;
+
+	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
+			     VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD);
+	if (ret)
+		return ret;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR,
+			    AEON_BOOT_ADDR);
+	if (ret)
+		return ret;
+
+	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			     VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD,
+			     0x3ffc, 0xc000);
+	if (ret)
+		return ret;
+
+	val = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+			   VEND1_GLB_REG_MDIO_INDIRECT_STATUS);
+	if (val > 1) {
+		phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val);
+		return -EINVAL;
+	}
+
+	/* Firmware is always aligned to u16 */
+	for (i = 0; i < size; i += 2) {
+		val = data[i + 1] << 8 | data[i];
+
+		ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+				    VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val);
+		if (ret)
+			return ret;
+	}
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR,
+			    lower_16_bits(AEON_CPU_BOOT_ADDR));
+	if (ret)
+		return ret;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR,
+			    upper_16_bits(AEON_CPU_BOOT_ADDR));
+	if (ret)
+		return ret;
+
+	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
+			      VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START);
+}
+
+static int aeon_firmware_load(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	const struct firmware *fw;
+	const char *fw_name;
+	int ret;
+
+	ret = of_property_read_string(dev->of_node, "firmware-name",
+				      &fw_name);
+	if (ret)
+		return ret;
+
+	ret = request_firmware(&fw, fw_name, dev);
+	if (ret) {
+		phydev_err(phydev, "failed to find FW file %s (%d)\n",
+			   fw_name, ret);
+		return ret;
+	}
+
+	ret = aeon_firmware_boot(phydev, fw->data, fw->size);
+
+	release_firmware(fw);
+
+	return ret;
+}
+
+static bool aeon_ipc_ready(u16 val, bool parity_status)
+{
+	u16 status;
+
+	if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status)
+		return false;
+
+	status = val & AEON_IPC_STS_STATUS;
+
+	return status != AEON_IPC_STS_STATUS_RCVD &&
+	       status != AEON_IPC_STS_STATUS_PROCESS &&
+	       status != AEON_IPC_STS_STATUS_BUSY;
+}
+
+static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status)
+{
+	u16 val;
+
+	/* Exit condition logic:
+	 * - Wait for parity bit equal
+	 * - Wait for status success, error OR ready
+	 */
+	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val,
+					 aeon_ipc_ready(val, parity_status),
+					 AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false);
+}
+
+static int aeon_ipc_send_cmd(struct phy_device *phydev,
+			     struct as21xxx_priv *priv,
+			     u16 cmd, u16 *ret_sts)
+{
+	bool curr_parity;
+	int ret;
+
+	/* The IPC sync by using a single parity bit.
+	 * Each CMD have alternately this bit set or clear
+	 * to understand correct flow and packet order.
+	 */
+	curr_parity = priv->parity_status;
+	if (priv->parity_status)
+		cmd |= AEON_IPC_CMD_PARITY;
+
+	/* Always update parity for next packet */
+	priv->parity_status = !priv->parity_status;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd);
+	if (ret)
+		return ret;
+
+	/* Wait for packet to be processed */
+	usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000);
+
+	/* With no ret_sts, ignore waiting for packet completion
+	 * (ipc parity bit sync)
+	 */
+	if (!ret_sts)
+		return 0;
+
+	ret = aeon_ipc_wait_cmd(phydev, curr_parity);
+	if (ret)
+		return ret;
+
+	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS);
+	if (ret < 0)
+		return ret;
+
+	*ret_sts = ret;
+	if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* If data is NULL, return 0 or negative error.
+ * If data not NULL, return number of Bytes received from IPC or
+ * a negative error.
+ */
+static int aeon_ipc_send_msg(struct phy_device *phydev,
+			     u16 opcode, u16 *data, unsigned int data_len,
+			     u16 *ret_data)
+{
+	struct as21xxx_priv *priv = phydev->priv;
+	unsigned int ret_size;
+	u16 cmd, ret_sts;
+	int ret;
+	int i;
+
+	/* IPC have a max of 8 register to transfer data,
+	 * make sure we never exceed this.
+	 */
+	if (data_len > AEON_IPC_DATA_MAX)
+		return -EINVAL;
+
+	for (i = 0; i < data_len / sizeof(u16); i++)
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i),
+			      data[i]);
+
+	cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) |
+	      FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode);
+
+	mutex_lock(&priv->ipc_lock);
+
+	ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts);
+	if (ret) {
+		phydev_err(phydev, "failed to send ipc msg for %x: %d\n",
+			   opcode, ret);
+		goto out;
+	}
+
+	if (!data)
+		goto out;
+
+	if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Prevent IPC from stack smashing the kernel.
+	 * We can't trust IPC to return a good value and we always
+	 * preallocate space for 16 Bytes.
+	 */
+	ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts);
+	if (ret_size > AEON_IPC_DATA_MAX) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Read data from IPC data register for ret_size value from IPC */
+	for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) {
+		ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i));
+		if (ret < 0)
+			goto out;
+
+		ret_data[i] = ret;
+	}
+
+	ret = ret_size;
+
+out:
+	mutex_unlock(&priv->ipc_lock);
+
+	return ret;
+}
+
+static int aeon_ipc_noop(struct phy_device *phydev,
+			 struct as21xxx_priv *priv, u16 *ret_sts)
+{
+	u16 cmd;
+
+	cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) |
+	      FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP);
+
+	return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts);
+}
+
+/* Logic to sync parity bit with IPC.
+ * We send 2 NOP cmd with same partity and we wait for IPC
+ * to handle the packet only for the second one. This way
+ * we make sure we are sync for every next cmd.
+ */
+static int aeon_ipc_sync_parity(struct phy_device *phydev,
+				struct as21xxx_priv *priv)
+{
+	u16 ret_sts;
+	int ret;
+
+	mutex_lock(&priv->ipc_lock);
+
+	/* Send NOP with no parity */
+	aeon_ipc_noop(phydev, priv, NULL);
+
+	/* Reset packet parity */
+	priv->parity_status = false;
+
+	/* Send second NOP with no parity */
+	ret = aeon_ipc_noop(phydev, priv, &ret_sts);
+
+	mutex_unlock(&priv->ipc_lock);
+
+	/* We expect to return -EINVAL */
+	if (ret != -EINVAL)
+		return ret;
+
+	if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) {
+		phydev_err(phydev, "Invalid IPC status on sync parity: %x\n",
+			   ret_sts);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int aeon_ipc_get_fw_version(struct phy_device *phydev)
+{
+	u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1];
+	char fw_version[AEON_IPC_DATA_MAX + 1];
+	int ret;
+
+	data[0] = IPC_INFO_VERSION;
+
+	ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data,
+				sizeof(data), ret_data);
+	if (ret < 0)
+		return ret;
+
+	/* Make sure FW version is NULL terminated */
+	memcpy(fw_version, ret_data, ret);
+	fw_version[ret] = '\0';
+
+	phydev_info(phydev, "Firmware Version: %s\n", fw_version);
+
+	return 0;
+}
+
+static int aeon_dpc_ra_enable(struct phy_device *phydev)
+{
+	u16 data[2];
+
+	data[0] = IPC_CFG_PARAM_DIRECT;
+	data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA;
+
+	return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data,
+				 sizeof(data), NULL);
+}
+
+static int as21xxx_probe(struct phy_device *phydev)
+{
+	struct as21xxx_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&phydev->mdio.dev,
+			    sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	phydev->priv = priv;
+
+	ret = devm_mutex_init(&phydev->mdio.dev,
+			      &priv->ipc_lock);
+	if (ret)
+		return ret;
+
+	ret = aeon_ipc_sync_parity(phydev, priv);
+	if (ret)
+		return ret;
+
+	ret = aeon_ipc_get_fw_version(phydev);
+	if (ret)
+		return ret;
+
+	/* Enable PTP clk if not already Enabled */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK,
+			       VEND1_PTP_CLK_EN);
+	if (ret)
+		return ret;
+
+	return aeon_dpc_ra_enable(phydev);
+}
+
+static int as21xxx_read_link(struct phy_device *phydev, int *bmcr)
+{
+	int status;
+
+	/* Normal C22 BMCR report inconsistent data, use
+	 * the mapped C22 in C45 to have more consistent link info.
+	 */
+	*bmcr = phy_read_mmd(phydev, MDIO_MMD_AN,
+			     AS21XXX_MDIO_AN_C22 + MII_BMCR);
+	if (*bmcr < 0)
+		return *bmcr;
+
+	/* Autoneg is being started, therefore disregard current
+	 * link status and report link as down.
+	 */
+	if (*bmcr & BMCR_ANRESTART) {
+		phydev->link = 0;
+		return 0;
+	}
+
+	status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
+	if (status < 0)
+		return status;
+
+	phydev->link = !!(status & MDIO_STAT1_LSTATUS);
+
+	return 0;
+}
+
+static int as21xxx_read_c22_lpa(struct phy_device *phydev)
+{
+	int lpagb;
+
+	/* MII_STAT1000 are only filled in the mapped C22
+	 * in C45, use that to fill lpagb values and check.
+	 */
+	lpagb = phy_read_mmd(phydev, MDIO_MMD_AN,
+			     AS21XXX_MDIO_AN_C22 + MII_STAT1000);
+	if (lpagb < 0)
+		return lpagb;
+
+	if (lpagb & LPA_1000MSFAIL) {
+		int adv = phy_read_mmd(phydev, MDIO_MMD_AN,
+				       AS21XXX_MDIO_AN_C22 + MII_CTRL1000);
+
+		if (adv < 0)
+			return adv;
+
+		if (adv & CTL1000_ENABLE_MASTER)
+			phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
+		else
+			phydev_err(phydev, "Master/Slave resolution failed\n");
+		return -ENOLINK;
+	}
+
+	mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
+					lpagb);
+
+	return 0;
+}
+
+static int as21xxx_read_status(struct phy_device *phydev)
+{
+	int bmcr, old_link = phydev->link;
+	int ret;
+
+	ret = as21xxx_read_link(phydev, &bmcr);
+	if (ret)
+		return ret;
+
+	/* why bother the PHY if nothing can have changed */
+	if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
+		return 0;
+
+	phydev->speed = SPEED_UNKNOWN;
+	phydev->duplex = DUPLEX_UNKNOWN;
+	phydev->pause = 0;
+	phydev->asym_pause = 0;
+
+	if (phydev->autoneg == AUTONEG_ENABLE) {
+		ret = genphy_c45_read_lpa(phydev);
+		if (ret)
+			return ret;
+
+		ret = as21xxx_read_c22_lpa(phydev);
+		if (ret)
+			return ret;
+
+		phy_resolve_aneg_linkmode(phydev);
+	} else {
+		int speed;
+
+		linkmode_zero(phydev->lp_advertising);
+
+		speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+				     VEND1_SPEED_STATUS);
+		if (speed < 0)
+			return speed;
+
+		switch (speed & VEND1_SPEED_STATUS) {
+		case VEND1_SPEED_10000:
+			phydev->speed = SPEED_10000;
+			phydev->duplex = DUPLEX_FULL;
+			break;
+		case VEND1_SPEED_5000:
+			phydev->speed = SPEED_5000;
+			phydev->duplex = DUPLEX_FULL;
+			break;
+		case VEND1_SPEED_2500:
+			phydev->speed = SPEED_2500;
+			phydev->duplex = DUPLEX_FULL;
+			break;
+		case VEND1_SPEED_1000:
+			phydev->speed = SPEED_1000;
+			if (bmcr & BMCR_FULLDPLX)
+				phydev->duplex = DUPLEX_FULL;
+			else
+				phydev->duplex = DUPLEX_HALF;
+			break;
+		case VEND1_SPEED_100:
+			phydev->speed = SPEED_100;
+			phydev->duplex = DUPLEX_FULL;
+			break;
+		case VEND1_SPEED_10:
+			phydev->speed = SPEED_10;
+			phydev->duplex = DUPLEX_FULL;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int as21xxx_led_brightness_set(struct phy_device *phydev,
+				      u8 index, enum led_brightness value)
+{
+	u16 val = VEND1_LED_REG_A_EVENT_OFF;
+
+	if (index > AEON_MAX_LEDS)
+		return -EINVAL;
+
+	if (value)
+		val = VEND1_LED_REG_A_EVENT_ON;
+
+	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			      VEND1_LED_REG(index),
+			      VEND1_LED_REG_A_EVENT,
+			      FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
+}
+
+static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index,
+				       unsigned long rules)
+{
+	int i;
+
+	if (index > AEON_MAX_LEDS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
+		if (rules == as21xxx_led_supported_pattern[i].pattern)
+			return 0;
+
+	return -EOPNOTSUPP;
+}
+
+static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index,
+				      unsigned long *rules)
+{
+	int i, val;
+
+	if (index > AEON_MAX_LEDS)
+		return -EINVAL;
+
+	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index));
+	if (val < 0)
+		return val;
+
+	val = FIELD_GET(VEND1_LED_REG_A_EVENT, val);
+	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
+		if (val == as21xxx_led_supported_pattern[i].val) {
+			*rules = as21xxx_led_supported_pattern[i].pattern;
+			return 0;
+		}
+
+	/* Should be impossible */
+	return -EINVAL;
+}
+
+static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index,
+				      unsigned long rules)
+{
+	u16 val = 0;
+	int i;
+
+	if (index > AEON_MAX_LEDS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
+		if (rules == as21xxx_led_supported_pattern[i].pattern) {
+			val = as21xxx_led_supported_pattern[i].val;
+			break;
+		}
+
+	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			      VEND1_LED_REG(index),
+			      VEND1_LED_REG_A_EVENT,
+			      FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
+}
+
+static int as21xxx_led_polarity_set(struct phy_device *phydev, int index,
+				    unsigned long modes)
+{
+	bool led_active_low = false;
+	u16 mask, val = 0;
+	u32 mode;
+
+	if (index > AEON_MAX_LEDS)
+		return -EINVAL;
+
+	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+		switch (mode) {
+		case PHY_LED_ACTIVE_LOW:
+			led_active_low = true;
+			break;
+		case PHY_LED_ACTIVE_HIGH: /* default mode */
+			led_active_low = false;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
+	if (led_active_low)
+		val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
+
+	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			      VEND1_GLB_REG_CPU_CTRL,
+			      mask, val);
+}
+
+static int as21xxx_match_phy_device(struct phy_device *phydev,
+				    const struct phy_driver *phydrv)
+{
+	struct as21xxx_priv *priv;
+	u16 ret_sts;
+	u32 phy_id;
+	int ret;
+
+	/* Skip PHY that are not AS21xxx or already have firmware loaded */
+	if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX)
+		return genphy_match_phy_device(phydev, phydrv);
+
+	/* Read PHY ID to handle firmware just loaded */
+	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1);
+	if (ret < 0)
+		return ret;
+	phy_id = ret << 16;
+
+	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2);
+	if (ret < 0)
+		return ret;
+	phy_id |= ret;
+
+	/* With PHY ID not the generic AS21xxx one assume
+	 * the firmware just loaded
+	 */
+	if (phy_id != PHY_ID_AS21XXX)
+		return phy_id == phydrv->phy_id;
+
+	/* Allocate temp priv and load the firmware */
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->ipc_lock);
+
+	ret = aeon_firmware_load(phydev);
+	if (ret)
+		goto out;
+
+	/* Sync parity... */
+	ret = aeon_ipc_sync_parity(phydev, priv);
+	if (ret)
+		goto out;
+
+	/* ...and send a third NOOP cmd to wait for firmware finish loading */
+	ret = aeon_ipc_noop(phydev, priv, &ret_sts);
+	if (ret)
+		goto out;
+
+out:
+	mutex_destroy(&priv->ipc_lock);
+	kfree(priv);
+
+	/* Return can either be 0 or a negative error code.
+	 * Returning 0 here means THIS is NOT a suitable PHY.
+	 *
+	 * For the specific case of the generic Aeonsemi PHY ID that
+	 * needs the firmware the be loaded first to have a correct PHY ID,
+	 * this is OK as a matching PHY ID will be found right after.
+	 * This relies on the driver probe order where the first PHY driver
+	 * probed is the generic one.
+	 */
+	return ret;
+}
+
+static struct phy_driver as21xxx_drivers[] = {
+	{
+		/* PHY expose in C45 as 0x7500 0x9410
+		 * before firmware is loaded.
+		 * This driver entry must be attempted first to load
+		 * the firmware and thus update the ID registers.
+		 */
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX),
+		.name		= "Aeonsemi AS21xxx",
+		.match_phy_device = as21xxx_match_phy_device,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1),
+		.name		= "Aeonsemi AS21011JB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
+		.name		= "Aeonsemi AS21011PB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
+		.name		= "Aeonsemi AS21010PB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
+		.name		= "Aeonsemi AS21010JB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
+		.name		= "Aeonsemi AS21210PB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
+		.name		= "Aeonsemi AS21510JB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
+		.name		= "Aeonsemi AS21510PB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
+		.name		= "Aeonsemi AS21511JB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
+		.name		= "Aeonsemi AS21210JB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+	{
+		PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
+		.name		= "Aeonsemi AS21511PB1",
+		.probe		= as21xxx_probe,
+		.match_phy_device = as21xxx_match_phy_device,
+		.read_status	= as21xxx_read_status,
+		.led_brightness_set = as21xxx_led_brightness_set,
+		.led_hw_is_supported = as21xxx_led_hw_is_supported,
+		.led_hw_control_set = as21xxx_led_hw_control_set,
+		.led_hw_control_get = as21xxx_led_hw_control_get,
+		.led_polarity_set = as21xxx_led_polarity_set,
+	},
+};
+module_phy_driver(as21xxx_drivers);
+
+static struct mdio_device_id __maybe_unused as21xxx_tbl[] = {
+	{ PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) },
+	{ }
+};
+MODULE_DEVICE_TABLE(mdio, as21xxx_tbl);
+
+MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 6/7] dt-bindings: net: Document support for Aeonsemi PHYs
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
                   ` (4 preceding siblings ...)
  2025-05-15 11:27 ` [net-next PATCH v10 5/7] net: phy: Add support for Aeonsemi AS21xxx PHYs Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:27 ` [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes Christian Marangi
  6 siblings, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

Add Aeonsemi PHYs and the requirement of a firmware to correctly work.
Also document the max number of LEDs supported and what PHY ID expose
when no firmware is loaded.

Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
AS21210PB1 that all register with the PHY ID 0x7500 0x9410 on C45
registers before the firmware is loaded.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 .../bindings/net/aeonsemi,as21xxx.yaml        | 122 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 2 files changed, 123 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml

diff --git a/Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml b/Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml
new file mode 100644
index 000000000000..69eb29dc4d7b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/aeonsemi,as21xxx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aeonsemi AS21XXX Ethernet PHY
+
+maintainers:
+  - Christian Marangi <ansuelsmth@gmail.com>
+
+description: |
+  Aeonsemi AS21xxx Ethernet PHYs requires a firmware to be loaded to actually
+  work. The same firmware is compatible with various PHYs of the same family.
+
+  A PHY with not firmware loaded will be exposed on the MDIO bus with ID
+  0x7500 0x7500 or 0x7500 0x9410 on C45 registers.
+
+  This can be done and is implemented by OEM in 2 different way:
+    - Attached SPI flash directly to the PHY with the firmware. The PHY
+      will self load the firmware in the presence of this configuration.
+    - Manually provided firmware loaded from a file in the filesystem.
+
+  Each PHY can support up to 5 LEDs.
+
+  AS2xxx PHY Name logic:
+
+  AS21x1xxB1
+      ^ ^^
+      | |J: Supports SyncE/PTP
+      | |P: No SyncE/PTP support
+      | 1: Supports 2nd Serdes
+      | 2: Not 2nd Serdes support
+      0: 10G, 5G, 2.5G
+      5: 5G, 2.5G
+      2: 2.5G
+
+allOf:
+  - $ref: ethernet-phy.yaml#
+
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - ethernet-phy-id7500.9410
+          - ethernet-phy-id7500.9402
+          - ethernet-phy-id7500.9412
+          - ethernet-phy-id7500.9422
+          - ethernet-phy-id7500.9432
+          - ethernet-phy-id7500.9442
+          - ethernet-phy-id7500.9452
+          - ethernet-phy-id7500.9462
+          - ethernet-phy-id7500.9472
+          - ethernet-phy-id7500.9482
+          - ethernet-phy-id7500.9492
+  required:
+    - compatible
+
+properties:
+  reg:
+    maxItems: 1
+
+  firmware-name:
+    description: specify the name of PHY firmware to load
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: ethernet-phy-id7500.9410
+then:
+  required:
+    - firmware-name
+else:
+  properties:
+    firmware-name: false
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/leds/common.h>
+
+    mdio {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ethernet-phy@1f {
+            compatible = "ethernet-phy-id7500.9410",
+                         "ethernet-phy-ieee802.3-c45";
+
+            reg = <31>;
+            firmware-name = "as21x1x_fw.bin";
+
+            leds {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                led@0 {
+                    reg = <0>;
+                    color = <LED_COLOR_ID_GREEN>;
+                    function = LED_FUNCTION_LAN;
+                    function-enumerator = <0>;
+                    default-state = "keep";
+                };
+
+                led@1 {
+                    reg = <1>;
+                    color = <LED_COLOR_ID_GREEN>;
+                    function = LED_FUNCTION_LAN;
+                    function-enumerator = <1>;
+                    default-state = "keep";
+                };
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 6cc52e99c1f8..d11038a90113 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -650,6 +650,7 @@ AEONSEMI PHY DRIVER
 M:	Christian Marangi <ansuelsmth@gmail.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml
 F:	drivers/net/phy/as21xxx.c
 
 AF8133J THREE-AXIS MAGNETOMETER DRIVER
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
                   ` (5 preceding siblings ...)
  2025-05-15 11:27 ` [net-next PATCH v10 6/7] dt-bindings: net: Document support for Aeonsemi PHYs Christian Marangi
@ 2025-05-15 11:27 ` Christian Marangi
  2025-05-15 11:49   ` Benno Lossin
  2025-05-16 12:30   ` FUJITA Tomonori
  6 siblings, 2 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:27 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

Sync match_phy_device callback wrapper in net:phy rust with the C
changes where match_phy_device also provide the passed PHY driver.

As explained in the C commit, this is useful for match_phy_device to
access the PHY ID defined in the PHY driver permitting more generalized
functions.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index a59469c785e3..936a137a8a29 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -418,15 +418,18 @@ impl<T: Driver> Adapter<T> {
 
     /// # Safety
     ///
-    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+    /// `phydev` and `phydrv` must be passed by the corresponding callback in
+    //  `phy_driver`.
     unsafe extern "C" fn match_phy_device_callback(
         phydev: *mut bindings::phy_device,
+        phydrv: *const bindings::phy_driver
     ) -> crate::ffi::c_int {
         // SAFETY: This callback is called only in contexts
         // where we hold `phy_device->lock`, so the accessors on
         // `Device` are okay to call.
         let dev = unsafe { Device::from_raw(phydev) };
-        T::match_phy_device(dev) as i32
+        let drv = unsafe { T::from_raw(phydrv) };
+        T::match_phy_device(dev, drv) as i32
     }
 
     /// # Safety
@@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
 /// This trait is used to create a [`DriverVTable`].
 #[vtable]
 pub trait Driver {
+    /// # Safety
+    ///
+    /// For the duration of `'a`,
+    /// - the pointer must point at a valid `phy_driver`, and the caller
+    ///   must be in a context where all methods defined on this struct
+    ///   are safe to call.
+    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
+    where
+        Self: Sized,
+    {
+        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
+        let ptr = ptr.cast::<Self>();
+        // SAFETY: by the function requirements the pointer is valid and we have unique access for
+        // the duration of `'a`.
+        unsafe { &*ptr }
+    }
+
     /// Defines certain other features this PHY supports.
     /// It is a combination of the flags in the [`flags`] module.
     const FLAGS: u32 = 0;
@@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
 
     /// Returns true if this is a suitable driver for the given phydev.
     /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
-    fn match_phy_device(_dev: &Device) -> bool {
+    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
         false
     }
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-15 11:27 ` [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes Christian Marangi
@ 2025-05-15 11:49   ` Benno Lossin
  2025-05-15 11:51     ` Christian Marangi
  2025-05-16 12:30   ` FUJITA Tomonori
  1 sibling, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-15 11:49 UTC (permalink / raw)
  To: Christian Marangi, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

On Thu May 15, 2025 at 1:27 PM CEST, Christian Marangi wrote:
> Sync match_phy_device callback wrapper in net:phy rust with the C
> changes where match_phy_device also provide the passed PHY driver.
>
> As explained in the C commit, this is useful for match_phy_device to
> access the PHY ID defined in the PHY driver permitting more generalized
> functions.
>
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
>  rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
>  1 file changed, 23 insertions(+), 3 deletions(-)

You probably should do this in the same commit as the C changes,
otherwise the in-between commits will error.

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-15 11:49   ` Benno Lossin
@ 2025-05-15 11:51     ` Christian Marangi
  2025-05-15 12:01       ` Benno Lossin
  0 siblings, 1 reply; 27+ messages in thread
From: Christian Marangi @ 2025-05-15 11:51 UTC (permalink / raw)
  To: Benno Lossin
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

On Thu, May 15, 2025 at 01:49:35PM +0200, Benno Lossin wrote:
> On Thu May 15, 2025 at 1:27 PM CEST, Christian Marangi wrote:
> > Sync match_phy_device callback wrapper in net:phy rust with the C
> > changes where match_phy_device also provide the passed PHY driver.
> >
> > As explained in the C commit, this is useful for match_phy_device to
> > access the PHY ID defined in the PHY driver permitting more generalized
> > functions.
> >
> > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> > ---
> >  rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
> >  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> You probably should do this in the same commit as the C changes,
> otherwise the in-between commits will error.
> 

You are right, I will fix this in v11 but I would really want to know if
the Rust changes are correct. It's not my main language so it's all
discovering new stuff :D

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-15 11:51     ` Christian Marangi
@ 2025-05-15 12:01       ` Benno Lossin
  0 siblings, 0 replies; 27+ messages in thread
From: Benno Lossin @ 2025-05-15 12:01 UTC (permalink / raw)
  To: Christian Marangi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Heiner Kallweit, Russell King, Florian Fainelli,
	Broadcom internal kernel review list, Marek Behún,
	Andrei Botila, FUJITA Tomonori, Trevor Gross, Miguel Ojeda,
	Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Danilo Krummrich,
	Sabrina Dubroca, Michael Klein, Daniel Golle, netdev, devicetree,
	linux-kernel, rust-for-linux

On Thu May 15, 2025 at 1:51 PM CEST, Christian Marangi wrote:
> On Thu, May 15, 2025 at 01:49:35PM +0200, Benno Lossin wrote:
>> On Thu May 15, 2025 at 1:27 PM CEST, Christian Marangi wrote:
>> > Sync match_phy_device callback wrapper in net:phy rust with the C
>> > changes where match_phy_device also provide the passed PHY driver.
>> >
>> > As explained in the C commit, this is useful for match_phy_device to
>> > access the PHY ID defined in the PHY driver permitting more generalized
>> > functions.
>> >
>> > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
>> > ---
>> >  rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
>> >  1 file changed, 23 insertions(+), 3 deletions(-)
>> 
>> You probably should do this in the same commit as the C changes,
>> otherwise the in-between commits will error.
>> 
>
> You are right, I will fix this in v11 but I would really want to know if
> the Rust changes are correct. It's not my main language so it's all
> discovering new stuff :D

No worries :) I have lost some context on the PHY Rust bindings, so
Fujita will probably have to review it, but if I find the time, I'll
take a look.

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-15 11:27 ` [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes Christian Marangi
  2025-05-15 11:49   ` Benno Lossin
@ 2025-05-16 12:30   ` FUJITA Tomonori
  2025-05-16 14:48     ` Benno Lossin
  2025-05-16 15:10     ` Christian Marangi
  1 sibling, 2 replies; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-16 12:30 UTC (permalink / raw)
  To: ansuelsmth
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
	conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, fujita.tomonori,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

Hi,

On Thu, 15 May 2025 13:27:12 +0200
Christian Marangi <ansuelsmth@gmail.com> wrote:

> Sync match_phy_device callback wrapper in net:phy rust with the C
> changes where match_phy_device also provide the passed PHY driver.
> 
> As explained in the C commit, this is useful for match_phy_device to
> access the PHY ID defined in the PHY driver permitting more generalized
> functions.
> 
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
>  rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
>  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
> index a59469c785e3..936a137a8a29 100644
> --- a/rust/kernel/net/phy.rs
> +++ b/rust/kernel/net/phy.rs
> @@ -418,15 +418,18 @@ impl<T: Driver> Adapter<T> {
>  
>      /// # Safety
>      ///
> -    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
> +    /// `phydev` and `phydrv` must be passed by the corresponding callback in
> +    //  `phy_driver`.
>      unsafe extern "C" fn match_phy_device_callback(
>          phydev: *mut bindings::phy_device,
> +        phydrv: *const bindings::phy_driver
>      ) -> crate::ffi::c_int {
>          // SAFETY: This callback is called only in contexts
>          // where we hold `phy_device->lock`, so the accessors on
>          // `Device` are okay to call.
>          let dev = unsafe { Device::from_raw(phydev) };
> -        T::match_phy_device(dev) as i32
> +        let drv = unsafe { T::from_raw(phydrv) };
> +        T::match_phy_device(dev, drv) as i32
>      }
>  
>      /// # Safety
> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
>  /// This trait is used to create a [`DriverVTable`].
>  #[vtable]
>  pub trait Driver {
> +    /// # Safety
> +    ///
> +    /// For the duration of `'a`,
> +    /// - the pointer must point at a valid `phy_driver`, and the caller
> +    ///   must be in a context where all methods defined on this struct
> +    ///   are safe to call.
> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
> +    where
> +        Self: Sized,
> +    {
> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
> +        let ptr = ptr.cast::<Self>();
> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
> +        // the duration of `'a`.
> +        unsafe { &*ptr }
> +    }

We might need to update the comment. phy_driver is const so I think
that we can access to it any time.

>      /// Defines certain other features this PHY supports.
>      /// It is a combination of the flags in the [`flags`] module.
>      const FLAGS: u32 = 0;
> @@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
>  
>      /// Returns true if this is a suitable driver for the given phydev.
>      /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
> -    fn match_phy_device(_dev: &Device) -> bool {
> +    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
>          false
>      }

I think that it could be a bit simpler:

fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool

Or making it a trait method might be more idiomatic?

fn match_phy_device(&self, _dev: &mut Device) -> bool


Thanks!

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-16 12:30   ` FUJITA Tomonori
@ 2025-05-16 14:48     ` Benno Lossin
  2025-05-16 15:12       ` Christian Marangi
  2025-05-16 15:10     ` Christian Marangi
  1 sibling, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-16 14:48 UTC (permalink / raw)
  To: FUJITA Tomonori, ansuelsmth
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
	conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Fri May 16, 2025 at 2:30 PM CEST, FUJITA Tomonori wrote:
> On Thu, 15 May 2025 13:27:12 +0200
> Christian Marangi <ansuelsmth@gmail.com> wrote:
>> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
>>  /// This trait is used to create a [`DriverVTable`].
>>  #[vtable]
>>  pub trait Driver {
>> +    /// # Safety
>> +    ///
>> +    /// For the duration of `'a`,
>> +    /// - the pointer must point at a valid `phy_driver`, and the caller
>> +    ///   must be in a context where all methods defined on this struct
>> +    ///   are safe to call.
>> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
>> +    where
>> +        Self: Sized,
>> +    {
>> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
>> +        let ptr = ptr.cast::<Self>();
>> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
>> +        // the duration of `'a`.
>> +        unsafe { &*ptr }
>> +    }
>
> We might need to update the comment. phy_driver is const so I think
> that we can access to it any time.

Why is any type implementing `Driver` a transparent wrapper around
`bindings::phy_driver`?

>>      /// Defines certain other features this PHY supports.
>>      /// It is a combination of the flags in the [`flags`] module.
>>      const FLAGS: u32 = 0;
>> @@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
>>  
>>      /// Returns true if this is a suitable driver for the given phydev.
>>      /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
>> -    fn match_phy_device(_dev: &Device) -> bool {
>> +    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
>>          false
>>      }
>
> I think that it could be a bit simpler:
>
> fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool
>
> Or making it a trait method might be more idiomatic?
>
> fn match_phy_device(&self, _dev: &mut Device) -> bool

Yeah that would make most sense.

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-16 12:30   ` FUJITA Tomonori
  2025-05-16 14:48     ` Benno Lossin
@ 2025-05-16 15:10     ` Christian Marangi
  1 sibling, 0 replies; 27+ messages in thread
From: Christian Marangi @ 2025-05-16 15:10 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
	conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Fri, May 16, 2025 at 09:30:05PM +0900, FUJITA Tomonori wrote:
> Hi,
> 
> On Thu, 15 May 2025 13:27:12 +0200
> Christian Marangi <ansuelsmth@gmail.com> wrote:
> 
> > Sync match_phy_device callback wrapper in net:phy rust with the C
> > changes where match_phy_device also provide the passed PHY driver.
> > 
> > As explained in the C commit, this is useful for match_phy_device to
> > access the PHY ID defined in the PHY driver permitting more generalized
> > functions.
> > 
> > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> > ---
> >  rust/kernel/net/phy.rs | 26 +++++++++++++++++++++++---
> >  1 file changed, 23 insertions(+), 3 deletions(-)
> > 
> > diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
> > index a59469c785e3..936a137a8a29 100644
> > --- a/rust/kernel/net/phy.rs
> > +++ b/rust/kernel/net/phy.rs
> > @@ -418,15 +418,18 @@ impl<T: Driver> Adapter<T> {
> >  
> >      /// # Safety
> >      ///
> > -    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
> > +    /// `phydev` and `phydrv` must be passed by the corresponding callback in
> > +    //  `phy_driver`.
> >      unsafe extern "C" fn match_phy_device_callback(
> >          phydev: *mut bindings::phy_device,
> > +        phydrv: *const bindings::phy_driver
> >      ) -> crate::ffi::c_int {
> >          // SAFETY: This callback is called only in contexts
> >          // where we hold `phy_device->lock`, so the accessors on
> >          // `Device` are okay to call.
> >          let dev = unsafe { Device::from_raw(phydev) };
> > -        T::match_phy_device(dev) as i32
> > +        let drv = unsafe { T::from_raw(phydrv) };
> > +        T::match_phy_device(dev, drv) as i32
> >      }
> >  
> >      /// # Safety
> > @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
> >  /// This trait is used to create a [`DriverVTable`].
> >  #[vtable]
> >  pub trait Driver {
> > +    /// # Safety
> > +    ///
> > +    /// For the duration of `'a`,
> > +    /// - the pointer must point at a valid `phy_driver`, and the caller
> > +    ///   must be in a context where all methods defined on this struct
> > +    ///   are safe to call.
> > +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
> > +    where
> > +        Self: Sized,
> > +    {
> > +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
> > +        let ptr = ptr.cast::<Self>();
> > +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
> > +        // the duration of `'a`.
> > +        unsafe { &*ptr }
> > +    }
> 
> We might need to update the comment. phy_driver is const so I think
> that we can access to it any time.
>

Any hint for a better comment?

> >      /// Defines certain other features this PHY supports.
> >      /// It is a combination of the flags in the [`flags`] module.
> >      const FLAGS: u32 = 0;
> > @@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
> >  
> >      /// Returns true if this is a suitable driver for the given phydev.
> >      /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
> > -    fn match_phy_device(_dev: &Device) -> bool {
> > +    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
> >          false
> >      }
> 
> I think that it could be a bit simpler:
> 
> fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool
> 
> Or making it a trait method might be more idiomatic?
> 
> fn match_phy_device(&self, _dev: &mut Device) -> bool
> 
> 
> Thanks!

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-16 14:48     ` Benno Lossin
@ 2025-05-16 15:12       ` Christian Marangi
  2025-05-16 20:16         ` Benno Lossin
  0 siblings, 1 reply; 27+ messages in thread
From: Christian Marangi @ 2025-05-16 15:12 UTC (permalink / raw)
  To: Benno Lossin
  Cc: FUJITA Tomonori, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Fri, May 16, 2025 at 04:48:53PM +0200, Benno Lossin wrote:
> On Fri May 16, 2025 at 2:30 PM CEST, FUJITA Tomonori wrote:
> > On Thu, 15 May 2025 13:27:12 +0200
> > Christian Marangi <ansuelsmth@gmail.com> wrote:
> >> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
> >>  /// This trait is used to create a [`DriverVTable`].
> >>  #[vtable]
> >>  pub trait Driver {
> >> +    /// # Safety
> >> +    ///
> >> +    /// For the duration of `'a`,
> >> +    /// - the pointer must point at a valid `phy_driver`, and the caller
> >> +    ///   must be in a context where all methods defined on this struct
> >> +    ///   are safe to call.
> >> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
> >> +    where
> >> +        Self: Sized,
> >> +    {
> >> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
> >> +        let ptr = ptr.cast::<Self>();
> >> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
> >> +        // the duration of `'a`.
> >> +        unsafe { &*ptr }
> >> +    }
> >
> > We might need to update the comment. phy_driver is const so I think
> > that we can access to it any time.
> 
> Why is any type implementing `Driver` a transparent wrapper around
> `bindings::phy_driver`?
> 

Is this referred to a problem with using from_raw or more of a general
question on how the rust wrapper are done for phy code?

> >>      /// Defines certain other features this PHY supports.
> >>      /// It is a combination of the flags in the [`flags`] module.
> >>      const FLAGS: u32 = 0;
> >> @@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
> >>  
> >>      /// Returns true if this is a suitable driver for the given phydev.
> >>      /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
> >> -    fn match_phy_device(_dev: &Device) -> bool {
> >> +    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
> >>          false
> >>      }
> >
> > I think that it could be a bit simpler:
> >
> > fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool
> >
> > Or making it a trait method might be more idiomatic?
> >
> > fn match_phy_device(&self, _dev: &mut Device) -> bool
> 
> Yeah that would make most sense.
>

I think

fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool

more resemble the C parallel function so I think this suite the best,
should make it easier to port if ever (am I wrong?)

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-16 15:12       ` Christian Marangi
@ 2025-05-16 20:16         ` Benno Lossin
  2025-05-17  6:27           ` FUJITA Tomonori
  0 siblings, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-16 20:16 UTC (permalink / raw)
  To: Christian Marangi
  Cc: FUJITA Tomonori, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Fri May 16, 2025 at 5:12 PM CEST, Christian Marangi wrote:
> On Fri, May 16, 2025 at 04:48:53PM +0200, Benno Lossin wrote:
>> On Fri May 16, 2025 at 2:30 PM CEST, FUJITA Tomonori wrote:
>> > On Thu, 15 May 2025 13:27:12 +0200
>> > Christian Marangi <ansuelsmth@gmail.com> wrote:
>> >> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
>> >>  /// This trait is used to create a [`DriverVTable`].
>> >>  #[vtable]
>> >>  pub trait Driver {
>> >> +    /// # Safety
>> >> +    ///
>> >> +    /// For the duration of `'a`,
>> >> +    /// - the pointer must point at a valid `phy_driver`, and the caller
>> >> +    ///   must be in a context where all methods defined on this struct
>> >> +    ///   are safe to call.
>> >> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
>> >> +    where
>> >> +        Self: Sized,
>> >> +    {
>> >> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
>> >> +        let ptr = ptr.cast::<Self>();
>> >> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
>> >> +        // the duration of `'a`.
>> >> +        unsafe { &*ptr }
>> >> +    }
>> >
>> > We might need to update the comment. phy_driver is const so I think
>> > that we can access to it any time.
>> 
>> Why is any type implementing `Driver` a transparent wrapper around
>> `bindings::phy_driver`?
>> 
>
> Is this referred to a problem with using from_raw or more of a general
> question on how the rust wrapper are done for phy code?

I looked at the `phy.rs` file again and now I'm pretty sure the above
code is wrong. `Self` can be implemented on any type (even types like
`Infallible` that do not have any valid bit patterns, since it's an
empty enum). The abstraction for `bindings::phy_driver` is
`DriverVTable` not an object of type `Self`, so you should cast to that
pointer instead.

>> >>      /// Defines certain other features this PHY supports.
>> >>      /// It is a combination of the flags in the [`flags`] module.
>> >>      const FLAGS: u32 = 0;
>> >> @@ -602,7 +622,7 @@ fn get_features(_dev: &mut Device) -> Result {
>> >>  
>> >>      /// Returns true if this is a suitable driver for the given phydev.
>> >>      /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
>> >> -    fn match_phy_device(_dev: &Device) -> bool {
>> >> +    fn match_phy_device<T: Driver>(_dev: &mut Device, _drv: &T) -> bool {
>> >>          false
>> >>      }
>> >
>> > I think that it could be a bit simpler:
>> >
>> > fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool
>> >
>> > Or making it a trait method might be more idiomatic?
>> >
>> > fn match_phy_device(&self, _dev: &mut Device) -> bool
>> 
>> Yeah that would make most sense.
>>
>
> I think
>
> fn match_phy_device(_dev: &mut Device, _drv: &Self) -> bool
>
> more resemble the C parallel function so I think this suite the best,
> should make it easier to port if ever (am I wrong?)

I don't understand what you mean by "easier to port if ever". From a
Rust perspective, it makes much more sense to use the `&self` receiver,
since the driver is asked if it can take care of the device. If you want
to keep the order how it is in C that is also fine, but if I were to
write it, I'd use the receiver.

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-16 20:16         ` Benno Lossin
@ 2025-05-17  6:27           ` FUJITA Tomonori
  2025-05-17  8:06             ` Benno Lossin
  0 siblings, 1 reply; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-17  6:27 UTC (permalink / raw)
  To: lossin
  Cc: ansuelsmth, fujita.tomonori, andrew+netdev, davem, edumazet, kuba,
	pabeni, robh, krzk+dt, conor+dt, hkallweit1, linux,
	florian.fainelli, bcm-kernel-feedback-list, kabel, andrei.botila,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

Thanks for the review!

On Fri, 16 May 2025 22:16:23 +0200
"Benno Lossin" <lossin@kernel.org> wrote:

> On Fri May 16, 2025 at 5:12 PM CEST, Christian Marangi wrote:
>> On Fri, May 16, 2025 at 04:48:53PM +0200, Benno Lossin wrote:
>>> On Fri May 16, 2025 at 2:30 PM CEST, FUJITA Tomonori wrote:
>>> > On Thu, 15 May 2025 13:27:12 +0200
>>> > Christian Marangi <ansuelsmth@gmail.com> wrote:
>>> >> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
>>> >>  /// This trait is used to create a [`DriverVTable`].
>>> >>  #[vtable]
>>> >>  pub trait Driver {
>>> >> +    /// # Safety
>>> >> +    ///
>>> >> +    /// For the duration of `'a`,
>>> >> +    /// - the pointer must point at a valid `phy_driver`, and the caller
>>> >> +    ///   must be in a context where all methods defined on this struct
>>> >> +    ///   are safe to call.
>>> >> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
>>> >> +    where
>>> >> +        Self: Sized,
>>> >> +    {
>>> >> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
>>> >> +        let ptr = ptr.cast::<Self>();
>>> >> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
>>> >> +        // the duration of `'a`.
>>> >> +        unsafe { &*ptr }
>>> >> +    }
>>> >
>>> > We might need to update the comment. phy_driver is const so I think
>>> > that we can access to it any time.
>>> 
>>> Why is any type implementing `Driver` a transparent wrapper around
>>> `bindings::phy_driver`?
>>> 
>>
>> Is this referred to a problem with using from_raw or more of a general
>> question on how the rust wrapper are done for phy code?
> 
> I looked at the `phy.rs` file again and now I'm pretty sure the above
> code is wrong. `Self` can be implemented on any type (even types like
> `Infallible` that do not have any valid bit patterns, since it's an
> empty enum). The abstraction for `bindings::phy_driver` is
> `DriverVTable` not an object of type `Self`, so you should cast to that
> pointer instead.

Yeah.

I don't want to delay this patchset due to Rust side changes so
casting a pointer to bindings::phy_driver to DriverVTable is ok but
the following signature doesn't look useful for Rust phy drivers:

fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool

struct DriverVTable is only used to create an array of
bindings::phy_driver for C side, and it doesn't provide any
information to the Rust driver.

In match_phy_device(), for example, a device driver accesses to
PHY_DEVICE_ID, which the Driver trait provides. I think we need to
create an instance of the device driver's own type that implements the
Driver trait and make it accessible.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17  6:27           ` FUJITA Tomonori
@ 2025-05-17  8:06             ` Benno Lossin
  2025-05-17 13:13               ` FUJITA Tomonori
  0 siblings, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-17  8:06 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: ansuelsmth, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Sat May 17, 2025 at 8:27 AM CEST, FUJITA Tomonori wrote:
> On Fri, 16 May 2025 22:16:23 +0200
> "Benno Lossin" <lossin@kernel.org> wrote:
>> On Fri May 16, 2025 at 5:12 PM CEST, Christian Marangi wrote:
>>> On Fri, May 16, 2025 at 04:48:53PM +0200, Benno Lossin wrote:
>>>> On Fri May 16, 2025 at 2:30 PM CEST, FUJITA Tomonori wrote:
>>>> > On Thu, 15 May 2025 13:27:12 +0200
>>>> > Christian Marangi <ansuelsmth@gmail.com> wrote:
>>>> >> @@ -574,6 +577,23 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
>>>> >>  /// This trait is used to create a [`DriverVTable`].
>>>> >>  #[vtable]
>>>> >>  pub trait Driver {
>>>> >> +    /// # Safety
>>>> >> +    ///
>>>> >> +    /// For the duration of `'a`,
>>>> >> +    /// - the pointer must point at a valid `phy_driver`, and the caller
>>>> >> +    ///   must be in a context where all methods defined on this struct
>>>> >> +    ///   are safe to call.
>>>> >> +    unsafe fn from_raw<'a>(ptr: *const bindings::phy_driver) -> &'a Self
>>>> >> +    where
>>>> >> +        Self: Sized,
>>>> >> +    {
>>>> >> +        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_driver`.
>>>> >> +        let ptr = ptr.cast::<Self>();
>>>> >> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
>>>> >> +        // the duration of `'a`.
>>>> >> +        unsafe { &*ptr }
>>>> >> +    }
>>>> >
>>>> > We might need to update the comment. phy_driver is const so I think
>>>> > that we can access to it any time.
>>>> 
>>>> Why is any type implementing `Driver` a transparent wrapper around
>>>> `bindings::phy_driver`?
>>>> 
>>>
>>> Is this referred to a problem with using from_raw or more of a general
>>> question on how the rust wrapper are done for phy code?
>> 
>> I looked at the `phy.rs` file again and now I'm pretty sure the above
>> code is wrong. `Self` can be implemented on any type (even types like
>> `Infallible` that do not have any valid bit patterns, since it's an
>> empty enum). The abstraction for `bindings::phy_driver` is
>> `DriverVTable` not an object of type `Self`, so you should cast to that
>> pointer instead.
>
> Yeah.
>
> I don't want to delay this patchset due to Rust side changes so
> casting a pointer to bindings::phy_driver to DriverVTable is ok but
> the following signature doesn't look useful for Rust phy drivers:
>
> fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool
>
> struct DriverVTable is only used to create an array of
> bindings::phy_driver for C side, and it doesn't provide any
> information to the Rust driver.

Yeah, but we could add accessor functions that provide that information.
Although that doesn't really make sense at the moment, see below.

> In match_phy_device(), for example, a device driver accesses to
> PHY_DEVICE_ID, which the Driver trait provides. I think we need to
> create an instance of the device driver's own type that implements the
> Driver trait and make it accessible.

I think that's wrong, nothing stops me from implementing `Driver` for an
empty enum and that can't be instantiated. The reason that one wants to
have this in C is because the same `match` function is used for
different drivers (or maybe devices? I'm not too familiar with the
terminology). In Rust, you must implement the match function for a
single PHY_DEVICE_ID only, so maybe we don't need to change the
signature at all?

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17  8:06             ` Benno Lossin
@ 2025-05-17 13:13               ` FUJITA Tomonori
  2025-05-17 19:02                 ` Benno Lossin
  0 siblings, 1 reply; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-17 13:13 UTC (permalink / raw)
  To: lossin
  Cc: fujita.tomonori, ansuelsmth, andrew+netdev, davem, edumazet, kuba,
	pabeni, robh, krzk+dt, conor+dt, hkallweit1, linux,
	florian.fainelli, bcm-kernel-feedback-list, kabel, andrei.botila,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

On Sat, 17 May 2025 10:06:13 +0200
"Benno Lossin" <lossin@kernel.org> wrote:

>>> I looked at the `phy.rs` file again and now I'm pretty sure the above
>>> code is wrong. `Self` can be implemented on any type (even types like
>>> `Infallible` that do not have any valid bit patterns, since it's an
>>> empty enum). The abstraction for `bindings::phy_driver` is
>>> `DriverVTable` not an object of type `Self`, so you should cast to that
>>> pointer instead.
>>
>> Yeah.
>>
>> I don't want to delay this patchset due to Rust side changes so
>> casting a pointer to bindings::phy_driver to DriverVTable is ok but
>> the following signature doesn't look useful for Rust phy drivers:
>>
>> fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool
>>
>> struct DriverVTable is only used to create an array of
>> bindings::phy_driver for C side, and it doesn't provide any
>> information to the Rust driver.
> 
> Yeah, but we could add accessor functions that provide that information.

Yes. I thought that implementation was one of the options as well but
realized it makes sense because inside match_phy_device() callback, a
driver might call a helper function that takes a pointer to
bindings::phy_driver (please see below for details).


> Although that doesn't really make sense at the moment, see below.
>
>> In match_phy_device(), for example, a device driver accesses to
>> PHY_DEVICE_ID, which the Driver trait provides. I think we need to
>> create an instance of the device driver's own type that implements the
>> Driver trait and make it accessible.
> 
> I think that's wrong, nothing stops me from implementing `Driver` for an
> empty enum and that can't be instantiated. The reason that one wants to
> have this in C is because the same `match` function is used for
> different drivers (or maybe devices? I'm not too familiar with the
> terminology). In Rust, you must implement the match function for a
> single PHY_DEVICE_ID only, so maybe we don't need to change the
> signature at all?

I'm not sure I understand the last sentence. The Rust PHY abstraction
allows one module to support multiple drivers. So we can could the
similar trick that the second patch in this patchset does.

fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
    // do comparison workking for three drivers
}

#[vtable]
impl Driver for PhyA {
    ...
    fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
        match_device_id(dev, drv)
    }
}

#[vtable]
impl Driver for PhyB {
    ...
    fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
        match_device_id(dev, drv)
    }
}

#[vtable]
impl Driver for PhyC {
    ...
    fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
        match_device_id(dev, drv)
    }
}


The other use case, as mentioned above, is when using the generic helper
function inside match_phy_device() callback. For example, the 4th
patch in this patchset adds genphy_match_phy_device():

int genphy_match_phy_device(struct phy_device *phydev,
                           const struct phy_driver *phydrv)

We could add a wrapper for this function as phy::Device's method like

impl Device {
    ...
    pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 

Then a driver could do something like 5th patch in the patchset:

#[vtable]
impl Driver for PhyD {
    ...
    fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
       let val = dev.genphy_match_phy_device(drv);
       ...
    }
}

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17 13:13               ` FUJITA Tomonori
@ 2025-05-17 19:02                 ` Benno Lossin
  2025-05-17 20:09                   ` Christian Marangi
  2025-05-19 12:00                   ` FUJITA Tomonori
  0 siblings, 2 replies; 27+ messages in thread
From: Benno Lossin @ 2025-05-17 19:02 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: ansuelsmth, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Sat May 17, 2025 at 3:13 PM CEST, FUJITA Tomonori wrote:
> On Sat, 17 May 2025 10:06:13 +0200
> "Benno Lossin" <lossin@kernel.org> wrote:
>>>> I looked at the `phy.rs` file again and now I'm pretty sure the above
>>>> code is wrong. `Self` can be implemented on any type (even types like
>>>> `Infallible` that do not have any valid bit patterns, since it's an
>>>> empty enum). The abstraction for `bindings::phy_driver` is
>>>> `DriverVTable` not an object of type `Self`, so you should cast to that
>>>> pointer instead.
>>>
>>> Yeah.
>>>
>>> I don't want to delay this patchset due to Rust side changes so
>>> casting a pointer to bindings::phy_driver to DriverVTable is ok but
>>> the following signature doesn't look useful for Rust phy drivers:
>>>
>>> fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool
>>>
>>> struct DriverVTable is only used to create an array of
>>> bindings::phy_driver for C side, and it doesn't provide any
>>> information to the Rust driver.
>> 
>> Yeah, but we could add accessor functions that provide that information.
>
> Yes. I thought that implementation was one of the options as well but
> realized it makes sense because inside match_phy_device() callback, a
> driver might call a helper function that takes a pointer to
> bindings::phy_driver (please see below for details).
>
>
>> Although that doesn't really make sense at the moment, see below.
>>
>>> In match_phy_device(), for example, a device driver accesses to
>>> PHY_DEVICE_ID, which the Driver trait provides. I think we need to
>>> create an instance of the device driver's own type that implements the
>>> Driver trait and make it accessible.
>> 
>> I think that's wrong, nothing stops me from implementing `Driver` for an
>> empty enum and that can't be instantiated. The reason that one wants to
>> have this in C is because the same `match` function is used for
>> different drivers (or maybe devices? I'm not too familiar with the
>> terminology). In Rust, you must implement the match function for a
>> single PHY_DEVICE_ID only, so maybe we don't need to change the
>> signature at all?
>
> I'm not sure I understand the last sentence. The Rust PHY abstraction
> allows one module to support multiple drivers. So we can could the
> similar trick that the second patch in this patchset does.
>
> fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>     // do comparison workking for three drivers
> }

I wouldn't do it like this in Rust, instead this would be a "rustier"
function signature:

    fn match_device_id<T: Driver>(dev: &mut phy::Device) -> bool {
        // do the comparison with T::PHY_DEVICE_ID
        dev.id() == T::PHY_DEVICE_ID
    }

And then in the impls for Phy{A,B,C,D} do this:

    impl Driver for PhyA {
        fn match_phy_device(dev: &mut phy::Device) -> bool {
            match_device_id::<Self>(dev)
        }
    }

>
> #[vtable]
> impl Driver for PhyA {
>     ...
>     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>         match_device_id(dev, drv)
>     }
> }
>
> #[vtable]
> impl Driver for PhyB {
>     ...
>     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>         match_device_id(dev, drv)
>     }
> }
>
> #[vtable]
> impl Driver for PhyC {
>     ...
>     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>         match_device_id(dev, drv)
>     }
> }
>
>
> The other use case, as mentioned above, is when using the generic helper
> function inside match_phy_device() callback. For example, the 4th
> patch in this patchset adds genphy_match_phy_device():
>
> int genphy_match_phy_device(struct phy_device *phydev,
>                            const struct phy_driver *phydrv)
>
> We could add a wrapper for this function as phy::Device's method like
>
> impl Device {
>     ...
>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 

Not sure why this returns an `i32`, but we probably could have such a
function as well (though I wouldn't use the vtable for that).

---
Cheers,
Benno

> Then a driver could do something like 5th patch in the patchset:
>
> #[vtable]
> impl Driver for PhyD {
>     ...
>     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>        let val = dev.genphy_match_phy_device(drv);
>        ...
>     }
> }


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17 19:02                 ` Benno Lossin
@ 2025-05-17 20:09                   ` Christian Marangi
  2025-05-18  7:13                     ` Benno Lossin
  2025-05-19 12:00                   ` FUJITA Tomonori
  1 sibling, 1 reply; 27+ messages in thread
From: Christian Marangi @ 2025-05-17 20:09 UTC (permalink / raw)
  To: Benno Lossin
  Cc: FUJITA Tomonori, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Sat, May 17, 2025 at 09:02:51PM +0200, Benno Lossin wrote:
> On Sat May 17, 2025 at 3:13 PM CEST, FUJITA Tomonori wrote:
> > On Sat, 17 May 2025 10:06:13 +0200
> > "Benno Lossin" <lossin@kernel.org> wrote:
> >>>> I looked at the `phy.rs` file again and now I'm pretty sure the above
> >>>> code is wrong. `Self` can be implemented on any type (even types like
> >>>> `Infallible` that do not have any valid bit patterns, since it's an
> >>>> empty enum). The abstraction for `bindings::phy_driver` is
> >>>> `DriverVTable` not an object of type `Self`, so you should cast to that
> >>>> pointer instead.
> >>>
> >>> Yeah.
> >>>
> >>> I don't want to delay this patchset due to Rust side changes so
> >>> casting a pointer to bindings::phy_driver to DriverVTable is ok but
> >>> the following signature doesn't look useful for Rust phy drivers:
> >>>
> >>> fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool
> >>>
> >>> struct DriverVTable is only used to create an array of
> >>> bindings::phy_driver for C side, and it doesn't provide any
> >>> information to the Rust driver.
> >> 
> >> Yeah, but we could add accessor functions that provide that information.
> >
> > Yes. I thought that implementation was one of the options as well but
> > realized it makes sense because inside match_phy_device() callback, a
> > driver might call a helper function that takes a pointer to
> > bindings::phy_driver (please see below for details).
> >
> >
> >> Although that doesn't really make sense at the moment, see below.
> >>
> >>> In match_phy_device(), for example, a device driver accesses to
> >>> PHY_DEVICE_ID, which the Driver trait provides. I think we need to
> >>> create an instance of the device driver's own type that implements the
> >>> Driver trait and make it accessible.
> >> 
> >> I think that's wrong, nothing stops me from implementing `Driver` for an
> >> empty enum and that can't be instantiated. The reason that one wants to
> >> have this in C is because the same `match` function is used for
> >> different drivers (or maybe devices? I'm not too familiar with the
> >> terminology). In Rust, you must implement the match function for a
> >> single PHY_DEVICE_ID only, so maybe we don't need to change the
> >> signature at all?
> >
> > I'm not sure I understand the last sentence. The Rust PHY abstraction
> > allows one module to support multiple drivers. So we can could the
> > similar trick that the second patch in this patchset does.
> >
> > fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
> >     // do comparison workking for three drivers
> > }
> 
> I wouldn't do it like this in Rust, instead this would be a "rustier"
> function signature:
> 
>     fn match_device_id<T: Driver>(dev: &mut phy::Device) -> bool {
>         // do the comparison with T::PHY_DEVICE_ID
>         dev.id() == T::PHY_DEVICE_ID
>     }
> 
> And then in the impls for Phy{A,B,C,D} do this:
> 
>     impl Driver for PhyA {
>         fn match_phy_device(dev: &mut phy::Device) -> bool {
>             match_device_id::<Self>(dev)
>         }
>     }
> 

My 2 cent about the discussion and I'm totally detached from how it
works on Rust kernel code but shouldn't we try to keep parallel API and
args between C and Rust?

I know maybe some thing doesn't make sense from C to Rust but doesn't
deviates from C code introduce more confusion when something need to be
ported from C to Rust?

Again no idea if this apply so I'm just curious about this.

> >
> > #[vtable]
> > impl Driver for PhyA {
> >     ...
> >     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
> >         match_device_id(dev, drv)
> >     }
> > }
> >
> > #[vtable]
> > impl Driver for PhyB {
> >     ...
> >     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
> >         match_device_id(dev, drv)
> >     }
> > }
> >
> > #[vtable]
> > impl Driver for PhyC {
> >     ...
> >     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
> >         match_device_id(dev, drv)
> >     }
> > }
> >
> >
> > The other use case, as mentioned above, is when using the generic helper
> > function inside match_phy_device() callback. For example, the 4th
> > patch in this patchset adds genphy_match_phy_device():
> >
> > int genphy_match_phy_device(struct phy_device *phydev,
> >                            const struct phy_driver *phydrv)
> >
> > We could add a wrapper for this function as phy::Device's method like
> >
> > impl Device {
> >     ...
> >     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
> 
> Not sure why this returns an `i32`, but we probably could have such a
> function as well (though I wouldn't use the vtable for that).
>

Mhh looking at some comments, maybe the module needs some extra love here
and there.

> 
> > Then a driver could do something like 5th patch in the patchset:
> >
> > #[vtable]
> > impl Driver for PhyD {
> >     ...
> >     fn match_phy_device(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
> >        let val = dev.genphy_match_phy_device(drv);
> >        ...
> >     }
> > }
> 

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17 20:09                   ` Christian Marangi
@ 2025-05-18  7:13                     ` Benno Lossin
  0 siblings, 0 replies; 27+ messages in thread
From: Benno Lossin @ 2025-05-18  7:13 UTC (permalink / raw)
  To: Christian Marangi
  Cc: FUJITA Tomonori, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Sat May 17, 2025 at 10:09 PM CEST, Christian Marangi wrote:
> On Sat, May 17, 2025 at 09:02:51PM +0200, Benno Lossin wrote:
>> On Sat May 17, 2025 at 3:13 PM CEST, FUJITA Tomonori wrote:
>> > On Sat, 17 May 2025 10:06:13 +0200
>> > "Benno Lossin" <lossin@kernel.org> wrote:
>> >>>> I looked at the `phy.rs` file again and now I'm pretty sure the above
>> >>>> code is wrong. `Self` can be implemented on any type (even types like
>> >>>> `Infallible` that do not have any valid bit patterns, since it's an
>> >>>> empty enum). The abstraction for `bindings::phy_driver` is
>> >>>> `DriverVTable` not an object of type `Self`, so you should cast to that
>> >>>> pointer instead.
>> >>>
>> >>> Yeah.
>> >>>
>> >>> I don't want to delay this patchset due to Rust side changes so
>> >>> casting a pointer to bindings::phy_driver to DriverVTable is ok but
>> >>> the following signature doesn't look useful for Rust phy drivers:
>> >>>
>> >>> fn match_phy_device(_dev: &mut Device, _drv: &DriverVTable) -> bool
>> >>>
>> >>> struct DriverVTable is only used to create an array of
>> >>> bindings::phy_driver for C side, and it doesn't provide any
>> >>> information to the Rust driver.
>> >> 
>> >> Yeah, but we could add accessor functions that provide that information.
>> >
>> > Yes. I thought that implementation was one of the options as well but
>> > realized it makes sense because inside match_phy_device() callback, a
>> > driver might call a helper function that takes a pointer to
>> > bindings::phy_driver (please see below for details).
>> >
>> >
>> >> Although that doesn't really make sense at the moment, see below.
>> >>
>> >>> In match_phy_device(), for example, a device driver accesses to
>> >>> PHY_DEVICE_ID, which the Driver trait provides. I think we need to
>> >>> create an instance of the device driver's own type that implements the
>> >>> Driver trait and make it accessible.
>> >> 
>> >> I think that's wrong, nothing stops me from implementing `Driver` for an
>> >> empty enum and that can't be instantiated. The reason that one wants to
>> >> have this in C is because the same `match` function is used for
>> >> different drivers (or maybe devices? I'm not too familiar with the
>> >> terminology). In Rust, you must implement the match function for a
>> >> single PHY_DEVICE_ID only, so maybe we don't need to change the
>> >> signature at all?
>> >
>> > I'm not sure I understand the last sentence. The Rust PHY abstraction
>> > allows one module to support multiple drivers. So we can could the
>> > similar trick that the second patch in this patchset does.
>> >
>> > fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>> >     // do comparison workking for three drivers
>> > }
>> 
>> I wouldn't do it like this in Rust, instead this would be a "rustier"
>> function signature:
>> 
>>     fn match_device_id<T: Driver>(dev: &mut phy::Device) -> bool {
>>         // do the comparison with T::PHY_DEVICE_ID
>>         dev.id() == T::PHY_DEVICE_ID
>>     }
>> 
>> And then in the impls for Phy{A,B,C,D} do this:
>> 
>>     impl Driver for PhyA {
>>         fn match_phy_device(dev: &mut phy::Device) -> bool {
>>             match_device_id::<Self>(dev)
>>         }
>>     }
>> 
>
> My 2 cent about the discussion and I'm totally detached from how it
> works on Rust kernel code but shouldn't we try to keep parallel API and
> args between C and Rust?

It depends :) There are several things to consider in this from safety
to ease of use. Sometimes we diverge from the C implementation, because
it makes it safe. For example, from the very beginning, mutexes in Rust
have used guards, but those have only been recently-ish introduced in
C. Mutexes in Rust also store the value inside of them, making it
impossible to access the inner value without taking the lock. This makes
the API safer, but diverges from C.

Now in this case, we're talking about making an API more rusty and thus
diverging from the C side. One can argue for either side and we have to
strike a balance, but in the end it'll probably be up to each subsystem
how they will handle it. It's not as big of an argument as safety (which
we strive very hard for).

In this concrete case, a `DriverVTable` is just an adapter type that we
use to make a trait in Rust be compatible with a C vtable. From Rusts
perspective, the single origin of truth is the trait and the vtable is
derived from that. So from a Rust perspective it's much more natural to
use the trait than the vtable. (This might also end up being more
performant, since we statically know which ID the driver supports and
the C side needs to dynamically look it up.)

> I know maybe some thing doesn't make sense from C to Rust but doesn't
> deviates from C code introduce more confusion when something need to be
> ported from C to Rust?

Ideally we have people that work on both sides and can bridge that gap.
If not, then having a Rust expert and a C expert work together has
worked out great in the past. I don't see this becoming a big problem
unless one of the sides is poorly maintained, which could also happen in
C.

> Again no idea if this apply so I'm just curious about this.

No worries, glad to hear your perspective.

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-17 19:02                 ` Benno Lossin
  2025-05-17 20:09                   ` Christian Marangi
@ 2025-05-19 12:00                   ` FUJITA Tomonori
  2025-05-19 12:32                     ` Benno Lossin
  1 sibling, 1 reply; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-19 12:00 UTC (permalink / raw)
  To: lossin
  Cc: fujita.tomonori, ansuelsmth, andrew+netdev, davem, edumazet, kuba,
	pabeni, robh, krzk+dt, conor+dt, hkallweit1, linux,
	florian.fainelli, bcm-kernel-feedback-list, kabel, andrei.botila,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

On Sat, 17 May 2025 21:02:51 +0200
"Benno Lossin" <lossin@kernel.org> wrote:

>>> I think that's wrong, nothing stops me from implementing `Driver` for an
>>> empty enum and that can't be instantiated. The reason that one wants to
>>> have this in C is because the same `match` function is used for
>>> different drivers (or maybe devices? I'm not too familiar with the
>>> terminology). In Rust, you must implement the match function for a
>>> single PHY_DEVICE_ID only, so maybe we don't need to change the
>>> signature at all?
>>
>> I'm not sure I understand the last sentence. The Rust PHY abstraction
>> allows one module to support multiple drivers. So we can could the
>> similar trick that the second patch in this patchset does.
>>
>> fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>>     // do comparison workking for three drivers
>> }
> 
> I wouldn't do it like this in Rust, instead this would be a "rustier"
> function signature:
> 
>     fn match_device_id<T: Driver>(dev: &mut phy::Device) -> bool {
>         // do the comparison with T::PHY_DEVICE_ID
>         dev.id() == T::PHY_DEVICE_ID
>     }
> 
> And then in the impls for Phy{A,B,C,D} do this:
> 
>     impl Driver for PhyA {
>         fn match_phy_device(dev: &mut phy::Device) -> bool {
>             match_device_id::<Self>(dev)
>         }
>     }

Ah, yes, this works well.


>> The other use case, as mentioned above, is when using the generic helper
>> function inside match_phy_device() callback. For example, the 4th
>> patch in this patchset adds genphy_match_phy_device():
>>
>> int genphy_match_phy_device(struct phy_device *phydev,
>>                            const struct phy_driver *phydrv)
>>
>> We could add a wrapper for this function as phy::Device's method like
>>
>> impl Device {
>>     ...
>>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
> 
> Not sure why this returns an `i32`, but we probably could have such a

Maybe a bool would be more appropriate here because the C's comment
says:

Return: 1 if the PHY device matches the driver, 0 otherwise.

> function as well (though I wouldn't use the vtable for that).

What would you use instead?

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-19 12:00                   ` FUJITA Tomonori
@ 2025-05-19 12:32                     ` Benno Lossin
  2025-05-19 12:44                       ` FUJITA Tomonori
  0 siblings, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-19 12:32 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: ansuelsmth, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Mon May 19, 2025 at 2:00 PM CEST, FUJITA Tomonori wrote:
> On Sat, 17 May 2025 21:02:51 +0200
> "Benno Lossin" <lossin@kernel.org> wrote:
>>>> I think that's wrong, nothing stops me from implementing `Driver` for an
>>>> empty enum and that can't be instantiated. The reason that one wants to
>>>> have this in C is because the same `match` function is used for
>>>> different drivers (or maybe devices? I'm not too familiar with the
>>>> terminology). In Rust, you must implement the match function for a
>>>> single PHY_DEVICE_ID only, so maybe we don't need to change the
>>>> signature at all?
>>>
>>> I'm not sure I understand the last sentence. The Rust PHY abstraction
>>> allows one module to support multiple drivers. So we can could the
>>> similar trick that the second patch in this patchset does.
>>>
>>> fn match_device_id(dev: &mut phy::Device, drv: &phy::DriverVTable) -> bool {
>>>     // do comparison workking for three drivers
>>> }
>> 
>> I wouldn't do it like this in Rust, instead this would be a "rustier"
>> function signature:
>> 
>>     fn match_device_id<T: Driver>(dev: &mut phy::Device) -> bool {
>>         // do the comparison with T::PHY_DEVICE_ID
>>         dev.id() == T::PHY_DEVICE_ID
>>     }
>> 
>> And then in the impls for Phy{A,B,C,D} do this:
>> 
>>     impl Driver for PhyA {
>>         fn match_phy_device(dev: &mut phy::Device) -> bool {
>>             match_device_id::<Self>(dev)
>>         }
>>     }
>
> Ah, yes, this works well.
>
>
>>> The other use case, as mentioned above, is when using the generic helper
>>> function inside match_phy_device() callback. For example, the 4th
>>> patch in this patchset adds genphy_match_phy_device():
>>>
>>> int genphy_match_phy_device(struct phy_device *phydev,
>>>                            const struct phy_driver *phydrv)
>>>
>>> We could add a wrapper for this function as phy::Device's method like
>>>
>>> impl Device {
>>>     ...
>>>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
>> 
>> Not sure why this returns an `i32`, but we probably could have such a
>
> Maybe a bool would be more appropriate here because the C's comment
> says:
>
> Return: 1 if the PHY device matches the driver, 0 otherwise.
>
>> function as well (though I wouldn't use the vtable for that).
>
> What would you use instead?

The concept that I sketched above:

    impl Device {
        fn genphy_match_phy_device<T: Driver>(&self) -> bool {
            self.phy_id() == T::PHY_DEVICE_ID.id
        }
    }

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-19 12:32                     ` Benno Lossin
@ 2025-05-19 12:44                       ` FUJITA Tomonori
  2025-05-19 12:51                         ` Benno Lossin
  0 siblings, 1 reply; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-19 12:44 UTC (permalink / raw)
  To: lossin
  Cc: fujita.tomonori, ansuelsmth, andrew+netdev, davem, edumazet, kuba,
	pabeni, robh, krzk+dt, conor+dt, hkallweit1, linux,
	florian.fainelli, bcm-kernel-feedback-list, kabel, andrei.botila,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

On Mon, 19 May 2025 14:32:44 +0200
"Benno Lossin" <lossin@kernel.org> wrote:

>>>> The other use case, as mentioned above, is when using the generic helper
>>>> function inside match_phy_device() callback. For example, the 4th
>>>> patch in this patchset adds genphy_match_phy_device():
>>>>
>>>> int genphy_match_phy_device(struct phy_device *phydev,
>>>>                            const struct phy_driver *phydrv)
>>>>
>>>> We could add a wrapper for this function as phy::Device's method like
>>>>
>>>> impl Device {
>>>>     ...
>>>>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
>>> 
>>> Not sure why this returns an `i32`, but we probably could have such a
>>
>> Maybe a bool would be more appropriate here because the C's comment
>> says:
>>
>> Return: 1 if the PHY device matches the driver, 0 otherwise.
>>
>>> function as well (though I wouldn't use the vtable for that).
>>
>> What would you use instead?
> 
> The concept that I sketched above:
> 
>     impl Device {
>         fn genphy_match_phy_device<T: Driver>(&self) -> bool {
>             self.phy_id() == T::PHY_DEVICE_ID.id
>         }
>     }

I think there might be a misunderstanding.

Rust's genphy_match_phy_device() is supposed to be a wrapper for C's
genphy_match_phy_device():

https://lore.kernel.org/rust-for-linux/20250517201353.5137-5-ansuelsmth@gmail.com/


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-19 12:44                       ` FUJITA Tomonori
@ 2025-05-19 12:51                         ` Benno Lossin
  2025-05-19 12:58                           ` FUJITA Tomonori
  0 siblings, 1 reply; 27+ messages in thread
From: Benno Lossin @ 2025-05-19 12:51 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: ansuelsmth, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt, hkallweit1, linux, florian.fainelli,
	bcm-kernel-feedback-list, kabel, andrei.botila, tmgross, ojeda,
	alex.gaynor, boqun.feng, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, dakr, sd, michael, daniel, netdev,
	devicetree, linux-kernel, rust-for-linux

On Mon May 19, 2025 at 2:44 PM CEST, FUJITA Tomonori wrote:
> On Mon, 19 May 2025 14:32:44 +0200
> "Benno Lossin" <lossin@kernel.org> wrote:
>>>>> The other use case, as mentioned above, is when using the generic helper
>>>>> function inside match_phy_device() callback. For example, the 4th
>>>>> patch in this patchset adds genphy_match_phy_device():
>>>>>
>>>>> int genphy_match_phy_device(struct phy_device *phydev,
>>>>>                            const struct phy_driver *phydrv)
>>>>>
>>>>> We could add a wrapper for this function as phy::Device's method like
>>>>>
>>>>> impl Device {
>>>>>     ...
>>>>>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
>>>> 
>>>> Not sure why this returns an `i32`, but we probably could have such a
>>>
>>> Maybe a bool would be more appropriate here because the C's comment
>>> says:
>>>
>>> Return: 1 if the PHY device matches the driver, 0 otherwise.
>>>
>>>> function as well (though I wouldn't use the vtable for that).
>>>
>>> What would you use instead?
>> 
>> The concept that I sketched above:
>> 
>>     impl Device {
>>         fn genphy_match_phy_device<T: Driver>(&self) -> bool {
>>             self.phy_id() == T::PHY_DEVICE_ID.id
>>         }
>>     }
>
> I think there might be a misunderstanding.
>
> Rust's genphy_match_phy_device() is supposed to be a wrapper for C's
> genphy_match_phy_device():
>
> https://lore.kernel.org/rust-for-linux/20250517201353.5137-5-ansuelsmth@gmail.com/

Oh yeah you're right. But using `DriverVTable` for that doesn't sound
nice...

---
Cheers,
Benno

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes
  2025-05-19 12:51                         ` Benno Lossin
@ 2025-05-19 12:58                           ` FUJITA Tomonori
  0 siblings, 0 replies; 27+ messages in thread
From: FUJITA Tomonori @ 2025-05-19 12:58 UTC (permalink / raw)
  To: lossin
  Cc: fujita.tomonori, ansuelsmth, andrew+netdev, davem, edumazet, kuba,
	pabeni, robh, krzk+dt, conor+dt, hkallweit1, linux,
	florian.fainelli, bcm-kernel-feedback-list, kabel, andrei.botila,
	tmgross, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, dakr, sd, michael, daniel,
	netdev, devicetree, linux-kernel, rust-for-linux

On Mon, 19 May 2025 14:51:55 +0200
"Benno Lossin" <lossin@kernel.org> wrote:

> On Mon May 19, 2025 at 2:44 PM CEST, FUJITA Tomonori wrote:
>> On Mon, 19 May 2025 14:32:44 +0200
>> "Benno Lossin" <lossin@kernel.org> wrote:
>>>>>> The other use case, as mentioned above, is when using the generic helper
>>>>>> function inside match_phy_device() callback. For example, the 4th
>>>>>> patch in this patchset adds genphy_match_phy_device():
>>>>>>
>>>>>> int genphy_match_phy_device(struct phy_device *phydev,
>>>>>>                            const struct phy_driver *phydrv)
>>>>>>
>>>>>> We could add a wrapper for this function as phy::Device's method like
>>>>>>
>>>>>> impl Device {
>>>>>>     ...
>>>>>>     pub fn genphy_match_phy_device(&self, drv: &phy::DriverVTable) -> i32 
>>>>> 
>>>>> Not sure why this returns an `i32`, but we probably could have such a
>>>>
>>>> Maybe a bool would be more appropriate here because the C's comment
>>>> says:
>>>>
>>>> Return: 1 if the PHY device matches the driver, 0 otherwise.
>>>>
>>>>> function as well (though I wouldn't use the vtable for that).
>>>>
>>>> What would you use instead?
>>> 
>>> The concept that I sketched above:
>>> 
>>>     impl Device {
>>>         fn genphy_match_phy_device<T: Driver>(&self) -> bool {
>>>             self.phy_id() == T::PHY_DEVICE_ID.id
>>>         }
>>>     }
>>
>> I think there might be a misunderstanding.
>>
>> Rust's genphy_match_phy_device() is supposed to be a wrapper for C's
>> genphy_match_phy_device():
>>
>> https://lore.kernel.org/rust-for-linux/20250517201353.5137-5-ansuelsmth@gmail.com/
> 
> Oh yeah you're right. But using `DriverVTable` for that doesn't sound
> nice...

Agreed. We initially assumed that DriverVTable would be internal to
driver registration and not something driver developers would use
directly. Now that this has changed, it might be a good idea to rename
it.

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2025-05-19 12:58 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-15 11:27 [net-next PATCH v10 0/7] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 1/7] net: phy: pass PHY driver to .match_phy_device OP Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 2/7] net: phy: bcm87xx: simplify " Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 3/7] net: phy: nxp-c45-tja11xx: " Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 4/7] net: phy: introduce genphy_match_phy_device() Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 5/7] net: phy: Add support for Aeonsemi AS21xxx PHYs Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 6/7] dt-bindings: net: Document support for Aeonsemi PHYs Christian Marangi
2025-05-15 11:27 ` [net-next PATCH v10 7/7] rust: net::phy sync with match_phy_device C changes Christian Marangi
2025-05-15 11:49   ` Benno Lossin
2025-05-15 11:51     ` Christian Marangi
2025-05-15 12:01       ` Benno Lossin
2025-05-16 12:30   ` FUJITA Tomonori
2025-05-16 14:48     ` Benno Lossin
2025-05-16 15:12       ` Christian Marangi
2025-05-16 20:16         ` Benno Lossin
2025-05-17  6:27           ` FUJITA Tomonori
2025-05-17  8:06             ` Benno Lossin
2025-05-17 13:13               ` FUJITA Tomonori
2025-05-17 19:02                 ` Benno Lossin
2025-05-17 20:09                   ` Christian Marangi
2025-05-18  7:13                     ` Benno Lossin
2025-05-19 12:00                   ` FUJITA Tomonori
2025-05-19 12:32                     ` Benno Lossin
2025-05-19 12:44                       ` FUJITA Tomonori
2025-05-19 12:51                         ` Benno Lossin
2025-05-19 12:58                           ` FUJITA Tomonori
2025-05-16 15:10     ` Christian Marangi

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).