162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Cavium, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* ETHTOOL Support for VNIC_VF Device*/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/ethtool.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/net_tstamp.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "nic_reg.h" 1362306a36Sopenharmony_ci#include "nic.h" 1462306a36Sopenharmony_ci#include "nicvf_queues.h" 1562306a36Sopenharmony_ci#include "q_struct.h" 1662306a36Sopenharmony_ci#include "thunder_bgx.h" 1762306a36Sopenharmony_ci#include "../common/cavium_ptp.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define DRV_NAME "nicvf" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct nicvf_stat { 2262306a36Sopenharmony_ci char name[ETH_GSTRING_LEN]; 2362306a36Sopenharmony_ci unsigned int index; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define NICVF_HW_STAT(stat) { \ 2762306a36Sopenharmony_ci .name = #stat, \ 2862306a36Sopenharmony_ci .index = offsetof(struct nicvf_hw_stats, stat) / sizeof(u64), \ 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define NICVF_DRV_STAT(stat) { \ 3262306a36Sopenharmony_ci .name = #stat, \ 3362306a36Sopenharmony_ci .index = offsetof(struct nicvf_drv_stats, stat) / sizeof(u64), \ 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const struct nicvf_stat nicvf_hw_stats[] = { 3762306a36Sopenharmony_ci NICVF_HW_STAT(rx_bytes), 3862306a36Sopenharmony_ci NICVF_HW_STAT(rx_frames), 3962306a36Sopenharmony_ci NICVF_HW_STAT(rx_ucast_frames), 4062306a36Sopenharmony_ci NICVF_HW_STAT(rx_bcast_frames), 4162306a36Sopenharmony_ci NICVF_HW_STAT(rx_mcast_frames), 4262306a36Sopenharmony_ci NICVF_HW_STAT(rx_drops), 4362306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_red), 4462306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_red_bytes), 4562306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_overrun), 4662306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_overrun_bytes), 4762306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_bcast), 4862306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_mcast), 4962306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_l3_bcast), 5062306a36Sopenharmony_ci NICVF_HW_STAT(rx_drop_l3_mcast), 5162306a36Sopenharmony_ci NICVF_HW_STAT(rx_fcs_errors), 5262306a36Sopenharmony_ci NICVF_HW_STAT(rx_l2_errors), 5362306a36Sopenharmony_ci NICVF_HW_STAT(tx_bytes), 5462306a36Sopenharmony_ci NICVF_HW_STAT(tx_frames), 5562306a36Sopenharmony_ci NICVF_HW_STAT(tx_ucast_frames), 5662306a36Sopenharmony_ci NICVF_HW_STAT(tx_bcast_frames), 5762306a36Sopenharmony_ci NICVF_HW_STAT(tx_mcast_frames), 5862306a36Sopenharmony_ci NICVF_HW_STAT(tx_drops), 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const struct nicvf_stat nicvf_drv_stats[] = { 6262306a36Sopenharmony_ci NICVF_DRV_STAT(rx_bgx_truncated_pkts), 6362306a36Sopenharmony_ci NICVF_DRV_STAT(rx_jabber_errs), 6462306a36Sopenharmony_ci NICVF_DRV_STAT(rx_fcs_errs), 6562306a36Sopenharmony_ci NICVF_DRV_STAT(rx_bgx_errs), 6662306a36Sopenharmony_ci NICVF_DRV_STAT(rx_prel2_errs), 6762306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l2_hdr_malformed), 6862306a36Sopenharmony_ci NICVF_DRV_STAT(rx_oversize), 6962306a36Sopenharmony_ci NICVF_DRV_STAT(rx_undersize), 7062306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l2_len_mismatch), 7162306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l2_pclp), 7262306a36Sopenharmony_ci NICVF_DRV_STAT(rx_ip_ver_errs), 7362306a36Sopenharmony_ci NICVF_DRV_STAT(rx_ip_csum_errs), 7462306a36Sopenharmony_ci NICVF_DRV_STAT(rx_ip_hdr_malformed), 7562306a36Sopenharmony_ci NICVF_DRV_STAT(rx_ip_payload_malformed), 7662306a36Sopenharmony_ci NICVF_DRV_STAT(rx_ip_ttl_errs), 7762306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l3_pclp), 7862306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l4_malformed), 7962306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l4_csum_errs), 8062306a36Sopenharmony_ci NICVF_DRV_STAT(rx_udp_len_errs), 8162306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l4_port_errs), 8262306a36Sopenharmony_ci NICVF_DRV_STAT(rx_tcp_flag_errs), 8362306a36Sopenharmony_ci NICVF_DRV_STAT(rx_tcp_offset_errs), 8462306a36Sopenharmony_ci NICVF_DRV_STAT(rx_l4_pclp), 8562306a36Sopenharmony_ci NICVF_DRV_STAT(rx_truncated_pkts), 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci NICVF_DRV_STAT(tx_desc_fault), 8862306a36Sopenharmony_ci NICVF_DRV_STAT(tx_hdr_cons_err), 8962306a36Sopenharmony_ci NICVF_DRV_STAT(tx_subdesc_err), 9062306a36Sopenharmony_ci NICVF_DRV_STAT(tx_max_size_exceeded), 9162306a36Sopenharmony_ci NICVF_DRV_STAT(tx_imm_size_oflow), 9262306a36Sopenharmony_ci NICVF_DRV_STAT(tx_data_seq_err), 9362306a36Sopenharmony_ci NICVF_DRV_STAT(tx_mem_seq_err), 9462306a36Sopenharmony_ci NICVF_DRV_STAT(tx_lock_viol), 9562306a36Sopenharmony_ci NICVF_DRV_STAT(tx_data_fault), 9662306a36Sopenharmony_ci NICVF_DRV_STAT(tx_tstmp_conflict), 9762306a36Sopenharmony_ci NICVF_DRV_STAT(tx_tstmp_timeout), 9862306a36Sopenharmony_ci NICVF_DRV_STAT(tx_mem_fault), 9962306a36Sopenharmony_ci NICVF_DRV_STAT(tx_csum_overlap), 10062306a36Sopenharmony_ci NICVF_DRV_STAT(tx_csum_overflow), 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci NICVF_DRV_STAT(tx_tso), 10362306a36Sopenharmony_ci NICVF_DRV_STAT(tx_timeout), 10462306a36Sopenharmony_ci NICVF_DRV_STAT(txq_stop), 10562306a36Sopenharmony_ci NICVF_DRV_STAT(txq_wake), 10662306a36Sopenharmony_ci NICVF_DRV_STAT(rcv_buffer_alloc_failures), 10762306a36Sopenharmony_ci NICVF_DRV_STAT(page_alloc), 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct nicvf_stat nicvf_queue_stats[] = { 11162306a36Sopenharmony_ci { "bytes", 0 }, 11262306a36Sopenharmony_ci { "frames", 1 }, 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const unsigned int nicvf_n_hw_stats = ARRAY_SIZE(nicvf_hw_stats); 11662306a36Sopenharmony_cistatic const unsigned int nicvf_n_drv_stats = ARRAY_SIZE(nicvf_drv_stats); 11762306a36Sopenharmony_cistatic const unsigned int nicvf_n_queue_stats = ARRAY_SIZE(nicvf_queue_stats); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int nicvf_get_link_ksettings(struct net_device *netdev, 12062306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 12362306a36Sopenharmony_ci u32 supported, advertising; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci supported = 0; 12662306a36Sopenharmony_ci advertising = 0; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!nic->link_up) { 12962306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 13062306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci switch (nic->speed) { 13562306a36Sopenharmony_ci case SPEED_1000: 13662306a36Sopenharmony_ci cmd->base.port = PORT_MII | PORT_TP; 13762306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 13862306a36Sopenharmony_ci supported |= SUPPORTED_MII | SUPPORTED_TP; 13962306a36Sopenharmony_ci supported |= SUPPORTED_1000baseT_Full | 14062306a36Sopenharmony_ci SUPPORTED_1000baseT_Half | 14162306a36Sopenharmony_ci SUPPORTED_100baseT_Full | 14262306a36Sopenharmony_ci SUPPORTED_100baseT_Half | 14362306a36Sopenharmony_ci SUPPORTED_10baseT_Full | 14462306a36Sopenharmony_ci SUPPORTED_10baseT_Half; 14562306a36Sopenharmony_ci supported |= SUPPORTED_Autoneg; 14662306a36Sopenharmony_ci advertising |= ADVERTISED_1000baseT_Full | 14762306a36Sopenharmony_ci ADVERTISED_1000baseT_Half | 14862306a36Sopenharmony_ci ADVERTISED_100baseT_Full | 14962306a36Sopenharmony_ci ADVERTISED_100baseT_Half | 15062306a36Sopenharmony_ci ADVERTISED_10baseT_Full | 15162306a36Sopenharmony_ci ADVERTISED_10baseT_Half; 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case SPEED_10000: 15462306a36Sopenharmony_ci if (nic->mac_type == BGX_MODE_RXAUI) { 15562306a36Sopenharmony_ci cmd->base.port = PORT_TP; 15662306a36Sopenharmony_ci supported |= SUPPORTED_TP; 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 15962306a36Sopenharmony_ci supported |= SUPPORTED_FIBRE; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 16262306a36Sopenharmony_ci supported |= SUPPORTED_10000baseT_Full; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case SPEED_40000: 16562306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 16662306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 16762306a36Sopenharmony_ci supported |= SUPPORTED_FIBRE; 16862306a36Sopenharmony_ci supported |= SUPPORTED_40000baseCR4_Full; 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci cmd->base.duplex = nic->duplex; 17262306a36Sopenharmony_ci cmd->base.speed = nic->speed; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 17562306a36Sopenharmony_ci supported); 17662306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 17762306a36Sopenharmony_ci advertising); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic u32 nicvf_get_link(struct net_device *netdev) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return nic->link_up; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void nicvf_get_drvinfo(struct net_device *netdev, 19062306a36Sopenharmony_ci struct ethtool_drvinfo *info) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 19562306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(nic->pdev), sizeof(info->bus_info)); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic u32 nicvf_get_msglevel(struct net_device *netdev) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return nic->msg_enable; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void nicvf_set_msglevel(struct net_device *netdev, u32 lvl) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci nic->msg_enable = lvl; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void nicvf_get_qset_strings(struct nicvf *nic, u8 **data, int qset) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int stats, qidx; 21562306a36Sopenharmony_ci int start_qidx = qset * MAX_RCV_QUEUES_PER_QS; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { 21862306a36Sopenharmony_ci for (stats = 0; stats < nicvf_n_queue_stats; stats++) { 21962306a36Sopenharmony_ci sprintf(*data, "rxq%d: %s", qidx + start_qidx, 22062306a36Sopenharmony_ci nicvf_queue_stats[stats].name); 22162306a36Sopenharmony_ci *data += ETH_GSTRING_LEN; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { 22662306a36Sopenharmony_ci for (stats = 0; stats < nicvf_n_queue_stats; stats++) { 22762306a36Sopenharmony_ci sprintf(*data, "txq%d: %s", qidx + start_qidx, 22862306a36Sopenharmony_ci nicvf_queue_stats[stats].name); 22962306a36Sopenharmony_ci *data += ETH_GSTRING_LEN; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 23762306a36Sopenharmony_ci int stats; 23862306a36Sopenharmony_ci int sqs; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 24162306a36Sopenharmony_ci return; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (stats = 0; stats < nicvf_n_hw_stats; stats++) { 24462306a36Sopenharmony_ci memcpy(data, nicvf_hw_stats[stats].name, ETH_GSTRING_LEN); 24562306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci for (stats = 0; stats < nicvf_n_drv_stats; stats++) { 24962306a36Sopenharmony_ci memcpy(data, nicvf_drv_stats[stats].name, ETH_GSTRING_LEN); 25062306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci nicvf_get_qset_strings(nic, &data, 0); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 25662306a36Sopenharmony_ci if (!nic->snicvf[sqs]) 25762306a36Sopenharmony_ci continue; 25862306a36Sopenharmony_ci nicvf_get_qset_strings(nic->snicvf[sqs], &data, sqs + 1); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci for (stats = 0; stats < BGX_RX_STATS_COUNT; stats++) { 26262306a36Sopenharmony_ci sprintf(data, "bgx_rxstat%d: ", stats); 26362306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci for (stats = 0; stats < BGX_TX_STATS_COUNT; stats++) { 26762306a36Sopenharmony_ci sprintf(data, "bgx_txstat%d: ", stats); 26862306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int nicvf_get_sset_count(struct net_device *netdev, int sset) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 27562306a36Sopenharmony_ci int qstats_count; 27662306a36Sopenharmony_ci int sqs; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci qstats_count = nicvf_n_queue_stats * 28262306a36Sopenharmony_ci (nic->qs->rq_cnt + nic->qs->sq_cnt); 28362306a36Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 28462306a36Sopenharmony_ci struct nicvf *snic; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci snic = nic->snicvf[sqs]; 28762306a36Sopenharmony_ci if (!snic) 28862306a36Sopenharmony_ci continue; 28962306a36Sopenharmony_ci qstats_count += nicvf_n_queue_stats * 29062306a36Sopenharmony_ci (snic->qs->rq_cnt + snic->qs->sq_cnt); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return nicvf_n_hw_stats + nicvf_n_drv_stats + 29462306a36Sopenharmony_ci qstats_count + 29562306a36Sopenharmony_ci BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void nicvf_get_qset_stats(struct nicvf *nic, 29962306a36Sopenharmony_ci struct ethtool_stats *stats, u64 **data) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int stat, qidx; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (!nic) 30462306a36Sopenharmony_ci return; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { 30762306a36Sopenharmony_ci nicvf_update_rq_stats(nic, qidx); 30862306a36Sopenharmony_ci for (stat = 0; stat < nicvf_n_queue_stats; stat++) 30962306a36Sopenharmony_ci *((*data)++) = ((u64 *)&nic->qs->rq[qidx].stats) 31062306a36Sopenharmony_ci [nicvf_queue_stats[stat].index]; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { 31462306a36Sopenharmony_ci nicvf_update_sq_stats(nic, qidx); 31562306a36Sopenharmony_ci for (stat = 0; stat < nicvf_n_queue_stats; stat++) 31662306a36Sopenharmony_ci *((*data)++) = ((u64 *)&nic->qs->sq[qidx].stats) 31762306a36Sopenharmony_ci [nicvf_queue_stats[stat].index]; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void nicvf_get_ethtool_stats(struct net_device *netdev, 32262306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 32562306a36Sopenharmony_ci int stat, tmp_stats; 32662306a36Sopenharmony_ci int sqs, cpu; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci nicvf_update_stats(nic); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Update LMAC stats */ 33162306a36Sopenharmony_ci nicvf_update_lmac_stats(nic); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci for (stat = 0; stat < nicvf_n_hw_stats; stat++) 33462306a36Sopenharmony_ci *(data++) = ((u64 *)&nic->hw_stats) 33562306a36Sopenharmony_ci [nicvf_hw_stats[stat].index]; 33662306a36Sopenharmony_ci for (stat = 0; stat < nicvf_n_drv_stats; stat++) { 33762306a36Sopenharmony_ci tmp_stats = 0; 33862306a36Sopenharmony_ci for_each_possible_cpu(cpu) 33962306a36Sopenharmony_ci tmp_stats += ((u64 *)per_cpu_ptr(nic->drv_stats, cpu)) 34062306a36Sopenharmony_ci [nicvf_drv_stats[stat].index]; 34162306a36Sopenharmony_ci *(data++) = tmp_stats; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci nicvf_get_qset_stats(nic, stats, &data); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci for (sqs = 0; sqs < nic->sqs_count; sqs++) { 34762306a36Sopenharmony_ci if (!nic->snicvf[sqs]) 34862306a36Sopenharmony_ci continue; 34962306a36Sopenharmony_ci nicvf_get_qset_stats(nic->snicvf[sqs], stats, &data); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (stat = 0; stat < BGX_RX_STATS_COUNT; stat++) 35362306a36Sopenharmony_ci *(data++) = nic->bgx_stats.rx_stats[stat]; 35462306a36Sopenharmony_ci for (stat = 0; stat < BGX_TX_STATS_COUNT; stat++) 35562306a36Sopenharmony_ci *(data++) = nic->bgx_stats.tx_stats[stat]; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int nicvf_get_regs_len(struct net_device *dev) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return sizeof(u64) * NIC_VF_REG_COUNT; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void nicvf_get_regs(struct net_device *dev, 36462306a36Sopenharmony_ci struct ethtool_regs *regs, void *reg) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 36762306a36Sopenharmony_ci u64 *p = (u64 *)reg; 36862306a36Sopenharmony_ci u64 reg_offset; 36962306a36Sopenharmony_ci int mbox, key, stat, q; 37062306a36Sopenharmony_ci int i = 0; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci regs->version = 0; 37362306a36Sopenharmony_ci memset(p, 0, NIC_VF_REG_COUNT); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_CFG); 37662306a36Sopenharmony_ci /* Mailbox registers */ 37762306a36Sopenharmony_ci for (mbox = 0; mbox < NIC_PF_VF_MAILBOX_SIZE; mbox++) 37862306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 37962306a36Sopenharmony_ci NIC_VF_PF_MAILBOX_0_1 | (mbox << 3)); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_INT); 38262306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_INT_W1S); 38362306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1C); 38462306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1S); 38562306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci for (key = 0; key < RSS_HASH_KEY_SIZE; key++) 38862306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_KEY_0_4 | (key << 3)); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Tx/Rx statistics */ 39162306a36Sopenharmony_ci for (stat = 0; stat < TX_STATS_ENUM_LAST; stat++) 39262306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 39362306a36Sopenharmony_ci NIC_VNIC_TX_STAT_0_4 | (stat << 3)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci for (i = 0; i < RX_STATS_ENUM_LAST; i++) 39662306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, 39762306a36Sopenharmony_ci NIC_VNIC_RX_STAT_0_13 | (stat << 3)); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci p[i++] = nicvf_reg_read(nic, NIC_QSET_RQ_GEN_CFG); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* All completion queue's registers */ 40262306a36Sopenharmony_ci for (q = 0; q < MAX_CMP_QUEUES_PER_QS; q++) { 40362306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG, q); 40462306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG2, q); 40562306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_THRESH, q); 40662306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_BASE, q); 40762306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, q); 40862306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_TAIL, q); 40962306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DOOR, q); 41062306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, q); 41162306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS2, q); 41262306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DEBUG, q); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* All receive queue's registers */ 41662306a36Sopenharmony_ci for (q = 0; q < MAX_RCV_QUEUES_PER_QS; q++) { 41762306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RQ_0_7_CFG, q); 41862306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 41962306a36Sopenharmony_ci NIC_QSET_RQ_0_7_STAT_0_1, q); 42062306a36Sopenharmony_ci reg_offset = NIC_QSET_RQ_0_7_STAT_0_1 | (1 << 3); 42162306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci for (q = 0; q < MAX_SND_QUEUES_PER_QS; q++) { 42562306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, q); 42662306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_THRESH, q); 42762306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_BASE, q); 42862306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, q); 42962306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_TAIL, q); 43062306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q); 43162306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q); 43262306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q); 43362306a36Sopenharmony_ci /* Padding, was NIC_QSET_SQ_0_7_CNM_CHG, which 43462306a36Sopenharmony_ci * produces bus errors when read 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci p[i++] = 0; 43762306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q); 43862306a36Sopenharmony_ci reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3); 43962306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci for (q = 0; q < MAX_RCV_BUF_DESC_RINGS_PER_QS; q++) { 44362306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_CFG, q); 44462306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_THRESH, q); 44562306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_BASE, q); 44662306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, q); 44762306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, q); 44862306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_DOOR, q); 44962306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 45062306a36Sopenharmony_ci NIC_QSET_RBDR_0_1_STATUS0, q); 45162306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, 45262306a36Sopenharmony_ci NIC_QSET_RBDR_0_1_STATUS1, q); 45362306a36Sopenharmony_ci reg_offset = NIC_QSET_RBDR_0_1_PREFETCH_STATUS; 45462306a36Sopenharmony_ci p[i++] = nicvf_queue_reg_read(nic, reg_offset, q); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int nicvf_get_coalesce(struct net_device *netdev, 45962306a36Sopenharmony_ci struct ethtool_coalesce *cmd, 46062306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 46162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci cmd->rx_coalesce_usecs = nic->cq_coalesce_usecs; 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void nicvf_get_ringparam(struct net_device *netdev, 47062306a36Sopenharmony_ci struct ethtool_ringparam *ring, 47162306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 47262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 47562306a36Sopenharmony_ci struct queue_set *qs = nic->qs; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ring->rx_max_pending = MAX_CMP_QUEUE_LEN; 47862306a36Sopenharmony_ci ring->rx_pending = qs->cq_len; 47962306a36Sopenharmony_ci ring->tx_max_pending = MAX_SND_QUEUE_LEN; 48062306a36Sopenharmony_ci ring->tx_pending = qs->sq_len; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int nicvf_set_ringparam(struct net_device *netdev, 48462306a36Sopenharmony_ci struct ethtool_ringparam *ring, 48562306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 48662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 48962306a36Sopenharmony_ci struct queue_set *qs = nic->qs; 49062306a36Sopenharmony_ci u32 rx_count, tx_count; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Due to HW errata this is not supported on T88 pass 1.x silicon */ 49362306a36Sopenharmony_ci if (pass1_silicon(nic->pdev)) 49462306a36Sopenharmony_ci return -EINVAL; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci tx_count = clamp_t(u32, ring->tx_pending, 50062306a36Sopenharmony_ci MIN_SND_QUEUE_LEN, MAX_SND_QUEUE_LEN); 50162306a36Sopenharmony_ci rx_count = clamp_t(u32, ring->rx_pending, 50262306a36Sopenharmony_ci MIN_CMP_QUEUE_LEN, MAX_CMP_QUEUE_LEN); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if ((tx_count == qs->sq_len) && (rx_count == qs->cq_len)) 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Permitted lengths are 1K, 2K, 4K, 8K, 16K, 32K, 64K */ 50862306a36Sopenharmony_ci qs->sq_len = rounddown_pow_of_two(tx_count); 50962306a36Sopenharmony_ci qs->cq_len = rounddown_pow_of_two(rx_count); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (netif_running(netdev)) { 51262306a36Sopenharmony_ci nicvf_stop(netdev); 51362306a36Sopenharmony_ci nicvf_open(netdev); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int nicvf_get_rss_hash_opts(struct nicvf *nic, 52062306a36Sopenharmony_ci struct ethtool_rxnfc *info) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci info->data = 0; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci switch (info->flow_type) { 52562306a36Sopenharmony_ci case TCP_V4_FLOW: 52662306a36Sopenharmony_ci case TCP_V6_FLOW: 52762306a36Sopenharmony_ci case UDP_V4_FLOW: 52862306a36Sopenharmony_ci case UDP_V6_FLOW: 52962306a36Sopenharmony_ci case SCTP_V4_FLOW: 53062306a36Sopenharmony_ci case SCTP_V6_FLOW: 53162306a36Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 53262306a36Sopenharmony_ci fallthrough; 53362306a36Sopenharmony_ci case IPV4_FLOW: 53462306a36Sopenharmony_ci case IPV6_FLOW: 53562306a36Sopenharmony_ci info->data |= RXH_IP_SRC | RXH_IP_DST; 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci default: 53862306a36Sopenharmony_ci return -EINVAL; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int nicvf_get_rxnfc(struct net_device *dev, 54562306a36Sopenharmony_ci struct ethtool_rxnfc *info, u32 *rules) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 54862306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci switch (info->cmd) { 55162306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 55262306a36Sopenharmony_ci info->data = nic->rx_queues; 55362306a36Sopenharmony_ci ret = 0; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case ETHTOOL_GRXFH: 55662306a36Sopenharmony_ci return nicvf_get_rss_hash_opts(nic, info); 55762306a36Sopenharmony_ci default: 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci return ret; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int nicvf_set_rss_hash_opts(struct nicvf *nic, 56462306a36Sopenharmony_ci struct ethtool_rxnfc *info) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 56762306a36Sopenharmony_ci u64 rss_cfg = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!rss->enable) 57062306a36Sopenharmony_ci netdev_err(nic->netdev, 57162306a36Sopenharmony_ci "RSS is disabled, hash cannot be set\n"); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci netdev_info(nic->netdev, "Set RSS flow type = %d, data = %lld\n", 57462306a36Sopenharmony_ci info->flow_type, info->data); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST)) 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch (info->flow_type) { 58062306a36Sopenharmony_ci case TCP_V4_FLOW: 58162306a36Sopenharmony_ci case TCP_V6_FLOW: 58262306a36Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 58362306a36Sopenharmony_ci case 0: 58462306a36Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_TCP); 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 58762306a36Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_TCP); 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci default: 59062306a36Sopenharmony_ci return -EINVAL; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci case UDP_V4_FLOW: 59462306a36Sopenharmony_ci case UDP_V6_FLOW: 59562306a36Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 59662306a36Sopenharmony_ci case 0: 59762306a36Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_UDP); 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 60062306a36Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_UDP); 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci default: 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case SCTP_V4_FLOW: 60762306a36Sopenharmony_ci case SCTP_V6_FLOW: 60862306a36Sopenharmony_ci switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 60962306a36Sopenharmony_ci case 0: 61062306a36Sopenharmony_ci rss_cfg &= ~(1ULL << RSS_HASH_L4ETC); 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 61362306a36Sopenharmony_ci rss_cfg |= (1ULL << RSS_HASH_L4ETC); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci default: 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case IPV4_FLOW: 62062306a36Sopenharmony_ci case IPV6_FLOW: 62162306a36Sopenharmony_ci rss_cfg = RSS_HASH_IP; 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci default: 62462306a36Sopenharmony_ci return -EINVAL; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss_cfg); 62862306a36Sopenharmony_ci return 0; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int nicvf_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci switch (info->cmd) { 63662306a36Sopenharmony_ci case ETHTOOL_SRXFH: 63762306a36Sopenharmony_ci return nicvf_set_rss_hash_opts(nic, info); 63862306a36Sopenharmony_ci default: 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci return -EOPNOTSUPP; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic u32 nicvf_get_rxfh_key_size(struct net_device *netdev) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci return RSS_HASH_KEY_SIZE * sizeof(u64); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic u32 nicvf_get_rxfh_indir_size(struct net_device *dev) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return nic->rss_info.rss_size; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey, 65762306a36Sopenharmony_ci u8 *hfunc) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 66062306a36Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 66162306a36Sopenharmony_ci int idx; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (indir) { 66462306a36Sopenharmony_ci for (idx = 0; idx < rss->rss_size; idx++) 66562306a36Sopenharmony_ci indir[idx] = rss->ind_tbl[idx]; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (hkey) 66962306a36Sopenharmony_ci memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64)); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (hfunc) 67262306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int nicvf_set_rxfh(struct net_device *dev, const u32 *indir, 67862306a36Sopenharmony_ci const u8 *hkey, const u8 hfunc) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 68162306a36Sopenharmony_ci struct nicvf_rss_info *rss = &nic->rss_info; 68262306a36Sopenharmony_ci int idx; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 68562306a36Sopenharmony_ci return -EOPNOTSUPP; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!rss->enable) { 68862306a36Sopenharmony_ci netdev_err(nic->netdev, 68962306a36Sopenharmony_ci "RSS is disabled, cannot change settings\n"); 69062306a36Sopenharmony_ci return -EIO; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (indir) { 69462306a36Sopenharmony_ci for (idx = 0; idx < rss->rss_size; idx++) 69562306a36Sopenharmony_ci rss->ind_tbl[idx] = indir[idx]; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (hkey) { 69962306a36Sopenharmony_ci memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE * sizeof(u64)); 70062306a36Sopenharmony_ci nicvf_set_rss_key(nic); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci nicvf_config_rss(nic); 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/* Get no of queues device supports and current queue count */ 70862306a36Sopenharmony_cistatic void nicvf_get_channels(struct net_device *dev, 70962306a36Sopenharmony_ci struct ethtool_channels *channel) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci memset(channel, 0, sizeof(*channel)); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci channel->max_rx = nic->max_queues; 71662306a36Sopenharmony_ci channel->max_tx = nic->max_queues; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci channel->rx_count = nic->rx_queues; 71962306a36Sopenharmony_ci channel->tx_count = nic->tx_queues; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci/* Set no of Tx, Rx queues to be used */ 72362306a36Sopenharmony_cistatic int nicvf_set_channels(struct net_device *dev, 72462306a36Sopenharmony_ci struct ethtool_channels *channel) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 72762306a36Sopenharmony_ci int err = 0; 72862306a36Sopenharmony_ci bool if_up = netif_running(dev); 72962306a36Sopenharmony_ci u8 cqcount, txq_count; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (!channel->rx_count || !channel->tx_count) 73262306a36Sopenharmony_ci return -EINVAL; 73362306a36Sopenharmony_ci if (channel->rx_count > nic->max_queues) 73462306a36Sopenharmony_ci return -EINVAL; 73562306a36Sopenharmony_ci if (channel->tx_count > nic->max_queues) 73662306a36Sopenharmony_ci return -EINVAL; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (channel->tx_count + channel->rx_count > nic->max_queues) { 73962306a36Sopenharmony_ci if (nic->xdp_prog) { 74062306a36Sopenharmony_ci netdev_err(nic->netdev, 74162306a36Sopenharmony_ci "XDP mode, RXQs + TXQs > Max %d\n", 74262306a36Sopenharmony_ci nic->max_queues); 74362306a36Sopenharmony_ci return -EINVAL; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci xdp_clear_features_flag(nic->netdev); 74762306a36Sopenharmony_ci } else if (!pass1_silicon(nic->pdev)) { 74862306a36Sopenharmony_ci xdp_set_features_flag(dev, NETDEV_XDP_ACT_BASIC); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (if_up) 75262306a36Sopenharmony_ci nicvf_stop(dev); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci nic->rx_queues = channel->rx_count; 75562306a36Sopenharmony_ci nic->tx_queues = channel->tx_count; 75662306a36Sopenharmony_ci if (!nic->xdp_prog) 75762306a36Sopenharmony_ci nic->xdp_tx_queues = 0; 75862306a36Sopenharmony_ci else 75962306a36Sopenharmony_ci nic->xdp_tx_queues = channel->rx_count; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci txq_count = nic->xdp_tx_queues + nic->tx_queues; 76262306a36Sopenharmony_ci cqcount = max(nic->rx_queues, txq_count); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (cqcount > MAX_CMP_QUEUES_PER_QS) { 76562306a36Sopenharmony_ci nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS); 76662306a36Sopenharmony_ci nic->sqs_count = (nic->sqs_count / MAX_CMP_QUEUES_PER_QS) - 1; 76762306a36Sopenharmony_ci } else { 76862306a36Sopenharmony_ci nic->sqs_count = 0; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS); 77262306a36Sopenharmony_ci nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS); 77362306a36Sopenharmony_ci nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues); 77662306a36Sopenharmony_ci if (err) 77762306a36Sopenharmony_ci return err; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (if_up) 78062306a36Sopenharmony_ci nicvf_open(dev); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n", 78362306a36Sopenharmony_ci nic->tx_queues, nic->rx_queues); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void nicvf_get_pauseparam(struct net_device *dev, 78962306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 79262306a36Sopenharmony_ci union nic_mbx mbx = {}; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Supported only for 10G/40G interfaces */ 79562306a36Sopenharmony_ci if ((nic->mac_type == BGX_MODE_SGMII) || 79662306a36Sopenharmony_ci (nic->mac_type == BGX_MODE_QSGMII) || 79762306a36Sopenharmony_ci (nic->mac_type == BGX_MODE_RGMII)) 79862306a36Sopenharmony_ci return; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 80162306a36Sopenharmony_ci mbx.pfc.get = 1; 80262306a36Sopenharmony_ci if (!nicvf_send_msg_to_pf(nic, &mbx)) { 80362306a36Sopenharmony_ci pause->autoneg = nic->pfc.autoneg; 80462306a36Sopenharmony_ci pause->rx_pause = nic->pfc.fc_rx; 80562306a36Sopenharmony_ci pause->tx_pause = nic->pfc.fc_tx; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int nicvf_set_pauseparam(struct net_device *dev, 81062306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(dev); 81362306a36Sopenharmony_ci union nic_mbx mbx = {}; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* Supported only for 10G/40G interfaces */ 81662306a36Sopenharmony_ci if ((nic->mac_type == BGX_MODE_SGMII) || 81762306a36Sopenharmony_ci (nic->mac_type == BGX_MODE_QSGMII) || 81862306a36Sopenharmony_ci (nic->mac_type == BGX_MODE_RGMII)) 81962306a36Sopenharmony_ci return -EOPNOTSUPP; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (pause->autoneg) 82262306a36Sopenharmony_ci return -EOPNOTSUPP; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 82562306a36Sopenharmony_ci mbx.pfc.get = 0; 82662306a36Sopenharmony_ci mbx.pfc.fc_rx = pause->rx_pause; 82762306a36Sopenharmony_ci mbx.pfc.fc_tx = pause->tx_pause; 82862306a36Sopenharmony_ci if (nicvf_send_msg_to_pf(nic, &mbx)) 82962306a36Sopenharmony_ci return -EAGAIN; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci nic->pfc.fc_rx = pause->rx_pause; 83262306a36Sopenharmony_ci nic->pfc.fc_tx = pause->tx_pause; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int nicvf_get_ts_info(struct net_device *netdev, 83862306a36Sopenharmony_ci struct ethtool_ts_info *info) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct nicvf *nic = netdev_priv(netdev); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (!nic->ptp_clock) 84362306a36Sopenharmony_ci return ethtool_op_get_ts_info(netdev, info); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 84662306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 84762306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 84862306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 84962306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 85062306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci info->phc_index = cavium_ptp_clock_index(nic->ptp_clock); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 85762306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return 0; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic const struct ethtool_ops nicvf_ethtool_ops = { 86362306a36Sopenharmony_ci .get_link = nicvf_get_link, 86462306a36Sopenharmony_ci .get_drvinfo = nicvf_get_drvinfo, 86562306a36Sopenharmony_ci .get_msglevel = nicvf_get_msglevel, 86662306a36Sopenharmony_ci .set_msglevel = nicvf_set_msglevel, 86762306a36Sopenharmony_ci .get_strings = nicvf_get_strings, 86862306a36Sopenharmony_ci .get_sset_count = nicvf_get_sset_count, 86962306a36Sopenharmony_ci .get_ethtool_stats = nicvf_get_ethtool_stats, 87062306a36Sopenharmony_ci .get_regs_len = nicvf_get_regs_len, 87162306a36Sopenharmony_ci .get_regs = nicvf_get_regs, 87262306a36Sopenharmony_ci .get_coalesce = nicvf_get_coalesce, 87362306a36Sopenharmony_ci .get_ringparam = nicvf_get_ringparam, 87462306a36Sopenharmony_ci .set_ringparam = nicvf_set_ringparam, 87562306a36Sopenharmony_ci .get_rxnfc = nicvf_get_rxnfc, 87662306a36Sopenharmony_ci .set_rxnfc = nicvf_set_rxnfc, 87762306a36Sopenharmony_ci .get_rxfh_key_size = nicvf_get_rxfh_key_size, 87862306a36Sopenharmony_ci .get_rxfh_indir_size = nicvf_get_rxfh_indir_size, 87962306a36Sopenharmony_ci .get_rxfh = nicvf_get_rxfh, 88062306a36Sopenharmony_ci .set_rxfh = nicvf_set_rxfh, 88162306a36Sopenharmony_ci .get_channels = nicvf_get_channels, 88262306a36Sopenharmony_ci .set_channels = nicvf_set_channels, 88362306a36Sopenharmony_ci .get_pauseparam = nicvf_get_pauseparam, 88462306a36Sopenharmony_ci .set_pauseparam = nicvf_set_pauseparam, 88562306a36Sopenharmony_ci .get_ts_info = nicvf_get_ts_info, 88662306a36Sopenharmony_ci .get_link_ksettings = nicvf_get_link_ksettings, 88762306a36Sopenharmony_ci}; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_civoid nicvf_set_ethtool_ops(struct net_device *netdev) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci netdev->ethtool_ops = &nicvf_ethtool_ops; 89262306a36Sopenharmony_ci} 893