xref: /linux/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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(&eth_mac_stats->FramesTransmittedOK,
140 			  &mac_stats->eth_mac.FramesTransmittedOK);
141 	fbnic_set_counter(&eth_mac_stats->FramesReceivedOK,
142 			  &mac_stats->eth_mac.FramesReceivedOK);
143 	fbnic_set_counter(&eth_mac_stats->FrameCheckSequenceErrors,
144 			  &mac_stats->eth_mac.FrameCheckSequenceErrors);
145 	fbnic_set_counter(&eth_mac_stats->AlignmentErrors,
146 			  &mac_stats->eth_mac.AlignmentErrors);
147 	fbnic_set_counter(&eth_mac_stats->OctetsTransmittedOK,
148 			  &mac_stats->eth_mac.OctetsTransmittedOK);
149 	fbnic_set_counter(&eth_mac_stats->FramesLostDueToIntMACXmitError,
150 			  &mac_stats->eth_mac.FramesLostDueToIntMACXmitError);
151 	fbnic_set_counter(&eth_mac_stats->OctetsReceivedOK,
152 			  &mac_stats->eth_mac.OctetsReceivedOK);
153 	fbnic_set_counter(&eth_mac_stats->FramesLostDueToIntMACRcvError,
154 			  &mac_stats->eth_mac.FramesLostDueToIntMACRcvError);
155 	fbnic_set_counter(&eth_mac_stats->MulticastFramesXmittedOK,
156 			  &mac_stats->eth_mac.MulticastFramesXmittedOK);
157 	fbnic_set_counter(&eth_mac_stats->BroadcastFramesXmittedOK,
158 			  &mac_stats->eth_mac.BroadcastFramesXmittedOK);
159 	fbnic_set_counter(&eth_mac_stats->MulticastFramesReceivedOK,
160 			  &mac_stats->eth_mac.MulticastFramesReceivedOK);
161 	fbnic_set_counter(&eth_mac_stats->BroadcastFramesReceivedOK,
162 			  &mac_stats->eth_mac.BroadcastFramesReceivedOK);
163 	fbnic_set_counter(&eth_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, &regs->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