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
fbnic_get_ts_info(struct net_device * netdev,struct kernel_ethtool_ts_info * tsinfo)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
fbnic_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)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
fbnic_set_counter(u64 * stat,struct fbnic_stat_counter * counter)82 static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
83 {
84 if (counter->reported)
85 *stat = counter->value;
86 }
87
fbnic_get_strings(struct net_device * dev,u32 sset,u8 * data)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
fbnic_get_sset_count(struct net_device * dev,int sset)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
fbnic_get_ethtool_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)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
fbnic_get_eth_mac_stats(struct net_device * netdev,struct ethtool_eth_mac_stats * eth_mac_stats)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
fbnic_get_ts_stats(struct net_device * netdev,struct ethtool_ts_stats * ts_stats)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
fbnic_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * data)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
fbnic_get_regs_len(struct net_device * netdev)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
fbnic_set_ethtool_ops(struct net_device * dev)217 void fbnic_set_ethtool_ops(struct net_device *dev)
218 {
219 dev->ethtool_ops = &fbnic_ethtool_ops;
220 }
221