18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Cavium, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* ETHTOOL Support for VNIC_VF Device*/ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "nic_reg.h" 128c2ecf20Sopenharmony_ci#include "nic.h" 138c2ecf20Sopenharmony_ci#include "nicvf_queues.h" 148c2ecf20Sopenharmony_ci#include "q_struct.h" 158c2ecf20Sopenharmony_ci#include "thunder_bgx.h" 168c2ecf20Sopenharmony_ci#include "../common/cavium_ptp.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DRV_NAME "nicvf" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct nicvf_stat { 218c2ecf20Sopenharmony_ci char name[ETH_GSTRING_LEN]; 228c2ecf20Sopenharmony_ci unsigned int index; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define NICVF_HW_STAT(stat) { \ 268c2ecf20Sopenharmony_ci .name = #stat, \ 278c2ecf20Sopenharmony_ci .index = offsetof(struct nicvf_hw_stats, stat) / sizeof(u64), \ 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define NICVF_DRV_STAT(stat) { \ 318c2ecf20Sopenharmony_ci .name = #stat, \ 328c2ecf20Sopenharmony_ci .index = offsetof(struct nicvf_drv_stats, stat) / sizeof(u64), \ 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const struct nicvf_stat nicvf_hw_stats[] = { 368c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_bytes), 378c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_frames), 388c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_ucast_frames), 398c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_bcast_frames), 408c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_mcast_frames), 418c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drops), 428c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_red), 438c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_red_bytes), 448c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_overrun), 458c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_overrun_bytes), 468c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_bcast), 478c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_mcast), 488c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_l3_bcast), 498c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_drop_l3_mcast), 508c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_fcs_errors), 518c2ecf20Sopenharmony_ci NICVF_HW_STAT(rx_l2_errors), 528c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_bytes), 538c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_frames), 548c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_ucast_frames), 558c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_bcast_frames), 568c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_mcast_frames), 578c2ecf20Sopenharmony_ci NICVF_HW_STAT(tx_drops), 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const struct nicvf_stat nicvf_drv_stats[] = { 618c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_bgx_truncated_pkts), 628c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_jabber_errs), 638c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_fcs_errs), 648c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_bgx_errs), 658c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_prel2_errs), 668c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l2_hdr_malformed), 678c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_oversize), 688c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_undersize), 698c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l2_len_mismatch), 708c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l2_pclp), 718c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_ip_ver_errs), 728c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_ip_csum_errs), 738c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_ip_hdr_malformed), 748c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_ip_payload_malformed), 758c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_ip_ttl_errs), 768c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l3_pclp), 778c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l4_malformed), 788c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l4_csum_errs), 798c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_udp_len_errs), 808c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l4_port_errs), 818c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_tcp_flag_errs), 828c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_tcp_offset_errs), 838c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_l4_pclp), 848c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rx_truncated_pkts), 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_desc_fault), 878c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_hdr_cons_err), 888c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_subdesc_err), 898c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_max_size_exceeded), 908c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_imm_size_oflow), 918c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_data_seq_err), 928c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_mem_seq_err), 938c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_lock_viol), 948c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_data_fault), 958c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_tstmp_conflict), 968c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_tstmp_timeout), 978c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_mem_fault), 988c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_csum_overlap), 998c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_csum_overflow), 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_tso), 1028c2ecf20Sopenharmony_ci NICVF_DRV_STAT(tx_timeout), 1038c2ecf20Sopenharmony_ci NICVF_DRV_STAT(txq_stop), 1048c2ecf20Sopenharmony_ci NICVF_DRV_STAT(txq_wake), 1058c2ecf20Sopenharmony_ci NICVF_DRV_STAT(rcv_buffer_alloc_failures), 1068c2ecf20Sopenharmony_ci NICVF_DRV_STAT(page_alloc), 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic const struct nicvf_stat nicvf_queue_stats[] = { 1108c2ecf20Sopenharmony_ci { "bytes", 0 }, 1118c2ecf20Sopenharmony_ci { "frames", 1 }, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const unsigned int nicvf_n_hw_stats = ARRAY_SIZE(nicvf_hw_stats); 1158c2ecf20Sopenharmony_cistatic const unsigned int nicvf_n_drv_stats = ARRAY_SIZE(nicvf_drv_stats); 1168c2ecf20Sopenharmony_cistatic const unsigned int nicvf_n_queue_stats = ARRAY_SIZE(nicvf_queue_stats); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int nicvf_get_link_ksettings(struct net_device *netdev, 1198c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 1228c2ecf20Sopenharmony_ci u32 supported, advertising; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci supported = 0; 1258c2ecf20Sopenharmony_ci advertising = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!nic->link_up) { 1288c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 1298c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci switch (nic->speed) { 1348c2ecf20Sopenharmony_ci case SPEED_1000: 1358c2ecf20Sopenharmony_ci cmd->base.port = PORT_MII | PORT_TP; 1368c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 1378c2ecf20Sopenharmony_ci supported |= SUPPORTED_MII | SUPPORTED_TP; 1388c2ecf20Sopenharmony_ci supported |= SUPPORTED_1000baseT_Full | 1398c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Half | 1408c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Full | 1418c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Half | 1428c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full | 1438c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Half; 1448c2ecf20Sopenharmony_ci supported |= SUPPORTED_Autoneg; 1458c2ecf20Sopenharmony_ci advertising |= ADVERTISED_1000baseT_Full | 1468c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Half | 1478c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Full | 1488c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Half | 1498c2ecf20Sopenharmony_ci ADVERTISED_10baseT_Full | 1508c2ecf20Sopenharmony_ci ADVERTISED_10baseT_Half; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case SPEED_10000: 1538c2ecf20Sopenharmony_ci if (nic->mac_type == BGX_MODE_RXAUI) { 1548c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; 1558c2ecf20Sopenharmony_ci supported |= SUPPORTED_TP; 1568c2ecf20Sopenharmony_ci } else { 1578c2ecf20Sopenharmony_ci cmd->base.port = PORT_FIBRE; 1588c2ecf20Sopenharmony_ci supported |= SUPPORTED_FIBRE; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 1618c2ecf20Sopenharmony_ci supported |= SUPPORTED_10000baseT_Full; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case SPEED_40000: 1648c2ecf20Sopenharmony_ci cmd->base.port = PORT_FIBRE; 1658c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 1668c2ecf20Sopenharmony_ci supported |= SUPPORTED_FIBRE; 1678c2ecf20Sopenharmony_ci supported |= SUPPORTED_40000baseCR4_Full; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci cmd->base.duplex = nic->duplex; 1718c2ecf20Sopenharmony_ci cmd->base.speed = nic->speed; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 1748c2ecf20Sopenharmony_ci supported); 1758c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 1768c2ecf20Sopenharmony_ci advertising); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic u32 nicvf_get_link(struct net_device *netdev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return nic->link_up; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void nicvf_get_drvinfo(struct net_device *netdev, 1898c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 1948c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(nic->pdev), sizeof(info->bus_info)); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic u32 nicvf_get_msglevel(struct net_device *netdev) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return nic->msg_enable; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void nicvf_set_msglevel(struct net_device *netdev, u32 lvl) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci nic->msg_enable = lvl; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void nicvf_get_qset_strings(struct nicvf *nic, u8 **data, int qset) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci int stats, qidx; 2148c2ecf20Sopenharmony_ci int start_qidx = qset * MAX_RCV_QUEUES_PER_QS; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { 2178c2ecf20Sopenharmony_ci for (stats = 0; stats < nicvf_n_queue_stats; stats++) { 2188c2ecf20Sopenharmony_ci sprintf(*data, "rxq%d: %s", qidx + start_qidx, 2198c2ecf20Sopenharmony_ci nicvf_queue_stats[stats].name); 2208c2ecf20Sopenharmony_ci *data += ETH_GSTRING_LEN; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { 2258c2ecf20Sopenharmony_ci for (stats = 0; stats < nicvf_n_queue_stats; stats++) { 2268c2ecf20Sopenharmony_ci sprintf(*data, "txq%d: %s", qidx + start_qidx, 2278c2ecf20Sopenharmony_ci nicvf_queue_stats[stats].name); 2288c2ecf20Sopenharmony_ci *data += ETH_GSTRING_LEN; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 2368c2ecf20Sopenharmony_ci int stats; 2378c2ecf20Sopenharmony_ci int sqs; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (sset != ETH_SS_STATS) 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for (stats = 0; stats < nicvf_n_hw_stats; stats++) { 2438c2ecf20Sopenharmony_ci memcpy(data, nicvf_hw_stats[stats].name, ETH_GSTRING_LEN); 2448c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci for (stats = 0; stats < nicvf_n_drv_stats; stats++) { 2488c2ecf20Sopenharmony_ci memcpy(data, nicvf_drv_stats[stats].name, ETH_GSTRING_LEN); 2498c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci nicvf_get_qset_strings(nic, &data, 0); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 2558c2ecf20Sopenharmony_ci if (!nic->snicvf[sqs]) 2568c2ecf20Sopenharmony_ci continue; 2578c2ecf20Sopenharmony_ci nicvf_get_qset_strings(nic->snicvf[sqs], &data, sqs + 1); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci for (stats = 0; stats < BGX_RX_STATS_COUNT; stats++) { 2618c2ecf20Sopenharmony_ci sprintf(data, "bgx_rxstat%d: ", stats); 2628c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci for (stats = 0; stats < BGX_TX_STATS_COUNT; stats++) { 2668c2ecf20Sopenharmony_ci sprintf(data, "bgx_txstat%d: ", stats); 2678c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int nicvf_get_sset_count(struct net_device *netdev, int sset) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 2748c2ecf20Sopenharmony_ci int qstats_count; 2758c2ecf20Sopenharmony_ci int sqs; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (sset != ETH_SS_STATS) 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci qstats_count = nicvf_n_queue_stats * 2818c2ecf20Sopenharmony_ci (nic->qs->rq_cnt + nic->qs->sq_cnt); 2828c2ecf20Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 2838c2ecf20Sopenharmony_ci struct nicvf *snic; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci snic = nic->snicvf[sqs]; 2868c2ecf20Sopenharmony_ci if (!snic) 2878c2ecf20Sopenharmony_ci continue; 2888c2ecf20Sopenharmony_ci qstats_count += nicvf_n_queue_stats * 2898c2ecf20Sopenharmony_ci (snic->qs->rq_cnt + snic->qs->sq_cnt); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return nicvf_n_hw_stats + nicvf_n_drv_stats + 2938c2ecf20Sopenharmony_ci qstats_count + 2948c2ecf20Sopenharmony_ci BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void nicvf_get_qset_stats(struct nicvf *nic, 2988c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 **data) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int stat, qidx; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!nic) 3038c2ecf20Sopenharmony_ci return; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { 3068c2ecf20Sopenharmony_ci nicvf_update_rq_stats(nic, qidx); 3078c2ecf20Sopenharmony_ci for (stat = 0; stat < nicvf_n_queue_stats; stat++) 3088c2ecf20Sopenharmony_ci *((*data)++) = ((u64 *)&nic->qs->rq[qidx].stats) 3098c2ecf20Sopenharmony_ci [nicvf_queue_stats[stat].index]; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { 3138c2ecf20Sopenharmony_ci nicvf_update_sq_stats(nic, qidx); 3148c2ecf20Sopenharmony_ci for (stat = 0; stat < nicvf_n_queue_stats; stat++) 3158c2ecf20Sopenharmony_ci *((*data)++) = ((u64 *)&nic->qs->sq[qidx].stats) 3168c2ecf20Sopenharmony_ci [nicvf_queue_stats[stat].index]; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void nicvf_get_ethtool_stats(struct net_device *netdev, 3218c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 3248c2ecf20Sopenharmony_ci int stat, tmp_stats; 3258c2ecf20Sopenharmony_ci int sqs, cpu; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci nicvf_update_stats(nic); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Update LMAC stats */ 3308c2ecf20Sopenharmony_ci nicvf_update_lmac_stats(nic); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci for (stat = 0; stat < nicvf_n_hw_stats; stat++) 3338c2ecf20Sopenharmony_ci *(data++) = ((u64 *)&nic->hw_stats) 3348c2ecf20Sopenharmony_ci [nicvf_hw_stats[stat].index]; 3358c2ecf20Sopenharmony_ci for (stat = 0; stat < nicvf_n_drv_stats; stat++) { 3368c2ecf20Sopenharmony_ci tmp_stats = 0; 3378c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 3388c2ecf20Sopenharmony_ci tmp_stats += ((u64 *)per_cpu_ptr(nic->drv_stats, cpu)) 3398c2ecf20Sopenharmony_ci [nicvf_drv_stats[stat].index]; 3408c2ecf20Sopenharmony_ci *(data++) = tmp_stats; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci nicvf_get_qset_stats(nic, stats, &data); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 3468c2ecf20Sopenharmony_ci if (!nic->snicvf[sqs]) 3478c2ecf20Sopenharmony_ci continue; 3488c2ecf20Sopenharmony_ci nicvf_get_qset_stats(nic->snicvf[sqs], stats, &data); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci for (stat = 0; stat < BGX_RX_STATS_COUNT; stat++) 3528c2ecf20Sopenharmony_ci *(data++) = nic->bgx_stats.rx_stats[stat]; 3538c2ecf20Sopenharmony_ci for (stat = 0; stat < BGX_TX_STATS_COUNT; stat++) 3548c2ecf20Sopenharmony_ci *(data++) = nic->bgx_stats.tx_stats[stat]; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int nicvf_get_regs_len(struct net_device *dev) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci return sizeof(u64) * NIC_VF_REG_COUNT; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic void nicvf_get_regs(struct net_device *dev, 3638c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *reg) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 3668c2ecf20Sopenharmony_ci u64 *p = (u64 *)reg; 3678c2ecf20Sopenharmony_ci u64 reg_offset; 3688c2ecf20Sopenharmony_ci int mbox, key, stat, q; 3698c2ecf20Sopenharmony_ci int i = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci regs->version = 0; 3728c2ecf20Sopenharmony_ci memset(p, 0, NIC_VF_REG_COUNT); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_CFG); 3758c2ecf20Sopenharmony_ci /* Mailbox registers */ 3768c2ecf20Sopenharmony_ci for (mbox = 0; mbox < NIC_PF_VF_MAILBOX_SIZE; mbox++) 3778c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 3788c2ecf20Sopenharmony_ci NIC_VF_PF_MAILBOX_0_1 | (mbox << 3)); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_INT); 3818c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_INT_W1S); 3828c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1C); 3838c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1S); 3848c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci for (key = 0; key < RSS_HASH_KEY_SIZE; key++) 3878c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_KEY_0_4 | (key << 3)); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Tx/Rx statistics */ 3908c2ecf20Sopenharmony_ci for (stat = 0; stat < TX_STATS_ENUM_LAST; stat++) 3918c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 3928c2ecf20Sopenharmony_ci NIC_VNIC_TX_STAT_0_4 | (stat << 3)); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci for (i = 0; i < RX_STATS_ENUM_LAST; i++) 3958c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 3968c2ecf20Sopenharmony_ci NIC_VNIC_RX_STAT_0_13 | (stat << 3)); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_QSET_RQ_GEN_CFG); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* All completion queue's registers */ 4018c2ecf20Sopenharmony_ci for (q = 0; q < MAX_CMP_QUEUES_PER_QS; q++) { 4028c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG, q); 4038c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG2, q); 4048c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_THRESH, q); 4058c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_BASE, q); 4068c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, q); 4078c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_TAIL, q); 4088c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DOOR, q); 4098c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, q); 4108c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS2, q); 4118c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DEBUG, q); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* All receive queue's registers */ 4158c2ecf20Sopenharmony_ci for (q = 0; q < MAX_RCV_QUEUES_PER_QS; q++) { 4168c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RQ_0_7_CFG, q); 4178c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 4188c2ecf20Sopenharmony_ci NIC_QSET_RQ_0_7_STAT_0_1, q); 4198c2ecf20Sopenharmony_ci reg_offset = NIC_QSET_RQ_0_7_STAT_0_1 | (1 << 3); 4208c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci for (q = 0; q < MAX_SND_QUEUES_PER_QS; q++) { 4248c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, q); 4258c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_THRESH, q); 4268c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_BASE, q); 4278c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, q); 4288c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_TAIL, q); 4298c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q); 4308c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q); 4318c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q); 4328c2ecf20Sopenharmony_ci /* Padding, was NIC_QSET_SQ_0_7_CNM_CHG, which 4338c2ecf20Sopenharmony_ci * produces bus errors when read 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci p[i++] = 0; 4368c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q); 4378c2ecf20Sopenharmony_ci reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3); 4388c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (q = 0; q < MAX_RCV_BUF_DESC_RINGS_PER_QS; q++) { 4428c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_CFG, q); 4438c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_THRESH, q); 4448c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_BASE, q); 4458c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, q); 4468c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, q); 4478c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_DOOR, q); 4488c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 4498c2ecf20Sopenharmony_ci NIC_QSET_RBDR_0_1_STATUS0, q); 4508c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 4518c2ecf20Sopenharmony_ci NIC_QSET_RBDR_0_1_STATUS1, q); 4528c2ecf20Sopenharmony_ci reg_offset = NIC_QSET_RBDR_0_1_PREFETCH_STATUS; 4538c2ecf20Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int nicvf_get_coalesce(struct net_device *netdev, 4588c2ecf20Sopenharmony_ci struct ethtool_coalesce *cmd) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci cmd->rx_coalesce_usecs = nic->cq_coalesce_usecs; 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void nicvf_get_ringparam(struct net_device *netdev, 4678c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 4708c2ecf20Sopenharmony_ci struct queue_set *qs = nic->qs; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ring->rx_max_pending = MAX_CMP_QUEUE_LEN; 4738c2ecf20Sopenharmony_ci ring->rx_pending = qs->cq_len; 4748c2ecf20Sopenharmony_ci ring->tx_max_pending = MAX_SND_QUEUE_LEN; 4758c2ecf20Sopenharmony_ci ring->tx_pending = qs->sq_len; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int nicvf_set_ringparam(struct net_device *netdev, 4798c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 4828c2ecf20Sopenharmony_ci struct queue_set *qs = nic->qs; 4838c2ecf20Sopenharmony_ci u32 rx_count, tx_count; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Due to HW errata this is not supported on T88 pass 1.x silicon */ 4868c2ecf20Sopenharmony_ci if (pass1_silicon(nic->pdev)) 4878c2ecf20Sopenharmony_ci return -EINVAL; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 4908c2ecf20Sopenharmony_ci return -EINVAL; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci tx_count = clamp_t(u32, ring->tx_pending, 4938c2ecf20Sopenharmony_ci MIN_SND_QUEUE_LEN, MAX_SND_QUEUE_LEN); 4948c2ecf20Sopenharmony_ci rx_count = clamp_t(u32, ring->rx_pending, 4958c2ecf20Sopenharmony_ci MIN_CMP_QUEUE_LEN, MAX_CMP_QUEUE_LEN); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if ((tx_count == qs->sq_len) && (rx_count == qs->cq_len)) 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Permitted lengths are 1K, 2K, 4K, 8K, 16K, 32K, 64K */ 5018c2ecf20Sopenharmony_ci qs->sq_len = rounddown_pow_of_two(tx_count); 5028c2ecf20Sopenharmony_ci qs->cq_len = rounddown_pow_of_two(rx_count); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 5058c2ecf20Sopenharmony_ci nicvf_stop(netdev); 5068c2ecf20Sopenharmony_ci nicvf_open(netdev); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int nicvf_get_rss_hash_opts(struct nicvf *nic, 5138c2ecf20Sopenharmony_ci struct ethtool_rxnfc *info) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci info->data = 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci switch (info->flow_type) { 5188c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 5198c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 5208c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 5218c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 5228c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 5238c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 5248c2ecf20Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 5258c2ecf20Sopenharmony_ci fallthrough; 5268c2ecf20Sopenharmony_ci case IPV4_FLOW: 5278c2ecf20Sopenharmony_ci case IPV6_FLOW: 5288c2ecf20Sopenharmony_ci info->data |= RXH_IP_SRC | RXH_IP_DST; 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci default: 5318c2ecf20Sopenharmony_ci return -EINVAL; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int nicvf_get_rxnfc(struct net_device *dev, 5388c2ecf20Sopenharmony_ci struct ethtool_rxnfc *info, u32 *rules) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 5418c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci switch (info->cmd) { 5448c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 5458c2ecf20Sopenharmony_ci info->data = nic->rx_queues; 5468c2ecf20Sopenharmony_ci ret = 0; 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 5498c2ecf20Sopenharmony_ci return nicvf_get_rss_hash_opts(nic, info); 5508c2ecf20Sopenharmony_ci default: 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci return ret; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int nicvf_set_rss_hash_opts(struct nicvf *nic, 5578c2ecf20Sopenharmony_ci struct ethtool_rxnfc *info) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 5608c2ecf20Sopenharmony_ci u64 rss_cfg = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!rss->enable) 5638c2ecf20Sopenharmony_ci netdev_err(nic->netdev, 5648c2ecf20Sopenharmony_ci "RSS is disabled, hash cannot be set\n"); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci netdev_info(nic->netdev, "Set RSS flow type = %d, data = %lld\n", 5678c2ecf20Sopenharmony_ci info->flow_type, info->data); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST)) 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci switch (info->flow_type) { 5738c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 5748c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 5758c2ecf20Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 5768c2ecf20Sopenharmony_ci case 0: 5778c2ecf20Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_TCP); 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 5808c2ecf20Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_TCP); 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci default: 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 5878c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 5888c2ecf20Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 5898c2ecf20Sopenharmony_ci case 0: 5908c2ecf20Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_UDP); 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 5938c2ecf20Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_UDP); 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci default: 5968c2ecf20Sopenharmony_ci return -EINVAL; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 6008c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 6018c2ecf20Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 6028c2ecf20Sopenharmony_ci case 0: 6038c2ecf20Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_L4ETC); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 6068c2ecf20Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_L4ETC); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci default: 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci case IPV4_FLOW: 6138c2ecf20Sopenharmony_ci case IPV6_FLOW: 6148c2ecf20Sopenharmony_ci rss_cfg = RSS_HASH_IP; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci default: 6178c2ecf20Sopenharmony_ci return -EINVAL; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss_cfg); 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic int nicvf_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci switch (info->cmd) { 6298c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 6308c2ecf20Sopenharmony_ci return nicvf_set_rss_hash_opts(nic, info); 6318c2ecf20Sopenharmony_ci default: 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic u32 nicvf_get_rxfh_key_size(struct net_device *netdev) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci return RSS_HASH_KEY_SIZE * sizeof(u64); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic u32 nicvf_get_rxfh_indir_size(struct net_device *dev) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return nic->rss_info.rss_size; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey, 6508c2ecf20Sopenharmony_ci u8 *hfunc) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 6538c2ecf20Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 6548c2ecf20Sopenharmony_ci int idx; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (indir) { 6578c2ecf20Sopenharmony_ci for (idx = 0; idx < rss->rss_size; idx++) 6588c2ecf20Sopenharmony_ci indir[idx] = rss->ind_tbl[idx]; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (hkey) 6628c2ecf20Sopenharmony_ci memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64)); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (hfunc) 6658c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int nicvf_set_rxfh(struct net_device *dev, const u32 *indir, 6718c2ecf20Sopenharmony_ci const u8 *hkey, const u8 hfunc) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 6748c2ecf20Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 6758c2ecf20Sopenharmony_ci int idx; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 6788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!rss->enable) { 6818c2ecf20Sopenharmony_ci netdev_err(nic->netdev, 6828c2ecf20Sopenharmony_ci "RSS is disabled, cannot change settings\n"); 6838c2ecf20Sopenharmony_ci return -EIO; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (indir) { 6878c2ecf20Sopenharmony_ci for (idx = 0; idx < rss->rss_size; idx++) 6888c2ecf20Sopenharmony_ci rss->ind_tbl[idx] = indir[idx]; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (hkey) { 6928c2ecf20Sopenharmony_ci memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE * sizeof(u64)); 6938c2ecf20Sopenharmony_ci nicvf_set_rss_key(nic); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci nicvf_config_rss(nic); 6978c2ecf20Sopenharmony_ci return 0; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* Get no of queues device supports and current queue count */ 7018c2ecf20Sopenharmony_cistatic void nicvf_get_channels(struct net_device *dev, 7028c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci memset(channel, 0, sizeof(*channel)); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci channel->max_rx = nic->max_queues; 7098c2ecf20Sopenharmony_ci channel->max_tx = nic->max_queues; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci channel->rx_count = nic->rx_queues; 7128c2ecf20Sopenharmony_ci channel->tx_count = nic->tx_queues; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/* Set no of Tx, Rx queues to be used */ 7168c2ecf20Sopenharmony_cistatic int nicvf_set_channels(struct net_device *dev, 7178c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 7208c2ecf20Sopenharmony_ci int err = 0; 7218c2ecf20Sopenharmony_ci bool if_up = netif_running(dev); 7228c2ecf20Sopenharmony_ci u8 cqcount, txq_count; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (!channel->rx_count || !channel->tx_count) 7258c2ecf20Sopenharmony_ci return -EINVAL; 7268c2ecf20Sopenharmony_ci if (channel->rx_count > nic->max_queues) 7278c2ecf20Sopenharmony_ci return -EINVAL; 7288c2ecf20Sopenharmony_ci if (channel->tx_count > nic->max_queues) 7298c2ecf20Sopenharmony_ci return -EINVAL; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (nic->xdp_prog && 7328c2ecf20Sopenharmony_ci ((channel->tx_count + channel->rx_count) > nic->max_queues)) { 7338c2ecf20Sopenharmony_ci netdev_err(nic->netdev, 7348c2ecf20Sopenharmony_ci "XDP mode, RXQs + TXQs > Max %d\n", 7358c2ecf20Sopenharmony_ci nic->max_queues); 7368c2ecf20Sopenharmony_ci return -EINVAL; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (if_up) 7408c2ecf20Sopenharmony_ci nicvf_stop(dev); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci nic->rx_queues = channel->rx_count; 7438c2ecf20Sopenharmony_ci nic->tx_queues = channel->tx_count; 7448c2ecf20Sopenharmony_ci if (!nic->xdp_prog) 7458c2ecf20Sopenharmony_ci nic->xdp_tx_queues = 0; 7468c2ecf20Sopenharmony_ci else 7478c2ecf20Sopenharmony_ci nic->xdp_tx_queues = channel->rx_count; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci txq_count = nic->xdp_tx_queues + nic->tx_queues; 7508c2ecf20Sopenharmony_ci cqcount = max(nic->rx_queues, txq_count); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (cqcount > MAX_CMP_QUEUES_PER_QS) { 7538c2ecf20Sopenharmony_ci nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS); 7548c2ecf20Sopenharmony_ci nic->sqs_count = (nic->sqs_count / MAX_CMP_QUEUES_PER_QS) - 1; 7558c2ecf20Sopenharmony_ci } else { 7568c2ecf20Sopenharmony_ci nic->sqs_count = 0; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS); 7608c2ecf20Sopenharmony_ci nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS); 7618c2ecf20Sopenharmony_ci nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues); 7648c2ecf20Sopenharmony_ci if (err) 7658c2ecf20Sopenharmony_ci return err; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (if_up) 7688c2ecf20Sopenharmony_ci nicvf_open(dev); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n", 7718c2ecf20Sopenharmony_ci nic->tx_queues, nic->rx_queues); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return err; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic void nicvf_get_pauseparam(struct net_device *dev, 7778c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 7808c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Supported only for 10G/40G interfaces */ 7838c2ecf20Sopenharmony_ci if ((nic->mac_type == BGX_MODE_SGMII) || 7848c2ecf20Sopenharmony_ci (nic->mac_type == BGX_MODE_QSGMII) || 7858c2ecf20Sopenharmony_ci (nic->mac_type == BGX_MODE_RGMII)) 7868c2ecf20Sopenharmony_ci return; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 7898c2ecf20Sopenharmony_ci mbx.pfc.get = 1; 7908c2ecf20Sopenharmony_ci if (!nicvf_send_msg_to_pf(nic, &mbx)) { 7918c2ecf20Sopenharmony_ci pause->autoneg = nic->pfc.autoneg; 7928c2ecf20Sopenharmony_ci pause->rx_pause = nic->pfc.fc_rx; 7938c2ecf20Sopenharmony_ci pause->tx_pause = nic->pfc.fc_tx; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int nicvf_set_pauseparam(struct net_device *dev, 7988c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 8018c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* Supported only for 10G/40G interfaces */ 8048c2ecf20Sopenharmony_ci if ((nic->mac_type == BGX_MODE_SGMII) || 8058c2ecf20Sopenharmony_ci (nic->mac_type == BGX_MODE_QSGMII) || 8068c2ecf20Sopenharmony_ci (nic->mac_type == BGX_MODE_RGMII)) 8078c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (pause->autoneg) 8108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 8138c2ecf20Sopenharmony_ci mbx.pfc.get = 0; 8148c2ecf20Sopenharmony_ci mbx.pfc.fc_rx = pause->rx_pause; 8158c2ecf20Sopenharmony_ci mbx.pfc.fc_tx = pause->tx_pause; 8168c2ecf20Sopenharmony_ci if (nicvf_send_msg_to_pf(nic, &mbx)) 8178c2ecf20Sopenharmony_ci return -EAGAIN; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci nic->pfc.fc_rx = pause->rx_pause; 8208c2ecf20Sopenharmony_ci nic->pfc.fc_tx = pause->tx_pause; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return 0; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic int nicvf_get_ts_info(struct net_device *netdev, 8268c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (!nic->ptp_clock) 8318c2ecf20Sopenharmony_ci return ethtool_op_get_ts_info(netdev, info); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 8348c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 8358c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 8368c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 8378c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 8388c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci info->phc_index = cavium_ptp_clock_index(nic->ptp_clock); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 8458c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return 0; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic const struct ethtool_ops nicvf_ethtool_ops = { 8518c2ecf20Sopenharmony_ci .get_link = nicvf_get_link, 8528c2ecf20Sopenharmony_ci .get_drvinfo = nicvf_get_drvinfo, 8538c2ecf20Sopenharmony_ci .get_msglevel = nicvf_get_msglevel, 8548c2ecf20Sopenharmony_ci .set_msglevel = nicvf_set_msglevel, 8558c2ecf20Sopenharmony_ci .get_strings = nicvf_get_strings, 8568c2ecf20Sopenharmony_ci .get_sset_count = nicvf_get_sset_count, 8578c2ecf20Sopenharmony_ci .get_ethtool_stats = nicvf_get_ethtool_stats, 8588c2ecf20Sopenharmony_ci .get_regs_len = nicvf_get_regs_len, 8598c2ecf20Sopenharmony_ci .get_regs = nicvf_get_regs, 8608c2ecf20Sopenharmony_ci .get_coalesce = nicvf_get_coalesce, 8618c2ecf20Sopenharmony_ci .get_ringparam = nicvf_get_ringparam, 8628c2ecf20Sopenharmony_ci .set_ringparam = nicvf_set_ringparam, 8638c2ecf20Sopenharmony_ci .get_rxnfc = nicvf_get_rxnfc, 8648c2ecf20Sopenharmony_ci .set_rxnfc = nicvf_set_rxnfc, 8658c2ecf20Sopenharmony_ci .get_rxfh_key_size = nicvf_get_rxfh_key_size, 8668c2ecf20Sopenharmony_ci .get_rxfh_indir_size = nicvf_get_rxfh_indir_size, 8678c2ecf20Sopenharmony_ci .get_rxfh = nicvf_get_rxfh, 8688c2ecf20Sopenharmony_ci .set_rxfh = nicvf_set_rxfh, 8698c2ecf20Sopenharmony_ci .get_channels = nicvf_get_channels, 8708c2ecf20Sopenharmony_ci .set_channels = nicvf_set_channels, 8718c2ecf20Sopenharmony_ci .get_pauseparam = nicvf_get_pauseparam, 8728c2ecf20Sopenharmony_ci .set_pauseparam = nicvf_set_pauseparam, 8738c2ecf20Sopenharmony_ci .get_ts_info = nicvf_get_ts_info, 8748c2ecf20Sopenharmony_ci .get_link_ksettings = nicvf_get_link_ksettings, 8758c2ecf20Sopenharmony_ci}; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_civoid nicvf_set_ethtool_ops(struct net_device *netdev) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci netdev->ethtool_ops = &nicvf_ethtool_ops; 8808c2ecf20Sopenharmony_ci} 881