1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include <linux/ethtool.h> 5 #include <linux/netdevice.h> 6 #include <linux/pci.h> 7 8 #include "fbnic.h" 9 #include "fbnic_netdev.h" 10 #include "fbnic_tlv.h" 11 12 struct fbnic_stat { 13 u8 string[ETH_GSTRING_LEN]; 14 unsigned int size; 15 unsigned int offset; 16 }; 17 18 #define FBNIC_STAT_FIELDS(type, name, stat) { \ 19 .string = name, \ 20 .size = sizeof_field(struct type, stat), \ 21 .offset = offsetof(struct type, stat), \ 22 } 23 24 /* Hardware statistics not captured in rtnl_link_stats */ 25 #define FBNIC_HW_STAT(name, stat) \ 26 FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat) 27 28 static const struct fbnic_stat fbnic_gstrings_hw_stats[] = { 29 /* RPC */ 30 FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype), 31 FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr), 32 FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag), 33 FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag), 34 FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp), 35 FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp), 36 FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err), 37 FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err), 38 }; 39 40 #define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats) 41 #define FBNIC_HW_STATS_LEN FBNIC_HW_FIXED_STATS_LEN 42 43 static int 44 fbnic_get_ts_info(struct net_device *netdev, 45 struct kernel_ethtool_ts_info *tsinfo) 46 { 47 struct fbnic_net *fbn = netdev_priv(netdev); 48 49 tsinfo->phc_index = ptp_clock_index(fbn->fbd->ptp); 50 51 tsinfo->so_timestamping = 52 SOF_TIMESTAMPING_TX_SOFTWARE | 53 SOF_TIMESTAMPING_TX_HARDWARE | 54 SOF_TIMESTAMPING_RX_HARDWARE | 55 SOF_TIMESTAMPING_RAW_HARDWARE; 56 57 tsinfo->tx_types = 58 BIT(HWTSTAMP_TX_OFF) | 59 BIT(HWTSTAMP_TX_ON); 60 61 tsinfo->rx_filters = 62 BIT(HWTSTAMP_FILTER_NONE) | 63 BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | 64 BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | 65 BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 66 BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | 67 BIT(HWTSTAMP_FILTER_ALL); 68 69 return 0; 70 } 71 72 static void 73 fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) 74 { 75 struct fbnic_net *fbn = netdev_priv(netdev); 76 struct fbnic_dev *fbd = fbn->fbd; 77 78 fbnic_get_fw_ver_commit_str(fbd, drvinfo->fw_version, 79 sizeof(drvinfo->fw_version)); 80 } 81 82 static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter) 83 { 84 if (counter->reported) 85 *stat = counter->value; 86 } 87 88 static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) 89 { 90 int i; 91 92 switch (sset) { 93 case ETH_SS_STATS: 94 for (i = 0; i < FBNIC_HW_STATS_LEN; i++) 95 ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string); 96 break; 97 } 98 } 99 100 static int fbnic_get_sset_count(struct net_device *dev, int sset) 101 { 102 switch (sset) { 103 case ETH_SS_STATS: 104 return FBNIC_HW_STATS_LEN; 105 default: 106 return -EOPNOTSUPP; 107 } 108 } 109 110 static void fbnic_get_ethtool_stats(struct net_device *dev, 111 struct ethtool_stats *stats, u64 *data) 112 { 113 struct fbnic_net *fbn = netdev_priv(dev); 114 const struct fbnic_stat *stat; 115 int i; 116 117 fbnic_get_hw_stats(fbn->fbd); 118 119 for (i = 0; i < FBNIC_HW_STATS_LEN; i++) { 120 stat = &fbnic_gstrings_hw_stats[i]; 121 data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset); 122 } 123 } 124 125 static void 126 fbnic_get_eth_mac_stats(struct net_device *netdev, 127 struct ethtool_eth_mac_stats *eth_mac_stats) 128 { 129 struct fbnic_net *fbn = netdev_priv(netdev); 130 struct fbnic_mac_stats *mac_stats; 131 struct fbnic_dev *fbd = fbn->fbd; 132 const struct fbnic_mac *mac; 133 134 mac_stats = &fbd->hw_stats.mac; 135 mac = fbd->mac; 136 137 mac->get_eth_mac_stats(fbd, false, &mac_stats->eth_mac); 138 139 fbnic_set_counter(ð_mac_stats->FramesTransmittedOK, 140 &mac_stats->eth_mac.FramesTransmittedOK); 141 fbnic_set_counter(ð_mac_stats->FramesReceivedOK, 142 &mac_stats->eth_mac.FramesReceivedOK); 143 fbnic_set_counter(ð_mac_stats->FrameCheckSequenceErrors, 144 &mac_stats->eth_mac.FrameCheckSequenceErrors); 145 fbnic_set_counter(ð_mac_stats->AlignmentErrors, 146 &mac_stats->eth_mac.AlignmentErrors); 147 fbnic_set_counter(ð_mac_stats->OctetsTransmittedOK, 148 &mac_stats->eth_mac.OctetsTransmittedOK); 149 fbnic_set_counter(ð_mac_stats->FramesLostDueToIntMACXmitError, 150 &mac_stats->eth_mac.FramesLostDueToIntMACXmitError); 151 fbnic_set_counter(ð_mac_stats->OctetsReceivedOK, 152 &mac_stats->eth_mac.OctetsReceivedOK); 153 fbnic_set_counter(ð_mac_stats->FramesLostDueToIntMACRcvError, 154 &mac_stats->eth_mac.FramesLostDueToIntMACRcvError); 155 fbnic_set_counter(ð_mac_stats->MulticastFramesXmittedOK, 156 &mac_stats->eth_mac.MulticastFramesXmittedOK); 157 fbnic_set_counter(ð_mac_stats->BroadcastFramesXmittedOK, 158 &mac_stats->eth_mac.BroadcastFramesXmittedOK); 159 fbnic_set_counter(ð_mac_stats->MulticastFramesReceivedOK, 160 &mac_stats->eth_mac.MulticastFramesReceivedOK); 161 fbnic_set_counter(ð_mac_stats->BroadcastFramesReceivedOK, 162 &mac_stats->eth_mac.BroadcastFramesReceivedOK); 163 fbnic_set_counter(ð_mac_stats->FrameTooLongErrors, 164 &mac_stats->eth_mac.FrameTooLongErrors); 165 } 166 167 static void fbnic_get_ts_stats(struct net_device *netdev, 168 struct ethtool_ts_stats *ts_stats) 169 { 170 struct fbnic_net *fbn = netdev_priv(netdev); 171 u64 ts_packets, ts_lost; 172 struct fbnic_ring *ring; 173 unsigned int start; 174 int i; 175 176 ts_stats->pkts = fbn->tx_stats.ts_packets; 177 ts_stats->lost = fbn->tx_stats.ts_lost; 178 for (i = 0; i < fbn->num_tx_queues; i++) { 179 ring = fbn->tx[i]; 180 do { 181 start = u64_stats_fetch_begin(&ring->stats.syncp); 182 ts_packets = ring->stats.ts_packets; 183 ts_lost = ring->stats.ts_lost; 184 } while (u64_stats_fetch_retry(&ring->stats.syncp, start)); 185 ts_stats->pkts += ts_packets; 186 ts_stats->lost += ts_lost; 187 } 188 } 189 190 static void fbnic_get_regs(struct net_device *netdev, 191 struct ethtool_regs *regs, void *data) 192 { 193 struct fbnic_net *fbn = netdev_priv(netdev); 194 195 fbnic_csr_get_regs(fbn->fbd, data, ®s->version); 196 } 197 198 static int fbnic_get_regs_len(struct net_device *netdev) 199 { 200 struct fbnic_net *fbn = netdev_priv(netdev); 201 202 return fbnic_csr_regs_len(fbn->fbd) * sizeof(u32); 203 } 204 205 static const struct ethtool_ops fbnic_ethtool_ops = { 206 .get_drvinfo = fbnic_get_drvinfo, 207 .get_regs_len = fbnic_get_regs_len, 208 .get_regs = fbnic_get_regs, 209 .get_strings = fbnic_get_strings, 210 .get_ethtool_stats = fbnic_get_ethtool_stats, 211 .get_sset_count = fbnic_get_sset_count, 212 .get_ts_info = fbnic_get_ts_info, 213 .get_ts_stats = fbnic_get_ts_stats, 214 .get_eth_mac_stats = fbnic_get_eth_mac_stats, 215 }; 216 217 void fbnic_set_ethtool_ops(struct net_device *dev) 218 { 219 dev->ethtool_ops = &fbnic_ethtool_ops; 220 } 221