18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* Copyright 2017-2019 NXP */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include "enetc.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cistatic const u32 enetc_si_regs[] = { 98c2ecf20Sopenharmony_ci ENETC_SIMR, ENETC_SIPMAR0, ENETC_SIPMAR1, ENETC_SICBDRMR, 108c2ecf20Sopenharmony_ci ENETC_SICBDRSR, ENETC_SICBDRBAR0, ENETC_SICBDRBAR1, ENETC_SICBDRPIR, 118c2ecf20Sopenharmony_ci ENETC_SICBDRCIR, ENETC_SICBDRLENR, ENETC_SICAPR0, ENETC_SICAPR1, 128c2ecf20Sopenharmony_ci ENETC_SIUEFDCR 138c2ecf20Sopenharmony_ci}; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const u32 enetc_txbdr_regs[] = { 168c2ecf20Sopenharmony_ci ENETC_TBMR, ENETC_TBSR, ENETC_TBBAR0, ENETC_TBBAR1, 178c2ecf20Sopenharmony_ci ENETC_TBPIR, ENETC_TBCIR, ENETC_TBLENR, ENETC_TBIER, ENETC_TBICR0, 188c2ecf20Sopenharmony_ci ENETC_TBICR1 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const u32 enetc_rxbdr_regs[] = { 228c2ecf20Sopenharmony_ci ENETC_RBMR, ENETC_RBSR, ENETC_RBBSR, ENETC_RBCIR, ENETC_RBBAR0, 238c2ecf20Sopenharmony_ci ENETC_RBBAR1, ENETC_RBPIR, ENETC_RBLENR, ENETC_RBIER, ENETC_RBICR0, 248c2ecf20Sopenharmony_ci ENETC_RBICR1 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const u32 enetc_port_regs[] = { 288c2ecf20Sopenharmony_ci ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0), 298c2ecf20Sopenharmony_ci ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1, 308c2ecf20Sopenharmony_ci ENETC_PSICFGR0(0), ENETC_PRFSCAPR, ENETC_PTCMSDUR(0), 318c2ecf20Sopenharmony_ci ENETC_PM0_CMD_CFG, ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int enetc_get_reglen(struct net_device *ndev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 378c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 388c2ecf20Sopenharmony_ci int len; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci len = ARRAY_SIZE(enetc_si_regs); 418c2ecf20Sopenharmony_ci len += ARRAY_SIZE(enetc_txbdr_regs) * priv->num_tx_rings; 428c2ecf20Sopenharmony_ci len += ARRAY_SIZE(enetc_rxbdr_regs) * priv->num_rx_rings; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (hw->port) 458c2ecf20Sopenharmony_ci len += ARRAY_SIZE(enetc_port_regs); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci len *= sizeof(u32) * 2; /* store 2 entries per reg: addr and value */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return len; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void enetc_get_regs(struct net_device *ndev, struct ethtool_regs *regs, 538c2ecf20Sopenharmony_ci void *regbuf) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 568c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 578c2ecf20Sopenharmony_ci u32 *buf = (u32 *)regbuf; 588c2ecf20Sopenharmony_ci int i, j; 598c2ecf20Sopenharmony_ci u32 addr; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_si_regs); i++) { 628c2ecf20Sopenharmony_ci *buf++ = enetc_si_regs[i]; 638c2ecf20Sopenharmony_ci *buf++ = enetc_rd(hw, enetc_si_regs[i]); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 678c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(enetc_txbdr_regs); j++) { 688c2ecf20Sopenharmony_ci addr = ENETC_BDR(TX, i, enetc_txbdr_regs[j]); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci *buf++ = addr; 718c2ecf20Sopenharmony_ci *buf++ = enetc_rd(hw, addr); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 768c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(enetc_rxbdr_regs); j++) { 778c2ecf20Sopenharmony_ci addr = ENETC_BDR(RX, i, enetc_rxbdr_regs[j]); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci *buf++ = addr; 808c2ecf20Sopenharmony_ci *buf++ = enetc_rd(hw, addr); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!hw->port) 858c2ecf20Sopenharmony_ci return; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_port_regs); i++) { 888c2ecf20Sopenharmony_ci addr = ENETC_PORT_BASE + enetc_port_regs[i]; 898c2ecf20Sopenharmony_ci *buf++ = addr; 908c2ecf20Sopenharmony_ci *buf++ = enetc_rd(hw, addr); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic const struct { 958c2ecf20Sopenharmony_ci int reg; 968c2ecf20Sopenharmony_ci char name[ETH_GSTRING_LEN]; 978c2ecf20Sopenharmony_ci} enetc_si_counters[] = { 988c2ecf20Sopenharmony_ci { ENETC_SIROCT, "SI rx octets" }, 998c2ecf20Sopenharmony_ci { ENETC_SIRFRM, "SI rx frames" }, 1008c2ecf20Sopenharmony_ci { ENETC_SIRUCA, "SI rx u-cast frames" }, 1018c2ecf20Sopenharmony_ci { ENETC_SIRMCA, "SI rx m-cast frames" }, 1028c2ecf20Sopenharmony_ci { ENETC_SITOCT, "SI tx octets" }, 1038c2ecf20Sopenharmony_ci { ENETC_SITFRM, "SI tx frames" }, 1048c2ecf20Sopenharmony_ci { ENETC_SITUCA, "SI tx u-cast frames" }, 1058c2ecf20Sopenharmony_ci { ENETC_SITMCA, "SI tx m-cast frames" }, 1068c2ecf20Sopenharmony_ci { ENETC_RBDCR(0), "Rx ring 0 discarded frames" }, 1078c2ecf20Sopenharmony_ci { ENETC_RBDCR(1), "Rx ring 1 discarded frames" }, 1088c2ecf20Sopenharmony_ci { ENETC_RBDCR(2), "Rx ring 2 discarded frames" }, 1098c2ecf20Sopenharmony_ci { ENETC_RBDCR(3), "Rx ring 3 discarded frames" }, 1108c2ecf20Sopenharmony_ci { ENETC_RBDCR(4), "Rx ring 4 discarded frames" }, 1118c2ecf20Sopenharmony_ci { ENETC_RBDCR(5), "Rx ring 5 discarded frames" }, 1128c2ecf20Sopenharmony_ci { ENETC_RBDCR(6), "Rx ring 6 discarded frames" }, 1138c2ecf20Sopenharmony_ci { ENETC_RBDCR(7), "Rx ring 7 discarded frames" }, 1148c2ecf20Sopenharmony_ci { ENETC_RBDCR(8), "Rx ring 8 discarded frames" }, 1158c2ecf20Sopenharmony_ci { ENETC_RBDCR(9), "Rx ring 9 discarded frames" }, 1168c2ecf20Sopenharmony_ci { ENETC_RBDCR(10), "Rx ring 10 discarded frames" }, 1178c2ecf20Sopenharmony_ci { ENETC_RBDCR(11), "Rx ring 11 discarded frames" }, 1188c2ecf20Sopenharmony_ci { ENETC_RBDCR(12), "Rx ring 12 discarded frames" }, 1198c2ecf20Sopenharmony_ci { ENETC_RBDCR(13), "Rx ring 13 discarded frames" }, 1208c2ecf20Sopenharmony_ci { ENETC_RBDCR(14), "Rx ring 14 discarded frames" }, 1218c2ecf20Sopenharmony_ci { ENETC_RBDCR(15), "Rx ring 15 discarded frames" }, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const struct { 1258c2ecf20Sopenharmony_ci int reg; 1268c2ecf20Sopenharmony_ci char name[ETH_GSTRING_LEN]; 1278c2ecf20Sopenharmony_ci} enetc_port_counters[] = { 1288c2ecf20Sopenharmony_ci { ENETC_PM0_REOCT, "MAC rx ethernet octets" }, 1298c2ecf20Sopenharmony_ci { ENETC_PM0_RALN, "MAC rx alignment errors" }, 1308c2ecf20Sopenharmony_ci { ENETC_PM0_RXPF, "MAC rx valid pause frames" }, 1318c2ecf20Sopenharmony_ci { ENETC_PM0_RFRM, "MAC rx valid frames" }, 1328c2ecf20Sopenharmony_ci { ENETC_PM0_RFCS, "MAC rx fcs errors" }, 1338c2ecf20Sopenharmony_ci { ENETC_PM0_RVLAN, "MAC rx VLAN frames" }, 1348c2ecf20Sopenharmony_ci { ENETC_PM0_RERR, "MAC rx frame errors" }, 1358c2ecf20Sopenharmony_ci { ENETC_PM0_RUCA, "MAC rx unicast frames" }, 1368c2ecf20Sopenharmony_ci { ENETC_PM0_RMCA, "MAC rx multicast frames" }, 1378c2ecf20Sopenharmony_ci { ENETC_PM0_RBCA, "MAC rx broadcast frames" }, 1388c2ecf20Sopenharmony_ci { ENETC_PM0_RDRP, "MAC rx dropped packets" }, 1398c2ecf20Sopenharmony_ci { ENETC_PM0_RPKT, "MAC rx packets" }, 1408c2ecf20Sopenharmony_ci { ENETC_PM0_RUND, "MAC rx undersized packets" }, 1418c2ecf20Sopenharmony_ci { ENETC_PM0_R64, "MAC rx 64 byte packets" }, 1428c2ecf20Sopenharmony_ci { ENETC_PM0_R127, "MAC rx 65-127 byte packets" }, 1438c2ecf20Sopenharmony_ci { ENETC_PM0_R255, "MAC rx 128-255 byte packets" }, 1448c2ecf20Sopenharmony_ci { ENETC_PM0_R511, "MAC rx 256-511 byte packets" }, 1458c2ecf20Sopenharmony_ci { ENETC_PM0_R1023, "MAC rx 512-1023 byte packets" }, 1468c2ecf20Sopenharmony_ci { ENETC_PM0_R1522, "MAC rx 1024-1522 byte packets" }, 1478c2ecf20Sopenharmony_ci { ENETC_PM0_R1523X, "MAC rx 1523 to max-octet packets" }, 1488c2ecf20Sopenharmony_ci { ENETC_PM0_ROVR, "MAC rx oversized packets" }, 1498c2ecf20Sopenharmony_ci { ENETC_PM0_RJBR, "MAC rx jabber packets" }, 1508c2ecf20Sopenharmony_ci { ENETC_PM0_RFRG, "MAC rx fragment packets" }, 1518c2ecf20Sopenharmony_ci { ENETC_PM0_RCNP, "MAC rx control packets" }, 1528c2ecf20Sopenharmony_ci { ENETC_PM0_RDRNTP, "MAC rx fifo drop" }, 1538c2ecf20Sopenharmony_ci { ENETC_PM0_TEOCT, "MAC tx ethernet octets" }, 1548c2ecf20Sopenharmony_ci { ENETC_PM0_TOCT, "MAC tx octets" }, 1558c2ecf20Sopenharmony_ci { ENETC_PM0_TCRSE, "MAC tx carrier sense errors" }, 1568c2ecf20Sopenharmony_ci { ENETC_PM0_TXPF, "MAC tx valid pause frames" }, 1578c2ecf20Sopenharmony_ci { ENETC_PM0_TFRM, "MAC tx frames" }, 1588c2ecf20Sopenharmony_ci { ENETC_PM0_TFCS, "MAC tx fcs errors" }, 1598c2ecf20Sopenharmony_ci { ENETC_PM0_TVLAN, "MAC tx VLAN frames" }, 1608c2ecf20Sopenharmony_ci { ENETC_PM0_TERR, "MAC tx frame errors" }, 1618c2ecf20Sopenharmony_ci { ENETC_PM0_TUCA, "MAC tx unicast frames" }, 1628c2ecf20Sopenharmony_ci { ENETC_PM0_TMCA, "MAC tx multicast frames" }, 1638c2ecf20Sopenharmony_ci { ENETC_PM0_TBCA, "MAC tx broadcast frames" }, 1648c2ecf20Sopenharmony_ci { ENETC_PM0_TPKT, "MAC tx packets" }, 1658c2ecf20Sopenharmony_ci { ENETC_PM0_TUND, "MAC tx undersized packets" }, 1668c2ecf20Sopenharmony_ci { ENETC_PM0_T64, "MAC tx 64 byte packets" }, 1678c2ecf20Sopenharmony_ci { ENETC_PM0_T127, "MAC tx 65-127 byte packets" }, 1688c2ecf20Sopenharmony_ci { ENETC_PM0_T255, "MAC tx 128-255 byte packets" }, 1698c2ecf20Sopenharmony_ci { ENETC_PM0_T511, "MAC tx 256-511 byte packets" }, 1708c2ecf20Sopenharmony_ci { ENETC_PM0_T1023, "MAC tx 512-1023 byte packets" }, 1718c2ecf20Sopenharmony_ci { ENETC_PM0_T1522, "MAC tx 1024-1522 byte packets" }, 1728c2ecf20Sopenharmony_ci { ENETC_PM0_T1523X, "MAC tx 1523 to max-octet packets" }, 1738c2ecf20Sopenharmony_ci { ENETC_PM0_TCNP, "MAC tx control packets" }, 1748c2ecf20Sopenharmony_ci { ENETC_PM0_TDFR, "MAC tx deferred packets" }, 1758c2ecf20Sopenharmony_ci { ENETC_PM0_TMCOL, "MAC tx multiple collisions" }, 1768c2ecf20Sopenharmony_ci { ENETC_PM0_TSCOL, "MAC tx single collisions" }, 1778c2ecf20Sopenharmony_ci { ENETC_PM0_TLCOL, "MAC tx late collisions" }, 1788c2ecf20Sopenharmony_ci { ENETC_PM0_TECOL, "MAC tx excessive collisions" }, 1798c2ecf20Sopenharmony_ci { ENETC_UFDMF, "SI MAC nomatch u-cast discards" }, 1808c2ecf20Sopenharmony_ci { ENETC_MFDMF, "SI MAC nomatch m-cast discards" }, 1818c2ecf20Sopenharmony_ci { ENETC_PBFDSIR, "SI MAC nomatch b-cast discards" }, 1828c2ecf20Sopenharmony_ci { ENETC_PUFDVFR, "SI VLAN nomatch u-cast discards" }, 1838c2ecf20Sopenharmony_ci { ENETC_PMFDVFR, "SI VLAN nomatch m-cast discards" }, 1848c2ecf20Sopenharmony_ci { ENETC_PBFDVFR, "SI VLAN nomatch b-cast discards" }, 1858c2ecf20Sopenharmony_ci { ENETC_PFDMSAPR, "SI pruning discarded frames" }, 1868c2ecf20Sopenharmony_ci { ENETC_PICDR(0), "ICM DR0 discarded frames" }, 1878c2ecf20Sopenharmony_ci { ENETC_PICDR(1), "ICM DR1 discarded frames" }, 1888c2ecf20Sopenharmony_ci { ENETC_PICDR(2), "ICM DR2 discarded frames" }, 1898c2ecf20Sopenharmony_ci { ENETC_PICDR(3), "ICM DR3 discarded frames" }, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const char rx_ring_stats[][ETH_GSTRING_LEN] = { 1938c2ecf20Sopenharmony_ci "Rx ring %2d frames", 1948c2ecf20Sopenharmony_ci "Rx ring %2d alloc errors", 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic const char tx_ring_stats[][ETH_GSTRING_LEN] = { 1988c2ecf20Sopenharmony_ci "Tx ring %2d frames", 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int enetc_get_sset_count(struct net_device *ndev, int sset) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 2048c2ecf20Sopenharmony_ci int len; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (sset != ETH_SS_STATS) 2078c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci len = ARRAY_SIZE(enetc_si_counters) + 2108c2ecf20Sopenharmony_ci ARRAY_SIZE(tx_ring_stats) * priv->num_tx_rings + 2118c2ecf20Sopenharmony_ci ARRAY_SIZE(rx_ring_stats) * priv->num_rx_rings; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!enetc_si_is_pf(priv->si)) 2148c2ecf20Sopenharmony_ci return len; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci len += ARRAY_SIZE(enetc_port_counters); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return len; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 2248c2ecf20Sopenharmony_ci u8 *p = data; 2258c2ecf20Sopenharmony_ci int i, j; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci switch (stringset) { 2288c2ecf20Sopenharmony_ci case ETH_SS_STATS: 2298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++) { 2308c2ecf20Sopenharmony_ci strlcpy(p, enetc_si_counters[i].name, ETH_GSTRING_LEN); 2318c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 2348c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(tx_ring_stats); j++) { 2358c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, tx_ring_stats[j], 2368c2ecf20Sopenharmony_ci i); 2378c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 2418c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(rx_ring_stats); j++) { 2428c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, rx_ring_stats[j], 2438c2ecf20Sopenharmony_ci i); 2448c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (!enetc_si_is_pf(priv->si)) 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++) { 2528c2ecf20Sopenharmony_ci strlcpy(p, enetc_port_counters[i].name, 2538c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 2548c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void enetc_get_ethtool_stats(struct net_device *ndev, 2618c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 2648c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 2658c2ecf20Sopenharmony_ci int i, o = 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++) 2688c2ecf20Sopenharmony_ci data[o++] = enetc_rd64(hw, enetc_si_counters[i].reg); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 2718c2ecf20Sopenharmony_ci data[o++] = priv->tx_ring[i]->stats.packets; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 2748c2ecf20Sopenharmony_ci data[o++] = priv->rx_ring[i]->stats.packets; 2758c2ecf20Sopenharmony_ci data[o++] = priv->rx_ring[i]->stats.rx_alloc_errs; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!enetc_si_is_pf(priv->si)) 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++) 2828c2ecf20Sopenharmony_ci data[o++] = enetc_port_rd(hw, enetc_port_counters[i].reg); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#define ENETC_RSSHASH_L3 (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO | RXH_IP_SRC | \ 2868c2ecf20Sopenharmony_ci RXH_IP_DST) 2878c2ecf20Sopenharmony_ci#define ENETC_RSSHASH_L4 (ENETC_RSSHASH_L3 | RXH_L4_B_0_1 | RXH_L4_B_2_3) 2888c2ecf20Sopenharmony_cistatic int enetc_get_rsshash(struct ethtool_rxnfc *rxnfc) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci static const u32 rsshash[] = { 2918c2ecf20Sopenharmony_ci [TCP_V4_FLOW] = ENETC_RSSHASH_L4, 2928c2ecf20Sopenharmony_ci [UDP_V4_FLOW] = ENETC_RSSHASH_L4, 2938c2ecf20Sopenharmony_ci [SCTP_V4_FLOW] = ENETC_RSSHASH_L4, 2948c2ecf20Sopenharmony_ci [AH_ESP_V4_FLOW] = ENETC_RSSHASH_L3, 2958c2ecf20Sopenharmony_ci [IPV4_FLOW] = ENETC_RSSHASH_L3, 2968c2ecf20Sopenharmony_ci [TCP_V6_FLOW] = ENETC_RSSHASH_L4, 2978c2ecf20Sopenharmony_ci [UDP_V6_FLOW] = ENETC_RSSHASH_L4, 2988c2ecf20Sopenharmony_ci [SCTP_V6_FLOW] = ENETC_RSSHASH_L4, 2998c2ecf20Sopenharmony_ci [AH_ESP_V6_FLOW] = ENETC_RSSHASH_L3, 3008c2ecf20Sopenharmony_ci [IPV6_FLOW] = ENETC_RSSHASH_L3, 3018c2ecf20Sopenharmony_ci [ETHER_FLOW] = 0, 3028c2ecf20Sopenharmony_ci }; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (rxnfc->flow_type >= ARRAY_SIZE(rsshash)) 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci rxnfc->data = rsshash[rxnfc->flow_type]; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* current HW spec does byte reversal on everything including MAC addresses */ 3138c2ecf20Sopenharmony_cistatic void ether_addr_copy_swap(u8 *dst, const u8 *src) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci int i; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 3188c2ecf20Sopenharmony_ci dst[i] = src[ETH_ALEN - i - 1]; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int enetc_set_cls_entry(struct enetc_si *si, 3228c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fs, bool en) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *l4ip4_h, *l4ip4_m; 3258c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *l3ip4_h, *l3ip4_m; 3268c2ecf20Sopenharmony_ci struct ethhdr *eth_h, *eth_m; 3278c2ecf20Sopenharmony_ci struct enetc_cmd_rfse rfse = { {0} }; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!en) 3308c2ecf20Sopenharmony_ci goto done; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci switch (fs->flow_type & 0xff) { 3338c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 3348c2ecf20Sopenharmony_ci l4ip4_h = &fs->h_u.tcp_ip4_spec; 3358c2ecf20Sopenharmony_ci l4ip4_m = &fs->m_u.tcp_ip4_spec; 3368c2ecf20Sopenharmony_ci goto l4ip4; 3378c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 3388c2ecf20Sopenharmony_ci l4ip4_h = &fs->h_u.udp_ip4_spec; 3398c2ecf20Sopenharmony_ci l4ip4_m = &fs->m_u.udp_ip4_spec; 3408c2ecf20Sopenharmony_ci goto l4ip4; 3418c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 3428c2ecf20Sopenharmony_ci l4ip4_h = &fs->h_u.sctp_ip4_spec; 3438c2ecf20Sopenharmony_ci l4ip4_m = &fs->m_u.sctp_ip4_spec; 3448c2ecf20Sopenharmony_cil4ip4: 3458c2ecf20Sopenharmony_ci rfse.sip_h[0] = l4ip4_h->ip4src; 3468c2ecf20Sopenharmony_ci rfse.sip_m[0] = l4ip4_m->ip4src; 3478c2ecf20Sopenharmony_ci rfse.dip_h[0] = l4ip4_h->ip4dst; 3488c2ecf20Sopenharmony_ci rfse.dip_m[0] = l4ip4_m->ip4dst; 3498c2ecf20Sopenharmony_ci rfse.sport_h = ntohs(l4ip4_h->psrc); 3508c2ecf20Sopenharmony_ci rfse.sport_m = ntohs(l4ip4_m->psrc); 3518c2ecf20Sopenharmony_ci rfse.dport_h = ntohs(l4ip4_h->pdst); 3528c2ecf20Sopenharmony_ci rfse.dport_m = ntohs(l4ip4_m->pdst); 3538c2ecf20Sopenharmony_ci if (l4ip4_m->tos) 3548c2ecf20Sopenharmony_ci netdev_warn(si->ndev, "ToS field is not supported and was ignored\n"); 3558c2ecf20Sopenharmony_ci rfse.ethtype_h = ETH_P_IP; /* IPv4 */ 3568c2ecf20Sopenharmony_ci rfse.ethtype_m = 0xffff; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case IP_USER_FLOW: 3598c2ecf20Sopenharmony_ci l3ip4_h = &fs->h_u.usr_ip4_spec; 3608c2ecf20Sopenharmony_ci l3ip4_m = &fs->m_u.usr_ip4_spec; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci rfse.sip_h[0] = l3ip4_h->ip4src; 3638c2ecf20Sopenharmony_ci rfse.sip_m[0] = l3ip4_m->ip4src; 3648c2ecf20Sopenharmony_ci rfse.dip_h[0] = l3ip4_h->ip4dst; 3658c2ecf20Sopenharmony_ci rfse.dip_m[0] = l3ip4_m->ip4dst; 3668c2ecf20Sopenharmony_ci if (l3ip4_m->tos) 3678c2ecf20Sopenharmony_ci netdev_warn(si->ndev, "ToS field is not supported and was ignored\n"); 3688c2ecf20Sopenharmony_ci rfse.ethtype_h = ETH_P_IP; /* IPv4 */ 3698c2ecf20Sopenharmony_ci rfse.ethtype_m = 0xffff; 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case ETHER_FLOW: 3728c2ecf20Sopenharmony_ci eth_h = &fs->h_u.ether_spec; 3738c2ecf20Sopenharmony_ci eth_m = &fs->m_u.ether_spec; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ether_addr_copy_swap(rfse.smac_h, eth_h->h_source); 3768c2ecf20Sopenharmony_ci ether_addr_copy_swap(rfse.smac_m, eth_m->h_source); 3778c2ecf20Sopenharmony_ci ether_addr_copy_swap(rfse.dmac_h, eth_h->h_dest); 3788c2ecf20Sopenharmony_ci ether_addr_copy_swap(rfse.dmac_m, eth_m->h_dest); 3798c2ecf20Sopenharmony_ci rfse.ethtype_h = ntohs(eth_h->h_proto); 3808c2ecf20Sopenharmony_ci rfse.ethtype_m = ntohs(eth_m->h_proto); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci default: 3838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci rfse.mode |= ENETC_RFSE_EN; 3878c2ecf20Sopenharmony_ci if (fs->ring_cookie != RX_CLS_FLOW_DISC) { 3888c2ecf20Sopenharmony_ci rfse.mode |= ENETC_RFSE_MODE_BD; 3898c2ecf20Sopenharmony_ci rfse.result = fs->ring_cookie; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_cidone: 3928c2ecf20Sopenharmony_ci return enetc_set_fs_entry(si, &rfse, fs->location); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc, 3968c2ecf20Sopenharmony_ci u32 *rule_locs) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 3998c2ecf20Sopenharmony_ci int i, j; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci switch (rxnfc->cmd) { 4028c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 4038c2ecf20Sopenharmony_ci rxnfc->data = priv->num_rx_rings; 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 4068c2ecf20Sopenharmony_ci /* get RSS hash config */ 4078c2ecf20Sopenharmony_ci return enetc_get_rsshash(rxnfc); 4088c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 4098c2ecf20Sopenharmony_ci /* total number of entries */ 4108c2ecf20Sopenharmony_ci rxnfc->data = priv->si->num_fs_entries; 4118c2ecf20Sopenharmony_ci /* number of entries in use */ 4128c2ecf20Sopenharmony_ci rxnfc->rule_cnt = 0; 4138c2ecf20Sopenharmony_ci for (i = 0; i < priv->si->num_fs_entries; i++) 4148c2ecf20Sopenharmony_ci if (priv->cls_rules[i].used) 4158c2ecf20Sopenharmony_ci rxnfc->rule_cnt++; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 4188c2ecf20Sopenharmony_ci if (rxnfc->fs.location >= priv->si->num_fs_entries) 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* get entry x */ 4228c2ecf20Sopenharmony_ci rxnfc->fs = priv->cls_rules[rxnfc->fs.location].fs; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 4258c2ecf20Sopenharmony_ci /* total number of entries */ 4268c2ecf20Sopenharmony_ci rxnfc->data = priv->si->num_fs_entries; 4278c2ecf20Sopenharmony_ci /* array of indexes of used entries */ 4288c2ecf20Sopenharmony_ci j = 0; 4298c2ecf20Sopenharmony_ci for (i = 0; i < priv->si->num_fs_entries; i++) { 4308c2ecf20Sopenharmony_ci if (!priv->cls_rules[i].used) 4318c2ecf20Sopenharmony_ci continue; 4328c2ecf20Sopenharmony_ci if (j == rxnfc->rule_cnt) 4338c2ecf20Sopenharmony_ci return -EMSGSIZE; 4348c2ecf20Sopenharmony_ci rule_locs[j++] = i; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci /* number of entries in use */ 4378c2ecf20Sopenharmony_ci rxnfc->rule_cnt = j; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 4498c2ecf20Sopenharmony_ci int err; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci switch (rxnfc->cmd) { 4528c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 4538c2ecf20Sopenharmony_ci if (rxnfc->fs.location >= priv->si->num_fs_entries) 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (rxnfc->fs.ring_cookie >= priv->num_rx_rings && 4578c2ecf20Sopenharmony_ci rxnfc->fs.ring_cookie != RX_CLS_FLOW_DISC) 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci err = enetc_set_cls_entry(priv->si, &rxnfc->fs, true); 4618c2ecf20Sopenharmony_ci if (err) 4628c2ecf20Sopenharmony_ci return err; 4638c2ecf20Sopenharmony_ci priv->cls_rules[rxnfc->fs.location].fs = rxnfc->fs; 4648c2ecf20Sopenharmony_ci priv->cls_rules[rxnfc->fs.location].used = 1; 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 4678c2ecf20Sopenharmony_ci if (rxnfc->fs.location >= priv->si->num_fs_entries) 4688c2ecf20Sopenharmony_ci return -EINVAL; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci err = enetc_set_cls_entry(priv->si, &rxnfc->fs, false); 4718c2ecf20Sopenharmony_ci if (err) 4728c2ecf20Sopenharmony_ci return err; 4738c2ecf20Sopenharmony_ci priv->cls_rules[rxnfc->fs.location].used = 0; 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci default: 4768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic u32 enetc_get_rxfh_key_size(struct net_device *ndev) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* return the size of the RX flow hash key. PF only */ 4878c2ecf20Sopenharmony_ci return (priv->si->hw.port) ? ENETC_RSSHASH_KEY_SIZE : 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic u32 enetc_get_rxfh_indir_size(struct net_device *ndev) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* return the size of the RX flow hash indirection table */ 4958c2ecf20Sopenharmony_ci return priv->si->num_rss; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int enetc_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key, 4998c2ecf20Sopenharmony_ci u8 *hfunc) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5028c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 5038c2ecf20Sopenharmony_ci int err = 0, i; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* return hash function */ 5068c2ecf20Sopenharmony_ci if (hfunc) 5078c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* return hash key */ 5108c2ecf20Sopenharmony_ci if (key && hw->port) 5118c2ecf20Sopenharmony_ci for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++) 5128c2ecf20Sopenharmony_ci ((u32 *)key)[i] = enetc_port_rd(hw, ENETC_PRSSK(i)); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* return RSS table */ 5158c2ecf20Sopenharmony_ci if (indir) 5168c2ecf20Sopenharmony_ci err = enetc_get_rss_table(priv->si, indir, priv->si->num_rss); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return err; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_civoid enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int i; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++) 5268c2ecf20Sopenharmony_ci enetc_port_wr(hw, ENETC_PRSSK(i), ((u32 *)bytes)[i]); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic int enetc_set_rxfh(struct net_device *ndev, const u32 *indir, 5308c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5338c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 5348c2ecf20Sopenharmony_ci int err = 0; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* set hash key, if PF */ 5378c2ecf20Sopenharmony_ci if (key && hw->port) 5388c2ecf20Sopenharmony_ci enetc_set_rss_key(hw, key); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* set RSS table */ 5418c2ecf20Sopenharmony_ci if (indir) 5428c2ecf20Sopenharmony_ci err = enetc_set_rss_table(priv->si, indir, priv->si->num_rss); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return err; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void enetc_get_ringparam(struct net_device *ndev, 5488c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ring->rx_pending = priv->rx_bd_count; 5538c2ecf20Sopenharmony_ci ring->tx_pending = priv->tx_bd_count; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* do some h/w sanity checks for BDR length */ 5568c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 5578c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 5588c2ecf20Sopenharmony_ci u32 val = enetc_rxbdr_rd(hw, 0, ENETC_RBLENR); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (val != priv->rx_bd_count) 5618c2ecf20Sopenharmony_ci netif_err(priv, hw, ndev, "RxBDR[RBLENR] = %d!\n", val); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci val = enetc_txbdr_rd(hw, 0, ENETC_TBLENR); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (val != priv->tx_bd_count) 5668c2ecf20Sopenharmony_ci netif_err(priv, hw, ndev, "TxBDR[TBLENR] = %d!\n", val); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int enetc_get_coalesce(struct net_device *ndev, 5718c2ecf20Sopenharmony_ci struct ethtool_coalesce *ic) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5748c2ecf20Sopenharmony_ci struct enetc_int_vector *v = priv->int_vector[0]; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ic->tx_coalesce_usecs = enetc_cycles_to_usecs(priv->tx_ictt); 5778c2ecf20Sopenharmony_ci ic->rx_coalesce_usecs = enetc_cycles_to_usecs(v->rx_ictt); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ic->tx_max_coalesced_frames = ENETC_TXIC_PKTTHR; 5808c2ecf20Sopenharmony_ci ic->rx_max_coalesced_frames = ENETC_RXIC_PKTTHR; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ic->use_adaptive_rx_coalesce = priv->ic_mode & ENETC_IC_RX_ADAPTIVE; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int enetc_set_coalesce(struct net_device *ndev, 5888c2ecf20Sopenharmony_ci struct ethtool_coalesce *ic) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5918c2ecf20Sopenharmony_ci u32 rx_ictt, tx_ictt; 5928c2ecf20Sopenharmony_ci int i, ic_mode; 5938c2ecf20Sopenharmony_ci bool changed; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci tx_ictt = enetc_usecs_to_cycles(ic->tx_coalesce_usecs); 5968c2ecf20Sopenharmony_ci rx_ictt = enetc_usecs_to_cycles(ic->rx_coalesce_usecs); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (ic->rx_max_coalesced_frames != ENETC_RXIC_PKTTHR) 5998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (ic->tx_max_coalesced_frames != ENETC_TXIC_PKTTHR) 6028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ic_mode = ENETC_IC_NONE; 6058c2ecf20Sopenharmony_ci if (ic->use_adaptive_rx_coalesce) { 6068c2ecf20Sopenharmony_ci ic_mode |= ENETC_IC_RX_ADAPTIVE; 6078c2ecf20Sopenharmony_ci rx_ictt = 0x1; 6088c2ecf20Sopenharmony_ci } else { 6098c2ecf20Sopenharmony_ci ic_mode |= rx_ictt ? ENETC_IC_RX_MANUAL : 0; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ic_mode |= tx_ictt ? ENETC_IC_TX_MANUAL : 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* commit the settings */ 6158c2ecf20Sopenharmony_ci changed = (ic_mode != priv->ic_mode) || (priv->tx_ictt != tx_ictt); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci priv->ic_mode = ic_mode; 6188c2ecf20Sopenharmony_ci priv->tx_ictt = tx_ictt; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 6218c2ecf20Sopenharmony_ci struct enetc_int_vector *v = priv->int_vector[i]; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci v->rx_ictt = rx_ictt; 6248c2ecf20Sopenharmony_ci v->rx_dim_en = !!(ic_mode & ENETC_IC_RX_ADAPTIVE); 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (netif_running(ndev) && changed) { 6288c2ecf20Sopenharmony_ci /* reconfigure the operation mode of h/w interrupts, 6298c2ecf20Sopenharmony_ci * traffic needs to be paused in the process 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci enetc_stop(ndev); 6328c2ecf20Sopenharmony_ci enetc_start(ndev); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int enetc_get_ts_info(struct net_device *ndev, 6398c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci int *phc_idx; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci phc_idx = symbol_get(enetc_phc_index); 6448c2ecf20Sopenharmony_ci if (phc_idx) { 6458c2ecf20Sopenharmony_ci info->phc_index = *phc_idx; 6468c2ecf20Sopenharmony_ci symbol_put(enetc_phc_index); 6478c2ecf20Sopenharmony_ci } else { 6488c2ecf20Sopenharmony_ci info->phc_index = -1; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK 6528c2ecf20Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | 6538c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 6548c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE | 6558c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 6568c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 6578c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF) | 6608c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ON); 6618c2ecf20Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 6628c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 6638c2ecf20Sopenharmony_ci#else 6648c2ecf20Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | 6658c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 6668c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 6678c2ecf20Sopenharmony_ci#endif 6688c2ecf20Sopenharmony_ci return 0; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic void enetc_get_wol(struct net_device *dev, 6728c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci wol->supported = 0; 6758c2ecf20Sopenharmony_ci wol->wolopts = 0; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (dev->phydev) 6788c2ecf20Sopenharmony_ci phy_ethtool_get_wol(dev->phydev, wol); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int enetc_set_wol(struct net_device *dev, 6828c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci int ret; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!dev->phydev) 6878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci ret = phy_ethtool_set_wol(dev->phydev, wol); 6908c2ecf20Sopenharmony_ci if (!ret) 6918c2ecf20Sopenharmony_ci device_set_wakeup_enable(&dev->dev, wol->wolopts); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return ret; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic int enetc_get_link_ksettings(struct net_device *dev, 6978c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(dev); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!priv->phylink) 7028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_get(priv->phylink, cmd); 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic int enetc_set_link_ksettings(struct net_device *dev, 7088c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(dev); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!priv->phylink) 7138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_set(priv->phylink, cmd); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic const struct ethtool_ops enetc_pf_ethtool_ops = { 7198c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 7208c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 7218c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 7228c2ecf20Sopenharmony_ci .get_regs_len = enetc_get_reglen, 7238c2ecf20Sopenharmony_ci .get_regs = enetc_get_regs, 7248c2ecf20Sopenharmony_ci .get_sset_count = enetc_get_sset_count, 7258c2ecf20Sopenharmony_ci .get_strings = enetc_get_strings, 7268c2ecf20Sopenharmony_ci .get_ethtool_stats = enetc_get_ethtool_stats, 7278c2ecf20Sopenharmony_ci .get_rxnfc = enetc_get_rxnfc, 7288c2ecf20Sopenharmony_ci .set_rxnfc = enetc_set_rxnfc, 7298c2ecf20Sopenharmony_ci .get_rxfh_key_size = enetc_get_rxfh_key_size, 7308c2ecf20Sopenharmony_ci .get_rxfh_indir_size = enetc_get_rxfh_indir_size, 7318c2ecf20Sopenharmony_ci .get_rxfh = enetc_get_rxfh, 7328c2ecf20Sopenharmony_ci .set_rxfh = enetc_set_rxfh, 7338c2ecf20Sopenharmony_ci .get_ringparam = enetc_get_ringparam, 7348c2ecf20Sopenharmony_ci .get_coalesce = enetc_get_coalesce, 7358c2ecf20Sopenharmony_ci .set_coalesce = enetc_set_coalesce, 7368c2ecf20Sopenharmony_ci .get_link_ksettings = enetc_get_link_ksettings, 7378c2ecf20Sopenharmony_ci .set_link_ksettings = enetc_set_link_ksettings, 7388c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 7398c2ecf20Sopenharmony_ci .get_ts_info = enetc_get_ts_info, 7408c2ecf20Sopenharmony_ci .get_wol = enetc_get_wol, 7418c2ecf20Sopenharmony_ci .set_wol = enetc_set_wol, 7428c2ecf20Sopenharmony_ci}; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic const struct ethtool_ops enetc_vf_ethtool_ops = { 7458c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 7468c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 7478c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 7488c2ecf20Sopenharmony_ci .get_regs_len = enetc_get_reglen, 7498c2ecf20Sopenharmony_ci .get_regs = enetc_get_regs, 7508c2ecf20Sopenharmony_ci .get_sset_count = enetc_get_sset_count, 7518c2ecf20Sopenharmony_ci .get_strings = enetc_get_strings, 7528c2ecf20Sopenharmony_ci .get_ethtool_stats = enetc_get_ethtool_stats, 7538c2ecf20Sopenharmony_ci .get_rxnfc = enetc_get_rxnfc, 7548c2ecf20Sopenharmony_ci .set_rxnfc = enetc_set_rxnfc, 7558c2ecf20Sopenharmony_ci .get_rxfh_indir_size = enetc_get_rxfh_indir_size, 7568c2ecf20Sopenharmony_ci .get_rxfh = enetc_get_rxfh, 7578c2ecf20Sopenharmony_ci .set_rxfh = enetc_set_rxfh, 7588c2ecf20Sopenharmony_ci .get_ringparam = enetc_get_ringparam, 7598c2ecf20Sopenharmony_ci .get_coalesce = enetc_get_coalesce, 7608c2ecf20Sopenharmony_ci .set_coalesce = enetc_set_coalesce, 7618c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 7628c2ecf20Sopenharmony_ci .get_ts_info = enetc_get_ts_info, 7638c2ecf20Sopenharmony_ci}; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_civoid enetc_set_ethtool_ops(struct net_device *ndev) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (enetc_si_is_pf(priv->si)) 7708c2ecf20Sopenharmony_ci ndev->ethtool_ops = &enetc_pf_ethtool_ops; 7718c2ecf20Sopenharmony_ci else 7728c2ecf20Sopenharmony_ci ndev->ethtool_ops = &enetc_vf_ethtool_ops; 7738c2ecf20Sopenharmony_ci} 774