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

net: phy: at803x: add cable diagnostics support

The AR8031/AR8033 and the AR8035 support cable diagnostics. Adding
driver support is straightforward, so lets add it.

The PHY just do one pair at a time, so we have to start the test four
times. The cable_test_get_status() can block and therefore we can just
busy poll the test completion and continue with the next pair until we
are done.
The time delta counter seems to run at 125MHz which just gives us a
resolution of about 82.4cm per tick.

100m cable, A/B/C/D open:
Cable test started for device eth0.
Cable test completed for device eth0.
Pair: Pair A, result: Open Circuit
Pair: Pair A, fault length: 107.94m
Pair: Pair B, result: Open Circuit
Pair: Pair B, fault length: 104.64m
Pair: Pair C, result: Open Circuit
Pair: Pair C, fault length: 105.47m
Pair: Pair D, result: Open Circuit
Pair: Pair D, fault length: 107.94m

1m cable, A/B connected, C shorted, D open:
Cable test started for device eth0.
Cable test completed for device eth0.
Pair: Pair A, result: OK
Pair: Pair B, result: OK
Pair: Pair C, result: Short within Pair
Pair: Pair C, fault length: 0.82m
Pair: Pair D, result: Open Circuit
Pair: Pair D, fault length: 0.82m

Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michael Walle and committed by
David S. Miller
6cb75767 1b2f08df

