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.

net: phy: micrel: Cable Diag feature for lan8814 phy

Support for Cable Diagnostics in lan8814 phy

Signed-off-by: Divya Koppera <Divya.Koppera@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20220909083123.30134-1-Divya.Koppera@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Divya Koppera and committed by
Jakub Kicinski
21b688da 517ff3ce

+107 -18
+107 -18
drivers/net/phy/micrel.c
··· 92 92 #define KSZ9x31_LMD_VCT_DATA_HI_PULSE_MASK GENMASK(1, 0) 93 93 #define KSZ9x31_LMD_VCT_DATA_MASK GENMASK(7, 0) 94 94 95 + #define KSZPHY_WIRE_PAIR_MASK 0x3 96 + 97 + #define LAN8814_CABLE_DIAG 0x12 98 + #define LAN8814_CABLE_DIAG_STAT_MASK GENMASK(9, 8) 99 + #define LAN8814_CABLE_DIAG_VCT_DATA_MASK GENMASK(7, 0) 100 + #define LAN8814_PAIR_BIT_SHIFT 12 101 + 102 + #define LAN8814_WIRE_PAIR_MASK 0xF 103 + 95 104 /* Lan8814 general Interrupt control/status reg in GPHY specific block. */ 96 105 #define LAN8814_INTC 0x18 97 106 #define LAN8814_INTS 0x1B ··· 266 257 struct kszphy_type { 267 258 u32 led_mode_reg; 268 259 u16 interrupt_level_mask; 260 + u16 cable_diag_reg; 261 + unsigned long pair_mask; 269 262 bool has_broadcast_disable; 270 263 bool has_nand_tree_disable; 271 264 bool has_rmii_ref_clk_sel; ··· 324 313 325 314 static const struct kszphy_type lan8814_type = { 326 315 .led_mode_reg = ~LAN8814_LED_CTRL_1, 316 + .cable_diag_reg = LAN8814_CABLE_DIAG, 317 + .pair_mask = LAN8814_WIRE_PAIR_MASK, 318 + }; 319 + 320 + static const struct kszphy_type ksz886x_type = { 321 + .cable_diag_reg = KSZ8081_LMD, 322 + .pair_mask = KSZPHY_WIRE_PAIR_MASK, 327 323 }; 328 324 329 325 static const struct kszphy_type ksz8021_type = { ··· 1814 1796 return 0; 1815 1797 } 1816 1798 1799 + static int lan8814_cable_test_start(struct phy_device *phydev) 1800 + { 1801 + /* If autoneg is enabled, we won't be able to test cross pair 1802 + * short. In this case, the PHY will "detect" a link and 1803 + * confuse the internal state machine - disable auto neg here. 1804 + * Set the speed to 1000mbit and full duplex. 1805 + */ 1806 + return phy_modify(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100, 1807 + BMCR_SPEED1000 | BMCR_FULLDPLX); 1808 + } 1809 + 1817 1810 static int ksz886x_cable_test_start(struct phy_device *phydev) 1818 1811 { 1819 1812 if (phydev->dev_flags & MICREL_KSZ8_P1_ERRATA) ··· 1838 1809 return phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100); 1839 1810 } 1840 1811 1841 - static int ksz886x_cable_test_result_trans(u16 status) 1812 + static int ksz886x_cable_test_result_trans(u16 status, u16 mask) 1842 1813 { 1843 - switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) { 1814 + switch (FIELD_GET(mask, status)) { 1844 1815 case KSZ8081_LMD_STAT_NORMAL: 1845 1816 return ETHTOOL_A_CABLE_RESULT_CODE_OK; 1846 1817 case KSZ8081_LMD_STAT_SHORT: ··· 1854 1825 } 1855 1826 } 1856 1827 1857 - static bool ksz886x_cable_test_failed(u16 status) 1828 + static bool ksz886x_cable_test_failed(u16 status, u16 mask) 1858 1829 { 1859 - return FIELD_GET(KSZ8081_LMD_STAT_MASK, status) == 1830 + return FIELD_GET(mask, status) == 1860 1831 KSZ8081_LMD_STAT_FAIL; 1861 1832 } 1862 1833 1863 - static bool ksz886x_cable_test_fault_length_valid(u16 status) 1834 + static bool ksz886x_cable_test_fault_length_valid(u16 status, u16 mask) 1864 1835 { 1865 - switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) { 1836 + switch (FIELD_GET(mask, status)) { 1866 1837 case KSZ8081_LMD_STAT_OPEN: 1867 1838 fallthrough; 1868 1839 case KSZ8081_LMD_STAT_SHORT: ··· 1871 1842 return false; 1872 1843 } 1873 1844 1874 - static int ksz886x_cable_test_fault_length(u16 status) 1845 + static int ksz886x_cable_test_fault_length(struct phy_device *phydev, u16 status, u16 data_mask) 1875 1846 { 1876 1847 int dt; 1877 1848 1878 1849 /* According to the data sheet the distance to the fault is 1879 - * DELTA_TIME * 0.4 meters. 1850 + * DELTA_TIME * 0.4 meters for ksz phys. 1851 + * (DELTA_TIME - 22) * 0.8 for lan8814 phy. 1880 1852 */ 1881 - dt = FIELD_GET(KSZ8081_LMD_DELTA_TIME_MASK, status); 1853 + dt = FIELD_GET(data_mask, status); 1882 1854 1883 - return (dt * 400) / 10; 1855 + if ((phydev->phy_id & MICREL_PHY_ID_MASK) == PHY_ID_LAN8814) 1856 + return ((dt - 22) * 800) / 10; 1857 + else 1858 + return (dt * 400) / 10; 1884 1859 } 1885 1860 1886 1861 static int ksz886x_cable_test_wait_for_completion(struct phy_device *phydev) 1887 1862 { 1863 + const struct kszphy_type *type = phydev->drv->driver_data; 1888 1864 int val, ret; 1889 1865 1890 - ret = phy_read_poll_timeout(phydev, KSZ8081_LMD, val, 1866 + ret = phy_read_poll_timeout(phydev, type->cable_diag_reg, val, 1891 1867 !(val & KSZ8081_LMD_ENABLE_TEST), 1892 1868 30000, 100000, true); 1893 1869 1894 1870 return ret < 0 ? ret : 0; 1871 + } 1872 + 1873 + static int lan8814_cable_test_one_pair(struct phy_device *phydev, int pair) 1874 + { 1875 + static const int ethtool_pair[] = { ETHTOOL_A_CABLE_PAIR_A, 1876 + ETHTOOL_A_CABLE_PAIR_B, 1877 + ETHTOOL_A_CABLE_PAIR_C, 1878 + ETHTOOL_A_CABLE_PAIR_D, 1879 + }; 1880 + u32 fault_length; 1881 + int ret; 1882 + int val; 1883 + 1884 + val = KSZ8081_LMD_ENABLE_TEST; 1885 + val = val | (pair << LAN8814_PAIR_BIT_SHIFT); 1886 + 1887 + ret = phy_write(phydev, LAN8814_CABLE_DIAG, val); 1888 + if (ret < 0) 1889 + return ret; 1890 + 1891 + ret = ksz886x_cable_test_wait_for_completion(phydev); 1892 + if (ret) 1893 + return ret; 1894 + 1895 + val = phy_read(phydev, LAN8814_CABLE_DIAG); 1896 + if (val < 0) 1897 + return val; 1898 + 1899 + if (ksz886x_cable_test_failed(val, LAN8814_CABLE_DIAG_STAT_MASK)) 1900 + return -EAGAIN; 1901 + 1902 + ret = ethnl_cable_test_result(phydev, ethtool_pair[pair], 1903 + ksz886x_cable_test_result_trans(val, 1904 + LAN8814_CABLE_DIAG_STAT_MASK 1905 + )); 1906 + if (ret) 1907 + return ret; 1908 + 1909 + if (!ksz886x_cable_test_fault_length_valid(val, LAN8814_CABLE_DIAG_STAT_MASK)) 1910 + return 0; 1911 + 1912 + fault_length = ksz886x_cable_test_fault_length(phydev, val, 1913 + LAN8814_CABLE_DIAG_VCT_DATA_MASK); 1914 + 1915 + return ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], fault_length); 1895 1916 } 1896 1917 1897 1918 static int ksz886x_cable_test_one_pair(struct phy_device *phydev, int pair) ··· 1951 1872 ETHTOOL_A_CABLE_PAIR_B, 1952 1873 }; 1953 1874 int ret, val, mdix; 1875 + u32 fault_length; 1954 1876 1955 1877 /* There is no way to choice the pair, like we do one ksz9031. 1956 1878 * We can workaround this limitation by using the MDI-X functionality. ··· 1990 1910 if (val < 0) 1991 1911 return val; 1992 1912 1993 - if (ksz886x_cable_test_failed(val)) 1913 + if (ksz886x_cable_test_failed(val, KSZ8081_LMD_STAT_MASK)) 1994 1914 return -EAGAIN; 1995 1915 1996 1916 ret = ethnl_cable_test_result(phydev, ethtool_pair[pair], 1997 - ksz886x_cable_test_result_trans(val)); 1917 + ksz886x_cable_test_result_trans(val, KSZ8081_LMD_STAT_MASK)); 1998 1918 if (ret) 1999 1919 return ret; 2000 1920 2001 - if (!ksz886x_cable_test_fault_length_valid(val)) 1921 + if (!ksz886x_cable_test_fault_length_valid(val, KSZ8081_LMD_STAT_MASK)) 2002 1922 return 0; 2003 1923 2004 - return ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], 2005 - ksz886x_cable_test_fault_length(val)); 1924 + fault_length = ksz886x_cable_test_fault_length(phydev, val, KSZ8081_LMD_DELTA_TIME_MASK); 1925 + 1926 + return ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], fault_length); 2006 1927 } 2007 1928 2008 1929 static int ksz886x_cable_test_get_status(struct phy_device *phydev, 2009 1930 bool *finished) 2010 1931 { 2011 - unsigned long pair_mask = 0x3; 1932 + const struct kszphy_type *type = phydev->drv->driver_data; 1933 + unsigned long pair_mask = type->pair_mask; 2012 1934 int retries = 20; 2013 1935 int pair, ret; 2014 1936 ··· 2019 1937 /* Try harder if link partner is active */ 2020 1938 while (pair_mask && retries--) { 2021 1939 for_each_set_bit(pair, &pair_mask, 4) { 2022 - ret = ksz886x_cable_test_one_pair(phydev, pair); 1940 + if (type->cable_diag_reg == LAN8814_CABLE_DIAG) 1941 + ret = lan8814_cable_test_one_pair(phydev, pair); 1942 + else 1943 + ret = ksz886x_cable_test_one_pair(phydev, pair); 2023 1944 if (ret == -EAGAIN) 2024 1945 continue; 2025 1946 if (ret < 0) ··· 3196 3111 .phy_id = PHY_ID_LAN8814, 3197 3112 .phy_id_mask = MICREL_PHY_ID_MASK, 3198 3113 .name = "Microchip INDY Gigabit Quad PHY", 3114 + .flags = PHY_POLL_CABLE_TEST, 3199 3115 .config_init = lan8814_config_init, 3200 3116 .driver_data = &lan8814_type, 3201 3117 .probe = lan8814_probe, ··· 3209 3123 .resume = kszphy_resume, 3210 3124 .config_intr = lan8814_config_intr, 3211 3125 .handle_interrupt = lan8814_handle_interrupt, 3126 + .cable_test_start = lan8814_cable_test_start, 3127 + .cable_test_get_status = ksz886x_cable_test_get_status, 3212 3128 }, { 3213 3129 .phy_id = PHY_ID_LAN8804, 3214 3130 .phy_id_mask = MICREL_PHY_ID_MASK, ··· 3257 3169 .phy_id = PHY_ID_KSZ886X, 3258 3170 .phy_id_mask = MICREL_PHY_ID_MASK, 3259 3171 .name = "Micrel KSZ8851 Ethernet MAC or KSZ886X Switch", 3172 + .driver_data = &ksz886x_type, 3260 3173 /* PHY_BASIC_FEATURES */ 3261 3174 .flags = PHY_POLL_CABLE_TEST, 3262 3175 .config_init = kszphy_config_init,