162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/ethtool.h> 462306a36Sopenharmony_ci#include <linux/linkmode.h> 562306a36Sopenharmony_ci#include <linux/netdevice.h> 662306a36Sopenharmony_ci#include <linux/nvme.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1162306a36Sopenharmony_ci#include "funeth.h" 1262306a36Sopenharmony_ci#include "fun_port.h" 1362306a36Sopenharmony_ci#include "funeth_txrx.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Min queue depth. The smallest power-of-2 supporting jumbo frames with 4K 1662306a36Sopenharmony_ci * pages is 8. Require it for all types of queues though some could work with 1762306a36Sopenharmony_ci * fewer entries. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci#define FUNETH_MIN_QDEPTH 8 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const char mac_tx_stat_names[][ETH_GSTRING_LEN] = { 2262306a36Sopenharmony_ci "mac_tx_octets_total", 2362306a36Sopenharmony_ci "mac_tx_frames_total", 2462306a36Sopenharmony_ci "mac_tx_vlan_frames_ok", 2562306a36Sopenharmony_ci "mac_tx_unicast_frames", 2662306a36Sopenharmony_ci "mac_tx_multicast_frames", 2762306a36Sopenharmony_ci "mac_tx_broadcast_frames", 2862306a36Sopenharmony_ci "mac_tx_errors", 2962306a36Sopenharmony_ci "mac_tx_CBFCPAUSE0", 3062306a36Sopenharmony_ci "mac_tx_CBFCPAUSE1", 3162306a36Sopenharmony_ci "mac_tx_CBFCPAUSE2", 3262306a36Sopenharmony_ci "mac_tx_CBFCPAUSE3", 3362306a36Sopenharmony_ci "mac_tx_CBFCPAUSE4", 3462306a36Sopenharmony_ci "mac_tx_CBFCPAUSE5", 3562306a36Sopenharmony_ci "mac_tx_CBFCPAUSE6", 3662306a36Sopenharmony_ci "mac_tx_CBFCPAUSE7", 3762306a36Sopenharmony_ci "mac_tx_CBFCPAUSE8", 3862306a36Sopenharmony_ci "mac_tx_CBFCPAUSE9", 3962306a36Sopenharmony_ci "mac_tx_CBFCPAUSE10", 4062306a36Sopenharmony_ci "mac_tx_CBFCPAUSE11", 4162306a36Sopenharmony_ci "mac_tx_CBFCPAUSE12", 4262306a36Sopenharmony_ci "mac_tx_CBFCPAUSE13", 4362306a36Sopenharmony_ci "mac_tx_CBFCPAUSE14", 4462306a36Sopenharmony_ci "mac_tx_CBFCPAUSE15", 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const char mac_rx_stat_names[][ETH_GSTRING_LEN] = { 4862306a36Sopenharmony_ci "mac_rx_octets_total", 4962306a36Sopenharmony_ci "mac_rx_frames_total", 5062306a36Sopenharmony_ci "mac_rx_VLAN_frames_ok", 5162306a36Sopenharmony_ci "mac_rx_unicast_frames", 5262306a36Sopenharmony_ci "mac_rx_multicast_frames", 5362306a36Sopenharmony_ci "mac_rx_broadcast_frames", 5462306a36Sopenharmony_ci "mac_rx_drop_events", 5562306a36Sopenharmony_ci "mac_rx_errors", 5662306a36Sopenharmony_ci "mac_rx_alignment_errors", 5762306a36Sopenharmony_ci "mac_rx_CBFCPAUSE0", 5862306a36Sopenharmony_ci "mac_rx_CBFCPAUSE1", 5962306a36Sopenharmony_ci "mac_rx_CBFCPAUSE2", 6062306a36Sopenharmony_ci "mac_rx_CBFCPAUSE3", 6162306a36Sopenharmony_ci "mac_rx_CBFCPAUSE4", 6262306a36Sopenharmony_ci "mac_rx_CBFCPAUSE5", 6362306a36Sopenharmony_ci "mac_rx_CBFCPAUSE6", 6462306a36Sopenharmony_ci "mac_rx_CBFCPAUSE7", 6562306a36Sopenharmony_ci "mac_rx_CBFCPAUSE8", 6662306a36Sopenharmony_ci "mac_rx_CBFCPAUSE9", 6762306a36Sopenharmony_ci "mac_rx_CBFCPAUSE10", 6862306a36Sopenharmony_ci "mac_rx_CBFCPAUSE11", 6962306a36Sopenharmony_ci "mac_rx_CBFCPAUSE12", 7062306a36Sopenharmony_ci "mac_rx_CBFCPAUSE13", 7162306a36Sopenharmony_ci "mac_rx_CBFCPAUSE14", 7262306a36Sopenharmony_ci "mac_rx_CBFCPAUSE15", 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const char * const txq_stat_names[] = { 7662306a36Sopenharmony_ci "tx_pkts", 7762306a36Sopenharmony_ci "tx_bytes", 7862306a36Sopenharmony_ci "tx_cso", 7962306a36Sopenharmony_ci "tx_tso", 8062306a36Sopenharmony_ci "tx_encapsulated_tso", 8162306a36Sopenharmony_ci "tx_uso", 8262306a36Sopenharmony_ci "tx_more", 8362306a36Sopenharmony_ci "tx_queue_stops", 8462306a36Sopenharmony_ci "tx_queue_restarts", 8562306a36Sopenharmony_ci "tx_mapping_errors", 8662306a36Sopenharmony_ci "tx_tls_encrypted_packets", 8762306a36Sopenharmony_ci "tx_tls_encrypted_bytes", 8862306a36Sopenharmony_ci "tx_tls_ooo", 8962306a36Sopenharmony_ci "tx_tls_drop_no_sync_data", 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const char * const xdpq_stat_names[] = { 9362306a36Sopenharmony_ci "tx_xdp_pkts", 9462306a36Sopenharmony_ci "tx_xdp_bytes", 9562306a36Sopenharmony_ci "tx_xdp_full", 9662306a36Sopenharmony_ci "tx_xdp_mapping_errors", 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic const char * const rxq_stat_names[] = { 10062306a36Sopenharmony_ci "rx_pkts", 10162306a36Sopenharmony_ci "rx_bytes", 10262306a36Sopenharmony_ci "rx_cso", 10362306a36Sopenharmony_ci "gro_pkts", 10462306a36Sopenharmony_ci "gro_merged", 10562306a36Sopenharmony_ci "rx_xdp_tx", 10662306a36Sopenharmony_ci "rx_xdp_redir", 10762306a36Sopenharmony_ci "rx_xdp_drops", 10862306a36Sopenharmony_ci "rx_buffers", 10962306a36Sopenharmony_ci "rx_page_allocs", 11062306a36Sopenharmony_ci "rx_drops", 11162306a36Sopenharmony_ci "rx_budget_exhausted", 11262306a36Sopenharmony_ci "rx_mapping_errors", 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const char * const tls_stat_names[] = { 11662306a36Sopenharmony_ci "tx_tls_ctx", 11762306a36Sopenharmony_ci "tx_tls_del", 11862306a36Sopenharmony_ci "tx_tls_resync", 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void fun_link_modes_to_ethtool(u64 modes, 12262306a36Sopenharmony_ci unsigned long *ethtool_modes_map) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci#define ADD_LINK_MODE(mode) \ 12562306a36Sopenharmony_ci __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, ethtool_modes_map) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_AUTONEG) 12862306a36Sopenharmony_ci ADD_LINK_MODE(Autoneg); 12962306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_1000_X) 13062306a36Sopenharmony_ci ADD_LINK_MODE(1000baseX_Full); 13162306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_10G_R) { 13262306a36Sopenharmony_ci ADD_LINK_MODE(10000baseCR_Full); 13362306a36Sopenharmony_ci ADD_LINK_MODE(10000baseSR_Full); 13462306a36Sopenharmony_ci ADD_LINK_MODE(10000baseLR_Full); 13562306a36Sopenharmony_ci ADD_LINK_MODE(10000baseER_Full); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_25G_R) { 13862306a36Sopenharmony_ci ADD_LINK_MODE(25000baseCR_Full); 13962306a36Sopenharmony_ci ADD_LINK_MODE(25000baseSR_Full); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_40G_R4) { 14262306a36Sopenharmony_ci ADD_LINK_MODE(40000baseCR4_Full); 14362306a36Sopenharmony_ci ADD_LINK_MODE(40000baseSR4_Full); 14462306a36Sopenharmony_ci ADD_LINK_MODE(40000baseLR4_Full); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_50G_R2) { 14762306a36Sopenharmony_ci ADD_LINK_MODE(50000baseCR2_Full); 14862306a36Sopenharmony_ci ADD_LINK_MODE(50000baseSR2_Full); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_50G_R) { 15162306a36Sopenharmony_ci ADD_LINK_MODE(50000baseCR_Full); 15262306a36Sopenharmony_ci ADD_LINK_MODE(50000baseSR_Full); 15362306a36Sopenharmony_ci ADD_LINK_MODE(50000baseLR_ER_FR_Full); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_100G_R4) { 15662306a36Sopenharmony_ci ADD_LINK_MODE(100000baseCR4_Full); 15762306a36Sopenharmony_ci ADD_LINK_MODE(100000baseSR4_Full); 15862306a36Sopenharmony_ci ADD_LINK_MODE(100000baseLR4_ER4_Full); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_100G_R2) { 16162306a36Sopenharmony_ci ADD_LINK_MODE(100000baseCR2_Full); 16262306a36Sopenharmony_ci ADD_LINK_MODE(100000baseSR2_Full); 16362306a36Sopenharmony_ci ADD_LINK_MODE(100000baseLR2_ER2_FR2_Full); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_FEC_NONE) 16662306a36Sopenharmony_ci ADD_LINK_MODE(FEC_NONE); 16762306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_FEC_FC) 16862306a36Sopenharmony_ci ADD_LINK_MODE(FEC_BASER); 16962306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_FEC_RS) 17062306a36Sopenharmony_ci ADD_LINK_MODE(FEC_RS); 17162306a36Sopenharmony_ci if (modes & FUN_PORT_CAP_RX_PAUSE) 17262306a36Sopenharmony_ci ADD_LINK_MODE(Pause); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#undef ADD_LINK_MODE 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void set_asym_pause(u64 advertising, struct ethtool_link_ksettings *ks) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci bool rx_pause, tx_pause; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci rx_pause = advertising & FUN_PORT_CAP_RX_PAUSE; 18262306a36Sopenharmony_ci tx_pause = advertising & FUN_PORT_CAP_TX_PAUSE; 18362306a36Sopenharmony_ci if (tx_pause ^ rx_pause) 18462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 18562306a36Sopenharmony_ci Asym_Pause); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic unsigned int fun_port_type(unsigned int xcvr) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci if (!xcvr) 19162306a36Sopenharmony_ci return PORT_NONE; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci switch (xcvr & 7) { 19462306a36Sopenharmony_ci case FUN_XCVR_BASET: 19562306a36Sopenharmony_ci return PORT_TP; 19662306a36Sopenharmony_ci case FUN_XCVR_CU: 19762306a36Sopenharmony_ci return PORT_DA; 19862306a36Sopenharmony_ci default: 19962306a36Sopenharmony_ci return PORT_FIBRE; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int fun_get_link_ksettings(struct net_device *netdev, 20462306a36Sopenharmony_ci struct ethtool_link_ksettings *ks) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 20762306a36Sopenharmony_ci unsigned int seq, speed, xcvr; 20862306a36Sopenharmony_ci u64 lp_advertising; 20962306a36Sopenharmony_ci bool link_up; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, supported); 21262306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, advertising); 21362306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, lp_advertising); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Link settings change asynchronously, take a consistent snapshot */ 21662306a36Sopenharmony_ci do { 21762306a36Sopenharmony_ci seq = read_seqcount_begin(&fp->link_seq); 21862306a36Sopenharmony_ci link_up = netif_carrier_ok(netdev); 21962306a36Sopenharmony_ci speed = fp->link_speed; 22062306a36Sopenharmony_ci xcvr = fp->xcvr_type; 22162306a36Sopenharmony_ci lp_advertising = fp->lp_advertising; 22262306a36Sopenharmony_ci } while (read_seqcount_retry(&fp->link_seq, seq)); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (link_up) { 22562306a36Sopenharmony_ci ks->base.speed = speed; 22662306a36Sopenharmony_ci ks->base.duplex = DUPLEX_FULL; 22762306a36Sopenharmony_ci fun_link_modes_to_ethtool(lp_advertising, 22862306a36Sopenharmony_ci ks->link_modes.lp_advertising); 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci ks->base.speed = SPEED_UNKNOWN; 23162306a36Sopenharmony_ci ks->base.duplex = DUPLEX_UNKNOWN; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ks->base.autoneg = (fp->advertising & FUN_PORT_CAP_AUTONEG) ? 23562306a36Sopenharmony_ci AUTONEG_ENABLE : AUTONEG_DISABLE; 23662306a36Sopenharmony_ci ks->base.port = fun_port_type(xcvr); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci fun_link_modes_to_ethtool(fp->port_caps, ks->link_modes.supported); 23962306a36Sopenharmony_ci if (fp->port_caps & (FUN_PORT_CAP_RX_PAUSE | FUN_PORT_CAP_TX_PAUSE)) 24062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Asym_Pause); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci fun_link_modes_to_ethtool(fp->advertising, ks->link_modes.advertising); 24362306a36Sopenharmony_ci set_asym_pause(fp->advertising, ks); 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic u64 fun_advert_modes(const struct ethtool_link_ksettings *ks) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci u64 modes = 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#define HAS_MODE(mode) \ 25262306a36Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, mode) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (HAS_MODE(1000baseX_Full)) 25562306a36Sopenharmony_ci modes |= FUN_PORT_CAP_1000_X; 25662306a36Sopenharmony_ci if (HAS_MODE(10000baseCR_Full) || HAS_MODE(10000baseSR_Full) || 25762306a36Sopenharmony_ci HAS_MODE(10000baseLR_Full) || HAS_MODE(10000baseER_Full)) 25862306a36Sopenharmony_ci modes |= FUN_PORT_CAP_10G_R; 25962306a36Sopenharmony_ci if (HAS_MODE(25000baseCR_Full) || HAS_MODE(25000baseSR_Full)) 26062306a36Sopenharmony_ci modes |= FUN_PORT_CAP_25G_R; 26162306a36Sopenharmony_ci if (HAS_MODE(40000baseCR4_Full) || HAS_MODE(40000baseSR4_Full) || 26262306a36Sopenharmony_ci HAS_MODE(40000baseLR4_Full)) 26362306a36Sopenharmony_ci modes |= FUN_PORT_CAP_40G_R4; 26462306a36Sopenharmony_ci if (HAS_MODE(50000baseCR2_Full) || HAS_MODE(50000baseSR2_Full)) 26562306a36Sopenharmony_ci modes |= FUN_PORT_CAP_50G_R2; 26662306a36Sopenharmony_ci if (HAS_MODE(50000baseCR_Full) || HAS_MODE(50000baseSR_Full) || 26762306a36Sopenharmony_ci HAS_MODE(50000baseLR_ER_FR_Full)) 26862306a36Sopenharmony_ci modes |= FUN_PORT_CAP_50G_R; 26962306a36Sopenharmony_ci if (HAS_MODE(100000baseCR4_Full) || HAS_MODE(100000baseSR4_Full) || 27062306a36Sopenharmony_ci HAS_MODE(100000baseLR4_ER4_Full)) 27162306a36Sopenharmony_ci modes |= FUN_PORT_CAP_100G_R4; 27262306a36Sopenharmony_ci if (HAS_MODE(100000baseCR2_Full) || HAS_MODE(100000baseSR2_Full) || 27362306a36Sopenharmony_ci HAS_MODE(100000baseLR2_ER2_FR2_Full)) 27462306a36Sopenharmony_ci modes |= FUN_PORT_CAP_100G_R2; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return modes; 27762306a36Sopenharmony_ci#undef HAS_MODE 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic u64 fun_speed_to_link_mode(unsigned int speed) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci switch (speed) { 28362306a36Sopenharmony_ci case SPEED_100000: 28462306a36Sopenharmony_ci return FUN_PORT_CAP_100G_R4 | FUN_PORT_CAP_100G_R2; 28562306a36Sopenharmony_ci case SPEED_50000: 28662306a36Sopenharmony_ci return FUN_PORT_CAP_50G_R | FUN_PORT_CAP_50G_R2; 28762306a36Sopenharmony_ci case SPEED_40000: 28862306a36Sopenharmony_ci return FUN_PORT_CAP_40G_R4; 28962306a36Sopenharmony_ci case SPEED_25000: 29062306a36Sopenharmony_ci return FUN_PORT_CAP_25G_R; 29162306a36Sopenharmony_ci case SPEED_10000: 29262306a36Sopenharmony_ci return FUN_PORT_CAP_10G_R; 29362306a36Sopenharmony_ci case SPEED_1000: 29462306a36Sopenharmony_ci return FUN_PORT_CAP_1000_X; 29562306a36Sopenharmony_ci default: 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int fun_change_advert(struct funeth_priv *fp, u64 new_advert) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci int err; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (new_advert == fp->advertising) 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci err = fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT, new_advert); 30862306a36Sopenharmony_ci if (!err) 30962306a36Sopenharmony_ci fp->advertising = new_advert; 31062306a36Sopenharmony_ci return err; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci#define FUN_PORT_CAP_FEC_MASK \ 31462306a36Sopenharmony_ci (FUN_PORT_CAP_FEC_NONE | FUN_PORT_CAP_FEC_FC | FUN_PORT_CAP_FEC_RS) 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int fun_set_link_ksettings(struct net_device *netdev, 31762306a36Sopenharmony_ci const struct ethtool_link_ksettings *ks) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {}; 32062306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 32162306a36Sopenharmony_ci u64 new_advert; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* eswitch ports don't support mode changes */ 32462306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_VPORT) 32562306a36Sopenharmony_ci return -EOPNOTSUPP; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (ks->base.duplex == DUPLEX_HALF) 32862306a36Sopenharmony_ci return -EINVAL; 32962306a36Sopenharmony_ci if (ks->base.autoneg == AUTONEG_ENABLE && 33062306a36Sopenharmony_ci !(fp->port_caps & FUN_PORT_CAP_AUTONEG)) 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (ks->base.autoneg == AUTONEG_ENABLE) { 33462306a36Sopenharmony_ci if (linkmode_empty(ks->link_modes.advertising)) 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci fun_link_modes_to_ethtool(fp->port_caps, supported); 33862306a36Sopenharmony_ci if (!linkmode_subset(ks->link_modes.advertising, supported)) 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci new_advert = fun_advert_modes(ks) | FUN_PORT_CAP_AUTONEG; 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci new_advert = fun_speed_to_link_mode(ks->base.speed); 34462306a36Sopenharmony_ci new_advert &= fp->port_caps; 34562306a36Sopenharmony_ci if (!new_advert) 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci new_advert |= fp->advertising & 34962306a36Sopenharmony_ci (FUN_PORT_CAP_PAUSE_MASK | FUN_PORT_CAP_FEC_MASK); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return fun_change_advert(fp, new_advert); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void fun_get_pauseparam(struct net_device *netdev, 35562306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 35862306a36Sopenharmony_ci u8 active_pause = fp->active_fc; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci pause->rx_pause = !!(active_pause & FUN_PORT_CAP_RX_PAUSE); 36162306a36Sopenharmony_ci pause->tx_pause = !!(active_pause & FUN_PORT_CAP_TX_PAUSE); 36262306a36Sopenharmony_ci pause->autoneg = !!(fp->advertising & FUN_PORT_CAP_AUTONEG); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int fun_set_pauseparam(struct net_device *netdev, 36662306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 36962306a36Sopenharmony_ci u64 new_advert; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_VPORT) 37262306a36Sopenharmony_ci return -EOPNOTSUPP; 37362306a36Sopenharmony_ci /* Forcing PAUSE settings with AN enabled is unsupported. */ 37462306a36Sopenharmony_ci if (!pause->autoneg && (fp->advertising & FUN_PORT_CAP_AUTONEG)) 37562306a36Sopenharmony_ci return -EOPNOTSUPP; 37662306a36Sopenharmony_ci if (pause->autoneg && !(fp->advertising & FUN_PORT_CAP_AUTONEG)) 37762306a36Sopenharmony_ci return -EINVAL; 37862306a36Sopenharmony_ci if (pause->tx_pause && !(fp->port_caps & FUN_PORT_CAP_TX_PAUSE)) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci if (pause->rx_pause && !(fp->port_caps & FUN_PORT_CAP_RX_PAUSE)) 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci new_advert = fp->advertising & ~FUN_PORT_CAP_PAUSE_MASK; 38462306a36Sopenharmony_ci if (pause->tx_pause) 38562306a36Sopenharmony_ci new_advert |= FUN_PORT_CAP_TX_PAUSE; 38662306a36Sopenharmony_ci if (pause->rx_pause) 38762306a36Sopenharmony_ci new_advert |= FUN_PORT_CAP_RX_PAUSE; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return fun_change_advert(fp, new_advert); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int fun_restart_an(struct net_device *netdev) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!(fp->advertising & FUN_PORT_CAP_AUTONEG)) 39762306a36Sopenharmony_ci return -EOPNOTSUPP; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT, 40062306a36Sopenharmony_ci FUN_PORT_CAP_AUTONEG); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int fun_set_phys_id(struct net_device *netdev, 40462306a36Sopenharmony_ci enum ethtool_phys_id_state state) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 40762306a36Sopenharmony_ci unsigned int beacon; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_VPORT) 41062306a36Sopenharmony_ci return -EOPNOTSUPP; 41162306a36Sopenharmony_ci if (state != ETHTOOL_ID_ACTIVE && state != ETHTOOL_ID_INACTIVE) 41262306a36Sopenharmony_ci return -EOPNOTSUPP; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci beacon = state == ETHTOOL_ID_ACTIVE ? FUN_PORT_LED_BEACON_ON : 41562306a36Sopenharmony_ci FUN_PORT_LED_BEACON_OFF; 41662306a36Sopenharmony_ci return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_LED, beacon); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void fun_get_drvinfo(struct net_device *netdev, 42062306a36Sopenharmony_ci struct ethtool_drvinfo *info) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 42562306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(fp->pdev), sizeof(info->bus_info)); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic u32 fun_get_msglevel(struct net_device *netdev) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return fp->msg_enable; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void fun_set_msglevel(struct net_device *netdev, u32 value) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci fp->msg_enable = value; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int fun_get_regs_len(struct net_device *dev) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci return NVME_REG_ACQ + sizeof(u64); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void fun_get_regs(struct net_device *dev, struct ethtool_regs *regs, 44862306a36Sopenharmony_ci void *buf) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(dev); 45162306a36Sopenharmony_ci void __iomem *bar = fp->fdev->bar; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci regs->version = 0; 45462306a36Sopenharmony_ci *(u64 *)(buf + NVME_REG_CAP) = readq(bar + NVME_REG_CAP); 45562306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_VS) = readl(bar + NVME_REG_VS); 45662306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_INTMS) = readl(bar + NVME_REG_INTMS); 45762306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_INTMC) = readl(bar + NVME_REG_INTMC); 45862306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_CC) = readl(bar + NVME_REG_CC); 45962306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_CSTS) = readl(bar + NVME_REG_CSTS); 46062306a36Sopenharmony_ci *(u32 *)(buf + NVME_REG_AQA) = readl(bar + NVME_REG_AQA); 46162306a36Sopenharmony_ci *(u64 *)(buf + NVME_REG_ASQ) = readq(bar + NVME_REG_ASQ); 46262306a36Sopenharmony_ci *(u64 *)(buf + NVME_REG_ACQ) = readq(bar + NVME_REG_ACQ); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int fun_get_coalesce(struct net_device *netdev, 46662306a36Sopenharmony_ci struct ethtool_coalesce *coal, 46762306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kcoal, 46862306a36Sopenharmony_ci struct netlink_ext_ack *ext_ack) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci coal->rx_coalesce_usecs = fp->rx_coal_usec; 47362306a36Sopenharmony_ci coal->rx_max_coalesced_frames = fp->rx_coal_count; 47462306a36Sopenharmony_ci coal->use_adaptive_rx_coalesce = !fp->cq_irq_db; 47562306a36Sopenharmony_ci coal->tx_coalesce_usecs = fp->tx_coal_usec; 47662306a36Sopenharmony_ci coal->tx_max_coalesced_frames = fp->tx_coal_count; 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int fun_set_coalesce(struct net_device *netdev, 48162306a36Sopenharmony_ci struct ethtool_coalesce *coal, 48262306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kcoal, 48362306a36Sopenharmony_ci struct netlink_ext_ack *ext_ack) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 48662306a36Sopenharmony_ci struct funeth_rxq **rxqs; 48762306a36Sopenharmony_ci unsigned int i, db_val; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (coal->rx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M || 49062306a36Sopenharmony_ci coal->rx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M || 49162306a36Sopenharmony_ci (coal->rx_coalesce_usecs | coal->rx_max_coalesced_frames) == 0 || 49262306a36Sopenharmony_ci coal->tx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M || 49362306a36Sopenharmony_ci coal->tx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M || 49462306a36Sopenharmony_ci (coal->tx_coalesce_usecs | coal->tx_max_coalesced_frames) == 0) 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* a timer is required if there's any coalescing */ 49862306a36Sopenharmony_ci if ((coal->rx_max_coalesced_frames > 1 && !coal->rx_coalesce_usecs) || 49962306a36Sopenharmony_ci (coal->tx_max_coalesced_frames > 1 && !coal->tx_coalesce_usecs)) 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci fp->rx_coal_usec = coal->rx_coalesce_usecs; 50362306a36Sopenharmony_ci fp->rx_coal_count = coal->rx_max_coalesced_frames; 50462306a36Sopenharmony_ci fp->tx_coal_usec = coal->tx_coalesce_usecs; 50562306a36Sopenharmony_ci fp->tx_coal_count = coal->tx_max_coalesced_frames; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci db_val = FUN_IRQ_CQ_DB(fp->rx_coal_usec, fp->rx_coal_count); 50862306a36Sopenharmony_ci WRITE_ONCE(fp->cq_irq_db, db_val); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci rxqs = rtnl_dereference(fp->rxqs); 51162306a36Sopenharmony_ci if (!rxqs) 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_rx_queues; i++) 51562306a36Sopenharmony_ci WRITE_ONCE(rxqs[i]->irq_db_val, db_val); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci db_val = FUN_IRQ_SQ_DB(fp->tx_coal_usec, fp->tx_coal_count); 51862306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_tx_queues; i++) 51962306a36Sopenharmony_ci WRITE_ONCE(fp->txqs[i]->irq_db_val, db_val); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic void fun_get_channels(struct net_device *netdev, 52562306a36Sopenharmony_ci struct ethtool_channels *chan) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci chan->max_rx = netdev->num_rx_queues; 52862306a36Sopenharmony_ci chan->rx_count = netdev->real_num_rx_queues; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci chan->max_tx = netdev->num_tx_queues; 53162306a36Sopenharmony_ci chan->tx_count = netdev->real_num_tx_queues; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int fun_set_channels(struct net_device *netdev, 53562306a36Sopenharmony_ci struct ethtool_channels *chan) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci if (!chan->tx_count || !chan->rx_count) 53862306a36Sopenharmony_ci return -EINVAL; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (chan->tx_count == netdev->real_num_tx_queues && 54162306a36Sopenharmony_ci chan->rx_count == netdev->real_num_rx_queues) 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (netif_running(netdev)) 54562306a36Sopenharmony_ci return fun_change_num_queues(netdev, chan->tx_count, 54662306a36Sopenharmony_ci chan->rx_count); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci fun_set_ring_count(netdev, chan->tx_count, chan->rx_count); 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic void fun_get_ringparam(struct net_device *netdev, 55362306a36Sopenharmony_ci struct ethtool_ringparam *ring, 55462306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kring, 55562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 55862306a36Sopenharmony_ci unsigned int max_depth = fp->fdev->q_depth; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* We size CQs to be twice the RQ depth so max RQ depth is half the 56162306a36Sopenharmony_ci * max queue depth. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci ring->rx_max_pending = max_depth / 2; 56462306a36Sopenharmony_ci ring->tx_max_pending = max_depth; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ring->rx_pending = fp->rq_depth; 56762306a36Sopenharmony_ci ring->tx_pending = fp->sq_depth; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci kring->rx_buf_len = PAGE_SIZE; 57062306a36Sopenharmony_ci kring->cqe_size = FUNETH_CQE_SIZE; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int fun_set_ringparam(struct net_device *netdev, 57462306a36Sopenharmony_ci struct ethtool_ringparam *ring, 57562306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kring, 57662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 57962306a36Sopenharmony_ci int rc; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (ring->rx_mini_pending || ring->rx_jumbo_pending) 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* queue depths must be powers-of-2 */ 58562306a36Sopenharmony_ci if (!is_power_of_2(ring->rx_pending) || 58662306a36Sopenharmony_ci !is_power_of_2(ring->tx_pending)) 58762306a36Sopenharmony_ci return -EINVAL; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (ring->rx_pending < FUNETH_MIN_QDEPTH || 59062306a36Sopenharmony_ci ring->tx_pending < FUNETH_MIN_QDEPTH) 59162306a36Sopenharmony_ci return -EINVAL; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (fp->sq_depth == ring->tx_pending && 59462306a36Sopenharmony_ci fp->rq_depth == ring->rx_pending) 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (netif_running(netdev)) { 59862306a36Sopenharmony_ci struct fun_qset req = { 59962306a36Sopenharmony_ci .cq_depth = 2 * ring->rx_pending, 60062306a36Sopenharmony_ci .rq_depth = ring->rx_pending, 60162306a36Sopenharmony_ci .sq_depth = ring->tx_pending 60262306a36Sopenharmony_ci }; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci rc = fun_replace_queues(netdev, &req, extack); 60562306a36Sopenharmony_ci if (rc) 60662306a36Sopenharmony_ci return rc; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci fp->sq_depth = ring->tx_pending; 61062306a36Sopenharmony_ci fp->rq_depth = ring->rx_pending; 61162306a36Sopenharmony_ci fp->cq_depth = 2 * fp->rq_depth; 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int fun_get_sset_count(struct net_device *dev, int sset) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(dev); 61862306a36Sopenharmony_ci int n; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci switch (sset) { 62162306a36Sopenharmony_ci case ETH_SS_STATS: 62262306a36Sopenharmony_ci n = (dev->real_num_tx_queues + 1) * ARRAY_SIZE(txq_stat_names) + 62362306a36Sopenharmony_ci (dev->real_num_rx_queues + 1) * ARRAY_SIZE(rxq_stat_names) + 62462306a36Sopenharmony_ci (fp->num_xdpqs + 1) * ARRAY_SIZE(xdpq_stat_names) + 62562306a36Sopenharmony_ci ARRAY_SIZE(tls_stat_names); 62662306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_STATS) { 62762306a36Sopenharmony_ci n += ARRAY_SIZE(mac_tx_stat_names) + 62862306a36Sopenharmony_ci ARRAY_SIZE(mac_rx_stat_names); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci return n; 63162306a36Sopenharmony_ci default: 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 64062306a36Sopenharmony_ci unsigned int i, j; 64162306a36Sopenharmony_ci u8 *p = data; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci switch (sset) { 64462306a36Sopenharmony_ci case ETH_SS_STATS: 64562306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_STATS) { 64662306a36Sopenharmony_ci memcpy(p, mac_tx_stat_names, sizeof(mac_tx_stat_names)); 64762306a36Sopenharmony_ci p += sizeof(mac_tx_stat_names); 64862306a36Sopenharmony_ci memcpy(p, mac_rx_stat_names, sizeof(mac_rx_stat_names)); 64962306a36Sopenharmony_ci p += sizeof(mac_rx_stat_names); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_tx_queues; i++) { 65362306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++) 65462306a36Sopenharmony_ci ethtool_sprintf(&p, "%s[%u]", txq_stat_names[j], 65562306a36Sopenharmony_ci i); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++) 65862306a36Sopenharmony_ci ethtool_sprintf(&p, txq_stat_names[j]); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci for (i = 0; i < fp->num_xdpqs; i++) { 66162306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++) 66262306a36Sopenharmony_ci ethtool_sprintf(&p, "%s[%u]", 66362306a36Sopenharmony_ci xdpq_stat_names[j], i); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++) 66662306a36Sopenharmony_ci ethtool_sprintf(&p, xdpq_stat_names[j]); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_rx_queues; i++) { 66962306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++) 67062306a36Sopenharmony_ci ethtool_sprintf(&p, "%s[%u]", rxq_stat_names[j], 67162306a36Sopenharmony_ci i); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++) 67462306a36Sopenharmony_ci ethtool_sprintf(&p, rxq_stat_names[j]); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++) 67762306a36Sopenharmony_ci ethtool_sprintf(&p, tls_stat_names[j]); 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci default: 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic u64 *get_mac_stats(const struct funeth_priv *fp, u64 *data) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci#define TX_STAT(s) \ 68762306a36Sopenharmony_ci *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s]) 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci TX_STAT(etherStatsOctets); 69062306a36Sopenharmony_ci TX_STAT(etherStatsPkts); 69162306a36Sopenharmony_ci TX_STAT(VLANTransmittedOK); 69262306a36Sopenharmony_ci TX_STAT(ifOutUcastPkts); 69362306a36Sopenharmony_ci TX_STAT(ifOutMulticastPkts); 69462306a36Sopenharmony_ci TX_STAT(ifOutBroadcastPkts); 69562306a36Sopenharmony_ci TX_STAT(ifOutErrors); 69662306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_0); 69762306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_1); 69862306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_2); 69962306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_3); 70062306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_4); 70162306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_5); 70262306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_6); 70362306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_7); 70462306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_8); 70562306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_9); 70662306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_10); 70762306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_11); 70862306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_12); 70962306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_13); 71062306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_14); 71162306a36Sopenharmony_ci TX_STAT(CBFCPAUSEFramesTransmitted_15); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci#define RX_STAT(s) *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_##s]) 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci RX_STAT(etherStatsOctets); 71662306a36Sopenharmony_ci RX_STAT(etherStatsPkts); 71762306a36Sopenharmony_ci RX_STAT(VLANReceivedOK); 71862306a36Sopenharmony_ci RX_STAT(ifInUcastPkts); 71962306a36Sopenharmony_ci RX_STAT(ifInMulticastPkts); 72062306a36Sopenharmony_ci RX_STAT(ifInBroadcastPkts); 72162306a36Sopenharmony_ci RX_STAT(etherStatsDropEvents); 72262306a36Sopenharmony_ci RX_STAT(ifInErrors); 72362306a36Sopenharmony_ci RX_STAT(aAlignmentErrors); 72462306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_0); 72562306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_1); 72662306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_2); 72762306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_3); 72862306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_4); 72962306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_5); 73062306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_6); 73162306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_7); 73262306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_8); 73362306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_9); 73462306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_10); 73562306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_11); 73662306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_12); 73762306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_13); 73862306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_14); 73962306a36Sopenharmony_ci RX_STAT(CBFCPAUSEFramesReceived_15); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return data; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci#undef TX_STAT 74462306a36Sopenharmony_ci#undef RX_STAT 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic void fun_get_ethtool_stats(struct net_device *netdev, 74862306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 75162306a36Sopenharmony_ci struct funeth_txq_stats txs; 75262306a36Sopenharmony_ci struct funeth_rxq_stats rxs; 75362306a36Sopenharmony_ci struct funeth_txq **xdpqs; 75462306a36Sopenharmony_ci struct funeth_rxq **rxqs; 75562306a36Sopenharmony_ci unsigned int i, start; 75662306a36Sopenharmony_ci u64 *totals, *tot; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_STATS) 75962306a36Sopenharmony_ci data = get_mac_stats(fp, data); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci rxqs = rtnl_dereference(fp->rxqs); 76262306a36Sopenharmony_ci if (!rxqs) 76362306a36Sopenharmony_ci return; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci#define ADD_STAT(cnt) do { \ 76662306a36Sopenharmony_ci *data = (cnt); *tot++ += *data++; \ 76762306a36Sopenharmony_ci} while (0) 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Tx queues */ 77062306a36Sopenharmony_ci totals = data + netdev->real_num_tx_queues * ARRAY_SIZE(txq_stat_names); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_tx_queues; i++) { 77362306a36Sopenharmony_ci tot = totals; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci FUN_QSTAT_READ(fp->txqs[i], start, txs); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci ADD_STAT(txs.tx_pkts); 77862306a36Sopenharmony_ci ADD_STAT(txs.tx_bytes); 77962306a36Sopenharmony_ci ADD_STAT(txs.tx_cso); 78062306a36Sopenharmony_ci ADD_STAT(txs.tx_tso); 78162306a36Sopenharmony_ci ADD_STAT(txs.tx_encap_tso); 78262306a36Sopenharmony_ci ADD_STAT(txs.tx_uso); 78362306a36Sopenharmony_ci ADD_STAT(txs.tx_more); 78462306a36Sopenharmony_ci ADD_STAT(txs.tx_nstops); 78562306a36Sopenharmony_ci ADD_STAT(txs.tx_nrestarts); 78662306a36Sopenharmony_ci ADD_STAT(txs.tx_map_err); 78762306a36Sopenharmony_ci ADD_STAT(txs.tx_tls_pkts); 78862306a36Sopenharmony_ci ADD_STAT(txs.tx_tls_bytes); 78962306a36Sopenharmony_ci ADD_STAT(txs.tx_tls_fallback); 79062306a36Sopenharmony_ci ADD_STAT(txs.tx_tls_drops); 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci data += ARRAY_SIZE(txq_stat_names); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* XDP Tx queues */ 79562306a36Sopenharmony_ci xdpqs = rtnl_dereference(fp->xdpqs); 79662306a36Sopenharmony_ci totals = data + fp->num_xdpqs * ARRAY_SIZE(xdpq_stat_names); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci for (i = 0; i < fp->num_xdpqs; i++) { 79962306a36Sopenharmony_ci tot = totals; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci FUN_QSTAT_READ(xdpqs[i], start, txs); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ADD_STAT(txs.tx_pkts); 80462306a36Sopenharmony_ci ADD_STAT(txs.tx_bytes); 80562306a36Sopenharmony_ci ADD_STAT(txs.tx_xdp_full); 80662306a36Sopenharmony_ci ADD_STAT(txs.tx_map_err); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci data += ARRAY_SIZE(xdpq_stat_names); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Rx queues */ 81162306a36Sopenharmony_ci totals = data + netdev->real_num_rx_queues * ARRAY_SIZE(rxq_stat_names); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci for (i = 0; i < netdev->real_num_rx_queues; i++) { 81462306a36Sopenharmony_ci tot = totals; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci FUN_QSTAT_READ(rxqs[i], start, rxs); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ADD_STAT(rxs.rx_pkts); 81962306a36Sopenharmony_ci ADD_STAT(rxs.rx_bytes); 82062306a36Sopenharmony_ci ADD_STAT(rxs.rx_cso); 82162306a36Sopenharmony_ci ADD_STAT(rxs.gro_pkts); 82262306a36Sopenharmony_ci ADD_STAT(rxs.gro_merged); 82362306a36Sopenharmony_ci ADD_STAT(rxs.xdp_tx); 82462306a36Sopenharmony_ci ADD_STAT(rxs.xdp_redir); 82562306a36Sopenharmony_ci ADD_STAT(rxs.xdp_drops); 82662306a36Sopenharmony_ci ADD_STAT(rxs.rx_bufs); 82762306a36Sopenharmony_ci ADD_STAT(rxs.rx_page_alloc); 82862306a36Sopenharmony_ci ADD_STAT(rxs.rx_mem_drops + rxs.xdp_err); 82962306a36Sopenharmony_ci ADD_STAT(rxs.rx_budget); 83062306a36Sopenharmony_ci ADD_STAT(rxs.rx_map_err); 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci data += ARRAY_SIZE(rxq_stat_names); 83362306a36Sopenharmony_ci#undef ADD_STAT 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci *data++ = atomic64_read(&fp->tx_tls_add); 83662306a36Sopenharmony_ci *data++ = atomic64_read(&fp->tx_tls_del); 83762306a36Sopenharmony_ci *data++ = atomic64_read(&fp->tx_tls_resync); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci#define RX_STAT(fp, s) be64_to_cpu((fp)->stats[PORT_MAC_RX_##s]) 84162306a36Sopenharmony_ci#define TX_STAT(fp, s) \ 84262306a36Sopenharmony_ci be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s]) 84362306a36Sopenharmony_ci#define FEC_STAT(fp, s) \ 84462306a36Sopenharmony_ci be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + \ 84562306a36Sopenharmony_ci PORT_MAC_TX_STATS_MAX + PORT_MAC_FEC_##s]) 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void fun_get_pause_stats(struct net_device *netdev, 84862306a36Sopenharmony_ci struct ethtool_pause_stats *stats) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_STATS)) 85362306a36Sopenharmony_ci return; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci stats->tx_pause_frames = TX_STAT(fp, aPAUSEMACCtrlFramesTransmitted); 85662306a36Sopenharmony_ci stats->rx_pause_frames = RX_STAT(fp, aPAUSEMACCtrlFramesReceived); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic void fun_get_802_3_stats(struct net_device *netdev, 86062306a36Sopenharmony_ci struct ethtool_eth_mac_stats *stats) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_STATS)) 86562306a36Sopenharmony_ci return; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci stats->FramesTransmittedOK = TX_STAT(fp, aFramesTransmittedOK); 86862306a36Sopenharmony_ci stats->FramesReceivedOK = RX_STAT(fp, aFramesReceivedOK); 86962306a36Sopenharmony_ci stats->FrameCheckSequenceErrors = RX_STAT(fp, aFrameCheckSequenceErrors); 87062306a36Sopenharmony_ci stats->OctetsTransmittedOK = TX_STAT(fp, OctetsTransmittedOK); 87162306a36Sopenharmony_ci stats->OctetsReceivedOK = RX_STAT(fp, OctetsReceivedOK); 87262306a36Sopenharmony_ci stats->InRangeLengthErrors = RX_STAT(fp, aInRangeLengthErrors); 87362306a36Sopenharmony_ci stats->FrameTooLongErrors = RX_STAT(fp, aFrameTooLongErrors); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic void fun_get_802_3_ctrl_stats(struct net_device *netdev, 87762306a36Sopenharmony_ci struct ethtool_eth_ctrl_stats *stats) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_STATS)) 88262306a36Sopenharmony_ci return; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci stats->MACControlFramesTransmitted = TX_STAT(fp, MACControlFramesTransmitted); 88562306a36Sopenharmony_ci stats->MACControlFramesReceived = RX_STAT(fp, MACControlFramesReceived); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void fun_get_rmon_stats(struct net_device *netdev, 88962306a36Sopenharmony_ci struct ethtool_rmon_stats *stats, 89062306a36Sopenharmony_ci const struct ethtool_rmon_hist_range **ranges) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci static const struct ethtool_rmon_hist_range rmon_ranges[] = { 89362306a36Sopenharmony_ci { 64, 64 }, 89462306a36Sopenharmony_ci { 65, 127 }, 89562306a36Sopenharmony_ci { 128, 255 }, 89662306a36Sopenharmony_ci { 256, 511 }, 89762306a36Sopenharmony_ci { 512, 1023 }, 89862306a36Sopenharmony_ci { 1024, 1518 }, 89962306a36Sopenharmony_ci { 1519, 32767 }, 90062306a36Sopenharmony_ci {} 90162306a36Sopenharmony_ci }; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_STATS)) 90662306a36Sopenharmony_ci return; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci stats->undersize_pkts = RX_STAT(fp, etherStatsUndersizePkts); 90962306a36Sopenharmony_ci stats->oversize_pkts = RX_STAT(fp, etherStatsOversizePkts); 91062306a36Sopenharmony_ci stats->fragments = RX_STAT(fp, etherStatsFragments); 91162306a36Sopenharmony_ci stats->jabbers = RX_STAT(fp, etherStatsJabbers); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci stats->hist[0] = RX_STAT(fp, etherStatsPkts64Octets); 91462306a36Sopenharmony_ci stats->hist[1] = RX_STAT(fp, etherStatsPkts65to127Octets); 91562306a36Sopenharmony_ci stats->hist[2] = RX_STAT(fp, etherStatsPkts128to255Octets); 91662306a36Sopenharmony_ci stats->hist[3] = RX_STAT(fp, etherStatsPkts256to511Octets); 91762306a36Sopenharmony_ci stats->hist[4] = RX_STAT(fp, etherStatsPkts512to1023Octets); 91862306a36Sopenharmony_ci stats->hist[5] = RX_STAT(fp, etherStatsPkts1024to1518Octets); 91962306a36Sopenharmony_ci stats->hist[6] = RX_STAT(fp, etherStatsPkts1519toMaxOctets); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci stats->hist_tx[0] = TX_STAT(fp, etherStatsPkts64Octets); 92262306a36Sopenharmony_ci stats->hist_tx[1] = TX_STAT(fp, etherStatsPkts65to127Octets); 92362306a36Sopenharmony_ci stats->hist_tx[2] = TX_STAT(fp, etherStatsPkts128to255Octets); 92462306a36Sopenharmony_ci stats->hist_tx[3] = TX_STAT(fp, etherStatsPkts256to511Octets); 92562306a36Sopenharmony_ci stats->hist_tx[4] = TX_STAT(fp, etherStatsPkts512to1023Octets); 92662306a36Sopenharmony_ci stats->hist_tx[5] = TX_STAT(fp, etherStatsPkts1024to1518Octets); 92762306a36Sopenharmony_ci stats->hist_tx[6] = TX_STAT(fp, etherStatsPkts1519toMaxOctets); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci *ranges = rmon_ranges; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic void fun_get_fec_stats(struct net_device *netdev, 93362306a36Sopenharmony_ci struct ethtool_fec_stats *stats) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_STATS)) 93862306a36Sopenharmony_ci return; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci stats->corrected_blocks.total = FEC_STAT(fp, Correctable); 94162306a36Sopenharmony_ci stats->uncorrectable_blocks.total = FEC_STAT(fp, Uncorrectable); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci#undef RX_STAT 94562306a36Sopenharmony_ci#undef TX_STAT 94662306a36Sopenharmony_ci#undef FEC_STAT 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int fun_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, 94962306a36Sopenharmony_ci u32 *rule_locs) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci switch (cmd->cmd) { 95262306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 95362306a36Sopenharmony_ci cmd->data = netdev->real_num_rx_queues; 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci default: 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci return -EOPNOTSUPP; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int fun_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci return 0; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic u32 fun_get_rxfh_indir_size(struct net_device *netdev) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci return fp->indir_table_nentries; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic u32 fun_get_rxfh_key_size(struct net_device *netdev) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return sizeof(fp->rss_key); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic int fun_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, 98162306a36Sopenharmony_ci u8 *hfunc) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci const struct funeth_priv *fp = netdev_priv(netdev); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (!fp->rss_cfg) 98662306a36Sopenharmony_ci return -EOPNOTSUPP; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (indir) 98962306a36Sopenharmony_ci memcpy(indir, fp->indir_table, 99062306a36Sopenharmony_ci sizeof(u32) * fp->indir_table_nentries); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (key) 99362306a36Sopenharmony_ci memcpy(key, fp->rss_key, sizeof(fp->rss_key)); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci if (hfunc) 99662306a36Sopenharmony_ci *hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ? 99762306a36Sopenharmony_ci ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return 0; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic int fun_set_rxfh(struct net_device *netdev, const u32 *indir, 100362306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 100662306a36Sopenharmony_ci const u32 *rss_indir = indir ? indir : fp->indir_table; 100762306a36Sopenharmony_ci const u8 *rss_key = key ? key : fp->rss_key; 100862306a36Sopenharmony_ci enum fun_eth_hash_alg algo; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!fp->rss_cfg) 101162306a36Sopenharmony_ci return -EOPNOTSUPP; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (hfunc == ETH_RSS_HASH_NO_CHANGE) 101462306a36Sopenharmony_ci algo = fp->hash_algo; 101562306a36Sopenharmony_ci else if (hfunc == ETH_RSS_HASH_CRC32) 101662306a36Sopenharmony_ci algo = FUN_ETH_RSS_ALG_CRC32; 101762306a36Sopenharmony_ci else if (hfunc == ETH_RSS_HASH_TOP) 101862306a36Sopenharmony_ci algo = FUN_ETH_RSS_ALG_TOEPLITZ; 101962306a36Sopenharmony_ci else 102062306a36Sopenharmony_ci return -EINVAL; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* If the port is enabled try to reconfigure RSS and keep the new 102362306a36Sopenharmony_ci * settings if successful. If it is down we update the RSS settings 102462306a36Sopenharmony_ci * and apply them at the next UP time. 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_ci if (netif_running(netdev)) { 102762306a36Sopenharmony_ci int rc = fun_config_rss(netdev, algo, rss_key, rss_indir, 102862306a36Sopenharmony_ci FUN_ADMIN_SUBOP_MODIFY); 102962306a36Sopenharmony_ci if (rc) 103062306a36Sopenharmony_ci return rc; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci fp->hash_algo = algo; 103462306a36Sopenharmony_ci if (key) 103562306a36Sopenharmony_ci memcpy(fp->rss_key, key, sizeof(fp->rss_key)); 103662306a36Sopenharmony_ci if (indir) 103762306a36Sopenharmony_ci memcpy(fp->indir_table, indir, 103862306a36Sopenharmony_ci sizeof(u32) * fp->indir_table_nentries); 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int fun_get_ts_info(struct net_device *netdev, 104362306a36Sopenharmony_ci struct ethtool_ts_info *info) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | 104662306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 104762306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 104862306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 104962306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 105062306a36Sopenharmony_ci info->phc_index = -1; 105162306a36Sopenharmony_ci info->tx_types = BIT(HWTSTAMP_TX_OFF); 105262306a36Sopenharmony_ci info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); 105362306a36Sopenharmony_ci return 0; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic unsigned int to_ethtool_fec(unsigned int fun_fec) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci unsigned int fec = 0; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (fun_fec == FUN_PORT_FEC_NA) 106162306a36Sopenharmony_ci fec |= ETHTOOL_FEC_NONE; 106262306a36Sopenharmony_ci if (fun_fec & FUN_PORT_FEC_OFF) 106362306a36Sopenharmony_ci fec |= ETHTOOL_FEC_OFF; 106462306a36Sopenharmony_ci if (fun_fec & FUN_PORT_FEC_RS) 106562306a36Sopenharmony_ci fec |= ETHTOOL_FEC_RS; 106662306a36Sopenharmony_ci if (fun_fec & FUN_PORT_FEC_FC) 106762306a36Sopenharmony_ci fec |= ETHTOOL_FEC_BASER; 106862306a36Sopenharmony_ci if (fun_fec & FUN_PORT_FEC_AUTO) 106962306a36Sopenharmony_ci fec |= ETHTOOL_FEC_AUTO; 107062306a36Sopenharmony_ci return fec; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic int fun_get_fecparam(struct net_device *netdev, 107462306a36Sopenharmony_ci struct ethtool_fecparam *fec) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 107762306a36Sopenharmony_ci u64 fec_data; 107862306a36Sopenharmony_ci int rc; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci rc = fun_port_read_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, &fec_data); 108162306a36Sopenharmony_ci if (rc) 108262306a36Sopenharmony_ci return rc; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci fec->active_fec = to_ethtool_fec(fec_data & 0xff); 108562306a36Sopenharmony_ci fec->fec = to_ethtool_fec(fec_data >> 8); 108662306a36Sopenharmony_ci return 0; 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic int fun_set_fecparam(struct net_device *netdev, 109062306a36Sopenharmony_ci struct ethtool_fecparam *fec) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 109362306a36Sopenharmony_ci u64 fec_mode; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci switch (fec->fec) { 109662306a36Sopenharmony_ci case ETHTOOL_FEC_AUTO: 109762306a36Sopenharmony_ci fec_mode = FUN_PORT_FEC_AUTO; 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci case ETHTOOL_FEC_OFF: 110062306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_FEC_NONE)) 110162306a36Sopenharmony_ci return -EINVAL; 110262306a36Sopenharmony_ci fec_mode = FUN_PORT_FEC_OFF; 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case ETHTOOL_FEC_BASER: 110562306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_FEC_FC)) 110662306a36Sopenharmony_ci return -EINVAL; 110762306a36Sopenharmony_ci fec_mode = FUN_PORT_FEC_FC; 110862306a36Sopenharmony_ci break; 110962306a36Sopenharmony_ci case ETHTOOL_FEC_RS: 111062306a36Sopenharmony_ci if (!(fp->port_caps & FUN_PORT_CAP_FEC_RS)) 111162306a36Sopenharmony_ci return -EINVAL; 111262306a36Sopenharmony_ci fec_mode = FUN_PORT_FEC_RS; 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci default: 111562306a36Sopenharmony_ci return -EINVAL; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode); 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic int fun_get_port_module_page(struct net_device *netdev, 112262306a36Sopenharmony_ci const struct ethtool_module_eeprom *req, 112362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci union { 112662306a36Sopenharmony_ci struct fun_admin_port_req req; 112762306a36Sopenharmony_ci struct fun_admin_port_xcvr_read_rsp rsp; 112862306a36Sopenharmony_ci } cmd; 112962306a36Sopenharmony_ci struct funeth_priv *fp = netdev_priv(netdev); 113062306a36Sopenharmony_ci int rc; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (fp->port_caps & FUN_PORT_CAP_VPORT) { 113362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 113462306a36Sopenharmony_ci "Specified port is virtual, only physical ports have modules"); 113562306a36Sopenharmony_ci return -EOPNOTSUPP; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci cmd.req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_PORT, 113962306a36Sopenharmony_ci sizeof(cmd.req)); 114062306a36Sopenharmony_ci cmd.req.u.xcvr_read = 114162306a36Sopenharmony_ci FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(0, netdev->dev_port, 114262306a36Sopenharmony_ci req->bank, req->page, 114362306a36Sopenharmony_ci req->offset, req->length, 114462306a36Sopenharmony_ci req->i2c_address); 114562306a36Sopenharmony_ci rc = fun_submit_admin_sync_cmd(fp->fdev, &cmd.req.common, &cmd.rsp, 114662306a36Sopenharmony_ci sizeof(cmd.rsp), 0); 114762306a36Sopenharmony_ci if (rc) 114862306a36Sopenharmony_ci return rc; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci memcpy(req->data, cmd.rsp.data, req->length); 115162306a36Sopenharmony_ci return req->length; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic const struct ethtool_ops fun_ethtool_ops = { 115562306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 115662306a36Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES, 115762306a36Sopenharmony_ci .get_link_ksettings = fun_get_link_ksettings, 115862306a36Sopenharmony_ci .set_link_ksettings = fun_set_link_ksettings, 115962306a36Sopenharmony_ci .set_phys_id = fun_set_phys_id, 116062306a36Sopenharmony_ci .get_drvinfo = fun_get_drvinfo, 116162306a36Sopenharmony_ci .get_msglevel = fun_get_msglevel, 116262306a36Sopenharmony_ci .set_msglevel = fun_set_msglevel, 116362306a36Sopenharmony_ci .get_regs_len = fun_get_regs_len, 116462306a36Sopenharmony_ci .get_regs = fun_get_regs, 116562306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 116662306a36Sopenharmony_ci .get_coalesce = fun_get_coalesce, 116762306a36Sopenharmony_ci .set_coalesce = fun_set_coalesce, 116862306a36Sopenharmony_ci .get_ts_info = fun_get_ts_info, 116962306a36Sopenharmony_ci .get_ringparam = fun_get_ringparam, 117062306a36Sopenharmony_ci .set_ringparam = fun_set_ringparam, 117162306a36Sopenharmony_ci .get_sset_count = fun_get_sset_count, 117262306a36Sopenharmony_ci .get_strings = fun_get_strings, 117362306a36Sopenharmony_ci .get_ethtool_stats = fun_get_ethtool_stats, 117462306a36Sopenharmony_ci .get_rxnfc = fun_get_rxnfc, 117562306a36Sopenharmony_ci .set_rxnfc = fun_set_rxnfc, 117662306a36Sopenharmony_ci .get_rxfh_indir_size = fun_get_rxfh_indir_size, 117762306a36Sopenharmony_ci .get_rxfh_key_size = fun_get_rxfh_key_size, 117862306a36Sopenharmony_ci .get_rxfh = fun_get_rxfh, 117962306a36Sopenharmony_ci .set_rxfh = fun_set_rxfh, 118062306a36Sopenharmony_ci .get_channels = fun_get_channels, 118162306a36Sopenharmony_ci .set_channels = fun_set_channels, 118262306a36Sopenharmony_ci .get_fecparam = fun_get_fecparam, 118362306a36Sopenharmony_ci .set_fecparam = fun_set_fecparam, 118462306a36Sopenharmony_ci .get_pauseparam = fun_get_pauseparam, 118562306a36Sopenharmony_ci .set_pauseparam = fun_set_pauseparam, 118662306a36Sopenharmony_ci .nway_reset = fun_restart_an, 118762306a36Sopenharmony_ci .get_pause_stats = fun_get_pause_stats, 118862306a36Sopenharmony_ci .get_fec_stats = fun_get_fec_stats, 118962306a36Sopenharmony_ci .get_eth_mac_stats = fun_get_802_3_stats, 119062306a36Sopenharmony_ci .get_eth_ctrl_stats = fun_get_802_3_ctrl_stats, 119162306a36Sopenharmony_ci .get_rmon_stats = fun_get_rmon_stats, 119262306a36Sopenharmony_ci .get_module_eeprom_by_page = fun_get_port_module_page, 119362306a36Sopenharmony_ci}; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_civoid fun_set_ethtool_ops(struct net_device *netdev) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci netdev->ethtool_ops = &fun_ethtool_ops; 119862306a36Sopenharmony_ci} 1199