+176
+176
drivers/net/phy/at803x.c
··· 12 12 #include <linux/string.h> 13 13 #include <linux/netdevice.h> 14 14 #include <linux/etherdevice.h> 15 + #include <linux/ethtool_netlink.h> 15 16 #include <linux/of_gpio.h> 16 17 #include <linux/bitfield.h> 17 18 #include <linux/gpio/consumer.h> ··· 47 46 #define AT803X_SMART_SPEED_ENABLE BIT(5) 48 47 #define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) 49 48 #define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) 49 + #define AT803X_CDT 0x16 50 + #define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) 51 + #define AT803X_CDT_ENABLE_TEST BIT(0) 52 + #define AT803X_CDT_STATUS 0x1c 53 + #define AT803X_CDT_STATUS_STAT_NORMAL 0 54 + #define AT803X_CDT_STATUS_STAT_SHORT 1 55 + #define AT803X_CDT_STATUS_STAT_OPEN 2 56 + #define AT803X_CDT_STATUS_STAT_FAIL 3 57 + #define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) 58 + #define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) 50 59 #define AT803X_LED_CONTROL 0x18 51 60 52 61 #define AT803X_DEVICE_ADDR 0x03 ··· 805 794 } 806 795 } 807 796 797 + static int at803x_cable_test_result_trans(u16 status) 798 + { 799 + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { 800 + case AT803X_CDT_STATUS_STAT_NORMAL: 801 + return ETHTOOL_A_CABLE_RESULT_CODE_OK; 802 + case AT803X_CDT_STATUS_STAT_SHORT: 803 + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 804 + case AT803X_CDT_STATUS_STAT_OPEN: 805 + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 806 + case AT803X_CDT_STATUS_STAT_FAIL: 807 + default: 808 + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 809 + } 810 + } 811 + 812 + static bool at803x_cdt_test_failed(u16 status) 813 + { 814 + return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == 815 + AT803X_CDT_STATUS_STAT_FAIL; 816 + } 817 + 818 + static bool at803x_cdt_fault_length_valid(u16 status) 819 + { 820 + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { 821 + case AT803X_CDT_STATUS_STAT_OPEN: 822 + case AT803X_CDT_STATUS_STAT_SHORT: 823 + return true; 824 + } 825 + return false; 826 + } 827 + 828 + static int at803x_cdt_fault_length(u16 status) 829 + { 830 + int dt; 831 + 832 + /* According to the datasheet the distance to the fault is 833 + * DELTA_TIME * 0.824 meters. 834 + * 835 + * The author suspect the correct formula is: 836 + * 837 + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 838 + * 839 + * where c is the speed of light, VF is the velocity factor of 840 + * the twisted pair cable, 125MHz the counter frequency and 841 + * we need to divide by 2 because the hardware will measure the 842 + * round trip time to the fault and back to the PHY. 843 + * 844 + * With a VF of 0.69 we get the factor 0.824 mentioned in the 845 + * datasheet. 846 + */ 847 + dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status); 848 + 849 + return (dt * 824) / 10; 850 + } 851 + 852 + static int at803x_cdt_start(struct phy_device *phydev, int pair) 853 + { 854 + u16 cdt; 855 + 856 + cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | 857 + AT803X_CDT_ENABLE_TEST; 858 + 859 + return phy_write(phydev, AT803X_CDT, cdt); 860 + } 861 + 862 + static int at803x_cdt_wait_for_completion(struct phy_device *phydev) 863 + { 864 + int val, ret; 865 + 866 + /* One test run takes about 25ms */ 867 + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, 868 + !(val & AT803X_CDT_ENABLE_TEST), 869 + 30000, 100000, true); 870 + 871 + return ret < 0 ? ret : 0; 872 + } 873 + 874 + static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) 875 + { 876 + static const int ethtool_pair[] = { 877 + ETHTOOL_A_CABLE_PAIR_A, 878 + ETHTOOL_A_CABLE_PAIR_B, 879 + ETHTOOL_A_CABLE_PAIR_C, 880 + ETHTOOL_A_CABLE_PAIR_D, 881 + }; 882 + int ret, val; 883 + 884 + ret = at803x_cdt_start(phydev, pair); 885 + if (ret) 886 + return ret; 887 + 888 + ret = at803x_cdt_wait_for_completion(phydev); 889 + if (ret) 890 + return ret; 891 + 892 + val = phy_read(phydev, AT803X_CDT_STATUS); 893 + if (val < 0) 894 + return val; 895 + 896 + if (at803x_cdt_test_failed(val)) 897 + return 0; 898 + 899 + ethnl_cable_test_result(phydev, ethtool_pair[pair], 900 + at803x_cable_test_result_trans(val)); 901 + 902 + if (at803x_cdt_fault_length_valid(val)) 903 + ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], 904 + at803x_cdt_fault_length(val)); 905 + 906 + return 1; 907 + } 908 + 909 + static int at803x_cable_test_get_status(struct phy_device *phydev, 910 + bool *finished) 911 + { 912 + unsigned long pair_mask = 0xf; 913 + int retries = 20; 914 + int pair, ret; 915 + 916 + *finished = false; 917 + 918 + /* According to the datasheet the CDT can be performed when 919 + * there is no link partner or when the link partner is 920 + * auto-negotiating. Starting the test will restart the AN 921 + * automatically. It seems that doing this repeatedly we will 922 + * get a slot where our link partner won't disturb our 923 + * measurement. 924 + */ 925 + while (pair_mask && retries--) { 926 + for_each_set_bit(pair, &pair_mask, 4) { 927 + ret = at803x_cable_test_one_pair(phydev, pair); 928 + if (ret < 0) 929 + return ret; 930 + if (ret) 931 + clear_bit(pair, &pair_mask); 932 + } 933 + if (pair_mask) 934 + msleep(250); 935 + } 936 + 937 + *finished = true; 938 + 939 + return 0; 940 + } 941 + 942 + static int at803x_cable_test_start(struct phy_device *phydev) 943 + { 944 + /* Enable auto-negotiation, but advertise no capabilities, no link 945 + * will be established. A restart of the auto-negotiation is not 946 + * required, because the cable test will automatically break the link. 947 + */ 948 + phy_write(phydev, MII_BMCR, BMCR_ANENABLE); 949 + phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); 950 + phy_write(phydev, MII_CTRL1000, 0); 951 + 952 + /* we do all the (time consuming) work later */ 953 + return 0; 954 + } 955 + 808 956 static struct phy_driver at803x_driver[] = { 809 957 { 810 958 /* Qualcomm Atheros AR8035 */ 811 959 .phy_id = ATH8035_PHY_ID, 812 960 .name = "Qualcomm Atheros AR8035", 813 961 .phy_id_mask = AT803X_PHY_ID_MASK, 962 + .flags = PHY_POLL_CABLE_TEST, 814 963 .probe = at803x_probe, 815 964 .remove = at803x_remove, 816 965 .config_init = at803x_config_init, ··· 985 814 .config_intr = at803x_config_intr, 986 815 .get_tunable = at803x_get_tunable, 987 816 .set_tunable = at803x_set_tunable, 817 + .cable_test_start = at803x_cable_test_start, 818 + .cable_test_get_status = at803x_cable_test_get_status, 988 819 }, { 989 820 /* Qualcomm Atheros AR8030 */ 990 821 .phy_id = ATH8030_PHY_ID, ··· 1008 835 .phy_id = ATH8031_PHY_ID, 1009 836 .name = "Qualcomm Atheros AR8031/AR8033", 1010 837 .phy_id_mask = AT803X_PHY_ID_MASK, 838 + .flags = PHY_POLL_CABLE_TEST, 1011 839 .probe = at803x_probe, 1012 840 .remove = at803x_remove, 1013 841 .config_init = at803x_config_init, ··· 1024 850 .config_intr = &at803x_config_intr, 1025 851 .get_tunable = at803x_get_tunable, 1026 852 .set_tunable = at803x_set_tunable, 853 + .cable_test_start = at803x_cable_test_start, 854 + .cable_test_get_status = at803x_cable_test_get_status, 1027 855 }, { 1028 856 /* Qualcomm Atheros AR8032 */ 1029 857 PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),