diff options
-rw-r--r-- | drivers/net/phy/at803x.c | 186 |
1 files changed, 131 insertions, 55 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 19cfbf36fe80..a62442a55774 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -254,6 +254,7 @@ #define QCA808X_CDT_ENABLE_TEST BIT(15) #define QCA808X_CDT_INTER_CHECK_DIS BIT(13) +#define QCA808X_CDT_STATUS BIT(11) #define QCA808X_CDT_LENGTH_UNIT BIT(10) #define QCA808X_MMD3_CDT_STATUS 0x8064 @@ -261,16 +262,44 @@ #define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 #define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 #define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 -#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0) +#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) +#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) #define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) #define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) #define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) #define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) -#define QCA808X_CDT_STATUS_STAT_FAIL 0 -#define QCA808X_CDT_STATUS_STAT_NORMAL 1 -#define QCA808X_CDT_STATUS_STAT_OPEN 2 -#define QCA808X_CDT_STATUS_STAT_SHORT 3 + +#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) +#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) +#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) +#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) +#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) + +#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) +#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) +#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) +#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) + +/* NORMAL are MDI with type set to 0 */ +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI3) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI3) + +/* Added for reference of existence but should be handled by wait_for_completion already */ +#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) /* QCA808X 1G chip type */ #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d @@ -991,13 +1020,9 @@ static int at803x_read_specific_status(struct phy_device *phydev, static int at803x_read_status(struct phy_device *phydev) { - struct at803x_priv *priv = phydev->priv; struct at803x_ss_mask ss_mask = { 0 }; int err, old_link = phydev->link; - if (priv->is_1000basex) - return genphy_c37_read_status(phydev); - /* Update the link, but return if there was an error */ err = genphy_update_link(phydev); if (err) @@ -1192,10 +1217,8 @@ static bool at803x_cdt_fault_length_valid(u16 status) return false; } -static int at803x_cdt_fault_length(u16 status) +static int at803x_cdt_fault_length(int dt) { - int dt; - /* According to the datasheet the distance to the fault is * DELTA_TIME * 0.824 meters. * @@ -1211,8 +1234,6 @@ static int at803x_cdt_fault_length(u16 status) * With a VF of 0.69 we get the factor 0.824 mentioned in the * datasheet. */ - dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status); - return (dt * 824) / 10; } @@ -1265,9 +1286,11 @@ static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) ethnl_cable_test_result(phydev, ethtool_pair[pair], at803x_cable_test_result_trans(val)); - if (at803x_cdt_fault_length_valid(val)) + if (at803x_cdt_fault_length_valid(val)) { + val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val); ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], at803x_cdt_fault_length(val)); + } return 1; } @@ -1591,6 +1614,17 @@ static int at8031_config_intr(struct phy_device *phydev) return at803x_config_intr(phydev); } +/* AR8031 and AR8033 share the same read status logic */ +static int at8031_read_status(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + if (priv->is_1000basex) + return genphy_c37_read_status(phydev); + + return at803x_read_status(phydev); +} + /* AR8031 and AR8035 share the same cable test get status reg */ static int at8031_cable_test_get_status(struct phy_device *phydev, bool *finished) @@ -1943,8 +1977,17 @@ static int qca808x_soft_reset(struct phy_device *phydev) static bool qca808x_cdt_fault_length_valid(int cdt_code) { switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_SHORT: - case QCA808X_CDT_STATUS_STAT_OPEN: + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: return true; default: return false; @@ -1956,17 +1999,28 @@ static int qca808x_cable_test_result_trans(int cdt_code) switch (cdt_code) { case QCA808X_CDT_STATUS_STAT_NORMAL: return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case QCA808X_CDT_STATUS_STAT_SHORT: + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case QCA808X_CDT_STATUS_STAT_OPEN: + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; case QCA808X_CDT_STATUS_STAT_FAIL: default: return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; } } -static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair) +static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, + int result) { int val; u32 cdt_length_reg = 0; @@ -1992,7 +2046,12 @@ static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair) if (val < 0) return val; - return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10; + if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); + else + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); + + return at803x_cdt_fault_length(val); } static int qca808x_cable_test_start(struct phy_device *phydev) @@ -2036,16 +2095,48 @@ static int qca808x_cable_test_start(struct phy_device *phydev) return 0; } +static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, + u16 status) +{ + int length, result; + u16 pair_code; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); + break; + case ETHTOOL_A_CABLE_PAIR_B: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); + break; + case ETHTOOL_A_CABLE_PAIR_C: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); + break; + case ETHTOOL_A_CABLE_PAIR_D: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); + break; + default: + return -EINVAL; + } + + result = qca808x_cable_test_result_trans(pair_code); + ethnl_cable_test_result(phydev, pair, result); + + if (qca808x_cdt_fault_length_valid(pair_code)) { + length = qca808x_cdt_fault_length(phydev, pair, result); + ethnl_cable_test_fault_length(phydev, pair, length); + } + + return 0; +} + static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) { int ret, val; - int pair_a, pair_b, pair_c, pair_d; *finished = false; val = QCA808X_CDT_ENABLE_TEST | - QCA808X_CDT_LENGTH_UNIT | - QCA808X_CDT_INTER_CHECK_DIS; + QCA808X_CDT_LENGTH_UNIT; ret = at803x_cdt_start(phydev, val); if (ret) return ret; @@ -2058,36 +2149,21 @@ static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finish if (val < 0) return val; - pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val); - pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val); - pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val); - pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val); - - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, - qca808x_cable_test_result_trans(pair_a)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, - qca808x_cable_test_result_trans(pair_b)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, - qca808x_cable_test_result_trans(pair_c)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, - qca808x_cable_test_result_trans(pair_d)); - - if (qca808x_cdt_fault_length_valid(pair_a)) { - val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A); - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, val); - } - if (qca808x_cdt_fault_length_valid(pair_b)) { - val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B); - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B, val); - } - if (qca808x_cdt_fault_length_valid(pair_c)) { - val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C); - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C, val); - } - if (qca808x_cdt_fault_length_valid(pair_d)) { - val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D); - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D, val); - } + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); + if (ret) + return ret; *finished = true; @@ -2212,7 +2288,7 @@ static struct phy_driver at803x_driver[] = { .read_page = at803x_read_page, .write_page = at803x_write_page, .get_features = at803x_get_features, - .read_status = at803x_read_status, + .read_status = at8031_read_status, .config_intr = at8031_config_intr, .handle_interrupt = at803x_handle_interrupt, .get_tunable = at803x_get_tunable, |