1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/pci.h> 5 #include <linux/phy.h> 6 #include <linux/ethtool.h> 7 8 #include "wx_type.h" 9 #include "wx_ethtool.h" 10 #include "wx_hw.h" 11 12 struct wx_stats { 13 char stat_string[ETH_GSTRING_LEN]; 14 size_t sizeof_stat; 15 off_t stat_offset; 16 }; 17 18 #define WX_STAT(str, m) { \ 19 .stat_string = str, \ 20 .sizeof_stat = sizeof(((struct wx *)0)->m), \ 21 .stat_offset = offsetof(struct wx, m) } 22 23 static const struct wx_stats wx_gstrings_stats[] = { 24 WX_STAT("rx_dma_pkts", stats.gprc), 25 WX_STAT("tx_dma_pkts", stats.gptc), 26 WX_STAT("rx_dma_bytes", stats.gorc), 27 WX_STAT("tx_dma_bytes", stats.gotc), 28 WX_STAT("rx_total_pkts", stats.tpr), 29 WX_STAT("tx_total_pkts", stats.tpt), 30 WX_STAT("rx_long_length_count", stats.roc), 31 WX_STAT("rx_short_length_count", stats.ruc), 32 WX_STAT("os2bmc_rx_by_bmc", stats.o2bgptc), 33 WX_STAT("os2bmc_tx_by_bmc", stats.b2ospc), 34 WX_STAT("os2bmc_tx_by_host", stats.o2bspc), 35 WX_STAT("os2bmc_rx_by_host", stats.b2ogprc), 36 WX_STAT("rx_no_dma_resources", stats.rdmdrop), 37 WX_STAT("tx_busy", tx_busy), 38 WX_STAT("non_eop_descs", non_eop_descs), 39 WX_STAT("tx_restart_queue", restart_queue), 40 WX_STAT("rx_csum_offload_good_count", hw_csum_rx_good), 41 WX_STAT("rx_csum_offload_errors", hw_csum_rx_error), 42 WX_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed), 43 }; 44 45 /* drivers allocates num_tx_queues and num_rx_queues symmetrically so 46 * we set the num_rx_queues to evaluate to num_tx_queues. This is 47 * used because we do not have a good way to get the max number of 48 * rx queues with CONFIG_RPS disabled. 49 */ 50 #define WX_NUM_RX_QUEUES netdev->num_tx_queues 51 #define WX_NUM_TX_QUEUES netdev->num_tx_queues 52 53 #define WX_QUEUE_STATS_LEN ( \ 54 (WX_NUM_TX_QUEUES + WX_NUM_RX_QUEUES) * \ 55 (sizeof(struct wx_queue_stats) / sizeof(u64))) 56 #define WX_GLOBAL_STATS_LEN ARRAY_SIZE(wx_gstrings_stats) 57 #define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN) 58 59 int wx_get_sset_count(struct net_device *netdev, int sset) 60 { 61 switch (sset) { 62 case ETH_SS_STATS: 63 return WX_STATS_LEN; 64 default: 65 return -EOPNOTSUPP; 66 } 67 } 68 EXPORT_SYMBOL(wx_get_sset_count); 69 70 void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 71 { 72 u8 *p = data; 73 int i; 74 75 switch (stringset) { 76 case ETH_SS_STATS: 77 for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) 78 ethtool_sprintf(&p, wx_gstrings_stats[i].stat_string); 79 for (i = 0; i < netdev->num_tx_queues; i++) { 80 ethtool_sprintf(&p, "tx_queue_%u_packets", i); 81 ethtool_sprintf(&p, "tx_queue_%u_bytes", i); 82 } 83 for (i = 0; i < WX_NUM_RX_QUEUES; i++) { 84 ethtool_sprintf(&p, "rx_queue_%u_packets", i); 85 ethtool_sprintf(&p, "rx_queue_%u_bytes", i); 86 } 87 break; 88 } 89 } 90 EXPORT_SYMBOL(wx_get_strings); 91 92 void wx_get_ethtool_stats(struct net_device *netdev, 93 struct ethtool_stats *stats, u64 *data) 94 { 95 struct wx *wx = netdev_priv(netdev); 96 struct wx_ring *ring; 97 unsigned int start; 98 int i, j; 99 char *p; 100 101 wx_update_stats(wx); 102 103 for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) { 104 p = (char *)wx + wx_gstrings_stats[i].stat_offset; 105 data[i] = (wx_gstrings_stats[i].sizeof_stat == 106 sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 107 } 108 109 for (j = 0; j < netdev->num_tx_queues; j++) { 110 ring = wx->tx_ring[j]; 111 if (!ring) { 112 data[i++] = 0; 113 data[i++] = 0; 114 continue; 115 } 116 117 do { 118 start = u64_stats_fetch_begin(&ring->syncp); 119 data[i] = ring->stats.packets; 120 data[i + 1] = ring->stats.bytes; 121 } while (u64_stats_fetch_retry(&ring->syncp, start)); 122 i += 2; 123 } 124 for (j = 0; j < WX_NUM_RX_QUEUES; j++) { 125 ring = wx->rx_ring[j]; 126 if (!ring) { 127 data[i++] = 0; 128 data[i++] = 0; 129 continue; 130 } 131 132 do { 133 start = u64_stats_fetch_begin(&ring->syncp); 134 data[i] = ring->stats.packets; 135 data[i + 1] = ring->stats.bytes; 136 } while (u64_stats_fetch_retry(&ring->syncp, start)); 137 i += 2; 138 } 139 } 140 EXPORT_SYMBOL(wx_get_ethtool_stats); 141 142 void wx_get_mac_stats(struct net_device *netdev, 143 struct ethtool_eth_mac_stats *mac_stats) 144 { 145 struct wx *wx = netdev_priv(netdev); 146 struct wx_hw_stats *hwstats; 147 148 wx_update_stats(wx); 149 150 hwstats = &wx->stats; 151 mac_stats->MulticastFramesXmittedOK = hwstats->mptc; 152 mac_stats->BroadcastFramesXmittedOK = hwstats->bptc; 153 mac_stats->MulticastFramesReceivedOK = hwstats->mprc; 154 mac_stats->BroadcastFramesReceivedOK = hwstats->bprc; 155 } 156 EXPORT_SYMBOL(wx_get_mac_stats); 157 158 void wx_get_pause_stats(struct net_device *netdev, 159 struct ethtool_pause_stats *stats) 160 { 161 struct wx *wx = netdev_priv(netdev); 162 struct wx_hw_stats *hwstats; 163 164 wx_update_stats(wx); 165 166 hwstats = &wx->stats; 167 stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc; 168 stats->rx_pause_frames = hwstats->lxonoffrxc; 169 } 170 EXPORT_SYMBOL(wx_get_pause_stats); 171 172 void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) 173 { 174 struct wx *wx = netdev_priv(netdev); 175 176 strscpy(info->driver, wx->driver_name, sizeof(info->driver)); 177 strscpy(info->fw_version, wx->eeprom_id, sizeof(info->fw_version)); 178 strscpy(info->bus_info, pci_name(wx->pdev), sizeof(info->bus_info)); 179 if (wx->num_tx_queues <= WX_NUM_TX_QUEUES) { 180 info->n_stats = WX_STATS_LEN - 181 (WX_NUM_TX_QUEUES - wx->num_tx_queues) * 182 (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2; 183 } else { 184 info->n_stats = WX_STATS_LEN; 185 } 186 } 187 EXPORT_SYMBOL(wx_get_drvinfo); 188