| .. SPDX-License-Identifier: GPL-2.0 |
| .. _phy_link_topology: |
| |
| ================= |
| PHY link topology |
| ================= |
| |
| Overview |
| ======== |
| |
| The PHY link topology representation in the networking stack aims at representing |
| the hardware layout for any given Ethernet link. |
| |
| An Ethernet interface from userspace's point of view is nothing but a |
| :c:type:`struct net_device <net_device>`, which exposes configuration options |
| through the legacy ioctls and the ethtool netlink commands. The base assumption |
| when designing these configuration APIs were that the link looks something like :: |
| |
| +-----------------------+ +----------+ +--------------+ |
| | Ethernet Controller / | | Ethernet | | Connector / | |
| | MAC | ------ | PHY | ---- | Port | ---... to LP |
| +-----------------------+ +----------+ +--------------+ |
| struct net_device struct phy_device |
| |
| Commands that needs to configure the PHY will go through the net_device.phydev |
| field to reach the PHY and perform the relevant configuration. |
| |
| This assumption falls apart in more complex topologies that can arise when, |
| for example, using SFP transceivers (although that's not the only specific case). |
| |
| Here, we have 2 basic scenarios. Either the MAC is able to output a serialized |
| interface, that can directly be fed to an SFP cage, such as SGMII, 1000BaseX, |
| 10GBaseR, etc. |
| |
| The link topology then looks like this (when an SFP module is inserted) :: |
| |
| +-----+ SGMII +------------+ |
| | MAC | ------- | SFP Module | |
| +-----+ +------------+ |
| |
| Knowing that some modules embed a PHY, the actual link is more like :: |
| |
| +-----+ SGMII +--------------+ |
| | MAC | -------- | PHY (on SFP) | |
| +-----+ +--------------+ |
| |
| In this case, the SFP PHY is handled by phylib, and registered by phylink through |
| its SFP upstream ops. |
| |
| Now some Ethernet controllers aren't able to output a serialized interface, so |
| we can't directly connect them to an SFP cage. However, some PHYs can be used |
| as media-converters, to translate the non-serialized MAC MII interface to a |
| serialized MII interface fed to the SFP :: |
| |
| +-----+ RGMII +-----------------------+ SGMII +--------------+ |
| | MAC | ------- | PHY (media converter) | ------- | PHY (on SFP) | |
| +-----+ +-----------------------+ +--------------+ |
| |
| This is where the model of having a single net_device.phydev pointer shows its |
| limitations, as we now have 2 PHYs on the link. |
| |
| The phy_link topology framework aims at providing a way to keep track of every |
| PHY on the link, for use by both kernel drivers and subsystems, but also to |
| report the topology to userspace, allowing to target individual PHYs in configuration |
| commands. |
| |
| API |
| === |
| |
| The :c:type:`struct phy_link_topology <phy_link_topology>` is a per-netdevice |
| resource, that gets initialized at netdevice creation. Once it's initialized, |
| it is then possible to register PHYs to the topology through : |
| |
| :c:func:`phy_link_topo_add_phy` |
| |
| Besides registering the PHY to the topology, this call will also assign a unique |
| index to the PHY, which can then be reported to userspace to refer to this PHY |
| (akin to the ifindex). This index is a u32, ranging from 1 to U32_MAX. The value |
| 0 is reserved to indicate the PHY doesn't belong to any topology yet. |
| |
| The PHY can then be removed from the topology through |
| |
| :c:func:`phy_link_topo_del_phy` |
| |
| These function are already hooked into the phylib subsystem, so all PHYs that |
| are linked to a net_device through :c:func:`phy_attach_direct` will automatically |
| join the netdev's topology. |
| |
| PHYs that are on a SFP module will also be automatically registered IF the SFP |
| upstream is phylink (so, no media-converter). |
| |
| PHY drivers that can be used as SFP upstream need to call :c:func:`phy_sfp_attach_phy` |
| and :c:func:`phy_sfp_detach_phy`, which can be used as a |
| .attach_phy / .detach_phy implementation for the |
| :c:type:`struct sfp_upstream_ops <sfp_upstream_ops>`. |
| |
| UAPI |
| ==== |
| |
| There exist a set of netlink commands to query the link topology from userspace, |
| see ``Documentation/networking/ethtool-netlink.rst``. |
| |
| The whole point of having a topology representation is to assign the phyindex |
| field in :c:type:`struct phy_device <phy_device>`. This index is reported to |
| userspace using the ``ETHTOOL_MSG_PHY_GET`` ethtnl command. Performing a DUMP operation |
| will result in all PHYs from all net_device being listed. The DUMP command |
| accepts either a ``ETHTOOL_A_HEADER_DEV_INDEX`` or ``ETHTOOL_A_HEADER_DEV_NAME`` |
| to be passed in the request to filter the DUMP to a single net_device. |
| |
| The retrieved index can then be passed as a request parameter using the |
| ``ETHTOOL_A_HEADER_PHY_INDEX`` field in the following ethnl commands : |
| |
| * ``ETHTOOL_MSG_STRSET_GET`` to get the stats string set from a given PHY |
| * ``ETHTOOL_MSG_CABLE_TEST_ACT`` and ``ETHTOOL_MSG_CABLE_TEST_ACT``, to perform |
| cable testing on a given PHY on the link (most likely the outermost PHY) |
| * ``ETHTOOL_MSG_PSE_SET`` and ``ETHTOOL_MSG_PSE_GET`` for PHY-controlled PoE and PSE settings |
| * ``ETHTOOL_MSG_PLCA_GET_CFG``, ``ETHTOOL_MSG_PLCA_SET_CFG`` and ``ETHTOOL_MSG_PLCA_GET_STATUS`` |
| to set the PLCA (Physical Layer Collision Avoidance) parameters |
| |
| Note that the PHY index can be passed to other requests, which will silently |
| ignore it if present and irrelevant. |