162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// Copyright (c) 2016-2017 Hisilicon Limited. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/etherdevice.h> 562306a36Sopenharmony_ci#include <linux/string.h> 662306a36Sopenharmony_ci#include <linux/phy.h> 762306a36Sopenharmony_ci#include <linux/sfp.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "hns3_enet.h" 1062306a36Sopenharmony_ci#include "hns3_ethtool.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* tqp related stats */ 1362306a36Sopenharmony_ci#define HNS3_TQP_STAT(_string, _member) { \ 1462306a36Sopenharmony_ci .stats_string = _string, \ 1562306a36Sopenharmony_ci .stats_offset = offsetof(struct hns3_enet_ring, stats) +\ 1662306a36Sopenharmony_ci offsetof(struct ring_stats, _member), \ 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic const struct hns3_stats hns3_txq_stats[] = { 2062306a36Sopenharmony_ci /* Tx per-queue statistics */ 2162306a36Sopenharmony_ci HNS3_TQP_STAT("dropped", sw_err_cnt), 2262306a36Sopenharmony_ci HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt), 2362306a36Sopenharmony_ci HNS3_TQP_STAT("packets", tx_pkts), 2462306a36Sopenharmony_ci HNS3_TQP_STAT("bytes", tx_bytes), 2562306a36Sopenharmony_ci HNS3_TQP_STAT("more", tx_more), 2662306a36Sopenharmony_ci HNS3_TQP_STAT("push", tx_push), 2762306a36Sopenharmony_ci HNS3_TQP_STAT("mem_doorbell", tx_mem_doorbell), 2862306a36Sopenharmony_ci HNS3_TQP_STAT("wake", restart_queue), 2962306a36Sopenharmony_ci HNS3_TQP_STAT("busy", tx_busy), 3062306a36Sopenharmony_ci HNS3_TQP_STAT("copy", tx_copy), 3162306a36Sopenharmony_ci HNS3_TQP_STAT("vlan_err", tx_vlan_err), 3262306a36Sopenharmony_ci HNS3_TQP_STAT("l4_proto_err", tx_l4_proto_err), 3362306a36Sopenharmony_ci HNS3_TQP_STAT("l2l3l4_err", tx_l2l3l4_err), 3462306a36Sopenharmony_ci HNS3_TQP_STAT("tso_err", tx_tso_err), 3562306a36Sopenharmony_ci HNS3_TQP_STAT("over_max_recursion", over_max_recursion), 3662306a36Sopenharmony_ci HNS3_TQP_STAT("hw_limitation", hw_limitation), 3762306a36Sopenharmony_ci HNS3_TQP_STAT("bounce", tx_bounce), 3862306a36Sopenharmony_ci HNS3_TQP_STAT("spare_full", tx_spare_full), 3962306a36Sopenharmony_ci HNS3_TQP_STAT("copy_bits_err", copy_bits_err), 4062306a36Sopenharmony_ci HNS3_TQP_STAT("sgl", tx_sgl), 4162306a36Sopenharmony_ci HNS3_TQP_STAT("skb2sgl_err", skb2sgl_err), 4262306a36Sopenharmony_ci HNS3_TQP_STAT("map_sg_err", map_sg_err), 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct hns3_stats hns3_rxq_stats[] = { 4862306a36Sopenharmony_ci /* Rx per-queue statistics */ 4962306a36Sopenharmony_ci HNS3_TQP_STAT("dropped", sw_err_cnt), 5062306a36Sopenharmony_ci HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt), 5162306a36Sopenharmony_ci HNS3_TQP_STAT("packets", rx_pkts), 5262306a36Sopenharmony_ci HNS3_TQP_STAT("bytes", rx_bytes), 5362306a36Sopenharmony_ci HNS3_TQP_STAT("errors", rx_err_cnt), 5462306a36Sopenharmony_ci HNS3_TQP_STAT("reuse_pg_cnt", reuse_pg_cnt), 5562306a36Sopenharmony_ci HNS3_TQP_STAT("err_pkt_len", err_pkt_len), 5662306a36Sopenharmony_ci HNS3_TQP_STAT("err_bd_num", err_bd_num), 5762306a36Sopenharmony_ci HNS3_TQP_STAT("l2_err", l2_err), 5862306a36Sopenharmony_ci HNS3_TQP_STAT("l3l4_csum_err", l3l4_csum_err), 5962306a36Sopenharmony_ci HNS3_TQP_STAT("csum_complete", csum_complete), 6062306a36Sopenharmony_ci HNS3_TQP_STAT("multicast", rx_multicast), 6162306a36Sopenharmony_ci HNS3_TQP_STAT("non_reuse_pg", non_reuse_pg), 6262306a36Sopenharmony_ci HNS3_TQP_STAT("frag_alloc_err", frag_alloc_err), 6362306a36Sopenharmony_ci HNS3_TQP_STAT("frag_alloc", frag_alloc), 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define HNS3_PRIV_FLAGS_LEN ARRAY_SIZE(hns3_priv_flags) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define HNS3_RXQ_STATS_COUNT ARRAY_SIZE(hns3_rxq_stats) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_PKT_NUM 1 7362306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_RING_ID 0 7462306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_PACKET_SIZE 128 7562306a36Sopenharmony_ci#define HNS3_NIC_LB_SETUP_USEC 10000 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* Nic loopback test err */ 7862306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_NO_MEM_ERR 1 7962306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_TX_CNT_ERR 2 8062306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_RX_CNT_ERR 3 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(ndev); 8562306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 8662306a36Sopenharmony_ci int ret; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (!h->ae_algo->ops->set_loopback || 8962306a36Sopenharmony_ci !h->ae_algo->ops->set_promisc_mode) 9062306a36Sopenharmony_ci return -EOPNOTSUPP; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci switch (loop) { 9362306a36Sopenharmony_ci case HNAE3_LOOP_SERIAL_SERDES: 9462306a36Sopenharmony_ci case HNAE3_LOOP_PARALLEL_SERDES: 9562306a36Sopenharmony_ci case HNAE3_LOOP_APP: 9662306a36Sopenharmony_ci case HNAE3_LOOP_PHY: 9762306a36Sopenharmony_ci case HNAE3_LOOP_EXTERNAL: 9862306a36Sopenharmony_ci ret = h->ae_algo->ops->set_loopback(h, loop, en); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci default: 10162306a36Sopenharmony_ci ret = -ENOTSUPP; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (ret || ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) 10662306a36Sopenharmony_ci return ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (en) 10962306a36Sopenharmony_ci h->ae_algo->ops->set_promisc_mode(h, true, true); 11062306a36Sopenharmony_ci else 11162306a36Sopenharmony_ci /* recover promisc mode before loopback test */ 11262306a36Sopenharmony_ci hns3_request_update_promisc_mode(h); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(ndev); 12062306a36Sopenharmony_ci int ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = hns3_nic_reset_all_ring(h); 12362306a36Sopenharmony_ci if (ret) 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci ret = hns3_lp_setup(ndev, loop_mode, true); 12762306a36Sopenharmony_ci usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int ret; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci ret = hns3_lp_setup(ndev, loop_mode, false); 13762306a36Sopenharmony_ci if (ret) { 13862306a36Sopenharmony_ci netdev_err(ndev, "lb_setup return error: %d\n", ret); 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void hns3_lp_setup_skb(struct sk_buff *skb) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci#define HNS3_NIC_LB_DST_MAC_ADDR 0x1f 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci struct net_device *ndev = skb->dev; 15262306a36Sopenharmony_ci struct hnae3_handle *handle; 15362306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev; 15462306a36Sopenharmony_ci unsigned char *packet; 15562306a36Sopenharmony_ci struct ethhdr *ethh; 15662306a36Sopenharmony_ci unsigned int i; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 15962306a36Sopenharmony_ci ethh = skb_put(skb, sizeof(struct ethhdr)); 16062306a36Sopenharmony_ci packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* The dst mac addr of loopback packet is the same as the host' 16562306a36Sopenharmony_ci * mac addr, the SSU component may loop back the packet to host 16662306a36Sopenharmony_ci * before the packet reaches mac or serdes, which will defect 16762306a36Sopenharmony_ci * the purpose of mac or serdes selftest. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci handle = hns3_get_handle(ndev); 17062306a36Sopenharmony_ci ae_dev = pci_get_drvdata(handle->pdev); 17162306a36Sopenharmony_ci if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) 17262306a36Sopenharmony_ci ethh->h_dest[5] += HNS3_NIC_LB_DST_MAC_ADDR; 17362306a36Sopenharmony_ci eth_zero_addr(ethh->h_source); 17462306a36Sopenharmony_ci ethh->h_proto = htons(ETH_P_ARP); 17562306a36Sopenharmony_ci skb_reset_mac_header(skb); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci for (i = 0; i < HNS3_NIC_LB_TEST_PACKET_SIZE; i++) 17862306a36Sopenharmony_ci packet[i] = (unsigned char)(i & 0xff); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void hns3_lb_check_skb_data(struct hns3_enet_ring *ring, 18262306a36Sopenharmony_ci struct sk_buff *skb) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector; 18562306a36Sopenharmony_ci unsigned char *packet = skb->data; 18662306a36Sopenharmony_ci u32 len = skb_headlen(skb); 18762306a36Sopenharmony_ci u32 i; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci len = min_t(u32, len, HNS3_NIC_LB_TEST_PACKET_SIZE); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for (i = 0; i < len; i++) 19262306a36Sopenharmony_ci if (packet[i] != (unsigned char)(i & 0xff)) 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* The packet is correctly received */ 19662306a36Sopenharmony_ci if (i == HNS3_NIC_LB_TEST_PACKET_SIZE) 19762306a36Sopenharmony_ci tqp_vector->rx_group.total_packets++; 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "selftest:", DUMP_PREFIX_OFFSET, 16, 1, 20062306a36Sopenharmony_ci skb->data, len, true); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 20862306a36Sopenharmony_ci struct hnae3_knic_private_info *kinfo; 20962306a36Sopenharmony_ci u32 i, rcv_good_pkt_total = 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci kinfo = &h->kinfo; 21262306a36Sopenharmony_ci for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) { 21362306a36Sopenharmony_ci struct hns3_enet_ring *ring = &priv->ring[i]; 21462306a36Sopenharmony_ci struct hns3_enet_ring_group *rx_group; 21562306a36Sopenharmony_ci u64 pre_rx_pkt; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci rx_group = &ring->tqp_vector->rx_group; 21862306a36Sopenharmony_ci pre_rx_pkt = rx_group->total_packets; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci preempt_disable(); 22162306a36Sopenharmony_ci hns3_clean_rx_ring(ring, budget, hns3_lb_check_skb_data); 22262306a36Sopenharmony_ci preempt_enable(); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rcv_good_pkt_total += (rx_group->total_packets - pre_rx_pkt); 22562306a36Sopenharmony_ci rx_group->total_packets = pre_rx_pkt; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci return rcv_good_pkt_total; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid, 23162306a36Sopenharmony_ci u32 end_ringid) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 i; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci for (i = start_ringid; i <= end_ringid; i++) { 23662306a36Sopenharmony_ci struct hns3_enet_ring *ring = &priv->ring[i]; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci hns3_clean_tx_ring(ring, 0); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * hns3_lp_run_test - run loopback test 24462306a36Sopenharmony_ci * @ndev: net device 24562306a36Sopenharmony_ci * @mode: loopback type 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * Return: %0 for success or a NIC loopback test error code on failure 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 25262306a36Sopenharmony_ci struct sk_buff *skb; 25362306a36Sopenharmony_ci u32 i, good_cnt; 25462306a36Sopenharmony_ci int ret_val = 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci skb = alloc_skb(HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN, 25762306a36Sopenharmony_ci GFP_KERNEL); 25862306a36Sopenharmony_ci if (!skb) 25962306a36Sopenharmony_ci return HNS3_NIC_LB_TEST_NO_MEM_ERR; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci skb->dev = ndev; 26262306a36Sopenharmony_ci hns3_lp_setup_skb(skb); 26362306a36Sopenharmony_ci skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci good_cnt = 0; 26662306a36Sopenharmony_ci for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) { 26762306a36Sopenharmony_ci netdev_tx_t tx_ret; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci skb_get(skb); 27062306a36Sopenharmony_ci tx_ret = hns3_nic_net_xmit(skb, ndev); 27162306a36Sopenharmony_ci if (tx_ret == NETDEV_TX_OK) { 27262306a36Sopenharmony_ci good_cnt++; 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci kfree_skb(skb); 27562306a36Sopenharmony_ci netdev_err(ndev, "hns3_lb_run_test xmit failed: %d\n", 27662306a36Sopenharmony_ci tx_ret); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) { 28062306a36Sopenharmony_ci ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR; 28162306a36Sopenharmony_ci netdev_err(ndev, "mode %d sent fail, cnt=0x%x, budget=0x%x\n", 28262306a36Sopenharmony_ci mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM); 28362306a36Sopenharmony_ci goto out; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Allow 200 milliseconds for packets to go from Tx to Rx */ 28762306a36Sopenharmony_ci msleep(200); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci good_cnt = hns3_lb_check_rx_ring(priv, HNS3_NIC_LB_TEST_PKT_NUM); 29062306a36Sopenharmony_ci if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) { 29162306a36Sopenharmony_ci ret_val = HNS3_NIC_LB_TEST_RX_CNT_ERR; 29262306a36Sopenharmony_ci netdev_err(ndev, "mode %d recv fail, cnt=0x%x, budget=0x%x\n", 29362306a36Sopenharmony_ci mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciout: 29762306a36Sopenharmony_ci hns3_lb_clear_tx_ring(priv, HNS3_NIC_LB_TEST_RING_ID, 29862306a36Sopenharmony_ci HNS3_NIC_LB_TEST_RING_ID); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci kfree_skb(skb); 30162306a36Sopenharmony_ci return ret_val; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void hns3_set_selftest_param(struct hnae3_handle *h, int (*st_param)[2]) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci st_param[HNAE3_LOOP_EXTERNAL][0] = HNAE3_LOOP_EXTERNAL; 30762306a36Sopenharmony_ci st_param[HNAE3_LOOP_EXTERNAL][1] = 30862306a36Sopenharmony_ci h->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP; 31162306a36Sopenharmony_ci st_param[HNAE3_LOOP_APP][1] = 31262306a36Sopenharmony_ci h->flags & HNAE3_SUPPORT_APP_LOOPBACK; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci st_param[HNAE3_LOOP_SERIAL_SERDES][0] = HNAE3_LOOP_SERIAL_SERDES; 31562306a36Sopenharmony_ci st_param[HNAE3_LOOP_SERIAL_SERDES][1] = 31662306a36Sopenharmony_ci h->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci st_param[HNAE3_LOOP_PARALLEL_SERDES][0] = 31962306a36Sopenharmony_ci HNAE3_LOOP_PARALLEL_SERDES; 32062306a36Sopenharmony_ci st_param[HNAE3_LOOP_PARALLEL_SERDES][1] = 32162306a36Sopenharmony_ci h->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci st_param[HNAE3_LOOP_PHY][0] = HNAE3_LOOP_PHY; 32462306a36Sopenharmony_ci st_param[HNAE3_LOOP_PHY][1] = 32562306a36Sopenharmony_ci h->flags & HNAE3_SUPPORT_PHY_LOOPBACK; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void hns3_selftest_prepare(struct net_device *ndev, bool if_running) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 33162306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (if_running) 33462306a36Sopenharmony_ci ndev->netdev_ops->ndo_stop(ndev); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VLAN_8021Q) 33762306a36Sopenharmony_ci /* Disable the vlan filter for selftest does not support it */ 33862306a36Sopenharmony_ci if (h->ae_algo->ops->enable_vlan_filter && 33962306a36Sopenharmony_ci ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) 34062306a36Sopenharmony_ci h->ae_algo->ops->enable_vlan_filter(h, false); 34162306a36Sopenharmony_ci#endif 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Tell firmware to stop mac autoneg before loopback test start, 34462306a36Sopenharmony_ci * otherwise loopback test may be failed when the port is still 34562306a36Sopenharmony_ci * negotiating. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (h->ae_algo->ops->halt_autoneg) 34862306a36Sopenharmony_ci h->ae_algo->ops->halt_autoneg(h, true); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci set_bit(HNS3_NIC_STATE_TESTING, &priv->state); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void hns3_selftest_restore(struct net_device *ndev, bool if_running) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 35662306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci clear_bit(HNS3_NIC_STATE_TESTING, &priv->state); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (h->ae_algo->ops->halt_autoneg) 36162306a36Sopenharmony_ci h->ae_algo->ops->halt_autoneg(h, false); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VLAN_8021Q) 36462306a36Sopenharmony_ci if (h->ae_algo->ops->enable_vlan_filter && 36562306a36Sopenharmony_ci ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) 36662306a36Sopenharmony_ci h->ae_algo->ops->enable_vlan_filter(h, true); 36762306a36Sopenharmony_ci#endif 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (if_running) 37062306a36Sopenharmony_ci ndev->netdev_ops->ndo_open(ndev); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void hns3_do_selftest(struct net_device *ndev, int (*st_param)[2], 37462306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci int test_index = HNAE3_LOOP_APP; 37762306a36Sopenharmony_ci u32 i; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci for (i = HNAE3_LOOP_APP; i < HNAE3_LOOP_NONE; i++) { 38062306a36Sopenharmony_ci enum hnae3_loop loop_type = (enum hnae3_loop)st_param[i][0]; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (!st_param[i][1]) 38362306a36Sopenharmony_ci continue; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci data[test_index] = hns3_lp_up(ndev, loop_type); 38662306a36Sopenharmony_ci if (!data[test_index]) 38762306a36Sopenharmony_ci data[test_index] = hns3_lp_run_test(ndev, loop_type); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci hns3_lp_down(ndev, loop_type); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (data[test_index]) 39262306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci test_index++; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic void hns3_do_external_lb(struct net_device *ndev, 39962306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci data[HNAE3_LOOP_EXTERNAL] = hns3_lp_up(ndev, HNAE3_LOOP_EXTERNAL); 40262306a36Sopenharmony_ci if (!data[HNAE3_LOOP_EXTERNAL]) 40362306a36Sopenharmony_ci data[HNAE3_LOOP_EXTERNAL] = hns3_lp_run_test(ndev, HNAE3_LOOP_EXTERNAL); 40462306a36Sopenharmony_ci hns3_lp_down(ndev, HNAE3_LOOP_EXTERNAL); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (data[HNAE3_LOOP_EXTERNAL]) 40762306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/** 41362306a36Sopenharmony_ci * hns3_self_test - self test 41462306a36Sopenharmony_ci * @ndev: net device 41562306a36Sopenharmony_ci * @eth_test: test cmd 41662306a36Sopenharmony_ci * @data: test result 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_cistatic void hns3_self_test(struct net_device *ndev, 41962306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 42262306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 42362306a36Sopenharmony_ci int st_param[HNAE3_LOOP_NONE][2]; 42462306a36Sopenharmony_ci bool if_running = netif_running(ndev); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (hns3_nic_resetting(ndev)) { 42762306a36Sopenharmony_ci netdev_err(ndev, "dev resetting!"); 42862306a36Sopenharmony_ci return; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (!(eth_test->flags & ETH_TEST_FL_OFFLINE)) 43262306a36Sopenharmony_ci return; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (netif_msg_ifdown(h)) 43562306a36Sopenharmony_ci netdev_info(ndev, "self test start\n"); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci hns3_set_selftest_param(h, st_param); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* external loopback test requires that the link is up and the duplex is 44062306a36Sopenharmony_ci * full, do external test first to reduce the whole test time 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) { 44362306a36Sopenharmony_ci hns3_external_lb_prepare(ndev, if_running); 44462306a36Sopenharmony_ci hns3_do_external_lb(ndev, eth_test, data); 44562306a36Sopenharmony_ci hns3_external_lb_restore(ndev, if_running); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci hns3_selftest_prepare(ndev, if_running); 44962306a36Sopenharmony_ci hns3_do_selftest(ndev, st_param, eth_test, data); 45062306a36Sopenharmony_ci hns3_selftest_restore(ndev, if_running); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (netif_msg_ifdown(h)) 45362306a36Sopenharmony_ci netdev_info(ndev, "self test end\n"); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void hns3_update_limit_promisc_mode(struct net_device *netdev, 45762306a36Sopenharmony_ci bool enable) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (enable) 46262306a36Sopenharmony_ci set_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags); 46362306a36Sopenharmony_ci else 46462306a36Sopenharmony_ci clear_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci hns3_request_update_promisc_mode(handle); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic const struct hns3_pflag_desc hns3_priv_flags[HNAE3_PFLAG_MAX] = { 47062306a36Sopenharmony_ci { "limit_promisc", hns3_update_limit_promisc_mode } 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int hns3_get_sset_count(struct net_device *netdev, int stringset) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 47662306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = h->ae_algo->ops; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!ops->get_sset_count) 47962306a36Sopenharmony_ci return -EOPNOTSUPP; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci switch (stringset) { 48262306a36Sopenharmony_ci case ETH_SS_STATS: 48362306a36Sopenharmony_ci return ((HNS3_TQP_STATS_COUNT * h->kinfo.num_tqps) + 48462306a36Sopenharmony_ci ops->get_sset_count(h, stringset)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci case ETH_SS_TEST: 48762306a36Sopenharmony_ci return ops->get_sset_count(h, stringset); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 49062306a36Sopenharmony_ci return HNAE3_PFLAG_MAX; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci default: 49362306a36Sopenharmony_ci return -EOPNOTSUPP; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void *hns3_update_strings(u8 *data, const struct hns3_stats *stats, 49862306a36Sopenharmony_ci u32 stat_count, u32 num_tqps, const char *prefix) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci#define MAX_PREFIX_SIZE (6 + 4) 50162306a36Sopenharmony_ci u32 size_left; 50262306a36Sopenharmony_ci u32 i, j; 50362306a36Sopenharmony_ci u32 n1; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci for (i = 0; i < num_tqps; i++) { 50662306a36Sopenharmony_ci for (j = 0; j < stat_count; j++) { 50762306a36Sopenharmony_ci data[ETH_GSTRING_LEN - 1] = '\0'; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* first, prepend the prefix string */ 51062306a36Sopenharmony_ci n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%u_", 51162306a36Sopenharmony_ci prefix, i); 51262306a36Sopenharmony_ci size_left = (ETH_GSTRING_LEN - 1) - n1; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* now, concatenate the stats string to it */ 51562306a36Sopenharmony_ci strncat(data, stats[j].stats_string, size_left); 51662306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return data; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct hnae3_knic_private_info *kinfo = &handle->kinfo; 52662306a36Sopenharmony_ci const char tx_prefix[] = "txq"; 52762306a36Sopenharmony_ci const char rx_prefix[] = "rxq"; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* get strings for Tx */ 53062306a36Sopenharmony_ci data = hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT, 53162306a36Sopenharmony_ci kinfo->num_tqps, tx_prefix); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* get strings for Rx */ 53462306a36Sopenharmony_ci data = hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT, 53562306a36Sopenharmony_ci kinfo->num_tqps, rx_prefix); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return data; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 54362306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = h->ae_algo->ops; 54462306a36Sopenharmony_ci char *buff = (char *)data; 54562306a36Sopenharmony_ci int i; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!ops->get_strings) 54862306a36Sopenharmony_ci return; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci switch (stringset) { 55162306a36Sopenharmony_ci case ETH_SS_STATS: 55262306a36Sopenharmony_ci buff = hns3_get_strings_tqps(h, buff); 55362306a36Sopenharmony_ci ops->get_strings(h, stringset, (u8 *)buff); 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case ETH_SS_TEST: 55662306a36Sopenharmony_ci ops->get_strings(h, stringset, data); 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 55962306a36Sopenharmony_ci for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) { 56062306a36Sopenharmony_ci snprintf(buff, ETH_GSTRING_LEN, "%s", 56162306a36Sopenharmony_ci hns3_priv_flags[i].name); 56262306a36Sopenharmony_ci buff += ETH_GSTRING_LEN; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci default: 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct hnae3_knic_private_info *kinfo = &handle->kinfo; 57362306a36Sopenharmony_ci struct hns3_nic_priv *nic_priv = handle->priv; 57462306a36Sopenharmony_ci struct hns3_enet_ring *ring; 57562306a36Sopenharmony_ci u8 *stat; 57662306a36Sopenharmony_ci int i, j; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* get stats for Tx */ 57962306a36Sopenharmony_ci for (i = 0; i < kinfo->num_tqps; i++) { 58062306a36Sopenharmony_ci ring = &nic_priv->ring[i]; 58162306a36Sopenharmony_ci for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) { 58262306a36Sopenharmony_ci stat = (u8 *)ring + hns3_txq_stats[j].stats_offset; 58362306a36Sopenharmony_ci *data++ = *(u64 *)stat; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* get stats for Rx */ 58862306a36Sopenharmony_ci for (i = 0; i < kinfo->num_tqps; i++) { 58962306a36Sopenharmony_ci ring = &nic_priv->ring[i + kinfo->num_tqps]; 59062306a36Sopenharmony_ci for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) { 59162306a36Sopenharmony_ci stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset; 59262306a36Sopenharmony_ci *data++ = *(u64 *)stat; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return data; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* hns3_get_stats - get detail statistics. 60062306a36Sopenharmony_ci * @netdev: net device 60162306a36Sopenharmony_ci * @stats: statistics info. 60262306a36Sopenharmony_ci * @data: statistics data. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_cistatic void hns3_get_stats(struct net_device *netdev, 60562306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 60862306a36Sopenharmony_ci u64 *p = data; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (hns3_nic_resetting(netdev)) { 61162306a36Sopenharmony_ci netdev_err(netdev, "dev resetting, could not get stats\n"); 61262306a36Sopenharmony_ci return; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!h->ae_algo->ops->get_stats || !h->ae_algo->ops->update_stats) { 61662306a36Sopenharmony_ci netdev_err(netdev, "could not get any statistics\n"); 61762306a36Sopenharmony_ci return; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci h->ae_algo->ops->update_stats(h); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* get per-queue stats */ 62362306a36Sopenharmony_ci p = hns3_get_stats_tqps(h, p); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* get MAC & other misc hardware stats */ 62662306a36Sopenharmony_ci h->ae_algo->ops->get_stats(h, p); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void hns3_get_drvinfo(struct net_device *netdev, 63062306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 63362306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 63462306a36Sopenharmony_ci u32 fw_version; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!h->ae_algo->ops->get_fw_version) { 63762306a36Sopenharmony_ci netdev_err(netdev, "could not get fw version!\n"); 63862306a36Sopenharmony_ci return; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci strscpy(drvinfo->driver, dev_driver_string(&h->pdev->dev), 64262306a36Sopenharmony_ci sizeof(drvinfo->driver)); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(h->pdev), 64562306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci fw_version = priv->ae_handle->ae_algo->ops->get_fw_version(h); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 65062306a36Sopenharmony_ci "%lu.%lu.%lu.%lu", 65162306a36Sopenharmony_ci hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE3_MASK, 65262306a36Sopenharmony_ci HNAE3_FW_VERSION_BYTE3_SHIFT), 65362306a36Sopenharmony_ci hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE2_MASK, 65462306a36Sopenharmony_ci HNAE3_FW_VERSION_BYTE2_SHIFT), 65562306a36Sopenharmony_ci hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE1_MASK, 65662306a36Sopenharmony_ci HNAE3_FW_VERSION_BYTE1_SHIFT), 65762306a36Sopenharmony_ci hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE0_MASK, 65862306a36Sopenharmony_ci HNAE3_FW_VERSION_BYTE0_SHIFT)); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic u32 hns3_get_link(struct net_device *netdev) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (h->ae_algo->ops->get_status) 66662306a36Sopenharmony_ci return h->ae_algo->ops->get_status(h); 66762306a36Sopenharmony_ci else 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void hns3_get_ringparam(struct net_device *netdev, 67262306a36Sopenharmony_ci struct ethtool_ringparam *param, 67362306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_param, 67462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 67762306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 67862306a36Sopenharmony_ci int rx_queue_index = h->kinfo.num_tqps; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (hns3_nic_resetting(netdev) || !priv->ring) { 68162306a36Sopenharmony_ci netdev_err(netdev, "failed to get ringparam value, due to dev resetting or uninited\n"); 68262306a36Sopenharmony_ci return; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci param->tx_max_pending = HNS3_RING_MAX_PENDING; 68662306a36Sopenharmony_ci param->rx_max_pending = HNS3_RING_MAX_PENDING; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci param->tx_pending = priv->ring[0].desc_num; 68962306a36Sopenharmony_ci param->rx_pending = priv->ring[rx_queue_index].desc_num; 69062306a36Sopenharmony_ci kernel_param->rx_buf_len = priv->ring[rx_queue_index].buf_size; 69162306a36Sopenharmony_ci kernel_param->tx_push = test_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, 69262306a36Sopenharmony_ci &priv->state); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void hns3_get_pauseparam(struct net_device *netdev, 69662306a36Sopenharmony_ci struct ethtool_pauseparam *param) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 69962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (!test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps)) 70262306a36Sopenharmony_ci return; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (h->ae_algo->ops->get_pauseparam) 70562306a36Sopenharmony_ci h->ae_algo->ops->get_pauseparam(h, ¶m->autoneg, 70662306a36Sopenharmony_ci ¶m->rx_pause, ¶m->tx_pause); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int hns3_set_pauseparam(struct net_device *netdev, 71062306a36Sopenharmony_ci struct ethtool_pauseparam *param) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 71362306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (!test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps)) 71662306a36Sopenharmony_ci return -EOPNOTSUPP; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci netif_dbg(h, drv, netdev, 71962306a36Sopenharmony_ci "set pauseparam: autoneg=%u, rx:%u, tx:%u\n", 72062306a36Sopenharmony_ci param->autoneg, param->rx_pause, param->tx_pause); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (h->ae_algo->ops->set_pauseparam) 72362306a36Sopenharmony_ci return h->ae_algo->ops->set_pauseparam(h, param->autoneg, 72462306a36Sopenharmony_ci param->rx_pause, 72562306a36Sopenharmony_ci param->tx_pause); 72662306a36Sopenharmony_ci return -EOPNOTSUPP; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic void hns3_get_ksettings(struct hnae3_handle *h, 73062306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = h->ae_algo->ops; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* 1.auto_neg & speed & duplex from cmd */ 73562306a36Sopenharmony_ci if (ops->get_ksettings_an_result) 73662306a36Sopenharmony_ci ops->get_ksettings_an_result(h, 73762306a36Sopenharmony_ci &cmd->base.autoneg, 73862306a36Sopenharmony_ci &cmd->base.speed, 73962306a36Sopenharmony_ci &cmd->base.duplex, 74062306a36Sopenharmony_ci &cmd->lanes); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* 2.get link mode */ 74362306a36Sopenharmony_ci if (ops->get_link_mode) 74462306a36Sopenharmony_ci ops->get_link_mode(h, 74562306a36Sopenharmony_ci cmd->link_modes.supported, 74662306a36Sopenharmony_ci cmd->link_modes.advertising); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* 3.mdix_ctrl&mdix get from phy reg */ 74962306a36Sopenharmony_ci if (ops->get_mdix_mode) 75062306a36Sopenharmony_ci ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl, 75162306a36Sopenharmony_ci &cmd->base.eth_tp_mdix); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int hns3_get_link_ksettings(struct net_device *netdev, 75562306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 75862306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 75962306a36Sopenharmony_ci const struct hnae3_ae_ops *ops; 76062306a36Sopenharmony_ci u8 module_type; 76162306a36Sopenharmony_ci u8 media_type; 76262306a36Sopenharmony_ci u8 link_stat; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ops = h->ae_algo->ops; 76562306a36Sopenharmony_ci if (ops->get_media_type) 76662306a36Sopenharmony_ci ops->get_media_type(h, &media_type, &module_type); 76762306a36Sopenharmony_ci else 76862306a36Sopenharmony_ci return -EOPNOTSUPP; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci switch (media_type) { 77162306a36Sopenharmony_ci case HNAE3_MEDIA_TYPE_NONE: 77262306a36Sopenharmony_ci cmd->base.port = PORT_NONE; 77362306a36Sopenharmony_ci hns3_get_ksettings(h, cmd); 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case HNAE3_MEDIA_TYPE_FIBER: 77662306a36Sopenharmony_ci if (module_type == HNAE3_MODULE_TYPE_UNKNOWN) 77762306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 77862306a36Sopenharmony_ci else if (module_type == HNAE3_MODULE_TYPE_CR) 77962306a36Sopenharmony_ci cmd->base.port = PORT_DA; 78062306a36Sopenharmony_ci else 78162306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci hns3_get_ksettings(h, cmd); 78462306a36Sopenharmony_ci break; 78562306a36Sopenharmony_ci case HNAE3_MEDIA_TYPE_BACKPLANE: 78662306a36Sopenharmony_ci cmd->base.port = PORT_NONE; 78762306a36Sopenharmony_ci hns3_get_ksettings(h, cmd); 78862306a36Sopenharmony_ci break; 78962306a36Sopenharmony_ci case HNAE3_MEDIA_TYPE_COPPER: 79062306a36Sopenharmony_ci cmd->base.port = PORT_TP; 79162306a36Sopenharmony_ci if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) && 79262306a36Sopenharmony_ci ops->get_phy_link_ksettings) 79362306a36Sopenharmony_ci ops->get_phy_link_ksettings(h, cmd); 79462306a36Sopenharmony_ci else if (!netdev->phydev) 79562306a36Sopenharmony_ci hns3_get_ksettings(h, cmd); 79662306a36Sopenharmony_ci else 79762306a36Sopenharmony_ci phy_ethtool_ksettings_get(netdev->phydev, cmd); 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci default: 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci netdev_warn(netdev, "Unknown media type"); 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* mdio_support */ 80662306a36Sopenharmony_ci cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci link_stat = hns3_get_link(netdev); 80962306a36Sopenharmony_ci if (!link_stat) { 81062306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 81162306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return 0; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int hns3_check_ksettings_param(const struct net_device *netdev, 81862306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 82162306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 82262306a36Sopenharmony_ci u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN; 82362306a36Sopenharmony_ci u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN; 82462306a36Sopenharmony_ci u32 lane_num; 82562306a36Sopenharmony_ci u8 autoneg; 82662306a36Sopenharmony_ci u32 speed; 82762306a36Sopenharmony_ci u8 duplex; 82862306a36Sopenharmony_ci int ret; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* hw doesn't support use specified speed and duplex to negotiate, 83162306a36Sopenharmony_ci * unnecessary to check them when autoneg on. 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci if (cmd->base.autoneg) 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (ops->get_ksettings_an_result) { 83762306a36Sopenharmony_ci ops->get_ksettings_an_result(handle, &autoneg, &speed, &duplex, &lane_num); 83862306a36Sopenharmony_ci if (cmd->base.autoneg == autoneg && cmd->base.speed == speed && 83962306a36Sopenharmony_ci cmd->base.duplex == duplex && cmd->lanes == lane_num) 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (ops->get_media_type) 84462306a36Sopenharmony_ci ops->get_media_type(handle, &media_type, &module_type); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (cmd->base.duplex == DUPLEX_HALF && 84762306a36Sopenharmony_ci media_type != HNAE3_MEDIA_TYPE_COPPER) { 84862306a36Sopenharmony_ci netdev_err(netdev, 84962306a36Sopenharmony_ci "only copper port supports half duplex!"); 85062306a36Sopenharmony_ci return -EINVAL; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (ops->check_port_speed) { 85462306a36Sopenharmony_ci ret = ops->check_port_speed(handle, cmd->base.speed); 85562306a36Sopenharmony_ci if (ret) { 85662306a36Sopenharmony_ci netdev_err(netdev, "unsupported speed\n"); 85762306a36Sopenharmony_ci return ret; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic int hns3_set_link_ksettings(struct net_device *netdev, 86562306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 86862306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 86962306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 87062306a36Sopenharmony_ci int ret; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* Chip don't support this mode. */ 87362306a36Sopenharmony_ci if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF) 87462306a36Sopenharmony_ci return -EINVAL; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (cmd->lanes && !hnae3_ae_dev_lane_num_supported(ae_dev)) 87762306a36Sopenharmony_ci return -EOPNOTSUPP; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci netif_dbg(handle, drv, netdev, 88062306a36Sopenharmony_ci "set link(%s): autoneg=%u, speed=%u, duplex=%u, lanes=%u\n", 88162306a36Sopenharmony_ci netdev->phydev ? "phy" : "mac", 88262306a36Sopenharmony_ci cmd->base.autoneg, cmd->base.speed, cmd->base.duplex, 88362306a36Sopenharmony_ci cmd->lanes); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* Only support ksettings_set for netdev with phy attached for now */ 88662306a36Sopenharmony_ci if (netdev->phydev) { 88762306a36Sopenharmony_ci if (cmd->base.speed == SPEED_1000 && 88862306a36Sopenharmony_ci cmd->base.autoneg == AUTONEG_DISABLE) 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return phy_ethtool_ksettings_set(netdev->phydev, cmd); 89262306a36Sopenharmony_ci } else if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) && 89362306a36Sopenharmony_ci ops->set_phy_link_ksettings) { 89462306a36Sopenharmony_ci return ops->set_phy_link_ksettings(handle, cmd); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) 89862306a36Sopenharmony_ci return -EOPNOTSUPP; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci ret = hns3_check_ksettings_param(netdev, cmd); 90162306a36Sopenharmony_ci if (ret) 90262306a36Sopenharmony_ci return ret; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (ops->set_autoneg) { 90562306a36Sopenharmony_ci ret = ops->set_autoneg(handle, cmd->base.autoneg); 90662306a36Sopenharmony_ci if (ret) 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* hw doesn't support use specified speed and duplex to negotiate, 91162306a36Sopenharmony_ci * ignore them when autoneg on. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ci if (cmd->base.autoneg) { 91462306a36Sopenharmony_ci netdev_info(netdev, 91562306a36Sopenharmony_ci "autoneg is on, ignore the speed and duplex\n"); 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (ops->cfg_mac_speed_dup_h) 92062306a36Sopenharmony_ci ret = ops->cfg_mac_speed_dup_h(handle, cmd->base.speed, 92162306a36Sopenharmony_ci cmd->base.duplex, (u8)(cmd->lanes)); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return ret; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic u32 hns3_get_rss_key_size(struct net_device *netdev) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (!h->ae_algo->ops->get_rss_key_size) 93162306a36Sopenharmony_ci return 0; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci return h->ae_algo->ops->get_rss_key_size(h); 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic u32 hns3_get_rss_indir_size(struct net_device *netdev) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 93962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return ae_dev->dev_specs.rss_ind_tbl_size; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key, 94562306a36Sopenharmony_ci u8 *hfunc) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (!h->ae_algo->ops->get_rss) 95062306a36Sopenharmony_ci return -EOPNOTSUPP; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return h->ae_algo->ops->get_rss(h, indir, key, hfunc); 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic int hns3_set_rss(struct net_device *netdev, const u32 *indir, 95662306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 95962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (!h->ae_algo->ops->set_rss) 96262306a36Sopenharmony_ci return -EOPNOTSUPP; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if ((ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 && 96562306a36Sopenharmony_ci hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE && 96662306a36Sopenharmony_ci hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) { 96762306a36Sopenharmony_ci netdev_err(netdev, "hash func not supported\n"); 96862306a36Sopenharmony_ci return -EOPNOTSUPP; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (!indir) { 97262306a36Sopenharmony_ci netdev_err(netdev, 97362306a36Sopenharmony_ci "set rss failed for indir is empty\n"); 97462306a36Sopenharmony_ci return -EOPNOTSUPP; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return h->ae_algo->ops->set_rss(h, indir, key, hfunc); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic int hns3_get_rxnfc(struct net_device *netdev, 98162306a36Sopenharmony_ci struct ethtool_rxnfc *cmd, 98262306a36Sopenharmony_ci u32 *rule_locs) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci switch (cmd->cmd) { 98762306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 98862306a36Sopenharmony_ci cmd->data = h->kinfo.num_tqps; 98962306a36Sopenharmony_ci return 0; 99062306a36Sopenharmony_ci case ETHTOOL_GRXFH: 99162306a36Sopenharmony_ci if (h->ae_algo->ops->get_rss_tuple) 99262306a36Sopenharmony_ci return h->ae_algo->ops->get_rss_tuple(h, cmd); 99362306a36Sopenharmony_ci return -EOPNOTSUPP; 99462306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 99562306a36Sopenharmony_ci if (h->ae_algo->ops->get_fd_rule_cnt) 99662306a36Sopenharmony_ci return h->ae_algo->ops->get_fd_rule_cnt(h, cmd); 99762306a36Sopenharmony_ci return -EOPNOTSUPP; 99862306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 99962306a36Sopenharmony_ci if (h->ae_algo->ops->get_fd_rule_info) 100062306a36Sopenharmony_ci return h->ae_algo->ops->get_fd_rule_info(h, cmd); 100162306a36Sopenharmony_ci return -EOPNOTSUPP; 100262306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 100362306a36Sopenharmony_ci if (h->ae_algo->ops->get_fd_all_rules) 100462306a36Sopenharmony_ci return h->ae_algo->ops->get_fd_all_rules(h, cmd, 100562306a36Sopenharmony_ci rule_locs); 100662306a36Sopenharmony_ci return -EOPNOTSUPP; 100762306a36Sopenharmony_ci default: 100862306a36Sopenharmony_ci return -EOPNOTSUPP; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic const struct hns3_reset_type_map hns3_reset_type[] = { 101362306a36Sopenharmony_ci {ETH_RESET_MGMT, HNAE3_IMP_RESET}, 101462306a36Sopenharmony_ci {ETH_RESET_ALL, HNAE3_GLOBAL_RESET}, 101562306a36Sopenharmony_ci {ETH_RESET_DEDICATED, HNAE3_FUNC_RESET}, 101662306a36Sopenharmony_ci}; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic const struct hns3_reset_type_map hns3vf_reset_type[] = { 101962306a36Sopenharmony_ci {ETH_RESET_DEDICATED, HNAE3_VF_FUNC_RESET}, 102062306a36Sopenharmony_ci}; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int hns3_set_reset(struct net_device *netdev, u32 *flags) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci enum hnae3_reset_type rst_type = HNAE3_NONE_RESET; 102562306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 102662306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 102762306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = h->ae_algo->ops; 102862306a36Sopenharmony_ci const struct hns3_reset_type_map *rst_type_map; 102962306a36Sopenharmony_ci enum ethtool_reset_flags rst_flags; 103062306a36Sopenharmony_ci u32 i, size; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (ops->ae_dev_resetting && ops->ae_dev_resetting(h)) 103362306a36Sopenharmony_ci return -EBUSY; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (!ops->set_default_reset_request || !ops->reset_event) 103662306a36Sopenharmony_ci return -EOPNOTSUPP; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (h->flags & HNAE3_SUPPORT_VF) { 103962306a36Sopenharmony_ci rst_type_map = hns3vf_reset_type; 104062306a36Sopenharmony_ci size = ARRAY_SIZE(hns3vf_reset_type); 104162306a36Sopenharmony_ci } else { 104262306a36Sopenharmony_ci rst_type_map = hns3_reset_type; 104362306a36Sopenharmony_ci size = ARRAY_SIZE(hns3_reset_type); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci for (i = 0; i < size; i++) { 104762306a36Sopenharmony_ci if (rst_type_map[i].rst_flags == *flags) { 104862306a36Sopenharmony_ci rst_type = rst_type_map[i].rst_type; 104962306a36Sopenharmony_ci rst_flags = rst_type_map[i].rst_flags; 105062306a36Sopenharmony_ci break; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (rst_type == HNAE3_NONE_RESET || 105562306a36Sopenharmony_ci (rst_type == HNAE3_IMP_RESET && 105662306a36Sopenharmony_ci ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)) 105762306a36Sopenharmony_ci return -EOPNOTSUPP; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci netdev_info(netdev, "Setting reset type %d\n", rst_type); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci ops->set_default_reset_request(ae_dev, rst_type); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci ops->reset_event(h->pdev, h); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci *flags &= ~rst_flags; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci return 0; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic void hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, 107162306a36Sopenharmony_ci u32 tx_desc_num, u32 rx_desc_num) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 107462306a36Sopenharmony_ci int i; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci h->kinfo.num_tx_desc = tx_desc_num; 107762306a36Sopenharmony_ci h->kinfo.num_rx_desc = rx_desc_num; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci for (i = 0; i < h->kinfo.num_tqps; i++) { 108062306a36Sopenharmony_ci priv->ring[i].desc_num = tx_desc_num; 108162306a36Sopenharmony_ci priv->ring[i + h->kinfo.num_tqps].desc_num = rx_desc_num; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic struct hns3_enet_ring *hns3_backup_ringparam(struct hns3_nic_priv *priv) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct hnae3_handle *handle = priv->ae_handle; 108862306a36Sopenharmony_ci struct hns3_enet_ring *tmp_rings; 108962306a36Sopenharmony_ci int i; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci tmp_rings = kcalloc(handle->kinfo.num_tqps * 2, 109262306a36Sopenharmony_ci sizeof(struct hns3_enet_ring), GFP_KERNEL); 109362306a36Sopenharmony_ci if (!tmp_rings) 109462306a36Sopenharmony_ci return NULL; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci for (i = 0; i < handle->kinfo.num_tqps * 2; i++) { 109762306a36Sopenharmony_ci memcpy(&tmp_rings[i], &priv->ring[i], 109862306a36Sopenharmony_ci sizeof(struct hns3_enet_ring)); 109962306a36Sopenharmony_ci tmp_rings[i].skb = NULL; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return tmp_rings; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int hns3_check_ringparam(struct net_device *ndev, 110662306a36Sopenharmony_ci struct ethtool_ringparam *param, 110762306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_param) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci#define RX_BUF_LEN_2K 2048 111062306a36Sopenharmony_ci#define RX_BUF_LEN_4K 4096 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (hns3_nic_resetting(ndev) || !priv->ring) { 111562306a36Sopenharmony_ci netdev_err(ndev, "failed to set ringparam value, due to dev resetting or uninited\n"); 111662306a36Sopenharmony_ci return -EBUSY; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (param->rx_mini_pending || param->rx_jumbo_pending) 112162306a36Sopenharmony_ci return -EINVAL; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (kernel_param->rx_buf_len != RX_BUF_LEN_2K && 112462306a36Sopenharmony_ci kernel_param->rx_buf_len != RX_BUF_LEN_4K) { 112562306a36Sopenharmony_ci netdev_err(ndev, "Rx buf len only support 2048 and 4096\n"); 112662306a36Sopenharmony_ci return -EINVAL; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (param->tx_pending > HNS3_RING_MAX_PENDING || 113062306a36Sopenharmony_ci param->tx_pending < HNS3_RING_MIN_PENDING || 113162306a36Sopenharmony_ci param->rx_pending > HNS3_RING_MAX_PENDING || 113262306a36Sopenharmony_ci param->rx_pending < HNS3_RING_MIN_PENDING) { 113362306a36Sopenharmony_ci netdev_err(ndev, "Queue depth out of range [%d-%d]\n", 113462306a36Sopenharmony_ci HNS3_RING_MIN_PENDING, HNS3_RING_MAX_PENDING); 113562306a36Sopenharmony_ci return -EINVAL; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return 0; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic bool 114262306a36Sopenharmony_cihns3_is_ringparam_changed(struct net_device *ndev, 114362306a36Sopenharmony_ci struct ethtool_ringparam *param, 114462306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_param, 114562306a36Sopenharmony_ci struct hns3_ring_param *old_ringparam, 114662306a36Sopenharmony_ci struct hns3_ring_param *new_ringparam) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 114962306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 115062306a36Sopenharmony_ci u16 queue_num = h->kinfo.num_tqps; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci new_ringparam->tx_desc_num = ALIGN(param->tx_pending, 115362306a36Sopenharmony_ci HNS3_RING_BD_MULTIPLE); 115462306a36Sopenharmony_ci new_ringparam->rx_desc_num = ALIGN(param->rx_pending, 115562306a36Sopenharmony_ci HNS3_RING_BD_MULTIPLE); 115662306a36Sopenharmony_ci old_ringparam->tx_desc_num = priv->ring[0].desc_num; 115762306a36Sopenharmony_ci old_ringparam->rx_desc_num = priv->ring[queue_num].desc_num; 115862306a36Sopenharmony_ci old_ringparam->rx_buf_len = priv->ring[queue_num].buf_size; 115962306a36Sopenharmony_ci new_ringparam->rx_buf_len = kernel_param->rx_buf_len; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (old_ringparam->tx_desc_num == new_ringparam->tx_desc_num && 116262306a36Sopenharmony_ci old_ringparam->rx_desc_num == new_ringparam->rx_desc_num && 116362306a36Sopenharmony_ci old_ringparam->rx_buf_len == new_ringparam->rx_buf_len) { 116462306a36Sopenharmony_ci netdev_info(ndev, "descriptor number and rx buffer length not changed\n"); 116562306a36Sopenharmony_ci return false; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return true; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int hns3_change_rx_buf_len(struct net_device *ndev, u32 rx_buf_len) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 117462306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 117562306a36Sopenharmony_ci int i; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci h->kinfo.rx_buf_len = rx_buf_len; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci for (i = 0; i < h->kinfo.num_tqps; i++) { 118062306a36Sopenharmony_ci h->kinfo.tqp[i]->buf_size = rx_buf_len; 118162306a36Sopenharmony_ci priv->ring[i + h->kinfo.num_tqps].buf_size = rx_buf_len; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci return 0; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic int hns3_set_tx_push(struct net_device *netdev, u32 tx_push) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 119062306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 119162306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); 119262306a36Sopenharmony_ci u32 old_state = test_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (!test_bit(HNAE3_DEV_SUPPORT_TX_PUSH_B, ae_dev->caps) && tx_push) 119562306a36Sopenharmony_ci return -EOPNOTSUPP; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (tx_push == old_state) 119862306a36Sopenharmony_ci return 0; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci netdev_dbg(netdev, "Changing tx push from %s to %s\n", 120162306a36Sopenharmony_ci old_state ? "on" : "off", tx_push ? "on" : "off"); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (tx_push) 120462306a36Sopenharmony_ci set_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state); 120562306a36Sopenharmony_ci else 120662306a36Sopenharmony_ci clear_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic int hns3_set_ringparam(struct net_device *ndev, 121262306a36Sopenharmony_ci struct ethtool_ringparam *param, 121362306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_param, 121462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct hns3_ring_param old_ringparam, new_ringparam; 121762306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(ndev); 121862306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 121962306a36Sopenharmony_ci struct hns3_enet_ring *tmp_rings; 122062306a36Sopenharmony_ci bool if_running = netif_running(ndev); 122162306a36Sopenharmony_ci int ret, i; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci ret = hns3_check_ringparam(ndev, param, kernel_param); 122462306a36Sopenharmony_ci if (ret) 122562306a36Sopenharmony_ci return ret; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci ret = hns3_set_tx_push(ndev, kernel_param->tx_push); 122862306a36Sopenharmony_ci if (ret) 122962306a36Sopenharmony_ci return ret; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (!hns3_is_ringparam_changed(ndev, param, kernel_param, 123262306a36Sopenharmony_ci &old_ringparam, &new_ringparam)) 123362306a36Sopenharmony_ci return 0; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci tmp_rings = hns3_backup_ringparam(priv); 123662306a36Sopenharmony_ci if (!tmp_rings) { 123762306a36Sopenharmony_ci netdev_err(ndev, "backup ring param failed by allocating memory fail\n"); 123862306a36Sopenharmony_ci return -ENOMEM; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci netdev_info(ndev, 124262306a36Sopenharmony_ci "Changing Tx/Rx ring depth from %u/%u to %u/%u, Changing rx buffer len from %u to %u\n", 124362306a36Sopenharmony_ci old_ringparam.tx_desc_num, old_ringparam.rx_desc_num, 124462306a36Sopenharmony_ci new_ringparam.tx_desc_num, new_ringparam.rx_desc_num, 124562306a36Sopenharmony_ci old_ringparam.rx_buf_len, new_ringparam.rx_buf_len); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (if_running) 124862306a36Sopenharmony_ci ndev->netdev_ops->ndo_stop(ndev); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci hns3_change_all_ring_bd_num(priv, new_ringparam.tx_desc_num, 125162306a36Sopenharmony_ci new_ringparam.rx_desc_num); 125262306a36Sopenharmony_ci hns3_change_rx_buf_len(ndev, new_ringparam.rx_buf_len); 125362306a36Sopenharmony_ci ret = hns3_init_all_ring(priv); 125462306a36Sopenharmony_ci if (ret) { 125562306a36Sopenharmony_ci netdev_err(ndev, "set ringparam fail, revert to old value(%d)\n", 125662306a36Sopenharmony_ci ret); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci hns3_change_rx_buf_len(ndev, old_ringparam.rx_buf_len); 125962306a36Sopenharmony_ci hns3_change_all_ring_bd_num(priv, old_ringparam.tx_desc_num, 126062306a36Sopenharmony_ci old_ringparam.rx_desc_num); 126162306a36Sopenharmony_ci for (i = 0; i < h->kinfo.num_tqps * 2; i++) 126262306a36Sopenharmony_ci memcpy(&priv->ring[i], &tmp_rings[i], 126362306a36Sopenharmony_ci sizeof(struct hns3_enet_ring)); 126462306a36Sopenharmony_ci } else { 126562306a36Sopenharmony_ci for (i = 0; i < h->kinfo.num_tqps * 2; i++) 126662306a36Sopenharmony_ci hns3_fini_ring(&tmp_rings[i]); 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci kfree(tmp_rings); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (if_running) 127262306a36Sopenharmony_ci ret = ndev->netdev_ops->ndo_open(ndev); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci return ret; 127562306a36Sopenharmony_ci} 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_cistatic int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci switch (cmd->cmd) { 128262306a36Sopenharmony_ci case ETHTOOL_SRXFH: 128362306a36Sopenharmony_ci if (h->ae_algo->ops->set_rss_tuple) 128462306a36Sopenharmony_ci return h->ae_algo->ops->set_rss_tuple(h, cmd); 128562306a36Sopenharmony_ci return -EOPNOTSUPP; 128662306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 128762306a36Sopenharmony_ci if (h->ae_algo->ops->add_fd_entry) 128862306a36Sopenharmony_ci return h->ae_algo->ops->add_fd_entry(h, cmd); 128962306a36Sopenharmony_ci return -EOPNOTSUPP; 129062306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 129162306a36Sopenharmony_ci if (h->ae_algo->ops->del_fd_entry) 129262306a36Sopenharmony_ci return h->ae_algo->ops->del_fd_entry(h, cmd); 129362306a36Sopenharmony_ci return -EOPNOTSUPP; 129462306a36Sopenharmony_ci default: 129562306a36Sopenharmony_ci return -EOPNOTSUPP; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int hns3_nway_reset(struct net_device *netdev) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 130262306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 130362306a36Sopenharmony_ci struct phy_device *phy = netdev->phydev; 130462306a36Sopenharmony_ci int autoneg; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (!netif_running(netdev)) 130762306a36Sopenharmony_ci return 0; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (hns3_nic_resetting(netdev)) { 131062306a36Sopenharmony_ci netdev_err(netdev, "dev resetting!"); 131162306a36Sopenharmony_ci return -EBUSY; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (!ops->get_autoneg || !ops->restart_autoneg) 131562306a36Sopenharmony_ci return -EOPNOTSUPP; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci autoneg = ops->get_autoneg(handle); 131862306a36Sopenharmony_ci if (autoneg != AUTONEG_ENABLE) { 131962306a36Sopenharmony_ci netdev_err(netdev, 132062306a36Sopenharmony_ci "Autoneg is off, don't support to restart it\n"); 132162306a36Sopenharmony_ci return -EINVAL; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci netif_dbg(handle, drv, netdev, 132562306a36Sopenharmony_ci "nway reset (using %s)\n", phy ? "phy" : "mac"); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (phy) 132862306a36Sopenharmony_ci return genphy_restart_aneg(phy); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return ops->restart_autoneg(handle); 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic void hns3_get_channels(struct net_device *netdev, 133462306a36Sopenharmony_ci struct ethtool_channels *ch) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (h->ae_algo->ops->get_channels) 133962306a36Sopenharmony_ci h->ae_algo->ops->get_channels(h, ch); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic int hns3_get_coalesce(struct net_device *netdev, 134362306a36Sopenharmony_ci struct ethtool_coalesce *cmd, 134462306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 134562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 134862306a36Sopenharmony_ci struct hns3_enet_coalesce *tx_coal = &priv->tx_coal; 134962306a36Sopenharmony_ci struct hns3_enet_coalesce *rx_coal = &priv->rx_coal; 135062306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (hns3_nic_resetting(netdev)) 135362306a36Sopenharmony_ci return -EBUSY; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci cmd->use_adaptive_tx_coalesce = tx_coal->adapt_enable; 135662306a36Sopenharmony_ci cmd->use_adaptive_rx_coalesce = rx_coal->adapt_enable; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci cmd->tx_coalesce_usecs = tx_coal->int_gl; 135962306a36Sopenharmony_ci cmd->rx_coalesce_usecs = rx_coal->int_gl; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci cmd->tx_coalesce_usecs_high = h->kinfo.int_rl_setting; 136262306a36Sopenharmony_ci cmd->rx_coalesce_usecs_high = h->kinfo.int_rl_setting; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci cmd->tx_max_coalesced_frames = tx_coal->int_ql; 136562306a36Sopenharmony_ci cmd->rx_max_coalesced_frames = rx_coal->int_ql; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci kernel_coal->use_cqe_mode_tx = (priv->tx_cqe_mode == 136862306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_CQE); 136962306a36Sopenharmony_ci kernel_coal->use_cqe_mode_rx = (priv->rx_cqe_mode == 137062306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_CQE); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci return 0; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic int hns3_check_gl_coalesce_para(struct net_device *netdev, 137662306a36Sopenharmony_ci struct ethtool_coalesce *cmd) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 137962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 138062306a36Sopenharmony_ci u32 rx_gl, tx_gl; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (cmd->rx_coalesce_usecs > ae_dev->dev_specs.max_int_gl) { 138362306a36Sopenharmony_ci netdev_err(netdev, 138462306a36Sopenharmony_ci "invalid rx-usecs value, rx-usecs range is 0-%u\n", 138562306a36Sopenharmony_ci ae_dev->dev_specs.max_int_gl); 138662306a36Sopenharmony_ci return -EINVAL; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (cmd->tx_coalesce_usecs > ae_dev->dev_specs.max_int_gl) { 139062306a36Sopenharmony_ci netdev_err(netdev, 139162306a36Sopenharmony_ci "invalid tx-usecs value, tx-usecs range is 0-%u\n", 139262306a36Sopenharmony_ci ae_dev->dev_specs.max_int_gl); 139362306a36Sopenharmony_ci return -EINVAL; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* device version above V3(include V3), GL uses 1us unit, 139762306a36Sopenharmony_ci * so the round down is not needed. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_ci if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3) 140062306a36Sopenharmony_ci return 0; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci rx_gl = hns3_gl_round_down(cmd->rx_coalesce_usecs); 140362306a36Sopenharmony_ci if (rx_gl != cmd->rx_coalesce_usecs) { 140462306a36Sopenharmony_ci netdev_info(netdev, 140562306a36Sopenharmony_ci "rx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n", 140662306a36Sopenharmony_ci cmd->rx_coalesce_usecs, rx_gl); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci tx_gl = hns3_gl_round_down(cmd->tx_coalesce_usecs); 141062306a36Sopenharmony_ci if (tx_gl != cmd->tx_coalesce_usecs) { 141162306a36Sopenharmony_ci netdev_info(netdev, 141262306a36Sopenharmony_ci "tx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n", 141362306a36Sopenharmony_ci cmd->tx_coalesce_usecs, tx_gl); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci return 0; 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic int hns3_check_rl_coalesce_para(struct net_device *netdev, 142062306a36Sopenharmony_ci struct ethtool_coalesce *cmd) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci u32 rl; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci if (cmd->tx_coalesce_usecs_high != cmd->rx_coalesce_usecs_high) { 142562306a36Sopenharmony_ci netdev_err(netdev, 142662306a36Sopenharmony_ci "tx_usecs_high must be same as rx_usecs_high.\n"); 142762306a36Sopenharmony_ci return -EINVAL; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (cmd->rx_coalesce_usecs_high > HNS3_INT_RL_MAX) { 143162306a36Sopenharmony_ci netdev_err(netdev, 143262306a36Sopenharmony_ci "Invalid usecs_high value, usecs_high range is 0-%d\n", 143362306a36Sopenharmony_ci HNS3_INT_RL_MAX); 143462306a36Sopenharmony_ci return -EINVAL; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci rl = hns3_rl_round_down(cmd->rx_coalesce_usecs_high); 143862306a36Sopenharmony_ci if (rl != cmd->rx_coalesce_usecs_high) { 143962306a36Sopenharmony_ci netdev_info(netdev, 144062306a36Sopenharmony_ci "usecs_high(%u) rounded down to %u, because it must be multiple of 4.\n", 144162306a36Sopenharmony_ci cmd->rx_coalesce_usecs_high, rl); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci return 0; 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic int hns3_check_ql_coalesce_param(struct net_device *netdev, 144862306a36Sopenharmony_ci struct ethtool_coalesce *cmd) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 145162306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if ((cmd->tx_max_coalesced_frames || cmd->rx_max_coalesced_frames) && 145462306a36Sopenharmony_ci !ae_dev->dev_specs.int_ql_max) { 145562306a36Sopenharmony_ci netdev_err(netdev, "coalesced frames is not supported\n"); 145662306a36Sopenharmony_ci return -EOPNOTSUPP; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (cmd->tx_max_coalesced_frames > ae_dev->dev_specs.int_ql_max || 146062306a36Sopenharmony_ci cmd->rx_max_coalesced_frames > ae_dev->dev_specs.int_ql_max) { 146162306a36Sopenharmony_ci netdev_err(netdev, 146262306a36Sopenharmony_ci "invalid coalesced_frames value, range is 0-%u\n", 146362306a36Sopenharmony_ci ae_dev->dev_specs.int_ql_max); 146462306a36Sopenharmony_ci return -ERANGE; 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci return 0; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_cistatic int 147162306a36Sopenharmony_cihns3_check_cqe_coalesce_param(struct net_device *netdev, 147262306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 147562306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if ((kernel_coal->use_cqe_mode_tx || kernel_coal->use_cqe_mode_rx) && 147862306a36Sopenharmony_ci !hnae3_ae_dev_cq_supported(ae_dev)) { 147962306a36Sopenharmony_ci netdev_err(netdev, "coalesced cqe mode is not supported\n"); 148062306a36Sopenharmony_ci return -EOPNOTSUPP; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return 0; 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistatic int 148762306a36Sopenharmony_cihns3_check_coalesce_para(struct net_device *netdev, 148862306a36Sopenharmony_ci struct ethtool_coalesce *cmd, 148962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci int ret; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci ret = hns3_check_cqe_coalesce_param(netdev, kernel_coal); 149462306a36Sopenharmony_ci if (ret) 149562306a36Sopenharmony_ci return ret; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci ret = hns3_check_gl_coalesce_para(netdev, cmd); 149862306a36Sopenharmony_ci if (ret) { 149962306a36Sopenharmony_ci netdev_err(netdev, 150062306a36Sopenharmony_ci "Check gl coalesce param fail. ret = %d\n", ret); 150162306a36Sopenharmony_ci return ret; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci ret = hns3_check_rl_coalesce_para(netdev, cmd); 150562306a36Sopenharmony_ci if (ret) { 150662306a36Sopenharmony_ci netdev_err(netdev, 150762306a36Sopenharmony_ci "Check rl coalesce param fail. ret = %d\n", ret); 150862306a36Sopenharmony_ci return ret; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci return hns3_check_ql_coalesce_param(netdev, cmd); 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic void hns3_set_coalesce_per_queue(struct net_device *netdev, 151562306a36Sopenharmony_ci struct ethtool_coalesce *cmd, 151662306a36Sopenharmony_ci u32 queue) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci struct hns3_enet_tqp_vector *tx_vector, *rx_vector; 151962306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 152062306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 152162306a36Sopenharmony_ci int queue_num = h->kinfo.num_tqps; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci tx_vector = priv->ring[queue].tqp_vector; 152462306a36Sopenharmony_ci rx_vector = priv->ring[queue_num + queue].tqp_vector; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci tx_vector->tx_group.coal.adapt_enable = 152762306a36Sopenharmony_ci cmd->use_adaptive_tx_coalesce; 152862306a36Sopenharmony_ci rx_vector->rx_group.coal.adapt_enable = 152962306a36Sopenharmony_ci cmd->use_adaptive_rx_coalesce; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci tx_vector->tx_group.coal.int_gl = cmd->tx_coalesce_usecs; 153262306a36Sopenharmony_ci rx_vector->rx_group.coal.int_gl = cmd->rx_coalesce_usecs; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci tx_vector->tx_group.coal.int_ql = cmd->tx_max_coalesced_frames; 153562306a36Sopenharmony_ci rx_vector->rx_group.coal.int_ql = cmd->rx_max_coalesced_frames; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci hns3_set_vector_coalesce_tx_gl(tx_vector, 153862306a36Sopenharmony_ci tx_vector->tx_group.coal.int_gl); 153962306a36Sopenharmony_ci hns3_set_vector_coalesce_rx_gl(rx_vector, 154062306a36Sopenharmony_ci rx_vector->rx_group.coal.int_gl); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci hns3_set_vector_coalesce_rl(tx_vector, h->kinfo.int_rl_setting); 154362306a36Sopenharmony_ci hns3_set_vector_coalesce_rl(rx_vector, h->kinfo.int_rl_setting); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (tx_vector->tx_group.coal.ql_enable) 154662306a36Sopenharmony_ci hns3_set_vector_coalesce_tx_ql(tx_vector, 154762306a36Sopenharmony_ci tx_vector->tx_group.coal.int_ql); 154862306a36Sopenharmony_ci if (rx_vector->rx_group.coal.ql_enable) 154962306a36Sopenharmony_ci hns3_set_vector_coalesce_rx_ql(rx_vector, 155062306a36Sopenharmony_ci rx_vector->rx_group.coal.int_ql); 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic int hns3_set_coalesce(struct net_device *netdev, 155462306a36Sopenharmony_ci struct ethtool_coalesce *cmd, 155562306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 155662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 155962306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 156062306a36Sopenharmony_ci struct hns3_enet_coalesce *tx_coal = &priv->tx_coal; 156162306a36Sopenharmony_ci struct hns3_enet_coalesce *rx_coal = &priv->rx_coal; 156262306a36Sopenharmony_ci u16 queue_num = h->kinfo.num_tqps; 156362306a36Sopenharmony_ci enum dim_cq_period_mode tx_mode; 156462306a36Sopenharmony_ci enum dim_cq_period_mode rx_mode; 156562306a36Sopenharmony_ci int ret; 156662306a36Sopenharmony_ci int i; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (hns3_nic_resetting(netdev)) 156962306a36Sopenharmony_ci return -EBUSY; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci ret = hns3_check_coalesce_para(netdev, cmd, kernel_coal); 157262306a36Sopenharmony_ci if (ret) 157362306a36Sopenharmony_ci return ret; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci h->kinfo.int_rl_setting = 157662306a36Sopenharmony_ci hns3_rl_round_down(cmd->rx_coalesce_usecs_high); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci tx_coal->adapt_enable = cmd->use_adaptive_tx_coalesce; 157962306a36Sopenharmony_ci rx_coal->adapt_enable = cmd->use_adaptive_rx_coalesce; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci tx_coal->int_gl = cmd->tx_coalesce_usecs; 158262306a36Sopenharmony_ci rx_coal->int_gl = cmd->rx_coalesce_usecs; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci tx_coal->int_ql = cmd->tx_max_coalesced_frames; 158562306a36Sopenharmony_ci rx_coal->int_ql = cmd->rx_max_coalesced_frames; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci for (i = 0; i < queue_num; i++) 158862306a36Sopenharmony_ci hns3_set_coalesce_per_queue(netdev, cmd, i); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci tx_mode = kernel_coal->use_cqe_mode_tx ? 159162306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_CQE : 159262306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_EQE; 159362306a36Sopenharmony_ci rx_mode = kernel_coal->use_cqe_mode_rx ? 159462306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_CQE : 159562306a36Sopenharmony_ci DIM_CQ_PERIOD_MODE_START_FROM_EQE; 159662306a36Sopenharmony_ci hns3_cq_period_mode_init(priv, tx_mode, rx_mode); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return 0; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int hns3_get_regs_len(struct net_device *netdev) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (!h->ae_algo->ops->get_regs_len) 160662306a36Sopenharmony_ci return -EOPNOTSUPP; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci return h->ae_algo->ops->get_regs_len(h); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic void hns3_get_regs(struct net_device *netdev, 161262306a36Sopenharmony_ci struct ethtool_regs *cmd, void *data) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (!h->ae_algo->ops->get_regs) 161762306a36Sopenharmony_ci return; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci h->ae_algo->ops->get_regs(h, &cmd->version, data); 162062306a36Sopenharmony_ci} 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_cistatic int hns3_set_phys_id(struct net_device *netdev, 162362306a36Sopenharmony_ci enum ethtool_phys_id_state state) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (!h->ae_algo->ops->set_led_id) 162862306a36Sopenharmony_ci return -EOPNOTSUPP; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci return h->ae_algo->ops->set_led_id(h, state); 163162306a36Sopenharmony_ci} 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_cistatic u32 hns3_get_msglevel(struct net_device *netdev) 163462306a36Sopenharmony_ci{ 163562306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci return h->msg_enable; 163862306a36Sopenharmony_ci} 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cistatic void hns3_set_msglevel(struct net_device *netdev, u32 msg_level) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci h->msg_enable = msg_level; 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistatic void hns3_get_fec_stats(struct net_device *netdev, 164862306a36Sopenharmony_ci struct ethtool_fec_stats *fec_stats) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 165162306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 165262306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci if (!hnae3_ae_dev_fec_stats_supported(ae_dev) || !ops->get_fec_stats) 165562306a36Sopenharmony_ci return; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci ops->get_fec_stats(handle, fec_stats); 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci/* Translate local fec value into ethtool value. */ 166162306a36Sopenharmony_cistatic unsigned int loc_to_eth_fec(u8 loc_fec) 166262306a36Sopenharmony_ci{ 166362306a36Sopenharmony_ci u32 eth_fec = 0; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (loc_fec & BIT(HNAE3_FEC_AUTO)) 166662306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_AUTO; 166762306a36Sopenharmony_ci if (loc_fec & BIT(HNAE3_FEC_RS)) 166862306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_RS; 166962306a36Sopenharmony_ci if (loc_fec & BIT(HNAE3_FEC_LLRS)) 167062306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_LLRS; 167162306a36Sopenharmony_ci if (loc_fec & BIT(HNAE3_FEC_BASER)) 167262306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_BASER; 167362306a36Sopenharmony_ci if (loc_fec & BIT(HNAE3_FEC_NONE)) 167462306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_OFF; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci return eth_fec; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci/* Translate ethtool fec value into local value. */ 168062306a36Sopenharmony_cistatic unsigned int eth_to_loc_fec(unsigned int eth_fec) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci u32 loc_fec = 0; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_OFF) 168562306a36Sopenharmony_ci loc_fec |= BIT(HNAE3_FEC_NONE); 168662306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_AUTO) 168762306a36Sopenharmony_ci loc_fec |= BIT(HNAE3_FEC_AUTO); 168862306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_RS) 168962306a36Sopenharmony_ci loc_fec |= BIT(HNAE3_FEC_RS); 169062306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_LLRS) 169162306a36Sopenharmony_ci loc_fec |= BIT(HNAE3_FEC_LLRS); 169262306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_BASER) 169362306a36Sopenharmony_ci loc_fec |= BIT(HNAE3_FEC_BASER); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci return loc_fec; 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_cistatic int hns3_get_fecparam(struct net_device *netdev, 169962306a36Sopenharmony_ci struct ethtool_fecparam *fec) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 170262306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 170362306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 170462306a36Sopenharmony_ci u8 fec_ability; 170562306a36Sopenharmony_ci u8 fec_mode; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci if (!test_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps)) 170862306a36Sopenharmony_ci return -EOPNOTSUPP; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (!ops->get_fec) 171162306a36Sopenharmony_ci return -EOPNOTSUPP; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ops->get_fec(handle, &fec_ability, &fec_mode); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci fec->fec = loc_to_eth_fec(fec_ability); 171662306a36Sopenharmony_ci fec->active_fec = loc_to_eth_fec(fec_mode); 171762306a36Sopenharmony_ci if (!fec->active_fec) 171862306a36Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_OFF; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci return 0; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic int hns3_set_fecparam(struct net_device *netdev, 172462306a36Sopenharmony_ci struct ethtool_fecparam *fec) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 172762306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 172862306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 172962306a36Sopenharmony_ci u32 fec_mode; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (!test_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps)) 173262306a36Sopenharmony_ci return -EOPNOTSUPP; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (!ops->set_fec) 173562306a36Sopenharmony_ci return -EOPNOTSUPP; 173662306a36Sopenharmony_ci fec_mode = eth_to_loc_fec(fec->fec); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci netif_dbg(handle, drv, netdev, "set fecparam: mode=%u\n", fec_mode); 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci return ops->set_fec(handle, fec_mode); 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_cistatic int hns3_get_module_info(struct net_device *netdev, 174462306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci#define HNS3_SFF_8636_V1_3 0x03 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 174962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 175062306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 175162306a36Sopenharmony_ci struct hns3_sfp_type sfp_type; 175262306a36Sopenharmony_ci int ret; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 || 175562306a36Sopenharmony_ci !ops->get_module_eeprom) 175662306a36Sopenharmony_ci return -EOPNOTSUPP; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci memset(&sfp_type, 0, sizeof(sfp_type)); 175962306a36Sopenharmony_ci ret = ops->get_module_eeprom(handle, 0, sizeof(sfp_type) / sizeof(u8), 176062306a36Sopenharmony_ci (u8 *)&sfp_type); 176162306a36Sopenharmony_ci if (ret) 176262306a36Sopenharmony_ci return ret; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci switch (sfp_type.type) { 176562306a36Sopenharmony_ci case SFF8024_ID_SFP: 176662306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 176762306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 176862306a36Sopenharmony_ci break; 176962306a36Sopenharmony_ci case SFF8024_ID_QSFP_8438: 177062306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 177162306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 177262306a36Sopenharmony_ci break; 177362306a36Sopenharmony_ci case SFF8024_ID_QSFP_8436_8636: 177462306a36Sopenharmony_ci if (sfp_type.ext_type < HNS3_SFF_8636_V1_3) { 177562306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 177662306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 177762306a36Sopenharmony_ci } else { 177862306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 177962306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci break; 178262306a36Sopenharmony_ci case SFF8024_ID_QSFP28_8636: 178362306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 178462306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 178562306a36Sopenharmony_ci break; 178662306a36Sopenharmony_ci default: 178762306a36Sopenharmony_ci netdev_err(netdev, "Optical module unknown: %#x\n", 178862306a36Sopenharmony_ci sfp_type.type); 178962306a36Sopenharmony_ci return -EINVAL; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci return 0; 179362306a36Sopenharmony_ci} 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_cistatic int hns3_get_module_eeprom(struct net_device *netdev, 179662306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 179962306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); 180062306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 || 180362306a36Sopenharmony_ci !ops->get_module_eeprom) 180462306a36Sopenharmony_ci return -EOPNOTSUPP; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (!ee->len) 180762306a36Sopenharmony_ci return -EINVAL; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci memset(data, 0, ee->len); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci return ops->get_module_eeprom(handle, ee->offset, ee->len, data); 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic u32 hns3_get_priv_flags(struct net_device *netdev) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci return handle->priv_flags; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic int hns3_check_priv_flags(struct hnae3_handle *h, u32 changed) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci u32 i; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci for (i = 0; i < HNAE3_PFLAG_MAX; i++) 182662306a36Sopenharmony_ci if ((changed & BIT(i)) && !test_bit(i, &h->supported_pflags)) { 182762306a36Sopenharmony_ci netdev_err(h->netdev, "%s is unsupported\n", 182862306a36Sopenharmony_ci hns3_priv_flags[i].name); 182962306a36Sopenharmony_ci return -EOPNOTSUPP; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci return 0; 183362306a36Sopenharmony_ci} 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_cistatic int hns3_set_priv_flags(struct net_device *netdev, u32 pflags) 183662306a36Sopenharmony_ci{ 183762306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 183862306a36Sopenharmony_ci u32 changed = pflags ^ handle->priv_flags; 183962306a36Sopenharmony_ci int ret; 184062306a36Sopenharmony_ci u32 i; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci ret = hns3_check_priv_flags(handle, changed); 184362306a36Sopenharmony_ci if (ret) 184462306a36Sopenharmony_ci return ret; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci for (i = 0; i < HNAE3_PFLAG_MAX; i++) { 184762306a36Sopenharmony_ci if (changed & BIT(i)) { 184862306a36Sopenharmony_ci bool enable = !(handle->priv_flags & BIT(i)); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci if (enable) 185162306a36Sopenharmony_ci handle->priv_flags |= BIT(i); 185262306a36Sopenharmony_ci else 185362306a36Sopenharmony_ci handle->priv_flags &= ~BIT(i); 185462306a36Sopenharmony_ci hns3_priv_flags[i].handler(netdev, enable); 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_cistatic int hns3_get_tunable(struct net_device *netdev, 186262306a36Sopenharmony_ci const struct ethtool_tunable *tuna, 186362306a36Sopenharmony_ci void *data) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 186662306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 186762306a36Sopenharmony_ci int ret = 0; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci switch (tuna->id) { 187062306a36Sopenharmony_ci case ETHTOOL_TX_COPYBREAK: 187162306a36Sopenharmony_ci /* all the tx rings have the same tx_copybreak */ 187262306a36Sopenharmony_ci *(u32 *)data = priv->tx_copybreak; 187362306a36Sopenharmony_ci break; 187462306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 187562306a36Sopenharmony_ci *(u32 *)data = priv->rx_copybreak; 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci case ETHTOOL_TX_COPYBREAK_BUF_SIZE: 187862306a36Sopenharmony_ci *(u32 *)data = h->kinfo.tx_spare_buf_size; 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci default: 188162306a36Sopenharmony_ci ret = -EOPNOTSUPP; 188262306a36Sopenharmony_ci break; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci return ret; 188662306a36Sopenharmony_ci} 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_cistatic int hns3_set_tx_spare_buf_size(struct net_device *netdev, 188962306a36Sopenharmony_ci u32 data) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 189262306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 189362306a36Sopenharmony_ci int ret; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci h->kinfo.tx_spare_buf_size = data; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci ret = hns3_reset_notify(h, HNAE3_DOWN_CLIENT); 189862306a36Sopenharmony_ci if (ret) 189962306a36Sopenharmony_ci return ret; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci ret = hns3_reset_notify(h, HNAE3_UNINIT_CLIENT); 190262306a36Sopenharmony_ci if (ret) 190362306a36Sopenharmony_ci return ret; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci ret = hns3_reset_notify(h, HNAE3_INIT_CLIENT); 190662306a36Sopenharmony_ci if (ret) 190762306a36Sopenharmony_ci return ret; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci ret = hns3_reset_notify(h, HNAE3_UP_CLIENT); 191062306a36Sopenharmony_ci if (ret) 191162306a36Sopenharmony_ci hns3_reset_notify(h, HNAE3_UNINIT_CLIENT); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci return ret; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int hns3_set_tunable(struct net_device *netdev, 191762306a36Sopenharmony_ci const struct ethtool_tunable *tuna, 191862306a36Sopenharmony_ci const void *data) 191962306a36Sopenharmony_ci{ 192062306a36Sopenharmony_ci struct hns3_nic_priv *priv = netdev_priv(netdev); 192162306a36Sopenharmony_ci u32 old_tx_spare_buf_size, new_tx_spare_buf_size; 192262306a36Sopenharmony_ci struct hnae3_handle *h = priv->ae_handle; 192362306a36Sopenharmony_ci int i, ret = 0; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci if (hns3_nic_resetting(netdev) || !priv->ring) { 192662306a36Sopenharmony_ci netdev_err(netdev, "failed to set tunable value, dev resetting!"); 192762306a36Sopenharmony_ci return -EBUSY; 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci switch (tuna->id) { 193162306a36Sopenharmony_ci case ETHTOOL_TX_COPYBREAK: 193262306a36Sopenharmony_ci priv->tx_copybreak = *(u32 *)data; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci for (i = 0; i < h->kinfo.num_tqps; i++) 193562306a36Sopenharmony_ci priv->ring[i].tx_copybreak = priv->tx_copybreak; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci break; 193862306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 193962306a36Sopenharmony_ci priv->rx_copybreak = *(u32 *)data; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci for (i = h->kinfo.num_tqps; i < h->kinfo.num_tqps * 2; i++) 194262306a36Sopenharmony_ci priv->ring[i].rx_copybreak = priv->rx_copybreak; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci break; 194562306a36Sopenharmony_ci case ETHTOOL_TX_COPYBREAK_BUF_SIZE: 194662306a36Sopenharmony_ci old_tx_spare_buf_size = h->kinfo.tx_spare_buf_size; 194762306a36Sopenharmony_ci new_tx_spare_buf_size = *(u32 *)data; 194862306a36Sopenharmony_ci netdev_info(netdev, "request to set tx spare buf size from %u to %u\n", 194962306a36Sopenharmony_ci old_tx_spare_buf_size, new_tx_spare_buf_size); 195062306a36Sopenharmony_ci ret = hns3_set_tx_spare_buf_size(netdev, new_tx_spare_buf_size); 195162306a36Sopenharmony_ci if (ret || 195262306a36Sopenharmony_ci (!priv->ring->tx_spare && new_tx_spare_buf_size != 0)) { 195362306a36Sopenharmony_ci int ret1; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci netdev_warn(netdev, "change tx spare buf size fail, revert to old value\n"); 195662306a36Sopenharmony_ci ret1 = hns3_set_tx_spare_buf_size(netdev, 195762306a36Sopenharmony_ci old_tx_spare_buf_size); 195862306a36Sopenharmony_ci if (ret1) { 195962306a36Sopenharmony_ci netdev_err(netdev, "revert to old tx spare buf size fail\n"); 196062306a36Sopenharmony_ci return ret1; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci return ret; 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci if (!priv->ring->tx_spare) 196762306a36Sopenharmony_ci netdev_info(netdev, "the active tx spare buf size is 0, disable tx spare buffer\n"); 196862306a36Sopenharmony_ci else 196962306a36Sopenharmony_ci netdev_info(netdev, "the active tx spare buf size is %u, due to page order\n", 197062306a36Sopenharmony_ci priv->ring->tx_spare->len); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci break; 197362306a36Sopenharmony_ci default: 197462306a36Sopenharmony_ci ret = -EOPNOTSUPP; 197562306a36Sopenharmony_ci break; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci return ret; 197962306a36Sopenharmony_ci} 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci#define HNS3_ETHTOOL_COALESCE (ETHTOOL_COALESCE_USECS | \ 198262306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE | \ 198362306a36Sopenharmony_ci ETHTOOL_COALESCE_RX_USECS_HIGH | \ 198462306a36Sopenharmony_ci ETHTOOL_COALESCE_TX_USECS_HIGH | \ 198562306a36Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | \ 198662306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_CQE) 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci#define HNS3_ETHTOOL_RING (ETHTOOL_RING_USE_RX_BUF_LEN | \ 198962306a36Sopenharmony_ci ETHTOOL_RING_USE_TX_PUSH) 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic int hns3_get_ts_info(struct net_device *netdev, 199262306a36Sopenharmony_ci struct ethtool_ts_info *info) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (handle->ae_algo->ops->get_ts_info) 199762306a36Sopenharmony_ci return handle->ae_algo->ops->get_ts_info(handle, info); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci return ethtool_op_get_ts_info(netdev, info); 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_cistatic const struct hns3_ethtool_link_ext_state_mapping 200362306a36Sopenharmony_cihns3_link_ext_state_map[] = { 200462306a36Sopenharmony_ci {1, ETHTOOL_LINK_EXT_STATE_AUTONEG, 200562306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD}, 200662306a36Sopenharmony_ci {2, ETHTOOL_LINK_EXT_STATE_AUTONEG, 200762306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED}, 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci {256, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 201062306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT}, 201162306a36Sopenharmony_ci {257, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 201262306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY}, 201362306a36Sopenharmony_ci {512, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 201462306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT}, 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci {513, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 201762306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK}, 201862306a36Sopenharmony_ci {514, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 201962306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED}, 202062306a36Sopenharmony_ci {515, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 202162306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED}, 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci {768, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 202462306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS}, 202562306a36Sopenharmony_ci {769, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 202662306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_REFERENCE_CLOCK_LOST}, 202762306a36Sopenharmony_ci {770, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 202862306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_ALOS}, 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0}, 203162306a36Sopenharmony_ci {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 203262306a36Sopenharmony_ci ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci {1026, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0}, 203562306a36Sopenharmony_ci}; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_cistatic int hns3_get_link_ext_state(struct net_device *netdev, 203862306a36Sopenharmony_ci struct ethtool_link_ext_state_info *info) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci const struct hns3_ethtool_link_ext_state_mapping *map; 204162306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 204262306a36Sopenharmony_ci u32 status_code, i; 204362306a36Sopenharmony_ci int ret; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) 204662306a36Sopenharmony_ci return -ENODATA; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (!h->ae_algo->ops->get_link_diagnosis_info) 204962306a36Sopenharmony_ci return -EOPNOTSUPP; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci ret = h->ae_algo->ops->get_link_diagnosis_info(h, &status_code); 205262306a36Sopenharmony_ci if (ret) 205362306a36Sopenharmony_ci return ret; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hns3_link_ext_state_map); i++) { 205662306a36Sopenharmony_ci map = &hns3_link_ext_state_map[i]; 205762306a36Sopenharmony_ci if (map->status_code == status_code) { 205862306a36Sopenharmony_ci info->link_ext_state = map->link_ext_state; 205962306a36Sopenharmony_ci info->__link_ext_substate = map->link_ext_substate; 206062306a36Sopenharmony_ci return 0; 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci return -ENODATA; 206562306a36Sopenharmony_ci} 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_cistatic void hns3_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 206862306a36Sopenharmony_ci{ 206962306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 207062306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = hns3_get_ops(handle); 207162306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci if (!hnae3_ae_dev_wol_supported(ae_dev)) 207462306a36Sopenharmony_ci return; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci ops->get_wol(handle, wol); 207762306a36Sopenharmony_ci} 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_cistatic int hns3_set_wol(struct net_device *netdev, 208062306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 208162306a36Sopenharmony_ci{ 208262306a36Sopenharmony_ci struct hnae3_handle *handle = hns3_get_handle(netdev); 208362306a36Sopenharmony_ci const struct hnae3_ae_ops *ops = hns3_get_ops(handle); 208462306a36Sopenharmony_ci struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle); 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci if (!hnae3_ae_dev_wol_supported(ae_dev)) 208762306a36Sopenharmony_ci return -EOPNOTSUPP; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci return ops->set_wol(handle, wol); 209062306a36Sopenharmony_ci} 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_cistatic const struct ethtool_ops hns3vf_ethtool_ops = { 209362306a36Sopenharmony_ci .supported_coalesce_params = HNS3_ETHTOOL_COALESCE, 209462306a36Sopenharmony_ci .supported_ring_params = HNS3_ETHTOOL_RING, 209562306a36Sopenharmony_ci .get_drvinfo = hns3_get_drvinfo, 209662306a36Sopenharmony_ci .get_ringparam = hns3_get_ringparam, 209762306a36Sopenharmony_ci .set_ringparam = hns3_set_ringparam, 209862306a36Sopenharmony_ci .get_strings = hns3_get_strings, 209962306a36Sopenharmony_ci .get_ethtool_stats = hns3_get_stats, 210062306a36Sopenharmony_ci .get_sset_count = hns3_get_sset_count, 210162306a36Sopenharmony_ci .get_rxnfc = hns3_get_rxnfc, 210262306a36Sopenharmony_ci .set_rxnfc = hns3_set_rxnfc, 210362306a36Sopenharmony_ci .get_rxfh_key_size = hns3_get_rss_key_size, 210462306a36Sopenharmony_ci .get_rxfh_indir_size = hns3_get_rss_indir_size, 210562306a36Sopenharmony_ci .get_rxfh = hns3_get_rss, 210662306a36Sopenharmony_ci .set_rxfh = hns3_set_rss, 210762306a36Sopenharmony_ci .get_link_ksettings = hns3_get_link_ksettings, 210862306a36Sopenharmony_ci .get_channels = hns3_get_channels, 210962306a36Sopenharmony_ci .set_channels = hns3_set_channels, 211062306a36Sopenharmony_ci .get_coalesce = hns3_get_coalesce, 211162306a36Sopenharmony_ci .set_coalesce = hns3_set_coalesce, 211262306a36Sopenharmony_ci .get_regs_len = hns3_get_regs_len, 211362306a36Sopenharmony_ci .get_regs = hns3_get_regs, 211462306a36Sopenharmony_ci .get_link = hns3_get_link, 211562306a36Sopenharmony_ci .get_msglevel = hns3_get_msglevel, 211662306a36Sopenharmony_ci .set_msglevel = hns3_set_msglevel, 211762306a36Sopenharmony_ci .get_priv_flags = hns3_get_priv_flags, 211862306a36Sopenharmony_ci .set_priv_flags = hns3_set_priv_flags, 211962306a36Sopenharmony_ci .get_tunable = hns3_get_tunable, 212062306a36Sopenharmony_ci .set_tunable = hns3_set_tunable, 212162306a36Sopenharmony_ci .reset = hns3_set_reset, 212262306a36Sopenharmony_ci}; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_cistatic const struct ethtool_ops hns3_ethtool_ops = { 212562306a36Sopenharmony_ci .supported_coalesce_params = HNS3_ETHTOOL_COALESCE, 212662306a36Sopenharmony_ci .supported_ring_params = HNS3_ETHTOOL_RING, 212762306a36Sopenharmony_ci .cap_link_lanes_supported = true, 212862306a36Sopenharmony_ci .self_test = hns3_self_test, 212962306a36Sopenharmony_ci .get_drvinfo = hns3_get_drvinfo, 213062306a36Sopenharmony_ci .get_link = hns3_get_link, 213162306a36Sopenharmony_ci .get_ringparam = hns3_get_ringparam, 213262306a36Sopenharmony_ci .set_ringparam = hns3_set_ringparam, 213362306a36Sopenharmony_ci .get_pauseparam = hns3_get_pauseparam, 213462306a36Sopenharmony_ci .set_pauseparam = hns3_set_pauseparam, 213562306a36Sopenharmony_ci .get_strings = hns3_get_strings, 213662306a36Sopenharmony_ci .get_ethtool_stats = hns3_get_stats, 213762306a36Sopenharmony_ci .get_sset_count = hns3_get_sset_count, 213862306a36Sopenharmony_ci .get_rxnfc = hns3_get_rxnfc, 213962306a36Sopenharmony_ci .set_rxnfc = hns3_set_rxnfc, 214062306a36Sopenharmony_ci .get_rxfh_key_size = hns3_get_rss_key_size, 214162306a36Sopenharmony_ci .get_rxfh_indir_size = hns3_get_rss_indir_size, 214262306a36Sopenharmony_ci .get_rxfh = hns3_get_rss, 214362306a36Sopenharmony_ci .set_rxfh = hns3_set_rss, 214462306a36Sopenharmony_ci .get_link_ksettings = hns3_get_link_ksettings, 214562306a36Sopenharmony_ci .set_link_ksettings = hns3_set_link_ksettings, 214662306a36Sopenharmony_ci .nway_reset = hns3_nway_reset, 214762306a36Sopenharmony_ci .get_channels = hns3_get_channels, 214862306a36Sopenharmony_ci .set_channels = hns3_set_channels, 214962306a36Sopenharmony_ci .get_coalesce = hns3_get_coalesce, 215062306a36Sopenharmony_ci .set_coalesce = hns3_set_coalesce, 215162306a36Sopenharmony_ci .get_regs_len = hns3_get_regs_len, 215262306a36Sopenharmony_ci .get_regs = hns3_get_regs, 215362306a36Sopenharmony_ci .set_phys_id = hns3_set_phys_id, 215462306a36Sopenharmony_ci .get_msglevel = hns3_get_msglevel, 215562306a36Sopenharmony_ci .set_msglevel = hns3_set_msglevel, 215662306a36Sopenharmony_ci .get_fecparam = hns3_get_fecparam, 215762306a36Sopenharmony_ci .set_fecparam = hns3_set_fecparam, 215862306a36Sopenharmony_ci .get_fec_stats = hns3_get_fec_stats, 215962306a36Sopenharmony_ci .get_module_info = hns3_get_module_info, 216062306a36Sopenharmony_ci .get_module_eeprom = hns3_get_module_eeprom, 216162306a36Sopenharmony_ci .get_priv_flags = hns3_get_priv_flags, 216262306a36Sopenharmony_ci .set_priv_flags = hns3_set_priv_flags, 216362306a36Sopenharmony_ci .get_ts_info = hns3_get_ts_info, 216462306a36Sopenharmony_ci .get_tunable = hns3_get_tunable, 216562306a36Sopenharmony_ci .set_tunable = hns3_set_tunable, 216662306a36Sopenharmony_ci .reset = hns3_set_reset, 216762306a36Sopenharmony_ci .get_link_ext_state = hns3_get_link_ext_state, 216862306a36Sopenharmony_ci .get_wol = hns3_get_wol, 216962306a36Sopenharmony_ci .set_wol = hns3_set_wol, 217062306a36Sopenharmony_ci}; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_civoid hns3_ethtool_set_ops(struct net_device *netdev) 217362306a36Sopenharmony_ci{ 217462306a36Sopenharmony_ci struct hnae3_handle *h = hns3_get_handle(netdev); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci if (h->flags & HNAE3_SUPPORT_VF) 217762306a36Sopenharmony_ci netdev->ethtool_ops = &hns3vf_ethtool_ops; 217862306a36Sopenharmony_ci else 217962306a36Sopenharmony_ci netdev->ethtool_ops = &hns3_ethtool_ops; 218062306a36Sopenharmony_ci} 2181