From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4C5054AE12A for ; Wed, 2 Sep 2026 21:22:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384171; cv=none; b=HYH5uxHlpMjeJB0+bpseY7EevcRes+XTFPz8Nyo87ouhwmu7NDntTNP9H1TTrBRkXOcIBelN/rjb47y0GrlMmrjzECjYTdKtMA19Bm8R00PCCqm3CkVON8V9MIfIzfd+Ez0v2QLgQXrYz9YDyJ7Oxu9tT0qnfCmjZxcL8tYtV7I= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384171; c=relaxed/simple; bh=e2qLk7kSzIQ7RQ1K4lWiPuMfQLkCtQKDZdM/31lM2Y4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mPUyaReb1S1d60OIenVug7hfHXfYKQZq/8U0eO2aE6XF+sxPed2kwWq5wFrc+FBD0xqDswnYjUubHgO6FDxHdfez1XNSGFPdpYT3BEVHbgcQ9d8uvREmoKMszxC+liD3/IsSGVmKNuJ+eZwwHfmEHDyLE3lkSJpHG7qcNPurVK4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=Fob6TAeP; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="Fob6TAeP" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 552B21A1969; Wed, 2 Sep 2026 21:22:37 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 286876053C; Wed, 2 Sep 2026 21:22:37 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D269411C79331; Wed, 2 Sep 2026 23:22:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1788384151; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=m9//GANjALAZze1xUAwzEWuAcuvKp7+6LkSexJWodaw=; b=Fob6TAePET6/tkYx/XI3H/4lDHgGNLIiCmmCgQjJa6e8EGdtYQgV3rpqQcfO0iQaV89aUu NSMMtf3m4ermhZntT6POsZKEUmeCtC6tJSnmFw7cTimldJdVqsQR1b0fM5zhBgVs0lLBzH MCFapcNUhJtINtPZnWmrM+e4OxUt0M5XBGqtyDlfy/6D20/8mfRP4K7YAIjyUVgN3ODEug 4B4vkS1RltVLSyYjXIVfgvFwzc94t3kpwS7uIXv812go7cGIQoFg72hKqAFTxS6QiB8AxG jEC3YxNQFmpQGiUhKBGQ8tX93nTc4Q9vO/WqR2Fl6ILmYBG6/C5OBEtAd7Qt4Q== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , Vladimir Oltean , =?UTF-8?q?K=C3=B6ry=20Maincent?= , =?UTF-8?q?Marek=20Beh=C3=BAn?= , Oleksij Rempel , =?UTF-8?q?Nicol=C3=B2=20Veronese?= , Simon Horman , mwojtas@chromium.org, Romain Gantois , Daniel Golle , Dimitri Fedrau , Frank Wunderlich , Pietro Ameruoso Subject: [PATCH net-next v16 06/10] net: phy: phy_port: Store information about a port's upstream Date: Wed, 2 Sep 2026 23:21:30 +0200 Message-ID: <20260902212135.1805948-7-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260902212135.1805948-1-maxime.chevallier@bootlin.com> References: <20260902212135.1805948-1-maxime.chevallier@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 MII phy_ports are not meant to be connected directly to a link partner. They are meant to feed into some media converter devices that will expose an MDI phy_port, so far we only support SFP modules for that. In the case an MDI phy_port is backed by an MII port (e.g. a SFP module's port, backed by the SFP cage port), let's keep track of the port id of the MII port backing it. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_device.c | 29 +++++++++++++++++++++++++++-- drivers/net/phy/phylink.c | 5 +++++ include/linux/phy.h | 4 ++++ include/linux/phy_port.h | 3 +++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2d7dee8c4c7d..6fc191920596 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1493,6 +1493,7 @@ static int phy_sfp_connect_phy(void *upstream, struct phy_device *phy) int ret; phydev->has_sfp_mod_phy = true; + phy_set_upstream_port(phy, phydev->sfp_cage_port); /* If we aren't attached to a netdev, we can't add the SFP PHY to its * topology. @@ -1526,6 +1527,8 @@ static void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy) if (dev) phy_link_topo_del_phy(dev, phy); + + phy_set_upstream_port(phy, NULL); } /** @@ -1661,6 +1664,8 @@ static int phy_add_sfp_mod_port(struct phy_device *phydev) */ phydev->mod_port = port; + port->upstream_port = phydev->sfp_cage_port; + return 0; } @@ -1816,6 +1821,8 @@ static int phy_sfp_probe(struct phy_device *phydev) } } + phydev->sfp_cage_port = port; + ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops); if (ret) goto out_port; @@ -1825,14 +1832,13 @@ static int phy_sfp_probe(struct phy_device *phydev) */ sfp_bus_put(bus); - phydev->sfp_cage_port = port; - return ret; out_port: if (port) { phy_del_port(phydev, port); phy_port_destroy(port); + phydev->sfp_cage_port = NULL; } out_sfp: sfp_bus_put(bus); @@ -3753,6 +3759,25 @@ struct phy_port *phy_get_sfp_port(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(phy_get_sfp_port); +/** + * phy_set_upstream_port() - Sets the phy_port controlling the MII this PHY is + * attached to. + * @phydev: pointer to the PHY device we set the upstream of. + * @port: The phy_port upstream of this PHY, can be NULL. + */ +void phy_set_upstream_port(struct phy_device *phydev, struct phy_port *port) +{ + struct phy_port *local_port; + + ASSERT_RTNL(); + + phydev->upstream_port = port; + + phy_for_each_port(phydev, local_port) + local_port->upstream_port = port; +} +EXPORT_SYMBOL_GPL(phy_set_upstream_port); + /** * fwnode_mdio_find_device - Given a fwnode, find the mdio_device * @fwnode: pointer to the mdio_device's fwnode diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index d0a3faf6cd93..7168a0eeb1c4 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3956,6 +3956,8 @@ static int phylink_add_sfp_mod_port(struct phylink *pl) } } + port->upstream_port = pl->sfp_cage_port; + pl->mod_port = port; return 0; @@ -4059,6 +4061,8 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, pl->config->supported_interfaces); + phy_set_upstream_port(phy, pl->sfp_cage_port); + /* Do the initial configuration */ return phylink_sfp_config_phy(pl, phy); } @@ -4067,6 +4071,7 @@ static void phylink_sfp_disconnect_phy(void *upstream, struct phy_device *phydev) { phylink_disconnect_phy(upstream); + phy_set_upstream_port(phydev, NULL); } static const struct sfp_upstream_ops sfp_phylink_ops = { diff --git a/include/linux/phy.h b/include/linux/phy.h index ae8e39117693..25713b635b63 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -597,6 +597,7 @@ struct phy_oatc14_sqi_capability { * @sfp_bus: SFP bus attached to this PHY's fiber port * @sfp_cage_port: The phy_port connected to the downstream SFP cage * @mod_port: phy_port representing the SFP module, if it is phy-less + * @upstream_port: phy_port this PHY's MII attaches to, if any * @attached_dev: The attached enet driver's device instance ptr * @adjust_link: Callback for the enet controller to respond to changes: in the * link state. @@ -791,6 +792,7 @@ struct phy_device { struct sfp_bus *sfp_bus; struct phy_port *sfp_cage_port; struct phy_port *mod_port; + struct phy_port *upstream_port; struct phylink *phylink; struct net_device *attached_dev; struct mii_timestamper *mii_ts; @@ -2475,6 +2477,8 @@ int __phy_hwtstamp_set(struct phy_device *phydev, struct phy_port *phy_get_sfp_port(struct phy_device *phydev); +void phy_set_upstream_port(struct phy_device *phydev, struct phy_port *port); + /** * phy_module_driver() - Helper macro for registering PHY drivers * @__phy_drivers: array of PHY drivers to register diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h index 4e2a3fdd2f2e..8f45c031cbc1 100644 --- a/include/linux/phy_port.h +++ b/include/linux/phy_port.h @@ -40,6 +40,8 @@ struct phy_port_ops { * @head: Used by the port's parent to list ports * @parent_type: The type of device this port is directly connected to * @phy: If the parent is PHY_PORT_PHYDEV, the PHY controlling that port + * @upstream_port: Indicates the MII port that feeds this port, if any, + * e.g. the SFP cage port for a SFP module port. * @ops: Callback ops implemented by the port controller * @pairs: The number of pairs this port has, 0 if not applicable * @mediums: Bitmask of the physical mediums this port provides access to @@ -59,6 +61,7 @@ struct phy_port { union { struct phy_device *phy; }; + struct phy_port *upstream_port; const struct phy_port_ops *ops; -- 2.55.0