xref: /linux/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c (revision e78f70bad29c5ae1e1076698b690b15794e9b81e)
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/phylink.h>
6 #include <linux/netdevice.h>
7 
8 #include "../libwx/wx_ethtool.h"
9 #include "../libwx/wx_type.h"
10 #include "../libwx/wx_lib.h"
11 #include "txgbe_type.h"
12 #include "txgbe_fdir.h"
13 #include "txgbe_ethtool.h"
14 
15 int txgbe_get_link_ksettings(struct net_device *netdev,
16 			     struct ethtool_link_ksettings *cmd)
17 {
18 	struct wx *wx = netdev_priv(netdev);
19 	struct txgbe *txgbe = wx->priv;
20 	int err;
21 
22 	if (wx->mac.type == wx_mac_aml40)
23 		return -EOPNOTSUPP;
24 
25 	err = wx_get_link_ksettings(netdev, cmd);
26 	if (err)
27 		return err;
28 
29 	if (wx->mac.type == wx_mac_sp)
30 		return 0;
31 
32 	cmd->base.port = txgbe->link_port;
33 	cmd->base.autoneg = AUTONEG_DISABLE;
34 	linkmode_copy(cmd->link_modes.supported, txgbe->sfp_support);
35 	linkmode_copy(cmd->link_modes.advertising, txgbe->advertising);
36 
37 	return 0;
38 }
39 
40 static int txgbe_set_ringparam(struct net_device *netdev,
41 			       struct ethtool_ringparam *ring,
42 			       struct kernel_ethtool_ringparam *kernel_ring,
43 			       struct netlink_ext_ack *extack)
44 {
45 	struct wx *wx = netdev_priv(netdev);
46 	u32 new_rx_count, new_tx_count;
47 	struct wx_ring *temp_ring;
48 	int i, err = 0;
49 
50 	new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
51 	new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
52 
53 	new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
54 	new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
55 
56 	if (new_tx_count == wx->tx_ring_count &&
57 	    new_rx_count == wx->rx_ring_count)
58 		return 0;
59 
60 	err = wx_set_state_reset(wx);
61 	if (err)
62 		return err;
63 
64 	if (!netif_running(wx->netdev)) {
65 		for (i = 0; i < wx->num_tx_queues; i++)
66 			wx->tx_ring[i]->count = new_tx_count;
67 		for (i = 0; i < wx->num_rx_queues; i++)
68 			wx->rx_ring[i]->count = new_rx_count;
69 		wx->tx_ring_count = new_tx_count;
70 		wx->rx_ring_count = new_rx_count;
71 
72 		goto clear_reset;
73 	}
74 
75 	/* allocate temporary buffer to store rings in */
76 	i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
77 	temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
78 	if (!temp_ring) {
79 		err = -ENOMEM;
80 		goto clear_reset;
81 	}
82 
83 	txgbe_down(wx);
84 
85 	wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
86 	kvfree(temp_ring);
87 
88 	txgbe_up(wx);
89 
90 clear_reset:
91 	clear_bit(WX_STATE_RESETTING, wx->state);
92 	return err;
93 }
94 
95 static int txgbe_set_channels(struct net_device *dev,
96 			      struct ethtool_channels *ch)
97 {
98 	int err;
99 
100 	err = wx_set_channels(dev, ch);
101 	if (err < 0)
102 		return err;
103 
104 	/* use setup TC to update any traffic class queue mapping */
105 	return txgbe_setup_tc(dev, netdev_get_num_tc(dev));
106 }
107 
108 static int txgbe_get_ethtool_fdir_entry(struct txgbe *txgbe,
109 					struct ethtool_rxnfc *cmd)
110 {
111 	struct ethtool_rx_flow_spec *fsp =
112 		(struct ethtool_rx_flow_spec *)&cmd->fs;
113 	union txgbe_atr_input *mask = &txgbe->fdir_mask;
114 	struct txgbe_fdir_filter *rule = NULL;
115 	struct hlist_node *node;
116 
117 	/* report total rule count */
118 	cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2;
119 
120 	hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
121 				  fdir_node) {
122 		if (fsp->location <= rule->sw_idx)
123 			break;
124 	}
125 
126 	if (!rule || fsp->location != rule->sw_idx)
127 		return -EINVAL;
128 
129 	/* set flow type field */
130 	switch (rule->filter.formatted.flow_type) {
131 	case TXGBE_ATR_FLOW_TYPE_TCPV4:
132 		fsp->flow_type = TCP_V4_FLOW;
133 		break;
134 	case TXGBE_ATR_FLOW_TYPE_UDPV4:
135 		fsp->flow_type = UDP_V4_FLOW;
136 		break;
137 	case TXGBE_ATR_FLOW_TYPE_SCTPV4:
138 		fsp->flow_type = SCTP_V4_FLOW;
139 		break;
140 	case TXGBE_ATR_FLOW_TYPE_IPV4:
141 		fsp->flow_type = IP_USER_FLOW;
142 		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
143 		fsp->h_u.usr_ip4_spec.proto = 0;
144 		fsp->m_u.usr_ip4_spec.proto = 0;
145 		break;
146 	default:
147 		return -EINVAL;
148 	}
149 
150 	fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port;
151 	fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port;
152 	fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port;
153 	fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port;
154 	fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0];
155 	fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0];
156 	fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0];
157 	fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0];
158 	fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes;
159 	fsp->m_ext.vlan_etype = mask->formatted.flex_bytes;
160 	fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool);
161 	fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool);
162 	fsp->flow_type |= FLOW_EXT;
163 
164 	/* record action */
165 	if (rule->action == TXGBE_RDB_FDIR_DROP_QUEUE)
166 		fsp->ring_cookie = RX_CLS_FLOW_DISC;
167 	else
168 		fsp->ring_cookie = rule->action;
169 
170 	return 0;
171 }
172 
173 static int txgbe_get_ethtool_fdir_all(struct txgbe *txgbe,
174 				      struct ethtool_rxnfc *cmd,
175 				      u32 *rule_locs)
176 {
177 	struct txgbe_fdir_filter *rule;
178 	struct hlist_node *node;
179 	int cnt = 0;
180 
181 	/* report total rule count */
182 	cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2;
183 
184 	hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
185 				  fdir_node) {
186 		if (cnt == cmd->rule_cnt)
187 			return -EMSGSIZE;
188 		rule_locs[cnt] = rule->sw_idx;
189 		cnt++;
190 	}
191 
192 	cmd->rule_cnt = cnt;
193 
194 	return 0;
195 }
196 
197 static int txgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
198 			   u32 *rule_locs)
199 {
200 	struct wx *wx = netdev_priv(dev);
201 	struct txgbe *txgbe = wx->priv;
202 	int ret = -EOPNOTSUPP;
203 
204 	switch (cmd->cmd) {
205 	case ETHTOOL_GRXRINGS:
206 		cmd->data = wx->num_rx_queues;
207 		ret = 0;
208 		break;
209 	case ETHTOOL_GRXCLSRLCNT:
210 		cmd->rule_cnt = txgbe->fdir_filter_count;
211 		ret = 0;
212 		break;
213 	case ETHTOOL_GRXCLSRULE:
214 		ret = txgbe_get_ethtool_fdir_entry(txgbe, cmd);
215 		break;
216 	case ETHTOOL_GRXCLSRLALL:
217 		ret = txgbe_get_ethtool_fdir_all(txgbe, cmd, (u32 *)rule_locs);
218 		break;
219 	default:
220 		break;
221 	}
222 
223 	return ret;
224 }
225 
226 static int txgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
227 				       u8 *flow_type)
228 {
229 	switch (fsp->flow_type & ~FLOW_EXT) {
230 	case TCP_V4_FLOW:
231 		*flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
232 		break;
233 	case UDP_V4_FLOW:
234 		*flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
235 		break;
236 	case SCTP_V4_FLOW:
237 		*flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
238 		break;
239 	case IP_USER_FLOW:
240 		switch (fsp->h_u.usr_ip4_spec.proto) {
241 		case IPPROTO_TCP:
242 			*flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
243 			break;
244 		case IPPROTO_UDP:
245 			*flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
246 			break;
247 		case IPPROTO_SCTP:
248 			*flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
249 			break;
250 		case 0:
251 			if (!fsp->m_u.usr_ip4_spec.proto) {
252 				*flow_type = TXGBE_ATR_FLOW_TYPE_IPV4;
253 				break;
254 			}
255 			fallthrough;
256 		default:
257 			return -EINVAL;
258 		}
259 		break;
260 	default:
261 		return -EINVAL;
262 	}
263 
264 	return 0;
265 }
266 
267 static bool txgbe_match_ethtool_fdir_entry(struct txgbe *txgbe,
268 					   struct txgbe_fdir_filter *input)
269 {
270 	struct txgbe_fdir_filter *rule = NULL;
271 	struct hlist_node *node2;
272 
273 	hlist_for_each_entry_safe(rule, node2, &txgbe->fdir_filter_list,
274 				  fdir_node) {
275 		if (rule->filter.formatted.bkt_hash ==
276 		    input->filter.formatted.bkt_hash &&
277 		    rule->action == input->action) {
278 			wx_dbg(txgbe->wx, "FDIR entry already exist\n");
279 			return true;
280 		}
281 	}
282 	return false;
283 }
284 
285 static int txgbe_update_ethtool_fdir_entry(struct txgbe *txgbe,
286 					   struct txgbe_fdir_filter *input,
287 					   u16 sw_idx)
288 {
289 	struct hlist_node *node = NULL, *parent = NULL;
290 	struct txgbe_fdir_filter *rule;
291 	struct wx *wx = txgbe->wx;
292 	bool deleted = false;
293 	int err;
294 
295 	hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
296 				  fdir_node) {
297 		/* hash found, or no matching entry */
298 		if (rule->sw_idx >= sw_idx)
299 			break;
300 		parent = node;
301 	}
302 
303 	/* if there is an old rule occupying our place remove it */
304 	if (rule && rule->sw_idx == sw_idx) {
305 		/* hardware filters are only configured when interface is up,
306 		 * and we should not issue filter commands while the interface
307 		 * is down
308 		 */
309 		if (netif_running(wx->netdev) &&
310 		    (!input || rule->filter.formatted.bkt_hash !=
311 		     input->filter.formatted.bkt_hash)) {
312 			err = txgbe_fdir_erase_perfect_filter(wx,
313 							      &rule->filter,
314 							      sw_idx);
315 			if (err)
316 				return -EINVAL;
317 		}
318 
319 		hlist_del(&rule->fdir_node);
320 		kfree(rule);
321 		txgbe->fdir_filter_count--;
322 		deleted = true;
323 	}
324 
325 	/* If we weren't given an input, then this was a request to delete a
326 	 * filter. We should return -EINVAL if the filter wasn't found, but
327 	 * return 0 if the rule was successfully deleted.
328 	 */
329 	if (!input)
330 		return deleted ? 0 : -EINVAL;
331 
332 	/* initialize node and set software index */
333 	INIT_HLIST_NODE(&input->fdir_node);
334 
335 	/* add filter to the list */
336 	if (parent)
337 		hlist_add_behind(&input->fdir_node, parent);
338 	else
339 		hlist_add_head(&input->fdir_node,
340 			       &txgbe->fdir_filter_list);
341 
342 	/* update counts */
343 	txgbe->fdir_filter_count++;
344 
345 	return 0;
346 }
347 
348 static int txgbe_add_ethtool_fdir_entry(struct txgbe *txgbe,
349 					struct ethtool_rxnfc *cmd)
350 {
351 	struct ethtool_rx_flow_spec *fsp =
352 		(struct ethtool_rx_flow_spec *)&cmd->fs;
353 	struct txgbe_fdir_filter *input;
354 	union txgbe_atr_input mask;
355 	struct wx *wx = txgbe->wx;
356 	int err = -EINVAL;
357 	u16 ptype = 0;
358 	u8 queue;
359 
360 	if (!(test_bit(WX_FLAG_FDIR_PERFECT, wx->flags)))
361 		return -EOPNOTSUPP;
362 
363 	/* ring_cookie is a masked into a set of queues and txgbe pools or
364 	 * we use drop index
365 	 */
366 	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
367 		queue = TXGBE_RDB_FDIR_DROP_QUEUE;
368 	} else {
369 		u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
370 		u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
371 
372 		if (!vf && ring >= wx->num_rx_queues)
373 			return -EINVAL;
374 		else if (vf && (vf > wx->num_vfs ||
375 				ring >= wx->num_rx_queues_per_pool))
376 			return -EINVAL;
377 
378 		/* Map the ring onto the absolute queue index */
379 		if (!vf)
380 			queue = wx->rx_ring[ring]->reg_idx;
381 		else
382 			queue = ((vf - 1) * wx->num_rx_queues_per_pool) + ring;
383 	}
384 
385 	/* Don't allow indexes to exist outside of available space */
386 	if (fsp->location >= ((1024 << TXGBE_FDIR_PBALLOC_64K) - 2)) {
387 		wx_err(wx, "Location out of range\n");
388 		return -EINVAL;
389 	}
390 
391 	input = kzalloc(sizeof(*input), GFP_ATOMIC);
392 	if (!input)
393 		return -ENOMEM;
394 
395 	memset(&mask, 0, sizeof(union txgbe_atr_input));
396 
397 	/* set SW index */
398 	input->sw_idx = fsp->location;
399 
400 	/* record flow type */
401 	if (txgbe_flowspec_to_flow_type(fsp,
402 					&input->filter.formatted.flow_type)) {
403 		wx_err(wx, "Unrecognized flow type\n");
404 		goto err_out;
405 	}
406 
407 	mask.formatted.flow_type = TXGBE_ATR_L4TYPE_IPV6_MASK |
408 				   TXGBE_ATR_L4TYPE_MASK;
409 
410 	if (input->filter.formatted.flow_type == TXGBE_ATR_FLOW_TYPE_IPV4)
411 		mask.formatted.flow_type &= TXGBE_ATR_L4TYPE_IPV6_MASK;
412 
413 	/* Copy input into formatted structures */
414 	input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
415 	mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
416 	input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
417 	mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
418 	input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc;
419 	mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc;
420 	input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
421 	mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
422 
423 	if (fsp->flow_type & FLOW_EXT) {
424 		input->filter.formatted.vm_pool =
425 				(unsigned char)ntohl(fsp->h_ext.data[1]);
426 		mask.formatted.vm_pool =
427 				(unsigned char)ntohl(fsp->m_ext.data[1]);
428 		input->filter.formatted.flex_bytes =
429 						fsp->h_ext.vlan_etype;
430 		mask.formatted.flex_bytes = fsp->m_ext.vlan_etype;
431 	}
432 
433 	switch (input->filter.formatted.flow_type) {
434 	case TXGBE_ATR_FLOW_TYPE_TCPV4:
435 		ptype = WX_PTYPE_L2_IPV4_TCP;
436 		break;
437 	case TXGBE_ATR_FLOW_TYPE_UDPV4:
438 		ptype = WX_PTYPE_L2_IPV4_UDP;
439 		break;
440 	case TXGBE_ATR_FLOW_TYPE_SCTPV4:
441 		ptype = WX_PTYPE_L2_IPV4_SCTP;
442 		break;
443 	case TXGBE_ATR_FLOW_TYPE_IPV4:
444 		ptype = WX_PTYPE_L2_IPV4;
445 		break;
446 	default:
447 		break;
448 	}
449 
450 	input->filter.formatted.vlan_id = htons(ptype);
451 	if (mask.formatted.flow_type & TXGBE_ATR_L4TYPE_MASK)
452 		mask.formatted.vlan_id = htons(0xFFFF);
453 	else
454 		mask.formatted.vlan_id = htons(0xFFF8);
455 
456 	/* determine if we need to drop or route the packet */
457 	if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
458 		input->action = TXGBE_RDB_FDIR_DROP_QUEUE;
459 	else
460 		input->action = fsp->ring_cookie;
461 
462 	spin_lock(&txgbe->fdir_perfect_lock);
463 
464 	if (hlist_empty(&txgbe->fdir_filter_list)) {
465 		/* save mask and program input mask into HW */
466 		memcpy(&txgbe->fdir_mask, &mask, sizeof(mask));
467 		err = txgbe_fdir_set_input_mask(wx, &mask);
468 		if (err)
469 			goto err_unlock;
470 	} else if (memcmp(&txgbe->fdir_mask, &mask, sizeof(mask))) {
471 		wx_err(wx, "Hardware only supports one mask per port. To change the mask you must first delete all the rules.\n");
472 		goto err_unlock;
473 	}
474 
475 	/* apply mask and compute/store hash */
476 	txgbe_atr_compute_perfect_hash(&input->filter, &mask);
477 
478 	/* check if new entry does not exist on filter list */
479 	if (txgbe_match_ethtool_fdir_entry(txgbe, input))
480 		goto err_unlock;
481 
482 	/* only program filters to hardware if the net device is running, as
483 	 * we store the filters in the Rx buffer which is not allocated when
484 	 * the device is down
485 	 */
486 	if (netif_running(wx->netdev)) {
487 		err = txgbe_fdir_write_perfect_filter(wx, &input->filter,
488 						      input->sw_idx, queue);
489 		if (err)
490 			goto err_unlock;
491 	}
492 
493 	txgbe_update_ethtool_fdir_entry(txgbe, input, input->sw_idx);
494 
495 	spin_unlock(&txgbe->fdir_perfect_lock);
496 
497 	return 0;
498 err_unlock:
499 	spin_unlock(&txgbe->fdir_perfect_lock);
500 err_out:
501 	kfree(input);
502 	return err;
503 }
504 
505 static int txgbe_del_ethtool_fdir_entry(struct txgbe *txgbe,
506 					struct ethtool_rxnfc *cmd)
507 {
508 	struct ethtool_rx_flow_spec *fsp =
509 		(struct ethtool_rx_flow_spec *)&cmd->fs;
510 	int err = 0;
511 
512 	spin_lock(&txgbe->fdir_perfect_lock);
513 	err = txgbe_update_ethtool_fdir_entry(txgbe, NULL, fsp->location);
514 	spin_unlock(&txgbe->fdir_perfect_lock);
515 
516 	return err;
517 }
518 
519 static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
520 {
521 	struct wx *wx = netdev_priv(dev);
522 	struct txgbe *txgbe = wx->priv;
523 	int ret = -EOPNOTSUPP;
524 
525 	switch (cmd->cmd) {
526 	case ETHTOOL_SRXCLSRLINS:
527 		ret = txgbe_add_ethtool_fdir_entry(txgbe, cmd);
528 		break;
529 	case ETHTOOL_SRXCLSRLDEL:
530 		ret = txgbe_del_ethtool_fdir_entry(txgbe, cmd);
531 		break;
532 	default:
533 		break;
534 	}
535 
536 	return ret;
537 }
538 
539 static const struct ethtool_ops txgbe_ethtool_ops = {
540 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
541 				     ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
542 	.get_drvinfo		= wx_get_drvinfo,
543 	.nway_reset		= wx_nway_reset,
544 	.get_link		= ethtool_op_get_link,
545 	.get_link_ksettings	= txgbe_get_link_ksettings,
546 	.set_link_ksettings	= wx_set_link_ksettings,
547 	.get_sset_count		= wx_get_sset_count,
548 	.get_strings		= wx_get_strings,
549 	.get_ethtool_stats	= wx_get_ethtool_stats,
550 	.get_eth_mac_stats	= wx_get_mac_stats,
551 	.get_pause_stats	= wx_get_pause_stats,
552 	.get_pauseparam		= wx_get_pauseparam,
553 	.set_pauseparam		= wx_set_pauseparam,
554 	.get_ringparam		= wx_get_ringparam,
555 	.set_ringparam		= txgbe_set_ringparam,
556 	.get_coalesce		= wx_get_coalesce,
557 	.set_coalesce		= wx_set_coalesce,
558 	.get_channels		= wx_get_channels,
559 	.set_channels		= txgbe_set_channels,
560 	.get_rxnfc		= txgbe_get_rxnfc,
561 	.set_rxnfc		= txgbe_set_rxnfc,
562 	.get_msglevel		= wx_get_msglevel,
563 	.set_msglevel		= wx_set_msglevel,
564 	.get_ts_info		= wx_get_ts_info,
565 	.get_ts_stats		= wx_get_ptp_stats,
566 };
567 
568 void txgbe_set_ethtool_ops(struct net_device *netdev)
569 {
570 	netdev->ethtool_ops = &txgbe_ethtool_ops;
571 }
572