Commit 589e934d authored by Maxime Chevallier's avatar Maxime Chevallier Committed by Jakub Kicinski
Browse files

net: phy: Introduce PHY ports representation



Ethernet provides a wide variety of layer 1 protocols and standards for
data transmission. The front-facing ports of an interface have their own
complexity and configurability.

Introduce a representation of these front-facing ports. The current code
is minimalistic and only support ports controlled by PHY devices, but
the plan is to extend that to SFP as well as raw Ethernet MACs that
don't use PHY devices.

This minimal port representation allows describing the media and number
of pairs of a BaseT port. From that information, we can derive the
linkmodes usable on the port, which can be used to limit the
capabilities of an interface.

For now, the port pairs and medium is derived from devicetree, defined
by the PHY driver, or populated with default values (as we assume that
all PHYs expose at least one port).

The typical example is 100M ethernet. 100BaseTX works using only 2
pairs on a Cat 5 cables. However, in the situation where a 10/100/1000
capable PHY is wired to its RJ45 port through 2 pairs only, we have no
way of detecting that. The "max-speed" DT property can be used, but a
more accurate representation can be used :

mdi {
	connector-0 {
		media = "BaseT";
		pairs = <2>;
	};
};

From that information, we can derive the max speed reachable on the
port.

Another benefit of having that is to avoid vendor-specific DT properties
(micrel,fiber-mode or ti,fiber-mode).

This basic representation is meant to be expanded, by the introduction
of port ops, userspace listing of ports, and support for multi-port
devices.

Reviewed-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMaxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260108080041.553250-4-maxime.chevallier@bootlin.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 3f25ff74
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -18218,6 +18218,13 @@ F: drivers/net/phy/phy_link_topology.c
F:	include/linux/phy_link_topology.h
F:	net/ethtool/phy.c
NETWORKING [ETHTOOL PHY PORT]
M:	Maxime Chevallier <maxime.chevallier@bootlin.com>
F:	Documentation/devicetree/bindings/net/ethernet-connector.yaml
F:	drivers/net/phy/phy_port.c
F:	include/linux/phy_port.h
K:	struct\s+phy_port|phy_port_
NETWORKING [GENERAL]
M:	"David S. Miller" <davem@davemloft.net>
M:	Eric Dumazet <edumazet@google.com>
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@

libphy-y			:= phy.o phy-c45.o phy-core.o phy_device.o \
				   linkmode.o phy_link_topology.o \
				   phy_caps.o mdio_bus_provider.o
				   phy_caps.o mdio_bus_provider.o phy_port.o
mdio-bus-y			+= mdio_bus.o mdio_device.o

ifdef CONFIG_PHYLIB
+5 −0
Original line number Diff line number Diff line
@@ -61,4 +61,9 @@ const struct link_capabilities *
phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported,
		bool exact);

void phy_caps_medium_get_supported(unsigned long *supported,
				   enum ethtool_link_medium medium,
				   int lanes);
u32 phy_caps_mediums_from_linkmodes(unsigned long *linkmodes);

#endif /* __PHY_CAPS_H */
+6 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 */
#include <linux/export.h>
#include <linux/phy.h>
#include <linux/phy_port.h>
#include <linux/of.h>

#include "phylib.h"
@@ -208,7 +209,12 @@ EXPORT_SYMBOL_GPL(phy_interface_num_ports);

static void __set_phy_supported(struct phy_device *phydev, u32 max_speed)
{
	struct phy_port *port;

	phy_caps_linkmode_max_speed(max_speed, phydev->supported);

	phy_for_each_port(phydev, port)
		phy_caps_linkmode_max_speed(max_speed, port->supported);
}

/**
+57 −0
Original line number Diff line number Diff line
@@ -386,3 +386,60 @@ unsigned long phy_caps_from_interface(phy_interface_t interface)
	return link_caps;
}
EXPORT_SYMBOL_GPL(phy_caps_from_interface);

/**
 * phy_caps_medium_get_supported() - Returns linkmodes supported on a given medium
 * @supported: After this call, contains all possible linkmodes on a given medium,
 *	       and with the given number of pairs, or less.
 * @medium: The medium to get the support from
 * @pairs: The number of pairs used on the given medium. Only relevant for modes
 *	   that support this notion, such as BaseT. Pass 0 if not applicable.
 *
 * If no match exists, the supported field is left untouched.
 */
void phy_caps_medium_get_supported(unsigned long *supported,
				   enum ethtool_link_medium medium,
				   int pairs)
{
	int i;

	for (i = 0; i < __ETHTOOL_LINK_MODE_MASK_NBITS; i++) {
		/* Special bits such as Autoneg, Pause, Asym_pause, etc. are
		 * set and will be masked away by the port parent.
		 */
		if (link_mode_params[i].mediums == BIT(ETHTOOL_LINK_MEDIUM_NONE)) {
			linkmode_set_bit(i, supported);
			continue;
		}

		/* If this medium matches, and had a non-zero min-pairs */
		if (link_mode_params[i].mediums & BIT(medium) &&
		    (!link_mode_params[i].min_pairs ||
		      (link_mode_params[i].min_pairs <= pairs &&
		      link_mode_params[i].pairs >= pairs)))
			linkmode_set_bit(i, supported);
	}
}
EXPORT_SYMBOL_GPL(phy_caps_medium_get_supported);

/**
 * phy_caps_mediums_from_linkmodes() - Get all mediums from a linkmodes list
 * @linkmodes: A bitset of linkmodes to get the mediums from
 *
 * Returns: A bitset of ETHTOOL_MEDIUM_XXX values corresponding to all medium
 *	    types in the linkmodes list
 */
u32 phy_caps_mediums_from_linkmodes(unsigned long *linkmodes)
{
	const struct link_mode_info *linkmode;
	u32 mediums = 0;
	int i;

	for_each_set_bit(i, linkmodes, __ETHTOOL_LINK_MODE_MASK_NBITS) {
		linkmode = &link_mode_params[i];
		mediums |= linkmode->mediums;
	}

	return mediums;
}
EXPORT_SYMBOL_GPL(phy_caps_mediums_from_linkmodes);
Loading