1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include <linux/netdevice.h>
4 
5 #include "lan966x_main.h"
6 
7 /* Number of traffic classes */
8 #define LAN966X_NUM_TC			8
9 #define LAN966X_STATS_CHECK_DELAY	(2 * HZ)
10 
11 static const struct lan966x_stat_layout lan966x_stats_layout[] = {
12 	{ .name = "rx_octets", .offset = 0x00, },
13 	{ .name = "rx_unicast", .offset = 0x01, },
14 	{ .name = "rx_multicast", .offset = 0x02 },
15 	{ .name = "rx_broadcast", .offset = 0x03 },
16 	{ .name = "rx_short", .offset = 0x04 },
17 	{ .name = "rx_frag", .offset = 0x05 },
18 	{ .name = "rx_jabber", .offset = 0x06 },
19 	{ .name = "rx_crc", .offset = 0x07 },
20 	{ .name = "rx_symbol_err", .offset = 0x08 },
21 	{ .name = "rx_sz_64", .offset = 0x09 },
22 	{ .name = "rx_sz_65_127", .offset = 0x0a},
23 	{ .name = "rx_sz_128_255", .offset = 0x0b},
24 	{ .name = "rx_sz_256_511", .offset = 0x0c },
25 	{ .name = "rx_sz_512_1023", .offset = 0x0d },
26 	{ .name = "rx_sz_1024_1526", .offset = 0x0e },
27 	{ .name = "rx_sz_jumbo", .offset = 0x0f },
28 	{ .name = "rx_pause", .offset = 0x10 },
29 	{ .name = "rx_control", .offset = 0x11 },
30 	{ .name = "rx_long", .offset = 0x12 },
31 	{ .name = "rx_cat_drop", .offset = 0x13 },
32 	{ .name = "rx_red_prio_0", .offset = 0x14 },
33 	{ .name = "rx_red_prio_1", .offset = 0x15 },
34 	{ .name = "rx_red_prio_2", .offset = 0x16 },
35 	{ .name = "rx_red_prio_3", .offset = 0x17 },
36 	{ .name = "rx_red_prio_4", .offset = 0x18 },
37 	{ .name = "rx_red_prio_5", .offset = 0x19 },
38 	{ .name = "rx_red_prio_6", .offset = 0x1a },
39 	{ .name = "rx_red_prio_7", .offset = 0x1b },
40 	{ .name = "rx_yellow_prio_0", .offset = 0x1c },
41 	{ .name = "rx_yellow_prio_1", .offset = 0x1d },
42 	{ .name = "rx_yellow_prio_2", .offset = 0x1e },
43 	{ .name = "rx_yellow_prio_3", .offset = 0x1f },
44 	{ .name = "rx_yellow_prio_4", .offset = 0x20 },
45 	{ .name = "rx_yellow_prio_5", .offset = 0x21 },
46 	{ .name = "rx_yellow_prio_6", .offset = 0x22 },
47 	{ .name = "rx_yellow_prio_7", .offset = 0x23 },
48 	{ .name = "rx_green_prio_0", .offset = 0x24 },
49 	{ .name = "rx_green_prio_1", .offset = 0x25 },
50 	{ .name = "rx_green_prio_2", .offset = 0x26 },
51 	{ .name = "rx_green_prio_3", .offset = 0x27 },
52 	{ .name = "rx_green_prio_4", .offset = 0x28 },
53 	{ .name = "rx_green_prio_5", .offset = 0x29 },
54 	{ .name = "rx_green_prio_6", .offset = 0x2a },
55 	{ .name = "rx_green_prio_7", .offset = 0x2b },
56 	{ .name = "rx_assembly_err", .offset = 0x2c },
57 	{ .name = "rx_smd_err", .offset = 0x2d },
58 	{ .name = "rx_assembly_ok", .offset = 0x2e },
59 	{ .name = "rx_merge_frag", .offset = 0x2f },
60 	{ .name = "rx_pmac_octets", .offset = 0x30, },
61 	{ .name = "rx_pmac_unicast", .offset = 0x31, },
62 	{ .name = "rx_pmac_multicast", .offset = 0x32 },
63 	{ .name = "rx_pmac_broadcast", .offset = 0x33 },
64 	{ .name = "rx_pmac_short", .offset = 0x34 },
65 	{ .name = "rx_pmac_frag", .offset = 0x35 },
66 	{ .name = "rx_pmac_jabber", .offset = 0x36 },
67 	{ .name = "rx_pmac_crc", .offset = 0x37 },
68 	{ .name = "rx_pmac_symbol_err", .offset = 0x38 },
69 	{ .name = "rx_pmac_sz_64", .offset = 0x39 },
70 	{ .name = "rx_pmac_sz_65_127", .offset = 0x3a },
71 	{ .name = "rx_pmac_sz_128_255", .offset = 0x3b },
72 	{ .name = "rx_pmac_sz_256_511", .offset = 0x3c },
73 	{ .name = "rx_pmac_sz_512_1023", .offset = 0x3d },
74 	{ .name = "rx_pmac_sz_1024_1526", .offset = 0x3e },
75 	{ .name = "rx_pmac_sz_jumbo", .offset = 0x3f },
76 	{ .name = "rx_pmac_pause", .offset = 0x40 },
77 	{ .name = "rx_pmac_control", .offset = 0x41 },
78 	{ .name = "rx_pmac_long", .offset = 0x42 },
79 
80 	{ .name = "tx_octets", .offset = 0x80, },
81 	{ .name = "tx_unicast", .offset = 0x81, },
82 	{ .name = "tx_multicast", .offset = 0x82 },
83 	{ .name = "tx_broadcast", .offset = 0x83 },
84 	{ .name = "tx_col", .offset = 0x84 },
85 	{ .name = "tx_drop", .offset = 0x85 },
86 	{ .name = "tx_pause", .offset = 0x86 },
87 	{ .name = "tx_sz_64", .offset = 0x87 },
88 	{ .name = "tx_sz_65_127", .offset = 0x88 },
89 	{ .name = "tx_sz_128_255", .offset = 0x89 },
90 	{ .name = "tx_sz_256_511", .offset = 0x8a },
91 	{ .name = "tx_sz_512_1023", .offset = 0x8b },
92 	{ .name = "tx_sz_1024_1526", .offset = 0x8c },
93 	{ .name = "tx_sz_jumbo", .offset = 0x8d },
94 	{ .name = "tx_yellow_prio_0", .offset = 0x8e },
95 	{ .name = "tx_yellow_prio_1", .offset = 0x8f },
96 	{ .name = "tx_yellow_prio_2", .offset = 0x90 },
97 	{ .name = "tx_yellow_prio_3", .offset = 0x91 },
98 	{ .name = "tx_yellow_prio_4", .offset = 0x92 },
99 	{ .name = "tx_yellow_prio_5", .offset = 0x93 },
100 	{ .name = "tx_yellow_prio_6", .offset = 0x94 },
101 	{ .name = "tx_yellow_prio_7", .offset = 0x95 },
102 	{ .name = "tx_green_prio_0", .offset = 0x96 },
103 	{ .name = "tx_green_prio_1", .offset = 0x97 },
104 	{ .name = "tx_green_prio_2", .offset = 0x98 },
105 	{ .name = "tx_green_prio_3", .offset = 0x99 },
106 	{ .name = "tx_green_prio_4", .offset = 0x9a },
107 	{ .name = "tx_green_prio_5", .offset = 0x9b },
108 	{ .name = "tx_green_prio_6", .offset = 0x9c },
109 	{ .name = "tx_green_prio_7", .offset = 0x9d },
110 	{ .name = "tx_aged", .offset = 0x9e },
111 	{ .name = "tx_llct", .offset = 0x9f },
112 	{ .name = "tx_ct", .offset = 0xa0 },
113 	{ .name = "tx_mm_hold", .offset = 0xa1 },
114 	{ .name = "tx_merge_frag", .offset = 0xa2 },
115 	{ .name = "tx_pmac_octets", .offset = 0xa3, },
116 	{ .name = "tx_pmac_unicast", .offset = 0xa4, },
117 	{ .name = "tx_pmac_multicast", .offset = 0xa5 },
118 	{ .name = "tx_pmac_broadcast", .offset = 0xa6 },
119 	{ .name = "tx_pmac_pause", .offset = 0xa7 },
120 	{ .name = "tx_pmac_sz_64", .offset = 0xa8 },
121 	{ .name = "tx_pmac_sz_65_127", .offset = 0xa9 },
122 	{ .name = "tx_pmac_sz_128_255", .offset = 0xaa },
123 	{ .name = "tx_pmac_sz_256_511", .offset = 0xab },
124 	{ .name = "tx_pmac_sz_512_1023", .offset = 0xac },
125 	{ .name = "tx_pmac_sz_1024_1526", .offset = 0xad },
126 	{ .name = "tx_pmac_sz_jumbo", .offset = 0xae },
127 
128 	{ .name = "dr_local", .offset = 0x100 },
129 	{ .name = "dr_tail", .offset = 0x101 },
130 	{ .name = "dr_yellow_prio_0", .offset = 0x102 },
131 	{ .name = "dr_yellow_prio_1", .offset = 0x103 },
132 	{ .name = "dr_yellow_prio_2", .offset = 0x104 },
133 	{ .name = "dr_yellow_prio_3", .offset = 0x105 },
134 	{ .name = "dr_yellow_prio_4", .offset = 0x106 },
135 	{ .name = "dr_yellow_prio_5", .offset = 0x107 },
136 	{ .name = "dr_yellow_prio_6", .offset = 0x108 },
137 	{ .name = "dr_yellow_prio_7", .offset = 0x109 },
138 	{ .name = "dr_green_prio_0", .offset = 0x10a },
139 	{ .name = "dr_green_prio_1", .offset = 0x10b },
140 	{ .name = "dr_green_prio_2", .offset = 0x10c },
141 	{ .name = "dr_green_prio_3", .offset = 0x10d },
142 	{ .name = "dr_green_prio_4", .offset = 0x10e },
143 	{ .name = "dr_green_prio_5", .offset = 0x10f },
144 	{ .name = "dr_green_prio_6", .offset = 0x110 },
145 	{ .name = "dr_green_prio_7", .offset = 0x111 },
146 };
147 
148 /* The following numbers are indexes into lan966x_stats_layout[] */
149 #define SYS_COUNT_RX_OCT		  0
150 #define SYS_COUNT_RX_UC			  1
151 #define SYS_COUNT_RX_MC			  2
152 #define SYS_COUNT_RX_BC			  3
153 #define SYS_COUNT_RX_SHORT		  4
154 #define SYS_COUNT_RX_FRAG		  5
155 #define SYS_COUNT_RX_JABBER		  6
156 #define SYS_COUNT_RX_CRC		  7
157 #define SYS_COUNT_RX_SYMBOL_ERR		  8
158 #define SYS_COUNT_RX_SZ_64		  9
159 #define SYS_COUNT_RX_SZ_65_127		 10
160 #define SYS_COUNT_RX_SZ_128_255		 11
161 #define SYS_COUNT_RX_SZ_256_511		 12
162 #define SYS_COUNT_RX_SZ_512_1023	 13
163 #define SYS_COUNT_RX_SZ_1024_1526	 14
164 #define SYS_COUNT_RX_SZ_JUMBO		 15
165 #define SYS_COUNT_RX_PAUSE		 16
166 #define SYS_COUNT_RX_CONTROL		 17
167 #define SYS_COUNT_RX_LONG		 18
168 #define SYS_COUNT_RX_CAT_DROP		 19
169 #define SYS_COUNT_RX_RED_PRIO_0		 20
170 #define SYS_COUNT_RX_RED_PRIO_1		 21
171 #define SYS_COUNT_RX_RED_PRIO_2		 22
172 #define SYS_COUNT_RX_RED_PRIO_3		 23
173 #define SYS_COUNT_RX_RED_PRIO_4		 24
174 #define SYS_COUNT_RX_RED_PRIO_5		 25
175 #define SYS_COUNT_RX_RED_PRIO_6		 26
176 #define SYS_COUNT_RX_RED_PRIO_7		 27
177 #define SYS_COUNT_RX_YELLOW_PRIO_0	 28
178 #define SYS_COUNT_RX_YELLOW_PRIO_1	 29
179 #define SYS_COUNT_RX_YELLOW_PRIO_2	 30
180 #define SYS_COUNT_RX_YELLOW_PRIO_3	 31
181 #define SYS_COUNT_RX_YELLOW_PRIO_4	 32
182 #define SYS_COUNT_RX_YELLOW_PRIO_5	 33
183 #define SYS_COUNT_RX_YELLOW_PRIO_6	 34
184 #define SYS_COUNT_RX_YELLOW_PRIO_7	 35
185 #define SYS_COUNT_RX_GREEN_PRIO_0	 36
186 #define SYS_COUNT_RX_GREEN_PRIO_1	 37
187 #define SYS_COUNT_RX_GREEN_PRIO_2	 38
188 #define SYS_COUNT_RX_GREEN_PRIO_3	 39
189 #define SYS_COUNT_RX_GREEN_PRIO_4	 40
190 #define SYS_COUNT_RX_GREEN_PRIO_5	 41
191 #define SYS_COUNT_RX_GREEN_PRIO_6	 42
192 #define SYS_COUNT_RX_GREEN_PRIO_7	 43
193 #define SYS_COUNT_RX_ASSEMBLY_ERR	 44
194 #define SYS_COUNT_RX_SMD_ERR		 45
195 #define SYS_COUNT_RX_ASSEMBLY_OK	 46
196 #define SYS_COUNT_RX_MERGE_FRAG		 47
197 #define SYS_COUNT_RX_PMAC_OCT		 48
198 #define SYS_COUNT_RX_PMAC_UC		 49
199 #define SYS_COUNT_RX_PMAC_MC		 50
200 #define SYS_COUNT_RX_PMAC_BC		 51
201 #define SYS_COUNT_RX_PMAC_SHORT		 52
202 #define SYS_COUNT_RX_PMAC_FRAG		 53
203 #define SYS_COUNT_RX_PMAC_JABBER	 54
204 #define SYS_COUNT_RX_PMAC_CRC		 55
205 #define SYS_COUNT_RX_PMAC_SYMBOL_ERR	 56
206 #define SYS_COUNT_RX_PMAC_SZ_64		 57
207 #define SYS_COUNT_RX_PMAC_SZ_65_127	 58
208 #define SYS_COUNT_RX_PMAC_SZ_128_255	 59
209 #define SYS_COUNT_RX_PMAC_SZ_256_511	 60
210 #define SYS_COUNT_RX_PMAC_SZ_512_1023	 61
211 #define SYS_COUNT_RX_PMAC_SZ_1024_1526	 62
212 #define SYS_COUNT_RX_PMAC_SZ_JUMBO	 63
213 #define SYS_COUNT_RX_PMAC_PAUSE		 64
214 #define SYS_COUNT_RX_PMAC_CONTROL	 65
215 #define SYS_COUNT_RX_PMAC_LONG		 66
216 
217 #define SYS_COUNT_TX_OCT		 67
218 #define SYS_COUNT_TX_UC			 68
219 #define SYS_COUNT_TX_MC			 69
220 #define SYS_COUNT_TX_BC			 70
221 #define SYS_COUNT_TX_COL		 71
222 #define SYS_COUNT_TX_DROP		 72
223 #define SYS_COUNT_TX_PAUSE		 73
224 #define SYS_COUNT_TX_SZ_64		 74
225 #define SYS_COUNT_TX_SZ_65_127		 75
226 #define SYS_COUNT_TX_SZ_128_255		 76
227 #define SYS_COUNT_TX_SZ_256_511		 77
228 #define SYS_COUNT_TX_SZ_512_1023	 78
229 #define SYS_COUNT_TX_SZ_1024_1526	 79
230 #define SYS_COUNT_TX_SZ_JUMBO		 80
231 #define SYS_COUNT_TX_YELLOW_PRIO_0	 81
232 #define SYS_COUNT_TX_YELLOW_PRIO_1	 82
233 #define SYS_COUNT_TX_YELLOW_PRIO_2	 83
234 #define SYS_COUNT_TX_YELLOW_PRIO_3	 84
235 #define SYS_COUNT_TX_YELLOW_PRIO_4	 85
236 #define SYS_COUNT_TX_YELLOW_PRIO_5	 86
237 #define SYS_COUNT_TX_YELLOW_PRIO_6	 87
238 #define SYS_COUNT_TX_YELLOW_PRIO_7	 88
239 #define SYS_COUNT_TX_GREEN_PRIO_0	 89
240 #define SYS_COUNT_TX_GREEN_PRIO_1	 90
241 #define SYS_COUNT_TX_GREEN_PRIO_2	 91
242 #define SYS_COUNT_TX_GREEN_PRIO_3	 92
243 #define SYS_COUNT_TX_GREEN_PRIO_4	 93
244 #define SYS_COUNT_TX_GREEN_PRIO_5	 94
245 #define SYS_COUNT_TX_GREEN_PRIO_6	 95
246 #define SYS_COUNT_TX_GREEN_PRIO_7	 96
247 #define SYS_COUNT_TX_AGED		 97
248 #define SYS_COUNT_TX_LLCT		 98
249 #define SYS_COUNT_TX_CT			 99
250 #define SYS_COUNT_TX_MM_HOLD		100
251 #define SYS_COUNT_TX_MERGE_FRAG		101
252 #define SYS_COUNT_TX_PMAC_OCT		102
253 #define SYS_COUNT_TX_PMAC_UC		103
254 #define SYS_COUNT_TX_PMAC_MC		104
255 #define SYS_COUNT_TX_PMAC_BC		105
256 #define SYS_COUNT_TX_PMAC_PAUSE		106
257 #define SYS_COUNT_TX_PMAC_SZ_64		107
258 #define SYS_COUNT_TX_PMAC_SZ_65_127	108
259 #define SYS_COUNT_TX_PMAC_SZ_128_255	109
260 #define SYS_COUNT_TX_PMAC_SZ_256_511	110
261 #define SYS_COUNT_TX_PMAC_SZ_512_1023	111
262 #define SYS_COUNT_TX_PMAC_SZ_1024_1526	112
263 #define SYS_COUNT_TX_PMAC_SZ_JUMBO	113
264 
265 #define SYS_COUNT_DR_LOCAL		114
266 #define SYS_COUNT_DR_TAIL		115
267 #define SYS_COUNT_DR_YELLOW_PRIO_0	116
268 #define SYS_COUNT_DR_YELLOW_PRIO_1	117
269 #define SYS_COUNT_DR_YELLOW_PRIO_2	118
270 #define SYS_COUNT_DR_YELLOW_PRIO_3	119
271 #define SYS_COUNT_DR_YELLOW_PRIO_4	120
272 #define SYS_COUNT_DR_YELLOW_PRIO_5	121
273 #define SYS_COUNT_DR_YELLOW_PRIO_6	122
274 #define SYS_COUNT_DR_YELLOW_PRIO_7	123
275 #define SYS_COUNT_DR_GREEN_PRIO_0	124
276 #define SYS_COUNT_DR_GREEN_PRIO_1	125
277 #define SYS_COUNT_DR_GREEN_PRIO_2	126
278 #define SYS_COUNT_DR_GREEN_PRIO_3	127
279 #define SYS_COUNT_DR_GREEN_PRIO_4	128
280 #define SYS_COUNT_DR_GREEN_PRIO_5	129
281 #define SYS_COUNT_DR_GREEN_PRIO_6	130
282 #define SYS_COUNT_DR_GREEN_PRIO_7	131
283 
284 /* Add a possibly wrapping 32 bit value to a 64 bit counter */
285 static void lan966x_add_cnt(u64 *cnt, u32 val)
286 {
287 	if (val < (*cnt & U32_MAX))
288 		*cnt += (u64)1 << 32; /* value has wrapped */
289 
290 	*cnt = (*cnt & ~(u64)U32_MAX) + val;
291 }
292 
293 static void lan966x_stats_update(struct lan966x *lan966x)
294 {
295 	int i, j;
296 
297 	mutex_lock(&lan966x->stats_lock);
298 
299 	for (i = 0; i < lan966x->num_phys_ports; i++) {
300 		uint idx = i * lan966x->num_stats;
301 
302 		lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i),
303 		       lan966x, SYS_STAT_CFG);
304 
305 		for (j = 0; j < lan966x->num_stats; j++) {
306 			u32 offset = lan966x->stats_layout[j].offset;
307 
308 			lan966x_add_cnt(&lan966x->stats[idx++],
309 					lan_rd(lan966x, SYS_CNT(offset)));
310 		}
311 	}
312 
313 	mutex_unlock(&lan966x->stats_lock);
314 }
315 
316 static int lan966x_get_sset_count(struct net_device *dev, int sset)
317 {
318 	struct lan966x_port *port = netdev_priv(dev);
319 	struct lan966x *lan966x = port->lan966x;
320 
321 	if (sset != ETH_SS_STATS)
322 		return -EOPNOTSUPP;
323 
324 	return lan966x->num_stats;
325 }
326 
327 static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data)
328 {
329 	struct lan966x_port *port = netdev_priv(netdev);
330 	struct lan966x *lan966x = port->lan966x;
331 	int i;
332 
333 	if (sset != ETH_SS_STATS)
334 		return;
335 
336 	for (i = 0; i < lan966x->num_stats; i++)
337 		memcpy(data + i * ETH_GSTRING_LEN,
338 		       lan966x->stats_layout[i].name, ETH_GSTRING_LEN);
339 }
340 
341 static void lan966x_get_ethtool_stats(struct net_device *dev,
342 				      struct ethtool_stats *stats, u64 *data)
343 {
344 	struct lan966x_port *port = netdev_priv(dev);
345 	struct lan966x *lan966x = port->lan966x;
346 	int i;
347 
348 	/* check and update now */
349 	lan966x_stats_update(lan966x);
350 
351 	/* Copy all counters */
352 	for (i = 0; i < lan966x->num_stats; i++)
353 		*data++ = lan966x->stats[port->chip_port *
354 					 lan966x->num_stats + i];
355 }
356 
357 static void lan966x_get_eth_mac_stats(struct net_device *dev,
358 				      struct ethtool_eth_mac_stats *mac_stats)
359 {
360 	struct lan966x_port *port = netdev_priv(dev);
361 	struct lan966x *lan966x = port->lan966x;
362 	u32 idx;
363 
364 	lan966x_stats_update(lan966x);
365 
366 	idx = port->chip_port * lan966x->num_stats;
367 
368 	mutex_lock(&lan966x->stats_lock);
369 
370 	mac_stats->FramesTransmittedOK =
371 		lan966x->stats[idx + SYS_COUNT_TX_UC] +
372 		lan966x->stats[idx + SYS_COUNT_TX_MC] +
373 		lan966x->stats[idx + SYS_COUNT_TX_BC] +
374 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] +
375 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] +
376 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
377 	mac_stats->SingleCollisionFrames =
378 		lan966x->stats[idx + SYS_COUNT_TX_COL];
379 	mac_stats->MultipleCollisionFrames = 0;
380 	mac_stats->FramesReceivedOK =
381 		lan966x->stats[idx + SYS_COUNT_RX_UC] +
382 		lan966x->stats[idx + SYS_COUNT_RX_MC] +
383 		lan966x->stats[idx + SYS_COUNT_RX_BC];
384 	mac_stats->FrameCheckSequenceErrors =
385 		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
386 		lan966x->stats[idx + SYS_COUNT_RX_CRC];
387 	mac_stats->AlignmentErrors = 0;
388 	mac_stats->OctetsTransmittedOK =
389 		lan966x->stats[idx + SYS_COUNT_TX_OCT] +
390 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
391 	mac_stats->FramesWithDeferredXmissions =
392 		lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD];
393 	mac_stats->LateCollisions = 0;
394 	mac_stats->FramesAbortedDueToXSColls = 0;
395 	mac_stats->FramesLostDueToIntMACXmitError = 0;
396 	mac_stats->CarrierSenseErrors = 0;
397 	mac_stats->OctetsReceivedOK =
398 		lan966x->stats[idx + SYS_COUNT_RX_OCT];
399 	mac_stats->FramesLostDueToIntMACRcvError = 0;
400 	mac_stats->MulticastFramesXmittedOK =
401 		lan966x->stats[idx + SYS_COUNT_TX_MC] +
402 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC];
403 	mac_stats->BroadcastFramesXmittedOK =
404 		lan966x->stats[idx + SYS_COUNT_TX_BC] +
405 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
406 	mac_stats->FramesWithExcessiveDeferral = 0;
407 	mac_stats->MulticastFramesReceivedOK =
408 		lan966x->stats[idx + SYS_COUNT_RX_MC];
409 	mac_stats->BroadcastFramesReceivedOK =
410 		lan966x->stats[idx + SYS_COUNT_RX_BC];
411 	mac_stats->InRangeLengthErrors =
412 		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
413 		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
414 		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
415 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
416 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
417 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC];
418 	mac_stats->OutOfRangeLengthField =
419 		lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
420 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
421 		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
422 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
423 	mac_stats->FrameTooLongErrors =
424 		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
425 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
426 
427 	mutex_unlock(&lan966x->stats_lock);
428 }
429 
430 static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = {
431 	{    0,    64 },
432 	{   65,   127 },
433 	{  128,   255 },
434 	{  256,   511 },
435 	{  512,  1023 },
436 	{ 1024,  1518 },
437 	{ 1519, 10239 },
438 	{}
439 };
440 
441 static void lan966x_get_eth_rmon_stats(struct net_device *dev,
442 				       struct ethtool_rmon_stats *rmon_stats,
443 				       const struct ethtool_rmon_hist_range **ranges)
444 {
445 	struct lan966x_port *port = netdev_priv(dev);
446 	struct lan966x *lan966x = port->lan966x;
447 	u32 idx;
448 
449 	lan966x_stats_update(lan966x);
450 
451 	idx = port->chip_port * lan966x->num_stats;
452 
453 	mutex_lock(&lan966x->stats_lock);
454 
455 	rmon_stats->undersize_pkts =
456 		lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
457 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT];
458 	rmon_stats->oversize_pkts =
459 		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
460 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
461 	rmon_stats->fragments =
462 		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
463 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG];
464 	rmon_stats->jabbers =
465 		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
466 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER];
467 	rmon_stats->hist[0] =
468 		lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
469 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64];
470 	rmon_stats->hist[1] =
471 		lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
472 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127];
473 	rmon_stats->hist[2] =
474 		lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
475 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255];
476 	rmon_stats->hist[3] =
477 		lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
478 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511];
479 	rmon_stats->hist[4] =
480 		lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
481 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023];
482 	rmon_stats->hist[5] =
483 		lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
484 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
485 	rmon_stats->hist[6] =
486 		lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
487 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
488 
489 	rmon_stats->hist_tx[0] =
490 		lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
491 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64];
492 	rmon_stats->hist_tx[1] =
493 		lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
494 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127];
495 	rmon_stats->hist_tx[2] =
496 		lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
497 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255];
498 	rmon_stats->hist_tx[3] =
499 		lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
500 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511];
501 	rmon_stats->hist_tx[4] =
502 		lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
503 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023];
504 	rmon_stats->hist_tx[5] =
505 		lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
506 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
507 	rmon_stats->hist_tx[6] =
508 		lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
509 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
510 
511 	mutex_unlock(&lan966x->stats_lock);
512 
513 	*ranges = lan966x_rmon_ranges;
514 }
515 
516 static int lan966x_get_link_ksettings(struct net_device *ndev,
517 				      struct ethtool_link_ksettings *cmd)
518 {
519 	struct lan966x_port *port = netdev_priv(ndev);
520 
521 	return phylink_ethtool_ksettings_get(port->phylink, cmd);
522 }
523 
524 static int lan966x_set_link_ksettings(struct net_device *ndev,
525 				      const struct ethtool_link_ksettings *cmd)
526 {
527 	struct lan966x_port *port = netdev_priv(ndev);
528 
529 	return phylink_ethtool_ksettings_set(port->phylink, cmd);
530 }
531 
532 static void lan966x_get_pauseparam(struct net_device *dev,
533 				   struct ethtool_pauseparam *pause)
534 {
535 	struct lan966x_port *port = netdev_priv(dev);
536 
537 	phylink_ethtool_get_pauseparam(port->phylink, pause);
538 }
539 
540 static int lan966x_set_pauseparam(struct net_device *dev,
541 				  struct ethtool_pauseparam *pause)
542 {
543 	struct lan966x_port *port = netdev_priv(dev);
544 
545 	return phylink_ethtool_set_pauseparam(port->phylink, pause);
546 }
547 
548 static int lan966x_get_ts_info(struct net_device *dev,
549 			       struct ethtool_ts_info *info)
550 {
551 	struct lan966x_port *port = netdev_priv(dev);
552 	struct lan966x *lan966x = port->lan966x;
553 	struct lan966x_phc *phc;
554 
555 	if (!lan966x->ptp)
556 		return ethtool_op_get_ts_info(dev, info);
557 
558 	phc = &lan966x->phc[LAN966X_PHC_PORT];
559 
560 	info->phc_index = phc->clock ? ptp_clock_index(phc->clock) : -1;
561 	if (info->phc_index == -1) {
562 		info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
563 					 SOF_TIMESTAMPING_RX_SOFTWARE |
564 					 SOF_TIMESTAMPING_SOFTWARE;
565 		return 0;
566 	}
567 	info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
568 				 SOF_TIMESTAMPING_RX_SOFTWARE |
569 				 SOF_TIMESTAMPING_SOFTWARE |
570 				 SOF_TIMESTAMPING_TX_HARDWARE |
571 				 SOF_TIMESTAMPING_RX_HARDWARE |
572 				 SOF_TIMESTAMPING_RAW_HARDWARE;
573 	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
574 			 BIT(HWTSTAMP_TX_ONESTEP_SYNC);
575 	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
576 			   BIT(HWTSTAMP_FILTER_ALL);
577 
578 	return 0;
579 }
580 
581 const struct ethtool_ops lan966x_ethtool_ops = {
582 	.get_link_ksettings     = lan966x_get_link_ksettings,
583 	.set_link_ksettings     = lan966x_set_link_ksettings,
584 	.get_pauseparam		= lan966x_get_pauseparam,
585 	.set_pauseparam		= lan966x_set_pauseparam,
586 	.get_sset_count		= lan966x_get_sset_count,
587 	.get_strings		= lan966x_get_strings,
588 	.get_ethtool_stats	= lan966x_get_ethtool_stats,
589 	.get_eth_mac_stats      = lan966x_get_eth_mac_stats,
590 	.get_rmon_stats		= lan966x_get_eth_rmon_stats,
591 	.get_link		= ethtool_op_get_link,
592 	.get_ts_info		= lan966x_get_ts_info,
593 };
594 
595 static void lan966x_check_stats_work(struct work_struct *work)
596 {
597 	struct delayed_work *del_work = to_delayed_work(work);
598 	struct lan966x *lan966x = container_of(del_work, struct lan966x,
599 					       stats_work);
600 
601 	lan966x_stats_update(lan966x);
602 
603 	queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
604 			   LAN966X_STATS_CHECK_DELAY);
605 }
606 
607 void lan966x_stats_get(struct net_device *dev,
608 		       struct rtnl_link_stats64 *stats)
609 {
610 	struct lan966x_port *port = netdev_priv(dev);
611 	struct lan966x *lan966x = port->lan966x;
612 	u32 idx;
613 	int i;
614 
615 	idx = port->chip_port * lan966x->num_stats;
616 
617 	mutex_lock(&lan966x->stats_lock);
618 
619 	stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] +
620 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT];
621 
622 	stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
623 		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
624 		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
625 		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
626 		lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
627 		lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
628 		lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
629 		lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
630 		lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
631 		lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
632 		lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
633 		lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] +
634 		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
635 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
636 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
637 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
638 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] +
639 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] +
640 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] +
641 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] +
642 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] +
643 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] +
644 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO];
645 
646 	stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] +
647 		lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC];
648 
649 	stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
650 		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
651 		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
652 		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
653 		lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
654 		lan966x->stats[idx + SYS_COUNT_RX_LONG];
655 
656 	stats->rx_dropped = dev->stats.rx_dropped +
657 		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
658 		lan966x->stats[idx + SYS_COUNT_DR_LOCAL] +
659 		lan966x->stats[idx + SYS_COUNT_DR_TAIL] +
660 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_0] +
661 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_1] +
662 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_2] +
663 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_3] +
664 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_4] +
665 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_5] +
666 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_6] +
667 		lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_7];
668 
669 	for (i = 0; i < LAN966X_NUM_TC; i++) {
670 		stats->rx_dropped +=
671 			(lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] +
672 			 lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]);
673 	}
674 
675 	/* Get Tx stats */
676 	stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] +
677 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
678 
679 	stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
680 		lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
681 		lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
682 		lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
683 		lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
684 		lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
685 		lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] +
686 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] +
687 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] +
688 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] +
689 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] +
690 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] +
691 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] +
692 		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO];
693 
694 	stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] +
695 		lan966x->stats[idx + SYS_COUNT_TX_AGED];
696 
697 	stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL];
698 
699 	mutex_unlock(&lan966x->stats_lock);
700 }
701 
702 int lan966x_stats_init(struct lan966x *lan966x)
703 {
704 	char queue_name[32];
705 
706 	lan966x->stats_layout = lan966x_stats_layout;
707 	lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout);
708 	lan966x->stats = devm_kcalloc(lan966x->dev, lan966x->num_phys_ports *
709 				      lan966x->num_stats,
710 				      sizeof(u64), GFP_KERNEL);
711 	if (!lan966x->stats)
712 		return -ENOMEM;
713 
714 	/* Init stats worker */
715 	mutex_init(&lan966x->stats_lock);
716 	snprintf(queue_name, sizeof(queue_name), "%s-stats",
717 		 dev_name(lan966x->dev));
718 	lan966x->stats_queue = create_singlethread_workqueue(queue_name);
719 	if (!lan966x->stats_queue)
720 		return -ENOMEM;
721 
722 	INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work);
723 	queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
724 			   LAN966X_STATS_CHECK_DELAY);
725 
726 	return 0;
727 }
728