Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'NCN26000-PLCA-RS-support'

Piergiorgio Beruto says:

====================
net: add PLCA RS support and onsemi NCN26000

This patchset adds support for getting/setting the Physical Layer
Collision Avoidace (PLCA) Reconciliation Sublayer (RS) configuration and
status on Ethernet PHYs that supports it.

PLCA is a feature that provides improved media-access performance in terms
of throughput, latency and fairness for multi-drop (P2MP) half-duplex PHYs.
PLCA is defined in Clause 148 of the IEEE802.3 specifications as amended
by 802.3cg-2019. Currently, PLCA is supported by the 10BASE-T1S single-pair
Ethernet PHY defined in the same standard and related amendments. The OPEN
Alliance SIG TC14 defines additional specifications for the 10BASE-T1S PHY,
including a standard register map for PHYs that embeds the PLCA RS (see
PLCA management registers at https://www.opensig.org/about/specifications/).

The changes proposed herein add the appropriate ethtool netlink interface
for configuring the PLCA RS on PHYs that supports it. A separate patchset
further modifies the ethtool userspace program to show and modify the
configuration/status of the PLCA RS.

Additionally, this patchset adds support for the onsemi NCN26000
Industrial Ethernet 10BASE-T1S PHY that uses the newly added PLCA
infrastructure.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1233 -3
+138
Documentation/networking/ethtool-netlink.rst
··· 1716 1716 ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte 1717 1717 indicates queue number. 1718 1718 1719 + PLCA_GET_CFG 1720 + ============ 1721 + 1722 + Gets the IEEE 802.3cg-2019 Clause 148 Physical Layer Collision Avoidance 1723 + (PLCA) Reconciliation Sublayer (RS) attributes. 1724 + 1725 + Request contents: 1726 + 1727 + ===================================== ====== ========================== 1728 + ``ETHTOOL_A_PLCA_HEADER`` nested request header 1729 + ===================================== ====== ========================== 1730 + 1731 + Kernel response contents: 1732 + 1733 + ====================================== ====== ============================= 1734 + ``ETHTOOL_A_PLCA_HEADER`` nested reply header 1735 + ``ETHTOOL_A_PLCA_VERSION`` u16 Supported PLCA management 1736 + interface standard/version 1737 + ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State 1738 + ``ETHTOOL_A_PLCA_NODE_ID`` u32 PLCA unique local node ID 1739 + ``ETHTOOL_A_PLCA_NODE_CNT`` u32 Number of PLCA nodes on the 1740 + network, including the 1741 + coordinator 1742 + ``ETHTOOL_A_PLCA_TO_TMR`` u32 Transmit Opportunity Timer 1743 + value in bit-times (BT) 1744 + ``ETHTOOL_A_PLCA_BURST_CNT`` u32 Number of additional packets 1745 + the node is allowed to send 1746 + within a single TO 1747 + ``ETHTOOL_A_PLCA_BURST_TMR`` u32 Time to wait for the MAC to 1748 + transmit a new frame before 1749 + terminating the burst 1750 + ====================================== ====== ============================= 1751 + 1752 + When set, the optional ``ETHTOOL_A_PLCA_VERSION`` attribute indicates which 1753 + standard and version the PLCA management interface complies to. When not set, 1754 + the interface is vendor-specific and (possibly) supplied by the driver. 1755 + The OPEN Alliance SIG specifies a standard register map for 10BASE-T1S PHYs 1756 + embedding the PLCA Reconcialiation Sublayer. See "10BASE-T1S PLCA Management 1757 + Registers" at https://www.opensig.org/about/specifications/. 1758 + 1759 + When set, the optional ``ETHTOOL_A_PLCA_ENABLED`` attribute indicates the 1760 + administrative state of the PLCA RS. When not set, the node operates in "plain" 1761 + CSMA/CD mode. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.1 1762 + aPLCAAdminState / 30.16.1.2.1 acPLCAAdminControl. 1763 + 1764 + When set, the optional ``ETHTOOL_A_PLCA_NODE_ID`` attribute indicates the 1765 + configured local node ID of the PHY. This ID determines which transmit 1766 + opportunity (TO) is reserved for the node to transmit into. This option is 1767 + corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.4 aPLCALocalNodeID. The valid 1768 + range for this attribute is [0 .. 255] where 255 means "not configured". 1769 + 1770 + When set, the optional ``ETHTOOL_A_PLCA_NODE_CNT`` attribute indicates the 1771 + configured maximum number of PLCA nodes on the mixing-segment. This number 1772 + determines the total number of transmit opportunities generated during a 1773 + PLCA cycle. This attribute is relevant only for the PLCA coordinator, which is 1774 + the node with aPLCALocalNodeID set to 0. Follower nodes ignore this setting. 1775 + This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.3 1776 + aPLCANodeCount. The valid range for this attribute is [1 .. 255]. 1777 + 1778 + When set, the optional ``ETHTOOL_A_PLCA_TO_TMR`` attribute indicates the 1779 + configured value of the transmit opportunity timer in bit-times. This value 1780 + must be set equal across all nodes sharing the medium for PLCA to work 1781 + correctly. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.5 1782 + aPLCATransmitOpportunityTimer. The valid range for this attribute is 1783 + [0 .. 255]. 1784 + 1785 + When set, the optional ``ETHTOOL_A_PLCA_BURST_CNT`` attribute indicates the 1786 + configured number of extra packets that the node is allowed to send during a 1787 + single transmit opportunity. By default, this attribute is 0, meaning that 1788 + the node can only send a sigle frame per TO. When greater than 0, the PLCA RS 1789 + keeps the TO after any transmission, waiting for the MAC to send a new frame 1790 + for up to aPLCABurstTimer BTs. This can only happen a number of times per PLCA 1791 + cycle up to the value of this parameter. After that, the burst is over and the 1792 + normal counting of TOs resumes. This option is corresponding to 1793 + ``IEEE 802.3cg-2019`` 30.16.1.1.6 aPLCAMaxBurstCount. The valid range for this 1794 + attribute is [0 .. 255]. 1795 + 1796 + When set, the optional ``ETHTOOL_A_PLCA_BURST_TMR`` attribute indicates how 1797 + many bit-times the PLCA RS waits for the MAC to initiate a new transmission 1798 + when aPLCAMaxBurstCount is greater than 0. If the MAC fails to send a new 1799 + frame within this time, the burst ends and the counting of TOs resumes. 1800 + Otherwise, the new frame is sent as part of the current burst. This option 1801 + is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.7 aPLCABurstTimer. The 1802 + valid range for this attribute is [0 .. 255]. Although, the value should be 1803 + set greater than the Inter-Frame-Gap (IFG) time of the MAC (plus some margin) 1804 + for PLCA burst mode to work as intended. 1805 + 1806 + PLCA_SET_CFG 1807 + ============ 1808 + 1809 + Sets PLCA RS parameters. 1810 + 1811 + Request contents: 1812 + 1813 + ====================================== ====== ============================= 1814 + ``ETHTOOL_A_PLCA_HEADER`` nested request header 1815 + ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State 1816 + ``ETHTOOL_A_PLCA_NODE_ID`` u8 PLCA unique local node ID 1817 + ``ETHTOOL_A_PLCA_NODE_CNT`` u8 Number of PLCA nodes on the 1818 + netkork, including the 1819 + coordinator 1820 + ``ETHTOOL_A_PLCA_TO_TMR`` u8 Transmit Opportunity Timer 1821 + value in bit-times (BT) 1822 + ``ETHTOOL_A_PLCA_BURST_CNT`` u8 Number of additional packets 1823 + the node is allowed to send 1824 + within a single TO 1825 + ``ETHTOOL_A_PLCA_BURST_TMR`` u8 Time to wait for the MAC to 1826 + transmit a new frame before 1827 + terminating the burst 1828 + ====================================== ====== ============================= 1829 + 1830 + For a description of each attribute, see ``PLCA_GET_CFG``. 1831 + 1832 + PLCA_GET_STATUS 1833 + =============== 1834 + 1835 + Gets PLCA RS status information. 1836 + 1837 + Request contents: 1838 + 1839 + ===================================== ====== ========================== 1840 + ``ETHTOOL_A_PLCA_HEADER`` nested request header 1841 + ===================================== ====== ========================== 1842 + 1843 + Kernel response contents: 1844 + 1845 + ====================================== ====== ============================= 1846 + ``ETHTOOL_A_PLCA_HEADER`` nested reply header 1847 + ``ETHTOOL_A_PLCA_STATUS`` u8 PLCA RS operational status 1848 + ====================================== ====== ============================= 1849 + 1850 + When set, the ``ETHTOOL_A_PLCA_STATUS`` attribute indicates whether the node is 1851 + detecting the presence of the BEACON on the network. This flag is 1852 + corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.2 aPLCAStatus. 1853 + 1719 1854 Request translation 1720 1855 =================== 1721 1856 ··· 1952 1817 n/a ``ETHTOOL_MSG_PHC_VCLOCKS_GET`` 1953 1818 n/a ``ETHTOOL_MSG_MODULE_GET`` 1954 1819 n/a ``ETHTOOL_MSG_MODULE_SET`` 1820 + n/a ``ETHTOOL_MSG_PLCA_GET_CFG`` 1821 + n/a ``ETHTOOL_MSG_PLCA_SET_CFG`` 1822 + n/a ``ETHTOOL_MSG_PLCA_GET_STATUS`` 1955 1823 =================================== =====================================
+14
MAINTAINERS
··· 15584 15584 S: Maintained 15585 15585 F: arch/mips/boot/dts/ralink/omega2p.dts 15586 15586 15587 + ONSEMI ETHERNET PHY DRIVERS 15588 + M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com> 15589 + L: netdev@vger.kernel.org 15590 + S: Supported 15591 + W: http://www.onsemi.com 15592 + F: drivers/net/phy/ncn* 15593 + 15587 15594 OP-TEE DRIVER 15588 15595 M: Jens Wiklander <jens.wiklander@linaro.org> 15589 15596 L: op-tee@lists.trustedfirmware.org ··· 16622 16615 S: Maintained 16623 16616 F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml 16624 16617 F: drivers/iio/chemical/pms7003.c 16618 + 16619 + PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148) 16620 + M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com> 16621 + L: netdev@vger.kernel.org 16622 + S: Maintained 16623 + F: drivers/net/phy/mdio-open-alliance.h 16624 + F: net/ethtool/plca.c 16625 16625 16626 16626 PLDMFW LIBRARY 16627 16627 M: Jacob Keller <jacob.e.keller@intel.com>
+7
drivers/net/phy/Kconfig
··· 277 277 help 278 278 Currently supports the NXP TJA1100 and TJA1101 PHY. 279 279 280 + config NCN26000_PHY 281 + tristate "Onsemi 10BASE-T1S Ethernet PHY" 282 + help 283 + Adds support for the onsemi 10BASE-T1S Ethernet PHY. 284 + Currently supports the NCN26000 10BASE-T1S Industrial PHY 285 + with MII interface. 286 + 280 287 config AT803X_PHY 281 288 tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" 282 289 depends on REGULATOR
+1
drivers/net/phy/Makefile
··· 77 77 obj-$(CONFIG_MICROSEMI_PHY) += mscc/ 78 78 obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o 79 79 obj-$(CONFIG_NATIONAL_PHY) += national.o 80 + obj-$(CONFIG_NCN26000_PHY) += ncn26000.o 80 81 obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o 81 82 obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o 82 83 obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+46
drivers/net/phy/mdio-open-alliance.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * mdio-open-alliance.h - definition of OPEN Alliance SIG standard registers 4 + */ 5 + 6 + #ifndef __MDIO_OPEN_ALLIANCE__ 7 + #define __MDIO_OPEN_ALLIANCE__ 8 + 9 + #include <linux/mdio.h> 10 + 11 + /* NOTE: all OATC14 registers are located in MDIO_MMD_VEND2 */ 12 + 13 + /* Open Alliance TC14 (10BASE-T1S) registers */ 14 + #define MDIO_OATC14_PLCA_IDVER 0xca00 /* PLCA ID and version */ 15 + #define MDIO_OATC14_PLCA_CTRL0 0xca01 /* PLCA Control register 0 */ 16 + #define MDIO_OATC14_PLCA_CTRL1 0xca02 /* PLCA Control register 1 */ 17 + #define MDIO_OATC14_PLCA_STATUS 0xca03 /* PLCA Status register */ 18 + #define MDIO_OATC14_PLCA_TOTMR 0xca04 /* PLCA TO Timer register */ 19 + #define MDIO_OATC14_PLCA_BURST 0xca05 /* PLCA BURST mode register */ 20 + 21 + /* Open Alliance TC14 PLCA IDVER register */ 22 + #define MDIO_OATC14_PLCA_IDM 0xff00 /* PLCA MAP ID */ 23 + #define MDIO_OATC14_PLCA_VER 0x00ff /* PLCA MAP version */ 24 + 25 + /* Open Alliance TC14 PLCA CTRL0 register */ 26 + #define MDIO_OATC14_PLCA_EN BIT(15) /* PLCA enable */ 27 + #define MDIO_OATC14_PLCA_RST BIT(14) /* PLCA reset */ 28 + 29 + /* Open Alliance TC14 PLCA CTRL1 register */ 30 + #define MDIO_OATC14_PLCA_NCNT 0xff00 /* PLCA node count */ 31 + #define MDIO_OATC14_PLCA_ID 0x00ff /* PLCA local node ID */ 32 + 33 + /* Open Alliance TC14 PLCA STATUS register */ 34 + #define MDIO_OATC14_PLCA_PST BIT(15) /* PLCA status indication */ 35 + 36 + /* Open Alliance TC14 PLCA TOTMR register */ 37 + #define MDIO_OATC14_PLCA_TOT 0x00ff 38 + 39 + /* Open Alliance TC14 PLCA BURST register */ 40 + #define MDIO_OATC14_PLCA_MAXBC 0xff00 41 + #define MDIO_OATC14_PLCA_BTMR 0x00ff 42 + 43 + /* Version Identifiers */ 44 + #define OATC14_IDM 0x0a00 45 + 46 + #endif /* __MDIO_OPEN_ALLIANCE__ */
+171
drivers/net/phy/ncn26000.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 + /* 3 + * Driver for the onsemi 10BASE-T1S NCN26000 PHYs family. 4 + * 5 + * Copyright 2022 onsemi 6 + */ 7 + #include <linux/kernel.h> 8 + #include <linux/bitfield.h> 9 + #include <linux/errno.h> 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/mii.h> 13 + #include <linux/phy.h> 14 + 15 + #include "mdio-open-alliance.h" 16 + 17 + #define PHY_ID_NCN26000 0x180FF5A1 18 + 19 + #define NCN26000_REG_IRQ_CTL 16 20 + #define NCN26000_REG_IRQ_STATUS 17 21 + 22 + // the NCN26000 maps link_ctrl to BMCR_ANENABLE 23 + #define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE 24 + 25 + // the NCN26000 maps link_status to BMSR_ANEGCOMPLETE 26 + #define NCN26000_BMSR_LINK_STATUS_BIT BMSR_ANEGCOMPLETE 27 + 28 + #define NCN26000_IRQ_LINKST_BIT BIT(0) 29 + #define NCN26000_IRQ_PLCAST_BIT BIT(1) 30 + #define NCN26000_IRQ_LJABBER_BIT BIT(2) 31 + #define NCN26000_IRQ_RJABBER_BIT BIT(3) 32 + #define NCN26000_IRQ_PLCAREC_BIT BIT(4) 33 + #define NCN26000_IRQ_PHYSCOL_BIT BIT(5) 34 + #define NCN26000_IRQ_RESET_BIT BIT(15) 35 + 36 + #define TO_TMR_DEFAULT 32 37 + 38 + static int ncn26000_config_init(struct phy_device *phydev) 39 + { 40 + /* HW bug workaround: the default value of the PLCA TO_TIMER should be 41 + * 32, where the current version of NCN26000 reports 24. This will be 42 + * fixed in future PHY versions. For the time being, we force the 43 + * correct default here. 44 + */ 45 + return phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR, 46 + TO_TMR_DEFAULT); 47 + } 48 + 49 + static int ncn26000_config_aneg(struct phy_device *phydev) 50 + { 51 + /* Note: the NCN26000 supports only P2MP link mode. Therefore, AN is not 52 + * supported. However, this function is invoked by phylib to enable the 53 + * PHY, regardless of the AN support. 54 + */ 55 + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 56 + phydev->mdix = ETH_TP_MDI; 57 + 58 + // bring up the link 59 + return phy_write(phydev, MII_BMCR, NCN26000_BCMR_LINK_CTRL_BIT); 60 + } 61 + 62 + static int ncn26000_read_status(struct phy_device *phydev) 63 + { 64 + /* The NCN26000 reports NCN26000_LINK_STATUS_BIT if the link status of 65 + * the PHY is up. It further reports the logical AND of the link status 66 + * and the PLCA status in the BMSR_LSTATUS bit. 67 + */ 68 + int ret; 69 + 70 + /* The link state is latched low so that momentary link 71 + * drops can be detected. Do not double-read the status 72 + * in polling mode to detect such short link drops except 73 + * the link was already down. 74 + */ 75 + if (!phy_polling_mode(phydev) || !phydev->link) { 76 + ret = phy_read(phydev, MII_BMSR); 77 + if (ret < 0) 78 + return ret; 79 + else if (ret & NCN26000_BMSR_LINK_STATUS_BIT) 80 + goto upd_link; 81 + } 82 + 83 + ret = phy_read(phydev, MII_BMSR); 84 + if (ret < 0) 85 + return ret; 86 + 87 + upd_link: 88 + // update link status 89 + if (ret & NCN26000_BMSR_LINK_STATUS_BIT) { 90 + phydev->link = 1; 91 + phydev->pause = 0; 92 + phydev->duplex = DUPLEX_HALF; 93 + phydev->speed = SPEED_10; 94 + } else { 95 + phydev->link = 0; 96 + phydev->duplex = DUPLEX_UNKNOWN; 97 + phydev->speed = SPEED_UNKNOWN; 98 + } 99 + 100 + return 0; 101 + } 102 + 103 + static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev) 104 + { 105 + int ret; 106 + 107 + // read and aknowledge the IRQ status register 108 + ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS); 109 + 110 + // check only link status changes 111 + if (ret < 0 || (ret & NCN26000_REG_IRQ_STATUS) == 0) 112 + return IRQ_NONE; 113 + 114 + phy_trigger_machine(phydev); 115 + return IRQ_HANDLED; 116 + } 117 + 118 + static int ncn26000_config_intr(struct phy_device *phydev) 119 + { 120 + int ret; 121 + u16 irqe; 122 + 123 + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 124 + // acknowledge IRQs 125 + ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS); 126 + if (ret < 0) 127 + return ret; 128 + 129 + // get link status notifications 130 + irqe = NCN26000_IRQ_LINKST_BIT; 131 + } else { 132 + // disable all IRQs 133 + irqe = 0; 134 + } 135 + 136 + ret = phy_write(phydev, NCN26000_REG_IRQ_CTL, irqe); 137 + if (ret != 0) 138 + return ret; 139 + 140 + return 0; 141 + } 142 + 143 + static struct phy_driver ncn26000_driver[] = { 144 + { 145 + PHY_ID_MATCH_MODEL(PHY_ID_NCN26000), 146 + .name = "NCN26000", 147 + .features = PHY_BASIC_T1S_P2MP_FEATURES, 148 + .config_init = ncn26000_config_init, 149 + .config_intr = ncn26000_config_intr, 150 + .config_aneg = ncn26000_config_aneg, 151 + .read_status = ncn26000_read_status, 152 + .handle_interrupt = ncn26000_handle_interrupt, 153 + .get_plca_cfg = genphy_c45_plca_get_cfg, 154 + .set_plca_cfg = genphy_c45_plca_set_cfg, 155 + .get_plca_status = genphy_c45_plca_get_status, 156 + .soft_reset = genphy_soft_reset, 157 + }, 158 + }; 159 + 160 + module_phy_driver(ncn26000_driver); 161 + 162 + static struct mdio_device_id __maybe_unused ncn26000_tbl[] = { 163 + { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) }, 164 + { } 165 + }; 166 + 167 + MODULE_DEVICE_TABLE(mdio, ncn26000_tbl); 168 + 169 + MODULE_AUTHOR("Piergiorgio Beruto"); 170 + MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver"); 171 + MODULE_LICENSE("Dual BSD/GPL");
+193
drivers/net/phy/phy-c45.c
··· 8 8 #include <linux/mii.h> 9 9 #include <linux/phy.h> 10 10 11 + #include "mdio-open-alliance.h" 12 + 11 13 /** 12 14 * genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities 13 15 * @phydev: target phy_device struct ··· 932 930 MDIO_PMA_10GBR_FSRT_ENABLE); 933 931 } 934 932 EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain); 933 + 934 + /** 935 + * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers 936 + * @phydev: target phy_device struct 937 + * @plca_cfg: output structure to store the PLCA configuration 938 + * 939 + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA 940 + * Management Registers specifications, this function can be used to retrieve 941 + * the current PLCA configuration from the standard registers in MMD 31. 942 + */ 943 + int genphy_c45_plca_get_cfg(struct phy_device *phydev, 944 + struct phy_plca_cfg *plca_cfg) 945 + { 946 + int ret; 947 + 948 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_IDVER); 949 + if (ret < 0) 950 + return ret; 951 + 952 + if ((ret & MDIO_OATC14_PLCA_IDM) != OATC14_IDM) 953 + return -ENODEV; 954 + 955 + plca_cfg->version = ret & ~MDIO_OATC14_PLCA_IDM; 956 + 957 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL0); 958 + if (ret < 0) 959 + return ret; 960 + 961 + plca_cfg->enabled = !!(ret & MDIO_OATC14_PLCA_EN); 962 + 963 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL1); 964 + if (ret < 0) 965 + return ret; 966 + 967 + plca_cfg->node_cnt = (ret & MDIO_OATC14_PLCA_NCNT) >> 8; 968 + plca_cfg->node_id = (ret & MDIO_OATC14_PLCA_ID); 969 + 970 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR); 971 + if (ret < 0) 972 + return ret; 973 + 974 + plca_cfg->to_tmr = ret & MDIO_OATC14_PLCA_TOT; 975 + 976 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_BURST); 977 + if (ret < 0) 978 + return ret; 979 + 980 + plca_cfg->burst_cnt = (ret & MDIO_OATC14_PLCA_MAXBC) >> 8; 981 + plca_cfg->burst_tmr = (ret & MDIO_OATC14_PLCA_BTMR); 982 + 983 + return 0; 984 + } 985 + EXPORT_SYMBOL_GPL(genphy_c45_plca_get_cfg); 986 + 987 + /** 988 + * genphy_c45_plca_set_cfg - set PLCA configuration using standard registers 989 + * @phydev: target phy_device struct 990 + * @plca_cfg: structure containing the PLCA configuration. Fields set to -1 are 991 + * not to be changed. 992 + * 993 + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA 994 + * Management Registers specifications, this function can be used to modify 995 + * the PLCA configuration using the standard registers in MMD 31. 996 + */ 997 + int genphy_c45_plca_set_cfg(struct phy_device *phydev, 998 + const struct phy_plca_cfg *plca_cfg) 999 + { 1000 + int ret; 1001 + u16 val; 1002 + 1003 + // PLCA IDVER is read-only 1004 + if (plca_cfg->version >= 0) 1005 + return -EINVAL; 1006 + 1007 + // first of all, disable PLCA if required 1008 + if (plca_cfg->enabled == 0) { 1009 + ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 1010 + MDIO_OATC14_PLCA_CTRL0, 1011 + MDIO_OATC14_PLCA_EN); 1012 + 1013 + if (ret < 0) 1014 + return ret; 1015 + } 1016 + 1017 + // check if we need to set the PLCA node count, node ID, or both 1018 + if (plca_cfg->node_cnt >= 0 || plca_cfg->node_id >= 0) { 1019 + /* if one between node count and node ID is -not- to be 1020 + * changed, read the register to later perform merge/purge of 1021 + * the configuration as appropriate 1022 + */ 1023 + if (plca_cfg->node_cnt < 0 || plca_cfg->node_id < 0) { 1024 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, 1025 + MDIO_OATC14_PLCA_CTRL1); 1026 + 1027 + if (ret < 0) 1028 + return ret; 1029 + 1030 + val = ret; 1031 + } 1032 + 1033 + if (plca_cfg->node_cnt >= 0) 1034 + val = (val & ~MDIO_OATC14_PLCA_NCNT) | 1035 + (plca_cfg->node_cnt << 8); 1036 + 1037 + if (plca_cfg->node_id >= 0) 1038 + val = (val & ~MDIO_OATC14_PLCA_ID) | 1039 + (plca_cfg->node_id); 1040 + 1041 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 1042 + MDIO_OATC14_PLCA_CTRL1, val); 1043 + 1044 + if (ret < 0) 1045 + return ret; 1046 + } 1047 + 1048 + if (plca_cfg->to_tmr >= 0) { 1049 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 1050 + MDIO_OATC14_PLCA_TOTMR, 1051 + plca_cfg->to_tmr); 1052 + 1053 + if (ret < 0) 1054 + return ret; 1055 + } 1056 + 1057 + // check if we need to set the PLCA burst count, burst timer, or both 1058 + if (plca_cfg->burst_cnt >= 0 || plca_cfg->burst_tmr >= 0) { 1059 + /* if one between burst count and burst timer is -not- to be 1060 + * changed, read the register to later perform merge/purge of 1061 + * the configuration as appropriate 1062 + */ 1063 + if (plca_cfg->burst_cnt < 0 || plca_cfg->burst_tmr < 0) { 1064 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, 1065 + MDIO_OATC14_PLCA_BURST); 1066 + 1067 + if (ret < 0) 1068 + return ret; 1069 + 1070 + val = ret; 1071 + } 1072 + 1073 + if (plca_cfg->burst_cnt >= 0) 1074 + val = (val & ~MDIO_OATC14_PLCA_MAXBC) | 1075 + (plca_cfg->burst_cnt << 8); 1076 + 1077 + if (plca_cfg->burst_tmr >= 0) 1078 + val = (val & ~MDIO_OATC14_PLCA_BTMR) | 1079 + (plca_cfg->burst_tmr); 1080 + 1081 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 1082 + MDIO_OATC14_PLCA_BURST, val); 1083 + 1084 + if (ret < 0) 1085 + return ret; 1086 + } 1087 + 1088 + // if we need to enable PLCA, do it at the end 1089 + if (plca_cfg->enabled > 0) { 1090 + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, 1091 + MDIO_OATC14_PLCA_CTRL0, 1092 + MDIO_OATC14_PLCA_EN); 1093 + 1094 + if (ret < 0) 1095 + return ret; 1096 + } 1097 + 1098 + return 0; 1099 + } 1100 + EXPORT_SYMBOL_GPL(genphy_c45_plca_set_cfg); 1101 + 1102 + /** 1103 + * genphy_c45_plca_get_status - get PLCA status from standard registers 1104 + * @phydev: target phy_device struct 1105 + * @plca_st: output structure to store the PLCA status 1106 + * 1107 + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA 1108 + * Management Registers specifications, this function can be used to retrieve 1109 + * the current PLCA status information from the standard registers in MMD 31. 1110 + */ 1111 + int genphy_c45_plca_get_status(struct phy_device *phydev, 1112 + struct phy_plca_status *plca_st) 1113 + { 1114 + int ret; 1115 + 1116 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_STATUS); 1117 + if (ret < 0) 1118 + return ret; 1119 + 1120 + plca_st->pst = !!(ret & MDIO_OATC14_PLCA_PST); 1121 + return 0; 1122 + } 1123 + EXPORT_SYMBOL_GPL(genphy_c45_plca_get_status); 935 1124 936 1125 struct phy_driver genphy_c45_driver = { 937 1126 .phy_id = 0xffffffff,
+4 -1
drivers/net/phy/phy-core.c
··· 13 13 */ 14 14 const char *phy_speed_to_str(int speed) 15 15 { 16 - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 99, 16 + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102, 17 17 "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " 18 18 "If a speed or mode has been added please update phy_speed_to_str " 19 19 "and the PHY settings array.\n"); ··· 260 260 PHY_SETTING( 10, FULL, 10baseT_Full ), 261 261 PHY_SETTING( 10, HALF, 10baseT_Half ), 262 262 PHY_SETTING( 10, FULL, 10baseT1L_Full ), 263 + PHY_SETTING( 10, FULL, 10baseT1S_Full ), 264 + PHY_SETTING( 10, HALF, 10baseT1S_Half ), 265 + PHY_SETTING( 10, HALF, 10baseT1S_P2MP_Half ), 263 266 }; 264 267 #undef PHY_SETTING 265 268
+192
drivers/net/phy/phy.c
··· 544 544 EXPORT_SYMBOL(phy_ethtool_get_stats); 545 545 546 546 /** 547 + * phy_ethtool_get_plca_cfg - Get PLCA RS configuration 548 + * @phydev: the phy_device struct 549 + * @plca_cfg: where to store the retrieved configuration 550 + * 551 + * Retrieve the PLCA configuration from the PHY. Return 0 on success or a 552 + * negative value if an error occurred. 553 + */ 554 + int phy_ethtool_get_plca_cfg(struct phy_device *phydev, 555 + struct phy_plca_cfg *plca_cfg) 556 + { 557 + int ret; 558 + 559 + if (!phydev->drv) { 560 + ret = -EIO; 561 + goto out; 562 + } 563 + 564 + if (!phydev->drv->get_plca_cfg) { 565 + ret = -EOPNOTSUPP; 566 + goto out; 567 + } 568 + 569 + mutex_lock(&phydev->lock); 570 + ret = phydev->drv->get_plca_cfg(phydev, plca_cfg); 571 + 572 + mutex_unlock(&phydev->lock); 573 + out: 574 + return ret; 575 + } 576 + 577 + /** 578 + * plca_check_valid - Check PLCA configuration before enabling 579 + * @phydev: the phy_device struct 580 + * @plca_cfg: current PLCA configuration 581 + * @extack: extack for reporting useful error messages 582 + * 583 + * Checks whether the PLCA and PHY configuration are consistent and it is safe 584 + * to enable PLCA. Returns 0 on success or a negative value if the PLCA or PHY 585 + * configuration is not consistent. 586 + */ 587 + static int plca_check_valid(struct phy_device *phydev, 588 + const struct phy_plca_cfg *plca_cfg, 589 + struct netlink_ext_ack *extack) 590 + { 591 + int ret = 0; 592 + 593 + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, 594 + phydev->advertising)) { 595 + ret = -EOPNOTSUPP; 596 + NL_SET_ERR_MSG(extack, 597 + "Point to Multi-Point mode is not enabled"); 598 + } else if (plca_cfg->node_id >= 255) { 599 + NL_SET_ERR_MSG(extack, "PLCA node ID is not set"); 600 + ret = -EINVAL; 601 + } 602 + 603 + return ret; 604 + } 605 + 606 + /** 607 + * phy_ethtool_set_plca_cfg - Set PLCA RS configuration 608 + * @phydev: the phy_device struct 609 + * @plca_cfg: new PLCA configuration to apply 610 + * @extack: extack for reporting useful error messages 611 + * 612 + * Sets the PLCA configuration in the PHY. Return 0 on success or a 613 + * negative value if an error occurred. 614 + */ 615 + int phy_ethtool_set_plca_cfg(struct phy_device *phydev, 616 + const struct phy_plca_cfg *plca_cfg, 617 + struct netlink_ext_ack *extack) 618 + { 619 + struct phy_plca_cfg *curr_plca_cfg; 620 + int ret; 621 + 622 + if (!phydev->drv) { 623 + ret = -EIO; 624 + goto out; 625 + } 626 + 627 + if (!phydev->drv->set_plca_cfg || 628 + !phydev->drv->get_plca_cfg) { 629 + ret = -EOPNOTSUPP; 630 + goto out; 631 + } 632 + 633 + curr_plca_cfg = kmalloc(sizeof(*curr_plca_cfg), GFP_KERNEL); 634 + if (!curr_plca_cfg) { 635 + ret = -ENOMEM; 636 + goto out; 637 + } 638 + 639 + mutex_lock(&phydev->lock); 640 + 641 + ret = phydev->drv->get_plca_cfg(phydev, curr_plca_cfg); 642 + if (ret) 643 + goto out_drv; 644 + 645 + if (curr_plca_cfg->enabled < 0 && plca_cfg->enabled >= 0) { 646 + NL_SET_ERR_MSG(extack, 647 + "PHY does not support changing the PLCA 'enable' attribute"); 648 + ret = -EINVAL; 649 + goto out_drv; 650 + } 651 + 652 + if (curr_plca_cfg->node_id < 0 && plca_cfg->node_id >= 0) { 653 + NL_SET_ERR_MSG(extack, 654 + "PHY does not support changing the PLCA 'local node ID' attribute"); 655 + ret = -EINVAL; 656 + goto out_drv; 657 + } 658 + 659 + if (curr_plca_cfg->node_cnt < 0 && plca_cfg->node_cnt >= 0) { 660 + NL_SET_ERR_MSG(extack, 661 + "PHY does not support changing the PLCA 'node count' attribute"); 662 + ret = -EINVAL; 663 + goto out_drv; 664 + } 665 + 666 + if (curr_plca_cfg->to_tmr < 0 && plca_cfg->to_tmr >= 0) { 667 + NL_SET_ERR_MSG(extack, 668 + "PHY does not support changing the PLCA 'TO timer' attribute"); 669 + ret = -EINVAL; 670 + goto out_drv; 671 + } 672 + 673 + if (curr_plca_cfg->burst_cnt < 0 && plca_cfg->burst_cnt >= 0) { 674 + NL_SET_ERR_MSG(extack, 675 + "PHY does not support changing the PLCA 'burst count' attribute"); 676 + ret = -EINVAL; 677 + goto out_drv; 678 + } 679 + 680 + if (curr_plca_cfg->burst_tmr < 0 && plca_cfg->burst_tmr >= 0) { 681 + NL_SET_ERR_MSG(extack, 682 + "PHY does not support changing the PLCA 'burst timer' attribute"); 683 + ret = -EINVAL; 684 + goto out_drv; 685 + } 686 + 687 + // if enabling PLCA, perform a few sanity checks 688 + if (plca_cfg->enabled > 0) { 689 + // allow setting node_id concurrently with enabled 690 + if (plca_cfg->node_id >= 0) 691 + curr_plca_cfg->node_id = plca_cfg->node_id; 692 + 693 + ret = plca_check_valid(phydev, curr_plca_cfg, extack); 694 + if (ret) 695 + goto out_drv; 696 + } 697 + 698 + ret = phydev->drv->set_plca_cfg(phydev, plca_cfg); 699 + 700 + out_drv: 701 + kfree(curr_plca_cfg); 702 + mutex_unlock(&phydev->lock); 703 + out: 704 + return ret; 705 + } 706 + 707 + /** 708 + * phy_ethtool_get_plca_status - Get PLCA RS status information 709 + * @phydev: the phy_device struct 710 + * @plca_st: where to store the retrieved status information 711 + * 712 + * Retrieve the PLCA status information from the PHY. Return 0 on success or a 713 + * negative value if an error occurred. 714 + */ 715 + int phy_ethtool_get_plca_status(struct phy_device *phydev, 716 + struct phy_plca_status *plca_st) 717 + { 718 + int ret; 719 + 720 + if (!phydev->drv) { 721 + ret = -EIO; 722 + goto out; 723 + } 724 + 725 + if (!phydev->drv->get_plca_status) { 726 + ret = -EOPNOTSUPP; 727 + goto out; 728 + } 729 + 730 + mutex_lock(&phydev->lock); 731 + ret = phydev->drv->get_plca_status(phydev, plca_st); 732 + 733 + mutex_unlock(&phydev->lock); 734 + out: 735 + return ret; 736 + } 737 + 738 + /** 547 739 * phy_start_cable_test - Start a cable test 548 740 * 549 741 * @phydev: the phy_device struct
+17
drivers/net/phy/phy_device.c
··· 45 45 __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; 46 46 EXPORT_SYMBOL_GPL(phy_basic_t1_features); 47 47 48 + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1s_p2mp_features) __ro_after_init; 49 + EXPORT_SYMBOL_GPL(phy_basic_t1s_p2mp_features); 50 + 48 51 __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; 49 52 EXPORT_SYMBOL_GPL(phy_gbit_features); 50 53 ··· 101 98 }; 102 99 EXPORT_SYMBOL_GPL(phy_basic_t1_features_array); 103 100 101 + const int phy_basic_t1s_p2mp_features_array[2] = { 102 + ETHTOOL_LINK_MODE_TP_BIT, 103 + ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, 104 + }; 105 + EXPORT_SYMBOL_GPL(phy_basic_t1s_p2mp_features_array); 106 + 104 107 const int phy_gbit_features_array[2] = { 105 108 ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 106 109 ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ··· 146 137 linkmode_set_bit_array(phy_basic_t1_features_array, 147 138 ARRAY_SIZE(phy_basic_t1_features_array), 148 139 phy_basic_t1_features); 140 + 141 + /* 10 half, P2MP, TP */ 142 + linkmode_set_bit_array(phy_basic_t1s_p2mp_features_array, 143 + ARRAY_SIZE(phy_basic_t1s_p2mp_features_array), 144 + phy_basic_t1s_p2mp_features); 149 145 150 146 /* 10/100 half/full + 1000 half/full */ 151 147 linkmode_set_bit_array(phy_basic_ports_array, ··· 3283 3269 .get_sset_count = phy_ethtool_get_sset_count, 3284 3270 .get_strings = phy_ethtool_get_strings, 3285 3271 .get_stats = phy_ethtool_get_stats, 3272 + .get_plca_cfg = phy_ethtool_get_plca_cfg, 3273 + .set_plca_cfg = phy_ethtool_set_plca_cfg, 3274 + .get_plca_status = phy_ethtool_get_plca_status, 3286 3275 .start_cable_test = phy_start_cable_test, 3287 3276 .start_cable_test_tdr = phy_start_cable_test_tdr, 3288 3277 };
+5 -1
drivers/net/phy/phylink.c
··· 241 241 if (caps & MAC_ASYM_PAUSE) 242 242 __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes); 243 243 244 - if (caps & MAC_10HD) 244 + if (caps & MAC_10HD) { 245 245 __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes); 246 + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Half_BIT, linkmodes); 247 + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, linkmodes); 248 + } 246 249 247 250 if (caps & MAC_10FD) { 248 251 __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes); 249 252 __set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, linkmodes); 253 + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Full_BIT, linkmodes); 250 254 } 251 255 252 256 if (caps & MAC_100HD) {
+12
include/linux/ethtool.h
··· 802 802 803 803 struct phy_device; 804 804 struct phy_tdr_config; 805 + struct phy_plca_cfg; 806 + struct phy_plca_status; 805 807 806 808 /** 807 809 * struct ethtool_phy_ops - Optional PHY device options 808 810 * @get_sset_count: Get number of strings that @get_strings will write. 809 811 * @get_strings: Return a set of strings that describe the requested objects 810 812 * @get_stats: Return extended statistics about the PHY device. 813 + * @get_plca_cfg: Return PLCA configuration. 814 + * @set_plca_cfg: Set PLCA configuration. 815 + * @get_plca_status: Get PLCA configuration. 811 816 * @start_cable_test: Start a cable test 812 817 * @start_cable_test_tdr: Start a Time Domain Reflectometry cable test 813 818 * ··· 824 819 int (*get_strings)(struct phy_device *dev, u8 *data); 825 820 int (*get_stats)(struct phy_device *dev, 826 821 struct ethtool_stats *stats, u64 *data); 822 + int (*get_plca_cfg)(struct phy_device *dev, 823 + struct phy_plca_cfg *plca_cfg); 824 + int (*set_plca_cfg)(struct phy_device *dev, 825 + const struct phy_plca_cfg *plca_cfg, 826 + struct netlink_ext_ack *extack); 827 + int (*get_plca_status)(struct phy_device *dev, 828 + struct phy_plca_status *plca_st); 827 829 int (*start_cable_test)(struct phy_device *phydev, 828 830 struct netlink_ext_ack *extack); 829 831 int (*start_cable_test_tdr)(struct phy_device *phydev,
+84
include/linux/phy.h
··· 45 45 46 46 extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init; 47 47 extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; 48 + extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1s_p2mp_features) __ro_after_init; 48 49 extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; 49 50 extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init; 50 51 extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init; ··· 55 54 56 55 #define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features) 57 56 #define PHY_BASIC_T1_FEATURES ((unsigned long *)&phy_basic_t1_features) 57 + #define PHY_BASIC_T1S_P2MP_FEATURES ((unsigned long *)&phy_basic_t1s_p2mp_features) 58 58 #define PHY_GBIT_FEATURES ((unsigned long *)&phy_gbit_features) 59 59 #define PHY_GBIT_FIBRE_FEATURES ((unsigned long *)&phy_gbit_fibre_features) 60 60 #define PHY_GBIT_ALL_PORTS_FEATURES ((unsigned long *)&phy_gbit_all_ports_features) ··· 68 66 extern const int phy_all_ports_features_array[7]; 69 67 extern const int phy_10_100_features_array[4]; 70 68 extern const int phy_basic_t1_features_array[3]; 69 + extern const int phy_basic_t1s_p2mp_features_array[2]; 71 70 extern const int phy_gbit_features_array[2]; 72 71 extern const int phy_10gbit_features_array[1]; 73 72 ··· 777 774 #define PHY_PAIR_ALL -1 778 775 779 776 /** 777 + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision 778 + * Avoidance) Reconciliation Sublayer. 779 + * 780 + * @version: read-only PLCA register map version. -1 = not available. Ignored 781 + * when setting the configuration. Format is the same as reported by the PLCA 782 + * IDVER register (31.CA00). -1 = not available. 783 + * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't 784 + * set. 0 = disabled, anything else = enabled. 785 + * @node_id: the PLCA local node identifier. -1 = not available / don't set. 786 + * Allowed values [0 .. 254]. 255 = node disabled. 787 + * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only 788 + * meaningful for the coordinator (node_id = 0). -1 = not available / don't 789 + * set. Allowed values [1 .. 255]. 790 + * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the 791 + * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for 792 + * more details. The to_timer shall be set equal over all nodes. 793 + * -1 = not available / don't set. Allowed values [0 .. 255]. 794 + * @burst_cnt: controls how many additional frames a node is allowed to send in 795 + * single transmit opportunity (TO). The default value of 0 means that the 796 + * node is allowed exactly one frame per TO. A value of 1 allows two frames 797 + * per TO, and so on. -1 = not available / don't set. 798 + * Allowed values [0 .. 255]. 799 + * @burst_tmr: controls how many bit times to wait for the MAC to send a new 800 + * frame before interrupting the burst. This value should be set to a value 801 + * greater than the MAC inter-packet gap (which is typically 96 bits). 802 + * -1 = not available / don't set. Allowed values [0 .. 255]. 803 + * 804 + * A structure containing configuration parameters for setting/getting the PLCA 805 + * RS configuration. The driver does not need to implement all the parameters, 806 + * but should report what is actually used. 807 + */ 808 + struct phy_plca_cfg { 809 + int version; 810 + int enabled; 811 + int node_id; 812 + int node_cnt; 813 + int to_tmr; 814 + int burst_cnt; 815 + int burst_tmr; 816 + }; 817 + 818 + /** 819 + * struct phy_plca_status - Status of the PLCA (Physical Layer Collision 820 + * Avoidance) Reconciliation Sublayer. 821 + * 822 + * @pst: The PLCA status as reported by the PST bit in the PLCA STATUS 823 + * register(31.CA03), indicating BEACON activity. 824 + * 825 + * A structure containing status information of the PLCA RS configuration. 826 + * The driver does not need to implement all the parameters, but should report 827 + * what is actually used. 828 + */ 829 + struct phy_plca_status { 830 + bool pst; 831 + }; 832 + 833 + /** 780 834 * struct phy_driver - Driver structure for a particular PHY type 781 835 * 782 836 * @mdiodrv: Data common to all MDIO devices ··· 1044 984 int (*get_sqi)(struct phy_device *dev); 1045 985 /** @get_sqi_max: Get the maximum signal quality indication */ 1046 986 int (*get_sqi_max)(struct phy_device *dev); 987 + 988 + /* PLCA RS interface */ 989 + /** @get_plca_cfg: Return the current PLCA configuration */ 990 + int (*get_plca_cfg)(struct phy_device *dev, 991 + struct phy_plca_cfg *plca_cfg); 992 + /** @set_plca_cfg: Set the PLCA configuration */ 993 + int (*set_plca_cfg)(struct phy_device *dev, 994 + const struct phy_plca_cfg *plca_cfg); 995 + /** @get_plca_status: Return the current PLCA status info */ 996 + int (*get_plca_status)(struct phy_device *dev, 997 + struct phy_plca_status *plca_st); 1047 998 }; 1048 999 #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ 1049 1000 struct phy_driver, mdiodrv) ··· 1753 1682 int genphy_c45_pma_resume(struct phy_device *phydev); 1754 1683 int genphy_c45_pma_suspend(struct phy_device *phydev); 1755 1684 int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable); 1685 + int genphy_c45_plca_get_cfg(struct phy_device *phydev, 1686 + struct phy_plca_cfg *plca_cfg); 1687 + int genphy_c45_plca_set_cfg(struct phy_device *phydev, 1688 + const struct phy_plca_cfg *plca_cfg); 1689 + int genphy_c45_plca_get_status(struct phy_device *phydev, 1690 + struct phy_plca_status *plca_st); 1756 1691 1757 1692 /* Generic C45 PHY driver */ 1758 1693 extern struct phy_driver genphy_c45_driver; ··· 1857 1780 int phy_ethtool_get_sset_count(struct phy_device *phydev); 1858 1781 int phy_ethtool_get_stats(struct phy_device *phydev, 1859 1782 struct ethtool_stats *stats, u64 *data); 1783 + int phy_ethtool_get_plca_cfg(struct phy_device *phydev, 1784 + struct phy_plca_cfg *plca_cfg); 1785 + int phy_ethtool_set_plca_cfg(struct phy_device *phydev, 1786 + const struct phy_plca_cfg *plca_cfg, 1787 + struct netlink_ext_ack *extack); 1788 + int phy_ethtool_get_plca_status(struct phy_device *phydev, 1789 + struct phy_plca_status *plca_st); 1860 1790 1861 1791 static inline int phy_package_read(struct phy_device *phydev, u32 regnum) 1862 1792 {
+3
include/uapi/linux/ethtool.h
··· 1741 1741 ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96, 1742 1742 ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97, 1743 1743 ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98, 1744 + ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99, 1745 + ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100, 1746 + ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101, 1744 1747 1745 1748 /* must be last entry */ 1746 1749 __ETHTOOL_LINK_MODE_MASK_NBITS
+25
include/uapi/linux/ethtool_netlink.h
··· 52 52 ETHTOOL_MSG_PSE_GET, 53 53 ETHTOOL_MSG_PSE_SET, 54 54 ETHTOOL_MSG_RSS_GET, 55 + ETHTOOL_MSG_PLCA_GET_CFG, 56 + ETHTOOL_MSG_PLCA_SET_CFG, 57 + ETHTOOL_MSG_PLCA_GET_STATUS, 55 58 56 59 /* add new constants above here */ 57 60 __ETHTOOL_MSG_USER_CNT, ··· 102 99 ETHTOOL_MSG_MODULE_NTF, 103 100 ETHTOOL_MSG_PSE_GET_REPLY, 104 101 ETHTOOL_MSG_RSS_GET_REPLY, 102 + ETHTOOL_MSG_PLCA_GET_CFG_REPLY, 103 + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY, 104 + ETHTOOL_MSG_PLCA_NTF, 105 105 106 106 /* add new constants above here */ 107 107 __ETHTOOL_MSG_KERNEL_CNT, ··· 898 892 899 893 __ETHTOOL_A_RSS_CNT, 900 894 ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1), 895 + }; 896 + 897 + /* PLCA */ 898 + 899 + enum { 900 + ETHTOOL_A_PLCA_UNSPEC, 901 + ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */ 902 + ETHTOOL_A_PLCA_VERSION, /* u16 */ 903 + ETHTOOL_A_PLCA_ENABLED, /* u8 */ 904 + ETHTOOL_A_PLCA_STATUS, /* u8 */ 905 + ETHTOOL_A_PLCA_NODE_CNT, /* u32 */ 906 + ETHTOOL_A_PLCA_NODE_ID, /* u32 */ 907 + ETHTOOL_A_PLCA_TO_TMR, /* u32 */ 908 + ETHTOOL_A_PLCA_BURST_CNT, /* u32 */ 909 + ETHTOOL_A_PLCA_BURST_TMR, /* u32 */ 910 + 911 + /* add new constants above here */ 912 + __ETHTOOL_A_PLCA_CNT, 913 + ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1) 901 914 }; 902 915 903 916 /* generic netlink info */
+1 -1
net/ethtool/Makefile
··· 8 8 linkstate.o debug.o wol.o features.o privflags.o rings.o \ 9 9 channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ 10 10 tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \ 11 - pse-pd.o 11 + pse-pd.o plca.o
+8
net/ethtool/common.c
··· 208 208 __DEFINE_LINK_MODE_NAME(800000, DR8_2, Full), 209 209 __DEFINE_LINK_MODE_NAME(800000, SR8, Full), 210 210 __DEFINE_LINK_MODE_NAME(800000, VR8, Full), 211 + __DEFINE_LINK_MODE_NAME(10, T1S, Full), 212 + __DEFINE_LINK_MODE_NAME(10, T1S, Half), 213 + __DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half), 211 214 }; 212 215 static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS); 213 216 ··· 247 244 #define __LINK_MODE_LANES_X 1 248 245 #define __LINK_MODE_LANES_FX 1 249 246 #define __LINK_MODE_LANES_T1L 1 247 + #define __LINK_MODE_LANES_T1S 1 248 + #define __LINK_MODE_LANES_T1S_P2MP 1 250 249 #define __LINK_MODE_LANES_VR8 8 251 250 #define __LINK_MODE_LANES_DR8_2 8 252 251 ··· 371 366 __DEFINE_LINK_MODE_PARAMS(800000, DR8_2, Full), 372 367 __DEFINE_LINK_MODE_PARAMS(800000, SR8, Full), 373 368 __DEFINE_LINK_MODE_PARAMS(800000, VR8, Full), 369 + __DEFINE_LINK_MODE_PARAMS(10, T1S, Full), 370 + __DEFINE_LINK_MODE_PARAMS(10, T1S, Half), 371 + __DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half), 374 372 }; 375 373 static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS); 376 374
+29
net/ethtool/netlink.c
··· 288 288 [ETHTOOL_MSG_MODULE_GET] = &ethnl_module_request_ops, 289 289 [ETHTOOL_MSG_PSE_GET] = &ethnl_pse_request_ops, 290 290 [ETHTOOL_MSG_RSS_GET] = &ethnl_rss_request_ops, 291 + [ETHTOOL_MSG_PLCA_GET_CFG] = &ethnl_plca_cfg_request_ops, 292 + [ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops, 291 293 }; 292 294 293 295 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 605 603 [ETHTOOL_MSG_EEE_NTF] = &ethnl_eee_request_ops, 606 604 [ETHTOOL_MSG_FEC_NTF] = &ethnl_fec_request_ops, 607 605 [ETHTOOL_MSG_MODULE_NTF] = &ethnl_module_request_ops, 606 + [ETHTOOL_MSG_PLCA_NTF] = &ethnl_plca_cfg_request_ops, 608 607 }; 609 608 610 609 /* default notification handler */ ··· 699 696 [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify, 700 697 [ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify, 701 698 [ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify, 699 + [ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify, 702 700 }; 703 701 704 702 void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data) ··· 1050 1046 .doit = ethnl_default_doit, 1051 1047 .policy = ethnl_rss_get_policy, 1052 1048 .maxattr = ARRAY_SIZE(ethnl_rss_get_policy) - 1, 1049 + }, 1050 + { 1051 + .cmd = ETHTOOL_MSG_PLCA_GET_CFG, 1052 + .doit = ethnl_default_doit, 1053 + .start = ethnl_default_start, 1054 + .dumpit = ethnl_default_dumpit, 1055 + .done = ethnl_default_done, 1056 + .policy = ethnl_plca_get_cfg_policy, 1057 + .maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1, 1058 + }, 1059 + { 1060 + .cmd = ETHTOOL_MSG_PLCA_SET_CFG, 1061 + .flags = GENL_UNS_ADMIN_PERM, 1062 + .doit = ethnl_set_plca_cfg, 1063 + .policy = ethnl_plca_set_cfg_policy, 1064 + .maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1, 1065 + }, 1066 + { 1067 + .cmd = ETHTOOL_MSG_PLCA_GET_STATUS, 1068 + .doit = ethnl_default_doit, 1069 + .start = ethnl_default_start, 1070 + .dumpit = ethnl_default_dumpit, 1071 + .done = ethnl_default_done, 1072 + .policy = ethnl_plca_get_status_policy, 1073 + .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1, 1053 1074 }, 1054 1075 }; 1055 1076
+6
net/ethtool/netlink.h
··· 347 347 extern const struct ethnl_request_ops ethnl_module_request_ops; 348 348 extern const struct ethnl_request_ops ethnl_pse_request_ops; 349 349 extern const struct ethnl_request_ops ethnl_rss_request_ops; 350 + extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; 351 + extern const struct ethnl_request_ops ethnl_plca_status_request_ops; 350 352 351 353 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; 352 354 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; ··· 390 388 extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1]; 391 389 extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1]; 392 390 extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_CONTEXT + 1]; 391 + extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1]; 392 + extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]; 393 + extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; 393 394 394 395 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); 395 396 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); ··· 413 408 int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info); 414 409 int ethnl_set_module(struct sk_buff *skb, struct genl_info *info); 415 410 int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info); 411 + int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info); 416 412 417 413 extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; 418 414 extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
+277
net/ethtool/plca.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/phy.h> 4 + #include <linux/ethtool_netlink.h> 5 + 6 + #include "netlink.h" 7 + #include "common.h" 8 + 9 + struct plca_req_info { 10 + struct ethnl_req_info base; 11 + }; 12 + 13 + struct plca_reply_data { 14 + struct ethnl_reply_data base; 15 + struct phy_plca_cfg plca_cfg; 16 + struct phy_plca_status plca_st; 17 + }; 18 + 19 + // Helpers ------------------------------------------------------------------ // 20 + 21 + #define PLCA_REPDATA(__reply_base) \ 22 + container_of(__reply_base, struct plca_reply_data, base) 23 + 24 + static void plca_update_sint(int *dst, const struct nlattr *attr, 25 + bool *mod) 26 + { 27 + if (!attr) 28 + return; 29 + 30 + *dst = nla_get_u32(attr); 31 + *mod = true; 32 + } 33 + 34 + // PLCA get configuration message ------------------------------------------- // 35 + 36 + const struct nla_policy ethnl_plca_get_cfg_policy[] = { 37 + [ETHTOOL_A_PLCA_HEADER] = 38 + NLA_POLICY_NESTED(ethnl_header_policy), 39 + }; 40 + 41 + static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base, 42 + struct ethnl_reply_data *reply_base, 43 + struct genl_info *info) 44 + { 45 + struct plca_reply_data *data = PLCA_REPDATA(reply_base); 46 + struct net_device *dev = reply_base->dev; 47 + const struct ethtool_phy_ops *ops; 48 + int ret; 49 + 50 + // check that the PHY device is available and connected 51 + if (!dev->phydev) { 52 + ret = -EOPNOTSUPP; 53 + goto out; 54 + } 55 + 56 + // note: rtnl_lock is held already by ethnl_default_doit 57 + ops = ethtool_phy_ops; 58 + if (!ops || !ops->get_plca_cfg) { 59 + ret = -EOPNOTSUPP; 60 + goto out; 61 + } 62 + 63 + ret = ethnl_ops_begin(dev); 64 + if (!ret) 65 + goto out; 66 + 67 + memset(&data->plca_cfg, 0xff, 68 + sizeof_field(struct plca_reply_data, plca_cfg)); 69 + 70 + ret = ops->get_plca_cfg(dev->phydev, &data->plca_cfg); 71 + ethnl_ops_complete(dev); 72 + 73 + out: 74 + return ret; 75 + } 76 + 77 + static int plca_get_cfg_reply_size(const struct ethnl_req_info *req_base, 78 + const struct ethnl_reply_data *reply_base) 79 + { 80 + return nla_total_size(sizeof(u16)) + /* _VERSION */ 81 + nla_total_size(sizeof(u8)) + /* _ENABLED */ 82 + nla_total_size(sizeof(u32)) + /* _NODE_CNT */ 83 + nla_total_size(sizeof(u32)) + /* _NODE_ID */ 84 + nla_total_size(sizeof(u32)) + /* _TO_TIMER */ 85 + nla_total_size(sizeof(u32)) + /* _BURST_COUNT */ 86 + nla_total_size(sizeof(u32)); /* _BURST_TIMER */ 87 + } 88 + 89 + static int plca_get_cfg_fill_reply(struct sk_buff *skb, 90 + const struct ethnl_req_info *req_base, 91 + const struct ethnl_reply_data *reply_base) 92 + { 93 + const struct plca_reply_data *data = PLCA_REPDATA(reply_base); 94 + const struct phy_plca_cfg *plca = &data->plca_cfg; 95 + 96 + if ((plca->version >= 0 && 97 + nla_put_u16(skb, ETHTOOL_A_PLCA_VERSION, plca->version)) || 98 + (plca->enabled >= 0 && 99 + nla_put_u8(skb, ETHTOOL_A_PLCA_ENABLED, !!plca->enabled)) || 100 + (plca->node_id >= 0 && 101 + nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_ID, plca->node_id)) || 102 + (plca->node_cnt >= 0 && 103 + nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_CNT, plca->node_cnt)) || 104 + (plca->to_tmr >= 0 && 105 + nla_put_u32(skb, ETHTOOL_A_PLCA_TO_TMR, plca->to_tmr)) || 106 + (plca->burst_cnt >= 0 && 107 + nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_CNT, plca->burst_cnt)) || 108 + (plca->burst_tmr >= 0 && 109 + nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_TMR, plca->burst_tmr))) 110 + return -EMSGSIZE; 111 + 112 + return 0; 113 + }; 114 + 115 + const struct ethnl_request_ops ethnl_plca_cfg_request_ops = { 116 + .request_cmd = ETHTOOL_MSG_PLCA_GET_CFG, 117 + .reply_cmd = ETHTOOL_MSG_PLCA_GET_CFG_REPLY, 118 + .hdr_attr = ETHTOOL_A_PLCA_HEADER, 119 + .req_info_size = sizeof(struct plca_req_info), 120 + .reply_data_size = sizeof(struct plca_reply_data), 121 + 122 + .prepare_data = plca_get_cfg_prepare_data, 123 + .reply_size = plca_get_cfg_reply_size, 124 + .fill_reply = plca_get_cfg_fill_reply, 125 + }; 126 + 127 + // PLCA set configuration message ------------------------------------------- // 128 + 129 + const struct nla_policy ethnl_plca_set_cfg_policy[] = { 130 + [ETHTOOL_A_PLCA_HEADER] = 131 + NLA_POLICY_NESTED(ethnl_header_policy), 132 + [ETHTOOL_A_PLCA_ENABLED] = NLA_POLICY_MAX(NLA_U8, 1), 133 + [ETHTOOL_A_PLCA_NODE_ID] = NLA_POLICY_MAX(NLA_U32, 255), 134 + [ETHTOOL_A_PLCA_NODE_CNT] = NLA_POLICY_RANGE(NLA_U32, 1, 255), 135 + [ETHTOOL_A_PLCA_TO_TMR] = NLA_POLICY_MAX(NLA_U32, 255), 136 + [ETHTOOL_A_PLCA_BURST_CNT] = NLA_POLICY_MAX(NLA_U32, 255), 137 + [ETHTOOL_A_PLCA_BURST_TMR] = NLA_POLICY_MAX(NLA_U32, 255), 138 + }; 139 + 140 + int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info) 141 + { 142 + struct ethnl_req_info req_info = {}; 143 + struct nlattr **tb = info->attrs; 144 + const struct ethtool_phy_ops *ops; 145 + struct phy_plca_cfg plca_cfg; 146 + struct net_device *dev; 147 + bool mod = false; 148 + int ret; 149 + 150 + ret = ethnl_parse_header_dev_get(&req_info, 151 + tb[ETHTOOL_A_PLCA_HEADER], 152 + genl_info_net(info), info->extack, 153 + true); 154 + if (!ret) 155 + return ret; 156 + 157 + dev = req_info.dev; 158 + 159 + rtnl_lock(); 160 + 161 + // check that the PHY device is available and connected 162 + if (!dev->phydev) { 163 + ret = -EOPNOTSUPP; 164 + goto out_rtnl; 165 + } 166 + 167 + ops = ethtool_phy_ops; 168 + if (!ops || !ops->set_plca_cfg) { 169 + ret = -EOPNOTSUPP; 170 + goto out_rtnl; 171 + } 172 + 173 + ret = ethnl_ops_begin(dev); 174 + if (!ret) 175 + goto out_rtnl; 176 + 177 + memset(&plca_cfg, 0xff, sizeof(plca_cfg)); 178 + plca_update_sint(&plca_cfg.enabled, tb[ETHTOOL_A_PLCA_ENABLED], &mod); 179 + plca_update_sint(&plca_cfg.node_id, tb[ETHTOOL_A_PLCA_NODE_ID], &mod); 180 + plca_update_sint(&plca_cfg.node_cnt, tb[ETHTOOL_A_PLCA_NODE_CNT], &mod); 181 + plca_update_sint(&plca_cfg.to_tmr, tb[ETHTOOL_A_PLCA_TO_TMR], &mod); 182 + plca_update_sint(&plca_cfg.burst_cnt, tb[ETHTOOL_A_PLCA_BURST_CNT], 183 + &mod); 184 + plca_update_sint(&plca_cfg.burst_tmr, tb[ETHTOOL_A_PLCA_BURST_TMR], 185 + &mod); 186 + 187 + ret = 0; 188 + if (!mod) 189 + goto out_ops; 190 + 191 + ret = ops->set_plca_cfg(dev->phydev, &plca_cfg, info->extack); 192 + if (!ret) 193 + goto out_ops; 194 + 195 + ethtool_notify(dev, ETHTOOL_MSG_PLCA_NTF, NULL); 196 + 197 + out_ops: 198 + ethnl_ops_complete(dev); 199 + out_rtnl: 200 + rtnl_unlock(); 201 + ethnl_parse_header_dev_put(&req_info); 202 + 203 + return ret; 204 + } 205 + 206 + // PLCA get status message -------------------------------------------------- // 207 + 208 + const struct nla_policy ethnl_plca_get_status_policy[] = { 209 + [ETHTOOL_A_PLCA_HEADER] = 210 + NLA_POLICY_NESTED(ethnl_header_policy), 211 + }; 212 + 213 + static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base, 214 + struct ethnl_reply_data *reply_base, 215 + struct genl_info *info) 216 + { 217 + struct plca_reply_data *data = PLCA_REPDATA(reply_base); 218 + struct net_device *dev = reply_base->dev; 219 + const struct ethtool_phy_ops *ops; 220 + int ret; 221 + 222 + // check that the PHY device is available and connected 223 + if (!dev->phydev) { 224 + ret = -EOPNOTSUPP; 225 + goto out; 226 + } 227 + 228 + // note: rtnl_lock is held already by ethnl_default_doit 229 + ops = ethtool_phy_ops; 230 + if (!ops || !ops->get_plca_status) { 231 + ret = -EOPNOTSUPP; 232 + goto out; 233 + } 234 + 235 + ret = ethnl_ops_begin(dev); 236 + if (!ret) 237 + goto out; 238 + 239 + memset(&data->plca_st, 0xff, 240 + sizeof_field(struct plca_reply_data, plca_st)); 241 + 242 + ret = ops->get_plca_status(dev->phydev, &data->plca_st); 243 + ethnl_ops_complete(dev); 244 + out: 245 + return ret; 246 + } 247 + 248 + static int plca_get_status_reply_size(const struct ethnl_req_info *req_base, 249 + const struct ethnl_reply_data *reply_base) 250 + { 251 + return nla_total_size(sizeof(u8)); /* _STATUS */ 252 + } 253 + 254 + static int plca_get_status_fill_reply(struct sk_buff *skb, 255 + const struct ethnl_req_info *req_base, 256 + const struct ethnl_reply_data *reply_base) 257 + { 258 + const struct plca_reply_data *data = PLCA_REPDATA(reply_base); 259 + const u8 status = data->plca_st.pst; 260 + 261 + if (nla_put_u8(skb, ETHTOOL_A_PLCA_STATUS, !!status)) 262 + return -EMSGSIZE; 263 + 264 + return 0; 265 + }; 266 + 267 + const struct ethnl_request_ops ethnl_plca_status_request_ops = { 268 + .request_cmd = ETHTOOL_MSG_PLCA_GET_STATUS, 269 + .reply_cmd = ETHTOOL_MSG_PLCA_GET_STATUS_REPLY, 270 + .hdr_attr = ETHTOOL_A_PLCA_HEADER, 271 + .req_info_size = sizeof(struct plca_req_info), 272 + .reply_data_size = sizeof(struct plca_reply_data), 273 + 274 + .prepare_data = plca_get_status_prepare_data, 275 + .reply_size = plca_get_status_reply_size, 276 + .fill_reply = plca_get_status_fill_reply, 277 + };