net: hns3: add support ethtool extended link state

In order to know the reason of link up failure, add supporting ethtool
extended link state. Driver reads the link status code from firmware if
in link down state and converts it to ethtool extended link state.

Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Guangbin Huang 2021-08-16 10:15:29 +08:00 committed by Jakub Kicinski
parent edb40bbc17
commit f5c2b9f0fc
5 changed files with 101 additions and 0 deletions

View File

@ -718,6 +718,8 @@ struct hnae3_ae_ops {
u32 nsec, u32 sec);
int (*get_ts_info)(struct hnae3_handle *handle,
struct ethtool_ts_info *info);
int (*get_link_diagnosis_info)(struct hnae3_handle *handle,
u32 *status_code);
};
struct hnae3_dcb_ops {

View File

@ -1711,6 +1711,71 @@ static int hns3_get_ts_info(struct net_device *netdev,
return ethtool_op_get_ts_info(netdev, info);
}
static const struct hns3_ethtool_link_ext_state_mapping
hns3_link_ext_state_map[] = {
{1, ETHTOOL_LINK_EXT_STATE_AUTONEG,
ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
{2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
{256, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
{257, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
{512, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
{513, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
{514, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
{515, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
{768, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
{769, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_REFERENCE_CLOCK_LOST},
{770, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_ALOS},
{1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
{1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
{1026, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
};
static int hns3_get_link_ext_state(struct net_device *netdev,
struct ethtool_link_ext_state_info *info)
{
const struct hns3_ethtool_link_ext_state_mapping *map;
struct hnae3_handle *h = hns3_get_handle(netdev);
u32 status_code, i;
int ret;
if (netif_carrier_ok(netdev))
return -ENODATA;
if (!h->ae_algo->ops->get_link_diagnosis_info)
return -EOPNOTSUPP;
ret = h->ae_algo->ops->get_link_diagnosis_info(h, &status_code);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(hns3_link_ext_state_map); i++) {
map = &hns3_link_ext_state_map[i];
if (map->status_code == status_code) {
info->link_ext_state = map->link_ext_state;
info->__link_ext_substate = map->link_ext_substate;
return 0;
}
}
return -ENODATA;
}
static const struct ethtool_ops hns3vf_ethtool_ops = {
.supported_coalesce_params = HNS3_ETHTOOL_COALESCE,
.get_drvinfo = hns3_get_drvinfo,
@ -1782,6 +1847,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
.get_tunable = hns3_get_tunable,
.set_tunable = hns3_set_tunable,
.reset = hns3_set_reset,
.get_link_ext_state = hns3_get_link_ext_state,
};
void hns3_ethtool_set_ops(struct net_device *netdev)

View File

@ -22,4 +22,10 @@ struct hns3_pflag_desc {
void (*handler)(struct net_device *netdev, bool enable);
};
struct hns3_ethtool_link_ext_state_mapping {
u32 status_code;
enum ethtool_link_ext_state link_ext_state;
u8 link_ext_substate;
};
#endif

View File

@ -316,6 +316,9 @@ enum hclge_opcode_type {
/* PHY command */
HCLGE_OPC_PHY_LINK_KSETTING = 0x7025,
HCLGE_OPC_PHY_REG = 0x7026,
/* Query link diagnosis info command */
HCLGE_OPC_QUERY_LINK_DIAGNOSIS = 0x702A,
};
#define HCLGE_TQP_REG_OFFSET 0x80000

View File

@ -12843,6 +12843,29 @@ static int hclge_get_module_eeprom(struct hnae3_handle *handle, u32 offset,
return 0;
}
static int hclge_get_link_diagnosis_info(struct hnae3_handle *handle,
u32 *status_code)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret;
if (hdev->ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)
return -EOPNOTSUPP;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_LINK_DIAGNOSIS, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to query link diagnosis info, ret = %d\n", ret);
return ret;
}
*status_code = le32_to_cpu(desc.data[0]);
return 0;
}
static const struct hnae3_ae_ops hclge_ops = {
.init_ae_dev = hclge_init_ae_dev,
.uninit_ae_dev = hclge_uninit_ae_dev,
@ -12943,6 +12966,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_tx_hwts_info = hclge_ptp_set_tx_info,
.get_rx_hwts = hclge_ptp_get_rx_hwts,
.get_ts_info = hclge_ptp_get_ts_info,
.get_link_diagnosis_info = hclge_get_link_diagnosis_info,
};
static struct hnae3_ae_algo ae_algo = {