X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fhns3%2Fhns3_ethdev.c;h=fa01b588fd96557170fdc24799d3f1663e744cb2;hb=3b37cbe6179aeebc02b5e5cf3e39dfb2d5e69a01;hp=e02a7ec093e2a6b7ec69afae97e5b8b02f492c7e;hpb=c6332c3cf9f08f5426d53b927a821ea4a28697fb;p=dpdk.git diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c index e02a7ec093..fa01b588fd 100644 --- a/drivers/net/hns3/hns3_ethdev.c +++ b/drivers/net/hns3/hns3_ethdev.c @@ -1,11 +1,12 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2018-2019 Hisilicon Limited. + * Copyright(c) 2018-2021 HiSilicon Limited. */ #include #include #include #include +#include #include "hns3_ethdev.h" #include "hns3_logs.h" @@ -57,6 +58,7 @@ enum hns3_evt_cause { HNS3_VECTOR0_EVENT_RST, HNS3_VECTOR0_EVENT_MBX, HNS3_VECTOR0_EVENT_ERR, + HNS3_VECTOR0_EVENT_PTP, HNS3_VECTOR0_EVENT_OTHER, }; @@ -102,6 +104,7 @@ static int hns3_remove_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr); static int hns3_restore_fec(struct hns3_hw *hw); static int hns3_query_dev_fec_info(struct hns3_hw *hw); +static int hns3_do_stop(struct hns3_adapter *hns); void hns3_ether_format_addr(char *buf, uint16_t size, const struct rte_ether_addr *ether_addr) @@ -200,6 +203,13 @@ hns3_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval) goto out; } + /* Check for vector0 1588 event source */ + if (BIT(HNS3_VECTOR0_1588_INT_B) & vector0_int_stats) { + val = BIT(HNS3_VECTOR0_1588_INT_B); + ret = HNS3_VECTOR0_EVENT_PTP; + goto out; + } + /* check for vector0 msix event source */ if (vector0_int_stats & HNS3_VECTOR0_REG_MSIX_MASK || hw_err_src_reg & HNS3_RAS_REG_NFE_MASK) { @@ -216,9 +226,6 @@ hns3_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval) goto out; } - if (clearval && (vector0_int_stats || cmdq_src_val || hw_err_src_reg)) - hns3_warn(hw, "vector0_int_stats:0x%x cmdq_src_val:0x%x hw_err_src_reg:0x%x", - vector0_int_stats, cmdq_src_val, hw_err_src_reg); val = vector0_int_stats; ret = HNS3_VECTOR0_EVENT_OTHER; out: @@ -228,10 +235,17 @@ out: return ret; } +static bool +hns3_is_1588_event_type(uint32_t event_type) +{ + return (event_type == HNS3_VECTOR0_EVENT_PTP); +} + static void hns3_clear_event_cause(struct hns3_hw *hw, uint32_t event_type, uint32_t regclr) { - if (event_type == HNS3_VECTOR0_EVENT_RST) + if (event_type == HNS3_VECTOR0_EVENT_RST || + hns3_is_1588_event_type(event_type)) hns3_write_dev(hw, HNS3_MISC_RESET_STS_REG, regclr); else if (event_type == HNS3_VECTOR0_EVENT_MBX) hns3_write_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG, regclr); @@ -254,6 +268,36 @@ hns3_clear_all_event_cause(struct hns3_hw *hw) BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) | BIT(HNS3_VECTOR0_CORERESET_INT_B)); hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_MBX, 0); + hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_PTP, + BIT(HNS3_VECTOR0_1588_INT_B)); +} + +static void +hns3_handle_mac_tnl(struct hns3_hw *hw) +{ + struct hns3_cmd_desc desc; + uint32_t status; + int ret; + + /* query and clear mac tnl interruptions */ + hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_MAC_TNL_INT, true); + ret = hns3_cmd_send(hw, &desc, 1); + if (ret) { + hns3_err(hw, "failed to query mac tnl int, ret = %d.", ret); + return; + } + + status = rte_le_to_cpu_32(desc.data[0]); + if (status) { + hns3_warn(hw, "mac tnl int occurs, status = 0x%x.", status); + hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CLEAR_MAC_TNL_INT, + false); + desc.data[0] = rte_cpu_to_le_32(HNS3_MAC_TNL_INT_CLR); + ret = hns3_cmd_send(hw, &desc, 1); + if (ret) + hns3_err(hw, "failed to clear mac tnl int, ret = %d.", + ret); + } } static void @@ -264,24 +308,36 @@ hns3_interrupt_handler(void *param) struct hns3_hw *hw = &hns->hw; enum hns3_evt_cause event_cause; uint32_t clearval = 0; + uint32_t vector0_int; + uint32_t ras_int; + uint32_t cmdq_int; /* Disable interrupt */ hns3_pf_disable_irq0(hw); event_cause = hns3_check_event_cause(hns, &clearval); + vector0_int = hns3_read_dev(hw, HNS3_VECTOR0_OTHER_INT_STS_REG); + ras_int = hns3_read_dev(hw, HNS3_RAS_PF_OTHER_INT_STS_REG); + cmdq_int = hns3_read_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG); /* vector 0 interrupt is shared with reset and mailbox source events. */ if (event_cause == HNS3_VECTOR0_EVENT_ERR) { - hns3_warn(hw, "Received err interrupt"); + hns3_warn(hw, "received interrupt: vector0_int_stat:0x%x " + "ras_int_stat:0x%x cmdq_int_stat:0x%x", + vector0_int, ras_int, cmdq_int); hns3_handle_msix_error(hns, &hw->reset.request); hns3_handle_ras_error(hns, &hw->reset.request); + hns3_handle_mac_tnl(hw); hns3_schedule_reset(hns); } else if (event_cause == HNS3_VECTOR0_EVENT_RST) { - hns3_warn(hw, "Received reset interrupt"); + hns3_warn(hw, "received reset interrupt"); hns3_schedule_reset(hns); - } else if (event_cause == HNS3_VECTOR0_EVENT_MBX) + } else if (event_cause == HNS3_VECTOR0_EVENT_MBX) { hns3_dev_handle_mbx_msg(hw); - else - hns3_err(hw, "Received unknown event"); + } else { + hns3_warn(hw, "received unknown event: vector0_int_stat:0x%x " + "ras_int_stat:0x%x cmdq_int_stat:0x%x", + vector0_int, ras_int, cmdq_int); + } hns3_clear_event_cause(hw, event_cause, clearval); /* Enable interrupt if it is not cause by reset */ @@ -925,7 +981,7 @@ hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on) { struct hns3_hw *hw = &hns->hw; uint16_t port_base_vlan_state; - int ret; + int ret, err; if (on == 0 && pvid != hw->port_base_vlan_cfg.pvid) { if (hw->port_base_vlan_cfg.pvid != HNS3_INVALID_PVID) @@ -948,7 +1004,7 @@ hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on) if (ret) { hns3_err(hw, "failed to config rx vlan strip for pvid, " "ret = %d", ret); - return ret; + goto pvid_vlan_strip_fail; } if (pvid == HNS3_INVALID_PVID) @@ -957,13 +1013,27 @@ hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on) if (ret) { hns3_err(hw, "failed to update vlan filter entries, ret = %d", ret); - return ret; + goto vlan_filter_set_fail; } out: hw->port_base_vlan_cfg.state = port_base_vlan_state; hw->port_base_vlan_cfg.pvid = on ? pvid : HNS3_INVALID_PVID; return ret; + +vlan_filter_set_fail: + err = hns3_en_pvid_strip(hns, hw->port_base_vlan_cfg.state == + HNS3_PORT_BASE_VLAN_ENABLE); + if (err) + hns3_err(hw, "fail to rollback pvid strip, ret = %d", err); + +pvid_vlan_strip_fail: + err = hns3_vlan_txvlan_cfg(hns, hw->port_base_vlan_cfg.state, + hw->port_base_vlan_cfg.pvid); + if (err) + hns3_err(hw, "fail to rollback txvlan status, ret = %d", err); + + return ret; } static int @@ -2333,6 +2403,41 @@ hns3_init_ring_with_vector(struct hns3_hw *hw) return 0; } +static int +hns3_refresh_mtu(struct rte_eth_dev *dev, struct rte_eth_conf *conf) +{ + struct hns3_adapter *hns = dev->data->dev_private; + struct hns3_hw *hw = &hns->hw; + uint32_t max_rx_pkt_len; + uint16_t mtu; + int ret; + + if (!(conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)) + return 0; + + /* + * If jumbo frames are enabled, MTU needs to be refreshed + * according to the maximum RX packet length. + */ + max_rx_pkt_len = conf->rxmode.max_rx_pkt_len; + if (max_rx_pkt_len > HNS3_MAX_FRAME_LEN || + max_rx_pkt_len <= HNS3_DEFAULT_FRAME_LEN) { + hns3_err(hw, "maximum Rx packet length must be greater than %u " + "and no more than %u when jumbo frame enabled.", + (uint16_t)HNS3_DEFAULT_FRAME_LEN, + (uint16_t)HNS3_MAX_FRAME_LEN); + return -EINVAL; + } + + mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(max_rx_pkt_len); + ret = hns3_dev_mtu_set(dev, mtu); + if (ret) + return ret; + dev->data->mtu = mtu; + + return 0; +} + static int hns3_dev_configure(struct rte_eth_dev *dev) { @@ -2343,8 +2448,6 @@ hns3_dev_configure(struct rte_eth_dev *dev) uint16_t nb_rx_q = dev->data->nb_rx_queues; uint16_t nb_tx_q = dev->data->nb_tx_queues; struct rte_eth_rss_conf rss_conf; - uint32_t max_rx_pkt_len; - uint16_t mtu; bool gro_en; int ret; @@ -2392,28 +2495,13 @@ hns3_dev_configure(struct rte_eth_dev *dev) goto cfg_err; } - /* - * If jumbo frames are enabled, MTU needs to be refreshed - * according to the maximum RX packet length. - */ - if (conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) { - max_rx_pkt_len = conf->rxmode.max_rx_pkt_len; - if (max_rx_pkt_len > HNS3_MAX_FRAME_LEN || - max_rx_pkt_len <= HNS3_DEFAULT_FRAME_LEN) { - hns3_err(hw, "maximum Rx packet length must be greater " - "than %u and less than %u when jumbo frame enabled.", - (uint16_t)HNS3_DEFAULT_FRAME_LEN, - (uint16_t)HNS3_MAX_FRAME_LEN); - ret = -EINVAL; - goto cfg_err; - } + ret = hns3_refresh_mtu(dev, conf); + if (ret) + goto cfg_err; - mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(max_rx_pkt_len); - ret = hns3_dev_mtu_set(dev, mtu); - if (ret) - goto cfg_err; - dev->data->mtu = mtu; - } + ret = hns3_mbuf_dyn_rx_timestamp_register(dev, conf); + if (ret) + goto cfg_err; ret = hns3_dev_configure_vlan(dev); if (ret) @@ -2460,17 +2548,33 @@ hns3_set_mac_mtu(struct hns3_hw *hw, uint16_t new_mps) static int hns3_config_mtu(struct hns3_hw *hw, uint16_t mps) { + struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw); + uint16_t original_mps = hns->pf.mps; + int err; int ret; ret = hns3_set_mac_mtu(hw, mps); if (ret) { - hns3_err(hw, "Failed to set mtu, ret = %d", ret); + hns3_err(hw, "failed to set mtu, ret = %d", ret); return ret; } + hns->pf.mps = mps; ret = hns3_buffer_alloc(hw); - if (ret) - hns3_err(hw, "Failed to allocate buffer, ret = %d", ret); + if (ret) { + hns3_err(hw, "failed to allocate buffer, ret = %d", ret); + goto rollback; + } + + return 0; + +rollback: + err = hns3_set_mac_mtu(hw, original_mps); + if (err) { + hns3_err(hw, "fail to rollback MTU, err = %d", err); + return ret; + } + hns->pf.mps = original_mps; return ret; } @@ -2505,7 +2609,7 @@ hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) dev->data->port_id, mtu, ret); return ret; } - hns->pf.mps = (uint16_t)frame_size; + if (is_jumbo_frame) dev->data->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME; @@ -2565,10 +2669,16 @@ hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info) DEV_TX_OFFLOAD_MBUF_FAST_FREE | hns3_txvlan_cap_get(hw)); + if (hns3_dev_outer_udp_cksum_supported(hw)) + info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_UDP_CKSUM; + if (hns3_dev_indep_txrx_supported(hw)) info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP | RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP; + if (hns3_dev_ptp_supported(hw)) + info->rx_offload_capa |= DEV_RX_OFFLOAD_TIMESTAMP; + info->rx_desc_lim = (struct rte_eth_desc_lim) { .nb_max = HNS3_MAX_RING_DESC, .nb_min = HNS3_MIN_RING_DESC, @@ -2640,20 +2750,27 @@ hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version, } static int -hns3_dev_link_update(struct rte_eth_dev *eth_dev, - __rte_unused int wait_to_complete) +hns3_update_port_link_info(struct rte_eth_dev *eth_dev) { - struct hns3_adapter *hns = eth_dev->data->dev_private; - struct hns3_hw *hw = &hns->hw; - struct hns3_mac *mac = &hw->mac; - struct rte_eth_link new_link; + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + int ret; - if (!hns3_is_reset_pending(hns)) { - hns3_update_link_status(hw); - hns3_update_link_info(eth_dev); - } + (void)hns3_update_link_status(hw); + + ret = hns3_update_link_info(eth_dev); + if (ret) + hw->mac.link_status = ETH_LINK_DOWN; + + return ret; +} + +static void +hns3_setup_linkstatus(struct rte_eth_dev *eth_dev, + struct rte_eth_link *new_link) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + struct hns3_mac *mac = &hw->mac; - memset(&new_link, 0, sizeof(new_link)); switch (mac->link_speed) { case ETH_SPEED_NUM_10M: case ETH_SPEED_NUM_100M: @@ -2664,17 +2781,50 @@ hns3_dev_link_update(struct rte_eth_dev *eth_dev, case ETH_SPEED_NUM_50G: case ETH_SPEED_NUM_100G: case ETH_SPEED_NUM_200G: - new_link.link_speed = mac->link_speed; + new_link->link_speed = mac->link_speed; break; default: - new_link.link_speed = ETH_SPEED_NUM_100M; + if (mac->link_status) + new_link->link_speed = ETH_SPEED_NUM_UNKNOWN; + else + new_link->link_speed = ETH_SPEED_NUM_NONE; break; } - new_link.link_duplex = mac->link_duplex; - new_link.link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - new_link.link_autoneg = + new_link->link_duplex = mac->link_duplex; + new_link->link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + new_link->link_autoneg = !(eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED); +} + +static int +hns3_dev_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete) +{ +#define HNS3_LINK_CHECK_INTERVAL 100 /* 100ms */ +#define HNS3_MAX_LINK_CHECK_TIMES 20 /* 2s (100 * 20ms) in total */ + + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + uint32_t retry_cnt = HNS3_MAX_LINK_CHECK_TIMES; + struct hns3_mac *mac = &hw->mac; + struct rte_eth_link new_link; + int ret; + + do { + ret = hns3_update_port_link_info(eth_dev); + if (ret) { + hns3_err(hw, "failed to get port link info, ret = %d.", + ret); + break; + } + + if (!wait_to_complete || mac->link_status == ETH_LINK_UP) + break; + + rte_delay_ms(HNS3_LINK_CHECK_INTERVAL); + } while (retry_cnt--); + + memset(&new_link, 0, sizeof(new_link)); + hns3_setup_linkstatus(eth_dev, &new_link); return rte_eth_linkstatus_set(eth_dev, &new_link); } @@ -3064,9 +3214,11 @@ hns3_get_capability(struct hns3_hw *hw) hw->intr.gl_unit = HNS3_INTR_COALESCE_GL_UINT_2US; hw->tso_mode = HNS3_TSO_SW_CAL_PSEUDO_H_CSUM; hw->vlan_mode = HNS3_SW_SHIFT_AND_DISCARD_MODE; + hw->drop_stats_mode = HNS3_PKTS_DROP_STATS_MODE1; hw->min_tx_pkt_len = HNS3_HIP08_MIN_TX_PKT_LEN; pf->tqp_config_mode = HNS3_FIXED_MAX_TQP_NUM_MODE; hw->rss_info.ipv6_sctp_offload_supported = false; + hw->udp_cksum_mode = HNS3_SPECIAL_PORT_SW_CKSUM_MODE; return 0; } @@ -3082,13 +3234,46 @@ hns3_get_capability(struct hns3_hw *hw) hw->intr.gl_unit = HNS3_INTR_COALESCE_GL_UINT_1US; hw->tso_mode = HNS3_TSO_HW_CAL_PSEUDO_H_CSUM; hw->vlan_mode = HNS3_HW_SHIFT_AND_DISCARD_MODE; + hw->drop_stats_mode = HNS3_PKTS_DROP_STATS_MODE2; hw->min_tx_pkt_len = HNS3_HIP09_MIN_TX_PKT_LEN; pf->tqp_config_mode = HNS3_FLEX_MAX_TQP_NUM_MODE; hw->rss_info.ipv6_sctp_offload_supported = true; + hw->udp_cksum_mode = HNS3_SPECIAL_PORT_HW_CKSUM_MODE; return 0; } +static int +hns3_check_media_type(struct hns3_hw *hw, uint8_t media_type) +{ + int ret; + + switch (media_type) { + case HNS3_MEDIA_TYPE_COPPER: + if (!hns3_dev_copper_supported(hw)) { + PMD_INIT_LOG(ERR, + "Media type is copper, not supported."); + ret = -EOPNOTSUPP; + } else { + ret = 0; + } + break; + case HNS3_MEDIA_TYPE_FIBER: + ret = 0; + break; + case HNS3_MEDIA_TYPE_BACKPLANE: + PMD_INIT_LOG(ERR, "Media type is Backplane, not supported."); + ret = -EOPNOTSUPP; + break; + default: + PMD_INIT_LOG(ERR, "Unknown media type = %u!", media_type); + ret = -EINVAL; + break; + } + + return ret; +} + static int hns3_get_board_configuration(struct hns3_hw *hw) { @@ -3103,11 +3288,9 @@ hns3_get_board_configuration(struct hns3_hw *hw) return ret; } - if (cfg.media_type == HNS3_MEDIA_TYPE_COPPER && - !hns3_dev_copper_supported(hw)) { - PMD_INIT_LOG(ERR, "media type is copper, not supported."); - return -EOPNOTSUPP; - } + ret = hns3_check_media_type(hw, cfg.media_type); + if (ret) + return ret; hw->mac.media_type = cfg.media_type; hw->rss_size_max = cfg.rss_size_max; @@ -3952,6 +4135,8 @@ hns3_firmware_compat_config(struct hns3_hw *hw, bool is_init) if (is_init) { hns3_set_bit(compat, HNS3_LINK_EVENT_REPORT_EN_B, 1); hns3_set_bit(compat, HNS3_NCSI_ERROR_REPORT_EN_B, 0); + if (hw->mac.media_type == HNS3_MEDIA_TYPE_COPPER) + hns3_set_bit(compat, HNS3_FIRMWARE_PHY_DRIVER_EN_B, 1); } req->compat = rte_cpu_to_le_32(compat); @@ -4384,7 +4569,6 @@ static int hns3_cfg_mac_speed_dup(struct hns3_hw *hw, uint32_t speed, uint8_t duplex) { struct hns3_mac *mac = &hw->mac; - uint32_t cur_speed = mac->link_speed; int ret; duplex = hns3_check_speed_dup(duplex, speed); @@ -4395,14 +4579,11 @@ hns3_cfg_mac_speed_dup(struct hns3_hw *hw, uint32_t speed, uint8_t duplex) if (ret) return ret; - mac->link_speed = speed; - ret = hns3_dcb_port_shaper_cfg(hw); - if (ret) { - hns3_err(hw, "failed to configure port shaper, ret = %d.", ret); - mac->link_speed = cur_speed; + ret = hns3_port_shaper_update(hw, speed); + if (ret) return ret; - } + mac->link_speed = speed; mac->link_duplex = duplex; return 0; @@ -4433,6 +4614,78 @@ hns3_update_fiber_link_info(struct hns3_hw *hw) return hns3_cfg_mac_speed_dup(hw, speed, ETH_LINK_FULL_DUPLEX); } +static void +hns3_parse_copper_phy_params(struct hns3_cmd_desc *desc, struct hns3_mac *mac) +{ + struct hns3_phy_params_bd0_cmd *req; + + req = (struct hns3_phy_params_bd0_cmd *)desc[0].data; + mac->link_speed = rte_le_to_cpu_32(req->speed); + mac->link_duplex = hns3_get_bit(req->duplex, + HNS3_PHY_DUPLEX_CFG_B); + mac->link_autoneg = hns3_get_bit(req->autoneg, + HNS3_PHY_AUTONEG_CFG_B); + mac->supported_capa = rte_le_to_cpu_32(req->supported); + mac->advertising = rte_le_to_cpu_32(req->advertising); + mac->lp_advertising = rte_le_to_cpu_32(req->lp_advertising); + mac->support_autoneg = !!(mac->supported_capa & + HNS3_PHY_LINK_MODE_AUTONEG_BIT); +} + +static int +hns3_get_copper_phy_params(struct hns3_hw *hw, struct hns3_mac *mac) +{ + struct hns3_cmd_desc desc[HNS3_PHY_PARAM_CFG_BD_NUM]; + uint16_t i; + int ret; + + for (i = 0; i < HNS3_PHY_PARAM_CFG_BD_NUM - 1; i++) { + hns3_cmd_setup_basic_desc(&desc[i], HNS3_OPC_PHY_PARAM_CFG, + true); + desc[i].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT); + } + hns3_cmd_setup_basic_desc(&desc[i], HNS3_OPC_PHY_PARAM_CFG, true); + + ret = hns3_cmd_send(hw, desc, HNS3_PHY_PARAM_CFG_BD_NUM); + if (ret) { + hns3_err(hw, "get phy parameters failed, ret = %d.", ret); + return ret; + } + + hns3_parse_copper_phy_params(desc, mac); + + return 0; +} + +static int +hns3_update_copper_link_info(struct hns3_hw *hw) +{ + struct hns3_mac *mac = &hw->mac; + struct hns3_mac mac_info; + int ret; + + memset(&mac_info, 0, sizeof(struct hns3_mac)); + ret = hns3_get_copper_phy_params(hw, &mac_info); + if (ret) + return ret; + + if (mac_info.link_speed != mac->link_speed) { + ret = hns3_port_shaper_update(hw, mac_info.link_speed); + if (ret) + return ret; + } + + mac->link_speed = mac_info.link_speed; + mac->link_duplex = mac_info.link_duplex; + mac->link_autoneg = mac_info.link_autoneg; + mac->supported_capa = mac_info.supported_capa; + mac->advertising = mac_info.advertising; + mac->lp_advertising = mac_info.lp_advertising; + mac->support_autoneg = mac_info.support_autoneg; + + return 0; +} + static int hns3_update_link_info(struct rte_eth_dev *eth_dev) { @@ -4441,7 +4694,7 @@ hns3_update_link_info(struct rte_eth_dev *eth_dev) int ret = 0; if (hw->mac.media_type == HNS3_MEDIA_TYPE_COPPER) - return 0; + ret = hns3_update_copper_link_info(hw); else if (hw->mac.media_type == HNS3_MEDIA_TYPE_FIBER) ret = hns3_update_fiber_link_info(hw); @@ -4523,36 +4776,30 @@ hns3_update_link_status(struct hns3_hw *hw) if (state != hw->mac.link_status) { hw->mac.link_status = state; hns3_warn(hw, "Link status change to %s!", state ? "up" : "down"); + hns3_config_mac_tnl_int(hw, + state == ETH_LINK_UP ? true : false); return true; } return false; } -/* - * Current, the PF driver get link status by two ways: - * 1) Periodic polling in the intr thread context, driver call - * hns3_update_link_status to update link status. - * 2) Firmware report async interrupt, driver process the event in the intr - * thread context, and call hns3_update_link_status to update link status. - * - * If detect link status changed, driver need report LSE. One method is add the - * report LSE logic in hns3_update_link_status. - * - * But the PF driver ops(link_update) also call hns3_update_link_status to - * update link status. - * If we report LSE in hns3_update_link_status, it may lead to deadlock in the - * bonding application. - * - * So add the one new API which used only in intr thread context. - */ void -hns3_update_link_status_and_event(struct hns3_hw *hw) +hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query) { struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id]; - bool changed = hns3_update_link_status(hw); - if (changed) - rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL); + struct rte_eth_link new_link; + int ret; + + if (query) + hns3_update_port_link_info(dev); + + memset(&new_link, 0, sizeof(new_link)); + hns3_setup_linkstatus(dev, &new_link); + + ret = rte_eth_linkstatus_set(dev, &new_link); + if (ret == 0 && dev->data->dev_conf.intr_conf.lsc != 0) + hns3_start_report_lse(dev); } static void @@ -4562,16 +4809,36 @@ hns3_service_handler(void *param) struct hns3_adapter *hns = eth_dev->data->dev_private; struct hns3_hw *hw = &hns->hw; - if (!hns3_is_reset_pending(hns)) { - hns3_update_link_status_and_event(hw); - hns3_update_link_info(eth_dev); - } else { + if (!hns3_is_reset_pending(hns)) + hns3_update_linkstatus_and_event(hw, true); + else hns3_warn(hw, "Cancel the query when reset is pending"); - } rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev); } +static void +hns3_update_dev_lsc_cap(struct hns3_hw *hw, + int fw_compact_cmd_result) +{ + struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id]; + + if (hw->adapter_state != HNS3_NIC_UNINITIALIZED) + return; + + if (fw_compact_cmd_result != 0) { + /* + * If fw_compact_cmd_result is not zero, it means firmware don't + * support link status change interrupt. + * Framework already set RTE_ETH_DEV_INTR_LSC bit because driver + * declared RTE_PCI_DRV_INTR_LSC in drv_flags. It need to clear + * the RTE_ETH_DEV_INTR_LSC capability when detect firmware + * don't support link status change interrupt. + */ + dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC; + } +} + static int hns3_init_hardware(struct hns3_adapter *hns) { @@ -4659,6 +4926,7 @@ hns3_init_hardware(struct hns3_adapter *hns) if (ret) PMD_INIT_LOG(WARNING, "firmware compatible features not " "supported, ret = %d.", ret); + hns3_update_dev_lsc_cap(hw, ret); return 0; @@ -4742,6 +5010,13 @@ hns3_init_pf(struct rte_eth_dev *eth_dev) goto err_cmd_init; } + /* Hardware statistics of imissed registers cleared. */ + ret = hns3_update_imissed_stats(hw, true); + if (ret) { + hns3_err(hw, "clear imissed stats failed, ret = %d", ret); + return ret; + } + hns3_config_all_msix_error(hw, true); ret = rte_intr_callback_register(&pci_dev->intr_handle, @@ -4752,6 +5027,10 @@ hns3_init_pf(struct rte_eth_dev *eth_dev) goto err_intr_callback_register; } + ret = hns3_ptp_init(hw); + if (ret) + goto err_get_config; + /* Enable interrupt */ rte_intr_enable(&pci_dev->intr_handle); hns3_pf_enable_irq0(hw); @@ -4834,6 +5113,7 @@ hns3_uninit_pf(struct rte_eth_dev *eth_dev) (void)hns3_firmware_compat_config(hw, false); hns3_uninit_umv_space(hw); hns3_tqp_stats_uninit(hw); + hns3_config_mac_tnl_int(hw, false); hns3_pf_disable_irq0(hw); rte_intr_disable(&pci_dev->intr_handle); hns3_intr_unregister(&pci_dev->intr_handle, hns3_interrupt_handler, @@ -4864,6 +5144,8 @@ hns3_do_start(struct hns3_adapter *hns, bool reset_queue) return ret; } + hns3_enable_rxd_adv_layout(hw); + ret = hns3_init_queues(hns, reset_queue); if (ret) { PMD_INIT_LOG(ERR, "failed to init queues, ret = %d.", ret); @@ -5009,11 +5291,8 @@ hns3_dev_start(struct rte_eth_dev *dev) return ret; } ret = hns3_map_rx_interrupt(dev); - if (ret) { - hw->adapter_state = HNS3_NIC_CONFIGURED; - rte_spinlock_unlock(&hw->lock); - return ret; - } + if (ret) + goto map_rx_inter_err; /* * There are three register used to control the status of a TQP @@ -5027,19 +5306,12 @@ hns3_dev_start(struct rte_eth_dev *dev) * status of queue in the dpdk framework. */ ret = hns3_start_all_txqs(dev); - if (ret) { - hw->adapter_state = HNS3_NIC_CONFIGURED; - rte_spinlock_unlock(&hw->lock); - return ret; - } + if (ret) + goto map_rx_inter_err; ret = hns3_start_all_rxqs(dev); - if (ret) { - hns3_stop_all_txqs(dev); - hw->adapter_state = HNS3_NIC_CONFIGURED; - rte_spinlock_unlock(&hw->lock); - return ret; - } + if (ret) + goto start_all_rxqs_fail; hw->adapter_state = HNS3_NIC_STARTED; rte_spinlock_unlock(&hw->lock); @@ -5047,7 +5319,6 @@ hns3_dev_start(struct rte_eth_dev *dev) hns3_rx_scattered_calc(dev); hns3_set_rxtx_function(dev); hns3_mp_req_start_rxtx(dev); - rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, dev); hns3_restore_filter(dev); @@ -5062,8 +5333,22 @@ hns3_dev_start(struct rte_eth_dev *dev) hns3_tm_dev_start_proc(hw); + if (dev->data->dev_conf.intr_conf.lsc != 0) + hns3_dev_link_update(dev, 0); + rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, dev); + hns3_info(hw, "hns3 dev start successful!"); + return 0; + +start_all_rxqs_fail: + hns3_stop_all_txqs(dev); +map_rx_inter_err: + (void)hns3_do_stop(hns); + hw->adapter_state = HNS3_NIC_CONFIGURED; + rte_spinlock_unlock(&hw->lock); + + return ret; } static int @@ -5072,6 +5357,17 @@ hns3_do_stop(struct hns3_adapter *hns) struct hns3_hw *hw = &hns->hw; int ret; + /* + * The "hns3_do_stop" function will also be called by .stop_service to + * prepare reset. At the time of global or IMP reset, the command cannot + * be sent to stop the tx/rx queues. The mbuf in Tx/Rx queues may be + * accessed during the reset process. So the mbuf can not be released + * during reset and is required to be released after the reset is + * completed. + */ + if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) + hns3_dev_release_mbufs(hns); + ret = hns3_cfg_mac_mode(hw, false); if (ret) return ret; @@ -5146,14 +5442,15 @@ hns3_dev_stop(struct rte_eth_dev *dev) rte_spinlock_lock(&hw->lock); if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) { hns3_tm_dev_stop_proc(hw); + hns3_config_mac_tnl_int(hw, false); hns3_stop_tqps(hw); hns3_do_stop(hns); hns3_unmap_rx_interrupt(dev); - hns3_dev_release_mbufs(hns); hw->adapter_state = HNS3_NIC_CONFIGURED; } hns3_rx_scattered_reset(dev); rte_eal_alarm_cancel(hns3_service_handler, dev); + hns3_stop_report_lse(dev); rte_spinlock_unlock(&hw->lock); return 0; @@ -5278,6 +5575,11 @@ hns3_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) return -EOPNOTSUPP; } + if (hw->num_tc > 1) { + hns3_err(hw, "in multi-TC scenarios, MAC pause is not supported."); + return -EOPNOTSUPP; + } + hns3_get_fc_mode(hw, fc_conf->mode); if (hw->requested_mode == hw->current_mode && pf->pause_time == fc_conf->pause_time) @@ -5588,14 +5890,12 @@ hns3_record_imp_error(struct hns3_adapter *hns) reg_val = hns3_read_dev(hw, HNS3_VECTOR0_OTER_EN_REG); if (hns3_get_bit(reg_val, HNS3_VECTOR0_IMP_RD_POISON_B)) { hns3_warn(hw, "Detected IMP RD poison!"); - hns3_error_int_stats_add(hns, "IMP_RD_POISON_INT_STS"); hns3_set_bit(reg_val, HNS3_VECTOR0_IMP_RD_POISON_B, 0); hns3_write_dev(hw, HNS3_VECTOR0_OTER_EN_REG, reg_val); } if (hns3_get_bit(reg_val, HNS3_VECTOR0_IMP_CMDQ_ERR_B)) { hns3_warn(hw, "Detected IMP CMDQ error!"); - hns3_error_int_stats_add(hns, "CMDQ_MEM_ECC_INT_STS"); hns3_set_bit(reg_val, HNS3_VECTOR0_IMP_CMDQ_ERR_B, 0); hns3_write_dev(hw, HNS3_VECTOR0_OTER_EN_REG, reg_val); } @@ -5654,11 +5954,11 @@ hns3_stop_service(struct hns3_adapter *hns) struct rte_eth_dev *eth_dev; eth_dev = &rte_eth_devices[hw->data->port_id]; + hw->mac.link_status = ETH_LINK_DOWN; if (hw->adapter_state == HNS3_NIC_STARTED) { rte_eal_alarm_cancel(hns3_service_handler, eth_dev); - hns3_update_link_status_and_event(hw); + hns3_update_linkstatus_and_event(hw, false); } - hw->mac.link_status = ETH_LINK_DOWN; hns3_set_rxtx_function(eth_dev); rte_wmb(); @@ -5757,6 +6057,10 @@ hns3_restore_conf(struct hns3_adapter *hns) if (ret) goto err_promisc; + ret = hns3_restore_ptp(hns); + if (ret) + goto err_promisc; + ret = hns3_restore_rx_interrupt(hw); if (ret) goto err_promisc; @@ -6329,6 +6633,78 @@ hns3_get_module_info(struct rte_eth_dev *dev, return 0; } +static int +hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args) +{ + uint32_t hint = HNS3_IO_FUNC_HINT_NONE; + + RTE_SET_USED(key); + + if (strcmp(value, "vec") == 0) + hint = HNS3_IO_FUNC_HINT_VEC; + else if (strcmp(value, "sve") == 0) + hint = HNS3_IO_FUNC_HINT_SVE; + else if (strcmp(value, "simple") == 0) + hint = HNS3_IO_FUNC_HINT_SIMPLE; + else if (strcmp(value, "common") == 0) + hint = HNS3_IO_FUNC_HINT_COMMON; + + /* If the hint is valid then update output parameters */ + if (hint != HNS3_IO_FUNC_HINT_NONE) + *(uint32_t *)extra_args = hint; + + return 0; +} + +static const char * +hns3_get_io_hint_func_name(uint32_t hint) +{ + switch (hint) { + case HNS3_IO_FUNC_HINT_VEC: + return "vec"; + case HNS3_IO_FUNC_HINT_SVE: + return "sve"; + case HNS3_IO_FUNC_HINT_SIMPLE: + return "simple"; + case HNS3_IO_FUNC_HINT_COMMON: + return "common"; + default: + return "none"; + } +} + +void +hns3_parse_devargs(struct rte_eth_dev *dev) +{ + struct hns3_adapter *hns = dev->data->dev_private; + uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE; + uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE; + struct hns3_hw *hw = &hns->hw; + struct rte_kvargs *kvlist; + + if (dev->device->devargs == NULL) + return; + + kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL); + if (!kvlist) + return; + + rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT, + &hns3_parse_io_hint_func, &rx_func_hint); + rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT, + &hns3_parse_io_hint_func, &tx_func_hint); + rte_kvargs_free(kvlist); + + if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE) + hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT, + hns3_get_io_hint_func_name(rx_func_hint)); + hns->rx_func_hint = rx_func_hint; + if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE) + hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT, + hns3_get_io_hint_func_name(tx_func_hint)); + hns->tx_func_hint = tx_func_hint; +} + static const struct eth_dev_ops hns3_eth_dev_ops = { .dev_configure = hns3_dev_configure, .dev_start = hns3_dev_start, @@ -6374,7 +6750,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = { .rss_hash_conf_get = hns3_dev_rss_hash_conf_get, .reta_update = hns3_dev_rss_reta_update, .reta_query = hns3_dev_rss_reta_query, - .filter_ctrl = hns3_dev_filter_ctrl, + .flow_ops_get = hns3_dev_flow_ops_get, .vlan_filter_set = hns3_vlan_filter_set, .vlan_tpid_set = hns3_vlan_tpid_set, .vlan_offload_set = hns3_vlan_offload_set, @@ -6388,6 +6764,14 @@ static const struct eth_dev_ops hns3_eth_dev_ops = { .fec_get = hns3_fec_get, .fec_set = hns3_fec_set, .tm_ops_get = hns3_tm_ops_get, + .tx_done_cleanup = hns3_tx_done_cleanup, + .timesync_enable = hns3_timesync_enable, + .timesync_disable = hns3_timesync_disable, + .timesync_read_rx_timestamp = hns3_timesync_read_rx_timestamp, + .timesync_read_tx_timestamp = hns3_timesync_read_tx_timestamp, + .timesync_adjust_time = hns3_timesync_adjust_time, + .timesync_read_time = hns3_timesync_read_time, + .timesync_write_time = hns3_timesync_write_time, }; static const struct hns3_reset_ops hns3_reset_ops = { @@ -6448,6 +6832,7 @@ hns3_dev_init(struct rte_eth_dev *eth_dev) hw->adapter_state = HNS3_NIC_UNINITIALIZED; hns->is_vf = false; hw->data = eth_dev->data; + hns3_parse_devargs(eth_dev); /* * Set default max packet size according to the mtu @@ -6518,8 +6903,10 @@ err_mp_init_primary: err_mp_init_secondary: eth_dev->dev_ops = NULL; eth_dev->rx_pkt_burst = NULL; + eth_dev->rx_descriptor_status = NULL; eth_dev->tx_pkt_burst = NULL; eth_dev->tx_pkt_prepare = NULL; + eth_dev->tx_descriptor_status = NULL; rte_free(eth_dev->process_private); eth_dev->process_private = NULL; return ret; @@ -6573,7 +6960,7 @@ static const struct rte_pci_id pci_id_hns3_map[] = { static struct rte_pci_driver rte_hns3_pmd = { .id_table = pci_id_hns3_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, .probe = eth_hns3_pci_probe, .remove = eth_hns3_pci_remove, }; @@ -6581,5 +6968,8 @@ static struct rte_pci_driver rte_hns3_pmd = { RTE_PMD_REGISTER_PCI(net_hns3, rte_hns3_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_hns3, pci_id_hns3_map); RTE_PMD_REGISTER_KMOD_DEP(net_hns3, "* igb_uio | vfio-pci"); +RTE_PMD_REGISTER_PARAM_STRING(net_hns3, + HNS3_DEVARG_RX_FUNC_HINT "=vec|sve|simple|common " + HNS3_DEVARG_TX_FUNC_HINT "=vec|sve|simple|common "); RTE_LOG_REGISTER(hns3_logtype_init, pmd.net.hns3.init, NOTICE); RTE_LOG_REGISTER(hns3_logtype_driver, pmd.net.hns3.driver, NOTICE);