xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2*4882a593Smuzhiyun /* Copyright 2014-2016 Freescale Semiconductor Inc.
3*4882a593Smuzhiyun  * Copyright 2016 NXP
4*4882a593Smuzhiyun  * Copyright 2020 NXP
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/net_tstamp.h>
8*4882a593Smuzhiyun #include <linux/nospec.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "dpni.h"	/* DPNI_LINK_OPT_* */
11*4882a593Smuzhiyun #include "dpaa2-eth.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* To be kept in sync with DPNI statistics */
14*4882a593Smuzhiyun static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {
15*4882a593Smuzhiyun 	"[hw] rx frames",
16*4882a593Smuzhiyun 	"[hw] rx bytes",
17*4882a593Smuzhiyun 	"[hw] rx mcast frames",
18*4882a593Smuzhiyun 	"[hw] rx mcast bytes",
19*4882a593Smuzhiyun 	"[hw] rx bcast frames",
20*4882a593Smuzhiyun 	"[hw] rx bcast bytes",
21*4882a593Smuzhiyun 	"[hw] tx frames",
22*4882a593Smuzhiyun 	"[hw] tx bytes",
23*4882a593Smuzhiyun 	"[hw] tx mcast frames",
24*4882a593Smuzhiyun 	"[hw] tx mcast bytes",
25*4882a593Smuzhiyun 	"[hw] tx bcast frames",
26*4882a593Smuzhiyun 	"[hw] tx bcast bytes",
27*4882a593Smuzhiyun 	"[hw] rx filtered frames",
28*4882a593Smuzhiyun 	"[hw] rx discarded frames",
29*4882a593Smuzhiyun 	"[hw] rx nobuffer discards",
30*4882a593Smuzhiyun 	"[hw] tx discarded frames",
31*4882a593Smuzhiyun 	"[hw] tx confirmed frames",
32*4882a593Smuzhiyun 	"[hw] tx dequeued bytes",
33*4882a593Smuzhiyun 	"[hw] tx dequeued frames",
34*4882a593Smuzhiyun 	"[hw] tx rejected bytes",
35*4882a593Smuzhiyun 	"[hw] tx rejected frames",
36*4882a593Smuzhiyun 	"[hw] tx pending frames",
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define DPAA2_ETH_NUM_STATS	ARRAY_SIZE(dpaa2_ethtool_stats)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = {
42*4882a593Smuzhiyun 	/* per-cpu stats */
43*4882a593Smuzhiyun 	"[drv] tx conf frames",
44*4882a593Smuzhiyun 	"[drv] tx conf bytes",
45*4882a593Smuzhiyun 	"[drv] tx sg frames",
46*4882a593Smuzhiyun 	"[drv] tx sg bytes",
47*4882a593Smuzhiyun 	"[drv] rx sg frames",
48*4882a593Smuzhiyun 	"[drv] rx sg bytes",
49*4882a593Smuzhiyun 	"[drv] tx converted sg frames",
50*4882a593Smuzhiyun 	"[drv] tx converted sg bytes",
51*4882a593Smuzhiyun 	"[drv] enqueue portal busy",
52*4882a593Smuzhiyun 	/* Channel stats */
53*4882a593Smuzhiyun 	"[drv] dequeue portal busy",
54*4882a593Smuzhiyun 	"[drv] channel pull errors",
55*4882a593Smuzhiyun 	"[drv] cdan",
56*4882a593Smuzhiyun 	"[drv] xdp drop",
57*4882a593Smuzhiyun 	"[drv] xdp tx",
58*4882a593Smuzhiyun 	"[drv] xdp tx errors",
59*4882a593Smuzhiyun 	"[drv] xdp redirect",
60*4882a593Smuzhiyun 	/* FQ stats */
61*4882a593Smuzhiyun 	"[qbman] rx pending frames",
62*4882a593Smuzhiyun 	"[qbman] rx pending bytes",
63*4882a593Smuzhiyun 	"[qbman] tx conf pending frames",
64*4882a593Smuzhiyun 	"[qbman] tx conf pending bytes",
65*4882a593Smuzhiyun 	"[qbman] buffer count",
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define DPAA2_ETH_NUM_EXTRA_STATS	ARRAY_SIZE(dpaa2_ethtool_extras)
69*4882a593Smuzhiyun 
dpaa2_eth_get_drvinfo(struct net_device * net_dev,struct ethtool_drvinfo * drvinfo)70*4882a593Smuzhiyun static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
71*4882a593Smuzhiyun 				  struct ethtool_drvinfo *drvinfo)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
78*4882a593Smuzhiyun 		 "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
81*4882a593Smuzhiyun 		sizeof(drvinfo->bus_info));
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
dpaa2_eth_nway_reset(struct net_device * net_dev)84*4882a593Smuzhiyun static int dpaa2_eth_nway_reset(struct net_device *net_dev)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (priv->mac)
89*4882a593Smuzhiyun 		return phylink_ethtool_nway_reset(priv->mac->phylink);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return -EOPNOTSUPP;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static int
dpaa2_eth_get_link_ksettings(struct net_device * net_dev,struct ethtool_link_ksettings * link_settings)95*4882a593Smuzhiyun dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
96*4882a593Smuzhiyun 			     struct ethtool_link_ksettings *link_settings)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	if (priv->mac)
101*4882a593Smuzhiyun 		return phylink_ethtool_ksettings_get(priv->mac->phylink,
102*4882a593Smuzhiyun 						     link_settings);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	link_settings->base.autoneg = AUTONEG_DISABLE;
105*4882a593Smuzhiyun 	if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
106*4882a593Smuzhiyun 		link_settings->base.duplex = DUPLEX_FULL;
107*4882a593Smuzhiyun 	link_settings->base.speed = priv->link_state.rate;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static int
dpaa2_eth_set_link_ksettings(struct net_device * net_dev,const struct ethtool_link_ksettings * link_settings)113*4882a593Smuzhiyun dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
114*4882a593Smuzhiyun 			     const struct ethtool_link_ksettings *link_settings)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (!priv->mac)
119*4882a593Smuzhiyun 		return -ENOTSUPP;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
dpaa2_eth_get_pauseparam(struct net_device * net_dev,struct ethtool_pauseparam * pause)124*4882a593Smuzhiyun static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
125*4882a593Smuzhiyun 				     struct ethtool_pauseparam *pause)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
128*4882a593Smuzhiyun 	u64 link_options = priv->link_state.options;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (priv->mac) {
131*4882a593Smuzhiyun 		phylink_ethtool_get_pauseparam(priv->mac->phylink, pause);
132*4882a593Smuzhiyun 		return;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
136*4882a593Smuzhiyun 	pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
137*4882a593Smuzhiyun 	pause->autoneg = AUTONEG_DISABLE;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
dpaa2_eth_set_pauseparam(struct net_device * net_dev,struct ethtool_pauseparam * pause)140*4882a593Smuzhiyun static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
141*4882a593Smuzhiyun 				    struct ethtool_pauseparam *pause)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
144*4882a593Smuzhiyun 	struct dpni_link_cfg cfg = {0};
145*4882a593Smuzhiyun 	int err;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (!dpaa2_eth_has_pause_support(priv)) {
148*4882a593Smuzhiyun 		netdev_info(net_dev, "No pause frame support for DPNI version < %d.%d\n",
149*4882a593Smuzhiyun 			    DPNI_PAUSE_VER_MAJOR, DPNI_PAUSE_VER_MINOR);
150*4882a593Smuzhiyun 		return -EOPNOTSUPP;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (priv->mac)
154*4882a593Smuzhiyun 		return phylink_ethtool_set_pauseparam(priv->mac->phylink,
155*4882a593Smuzhiyun 						      pause);
156*4882a593Smuzhiyun 	if (pause->autoneg)
157*4882a593Smuzhiyun 		return -EOPNOTSUPP;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	cfg.rate = priv->link_state.rate;
160*4882a593Smuzhiyun 	cfg.options = priv->link_state.options;
161*4882a593Smuzhiyun 	if (pause->rx_pause)
162*4882a593Smuzhiyun 		cfg.options |= DPNI_LINK_OPT_PAUSE;
163*4882a593Smuzhiyun 	else
164*4882a593Smuzhiyun 		cfg.options &= ~DPNI_LINK_OPT_PAUSE;
165*4882a593Smuzhiyun 	if (!!pause->rx_pause ^ !!pause->tx_pause)
166*4882a593Smuzhiyun 		cfg.options |= DPNI_LINK_OPT_ASYM_PAUSE;
167*4882a593Smuzhiyun 	else
168*4882a593Smuzhiyun 		cfg.options &= ~DPNI_LINK_OPT_ASYM_PAUSE;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (cfg.options == priv->link_state.options)
171*4882a593Smuzhiyun 		return 0;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
174*4882a593Smuzhiyun 	if (err) {
175*4882a593Smuzhiyun 		netdev_err(net_dev, "dpni_set_link_state failed\n");
176*4882a593Smuzhiyun 		return err;
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	priv->link_state.options = cfg.options;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return 0;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
dpaa2_eth_get_strings(struct net_device * netdev,u32 stringset,u8 * data)184*4882a593Smuzhiyun static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
185*4882a593Smuzhiyun 				  u8 *data)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(netdev);
188*4882a593Smuzhiyun 	u8 *p = data;
189*4882a593Smuzhiyun 	int i;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	switch (stringset) {
192*4882a593Smuzhiyun 	case ETH_SS_STATS:
193*4882a593Smuzhiyun 		for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) {
194*4882a593Smuzhiyun 			strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
195*4882a593Smuzhiyun 			p += ETH_GSTRING_LEN;
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 		for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
198*4882a593Smuzhiyun 			strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
199*4882a593Smuzhiyun 			p += ETH_GSTRING_LEN;
200*4882a593Smuzhiyun 		}
201*4882a593Smuzhiyun 		if (priv->mac)
202*4882a593Smuzhiyun 			dpaa2_mac_get_strings(p);
203*4882a593Smuzhiyun 		break;
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
dpaa2_eth_get_sset_count(struct net_device * net_dev,int sset)207*4882a593Smuzhiyun static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	int num_ss_stats = DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
210*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	switch (sset) {
213*4882a593Smuzhiyun 	case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
214*4882a593Smuzhiyun 		if (priv->mac)
215*4882a593Smuzhiyun 			num_ss_stats += dpaa2_mac_get_sset_count();
216*4882a593Smuzhiyun 		return num_ss_stats;
217*4882a593Smuzhiyun 	default:
218*4882a593Smuzhiyun 		return -EOPNOTSUPP;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /** Fill in hardware counters, as returned by MC.
223*4882a593Smuzhiyun  */
dpaa2_eth_get_ethtool_stats(struct net_device * net_dev,struct ethtool_stats * stats,u64 * data)224*4882a593Smuzhiyun static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
225*4882a593Smuzhiyun 					struct ethtool_stats *stats,
226*4882a593Smuzhiyun 					u64 *data)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	int i = 0;
229*4882a593Smuzhiyun 	int j, k, err;
230*4882a593Smuzhiyun 	int num_cnt;
231*4882a593Smuzhiyun 	union dpni_statistics dpni_stats;
232*4882a593Smuzhiyun 	u32 fcnt, bcnt;
233*4882a593Smuzhiyun 	u32 fcnt_rx_total = 0, fcnt_tx_total = 0;
234*4882a593Smuzhiyun 	u32 bcnt_rx_total = 0, bcnt_tx_total = 0;
235*4882a593Smuzhiyun 	u32 buf_cnt;
236*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
237*4882a593Smuzhiyun 	struct dpaa2_eth_drv_stats *extras;
238*4882a593Smuzhiyun 	struct dpaa2_eth_ch_stats *ch_stats;
239*4882a593Smuzhiyun 	int dpni_stats_page_size[DPNI_STATISTICS_CNT] = {
240*4882a593Smuzhiyun 		sizeof(dpni_stats.page_0),
241*4882a593Smuzhiyun 		sizeof(dpni_stats.page_1),
242*4882a593Smuzhiyun 		sizeof(dpni_stats.page_2),
243*4882a593Smuzhiyun 		sizeof(dpni_stats.page_3),
244*4882a593Smuzhiyun 		sizeof(dpni_stats.page_4),
245*4882a593Smuzhiyun 		sizeof(dpni_stats.page_5),
246*4882a593Smuzhiyun 		sizeof(dpni_stats.page_6),
247*4882a593Smuzhiyun 	};
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	memset(data, 0,
250*4882a593Smuzhiyun 	       sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* Print standard counters, from DPNI statistics */
253*4882a593Smuzhiyun 	for (j = 0; j <= 6; j++) {
254*4882a593Smuzhiyun 		/* We're not interested in pages 4 & 5 for now */
255*4882a593Smuzhiyun 		if (j == 4 || j == 5)
256*4882a593Smuzhiyun 			continue;
257*4882a593Smuzhiyun 		err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
258*4882a593Smuzhiyun 					  j, &dpni_stats);
259*4882a593Smuzhiyun 		if (err == -EINVAL)
260*4882a593Smuzhiyun 			/* Older firmware versions don't support all pages */
261*4882a593Smuzhiyun 			memset(&dpni_stats, 0, sizeof(dpni_stats));
262*4882a593Smuzhiyun 		else if (err)
263*4882a593Smuzhiyun 			netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 		num_cnt = dpni_stats_page_size[j] / sizeof(u64);
266*4882a593Smuzhiyun 		for (k = 0; k < num_cnt; k++)
267*4882a593Smuzhiyun 			*(data + i++) = dpni_stats.raw.counter[k];
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/* Print per-cpu extra stats */
271*4882a593Smuzhiyun 	for_each_online_cpu(k) {
272*4882a593Smuzhiyun 		extras = per_cpu_ptr(priv->percpu_extras, k);
273*4882a593Smuzhiyun 		for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
274*4882a593Smuzhiyun 			*((__u64 *)data + i + j) += *((__u64 *)extras + j);
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 	i += j;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* Per-channel stats */
279*4882a593Smuzhiyun 	for (k = 0; k < priv->num_channels; k++) {
280*4882a593Smuzhiyun 		ch_stats = &priv->channel[k]->stats;
281*4882a593Smuzhiyun 		for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64) - 1; j++)
282*4882a593Smuzhiyun 			*((__u64 *)data + i + j) += *((__u64 *)ch_stats + j);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 	i += j;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	for (j = 0; j < priv->num_fqs; j++) {
287*4882a593Smuzhiyun 		/* Print FQ instantaneous counts */
288*4882a593Smuzhiyun 		err = dpaa2_io_query_fq_count(NULL, priv->fq[j].fqid,
289*4882a593Smuzhiyun 					      &fcnt, &bcnt);
290*4882a593Smuzhiyun 		if (err) {
291*4882a593Smuzhiyun 			netdev_warn(net_dev, "FQ query error %d", err);
292*4882a593Smuzhiyun 			return;
293*4882a593Smuzhiyun 		}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		if (priv->fq[j].type == DPAA2_TX_CONF_FQ) {
296*4882a593Smuzhiyun 			fcnt_tx_total += fcnt;
297*4882a593Smuzhiyun 			bcnt_tx_total += bcnt;
298*4882a593Smuzhiyun 		} else {
299*4882a593Smuzhiyun 			fcnt_rx_total += fcnt;
300*4882a593Smuzhiyun 			bcnt_rx_total += bcnt;
301*4882a593Smuzhiyun 		}
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	*(data + i++) = fcnt_rx_total;
305*4882a593Smuzhiyun 	*(data + i++) = bcnt_rx_total;
306*4882a593Smuzhiyun 	*(data + i++) = fcnt_tx_total;
307*4882a593Smuzhiyun 	*(data + i++) = bcnt_tx_total;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	err = dpaa2_io_query_bp_count(NULL, priv->bpid, &buf_cnt);
310*4882a593Smuzhiyun 	if (err) {
311*4882a593Smuzhiyun 		netdev_warn(net_dev, "Buffer count query error %d\n", err);
312*4882a593Smuzhiyun 		return;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 	*(data + i++) = buf_cnt;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	if (priv->mac)
317*4882a593Smuzhiyun 		dpaa2_mac_get_ethtool_stats(priv->mac, data + i);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
dpaa2_eth_prep_eth_rule(struct ethhdr * eth_value,struct ethhdr * eth_mask,void * key,void * mask,u64 * fields)320*4882a593Smuzhiyun static int dpaa2_eth_prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask,
321*4882a593Smuzhiyun 				   void *key, void *mask, u64 *fields)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	int off;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (eth_mask->h_proto) {
326*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
327*4882a593Smuzhiyun 		*(__be16 *)(key + off) = eth_value->h_proto;
328*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = eth_mask->h_proto;
329*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_ETHTYPE;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (!is_zero_ether_addr(eth_mask->h_source)) {
333*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_SA);
334*4882a593Smuzhiyun 		ether_addr_copy(key + off, eth_value->h_source);
335*4882a593Smuzhiyun 		ether_addr_copy(mask + off, eth_mask->h_source);
336*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_ETHSRC;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (!is_zero_ether_addr(eth_mask->h_dest)) {
340*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA);
341*4882a593Smuzhiyun 		ether_addr_copy(key + off, eth_value->h_dest);
342*4882a593Smuzhiyun 		ether_addr_copy(mask + off, eth_mask->h_dest);
343*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_ETHDST;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
dpaa2_eth_prep_uip_rule(struct ethtool_usrip4_spec * uip_value,struct ethtool_usrip4_spec * uip_mask,void * key,void * mask,u64 * fields)349*4882a593Smuzhiyun static int dpaa2_eth_prep_uip_rule(struct ethtool_usrip4_spec *uip_value,
350*4882a593Smuzhiyun 				   struct ethtool_usrip4_spec *uip_mask,
351*4882a593Smuzhiyun 				   void *key, void *mask, u64 *fields)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	int off;
354*4882a593Smuzhiyun 	u32 tmp_value, tmp_mask;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (uip_mask->tos || uip_mask->ip_ver)
357*4882a593Smuzhiyun 		return -EOPNOTSUPP;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (uip_mask->ip4src) {
360*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC);
361*4882a593Smuzhiyun 		*(__be32 *)(key + off) = uip_value->ip4src;
362*4882a593Smuzhiyun 		*(__be32 *)(mask + off) = uip_mask->ip4src;
363*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_IPSRC;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	if (uip_mask->ip4dst) {
367*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST);
368*4882a593Smuzhiyun 		*(__be32 *)(key + off) = uip_value->ip4dst;
369*4882a593Smuzhiyun 		*(__be32 *)(mask + off) = uip_mask->ip4dst;
370*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_IPDST;
371*4882a593Smuzhiyun 	}
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (uip_mask->proto) {
374*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO);
375*4882a593Smuzhiyun 		*(u8 *)(key + off) = uip_value->proto;
376*4882a593Smuzhiyun 		*(u8 *)(mask + off) = uip_mask->proto;
377*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_IPPROTO;
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (uip_mask->l4_4_bytes) {
381*4882a593Smuzhiyun 		tmp_value = be32_to_cpu(uip_value->l4_4_bytes);
382*4882a593Smuzhiyun 		tmp_mask = be32_to_cpu(uip_mask->l4_4_bytes);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC);
385*4882a593Smuzhiyun 		*(__be16 *)(key + off) = htons(tmp_value >> 16);
386*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = htons(tmp_mask >> 16);
387*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_L4SRC;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST);
390*4882a593Smuzhiyun 		*(__be16 *)(key + off) = htons(tmp_value & 0xFFFF);
391*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = htons(tmp_mask & 0xFFFF);
392*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_L4DST;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	/* Only apply the rule for IPv4 frames */
396*4882a593Smuzhiyun 	off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
397*4882a593Smuzhiyun 	*(__be16 *)(key + off) = htons(ETH_P_IP);
398*4882a593Smuzhiyun 	*(__be16 *)(mask + off) = htons(0xFFFF);
399*4882a593Smuzhiyun 	*fields |= DPAA2_ETH_DIST_ETHTYPE;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
dpaa2_eth_prep_l4_rule(struct ethtool_tcpip4_spec * l4_value,struct ethtool_tcpip4_spec * l4_mask,void * key,void * mask,u8 l4_proto,u64 * fields)404*4882a593Smuzhiyun static int dpaa2_eth_prep_l4_rule(struct ethtool_tcpip4_spec *l4_value,
405*4882a593Smuzhiyun 				  struct ethtool_tcpip4_spec *l4_mask,
406*4882a593Smuzhiyun 				  void *key, void *mask, u8 l4_proto, u64 *fields)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	int off;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (l4_mask->tos)
411*4882a593Smuzhiyun 		return -EOPNOTSUPP;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (l4_mask->ip4src) {
414*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC);
415*4882a593Smuzhiyun 		*(__be32 *)(key + off) = l4_value->ip4src;
416*4882a593Smuzhiyun 		*(__be32 *)(mask + off) = l4_mask->ip4src;
417*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_IPSRC;
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	if (l4_mask->ip4dst) {
421*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST);
422*4882a593Smuzhiyun 		*(__be32 *)(key + off) = l4_value->ip4dst;
423*4882a593Smuzhiyun 		*(__be32 *)(mask + off) = l4_mask->ip4dst;
424*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_IPDST;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	if (l4_mask->psrc) {
428*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC);
429*4882a593Smuzhiyun 		*(__be16 *)(key + off) = l4_value->psrc;
430*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = l4_mask->psrc;
431*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_L4SRC;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (l4_mask->pdst) {
435*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST);
436*4882a593Smuzhiyun 		*(__be16 *)(key + off) = l4_value->pdst;
437*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = l4_mask->pdst;
438*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_L4DST;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/* Only apply the rule for IPv4 frames with the specified L4 proto */
442*4882a593Smuzhiyun 	off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
443*4882a593Smuzhiyun 	*(__be16 *)(key + off) = htons(ETH_P_IP);
444*4882a593Smuzhiyun 	*(__be16 *)(mask + off) = htons(0xFFFF);
445*4882a593Smuzhiyun 	*fields |= DPAA2_ETH_DIST_ETHTYPE;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO);
448*4882a593Smuzhiyun 	*(u8 *)(key + off) = l4_proto;
449*4882a593Smuzhiyun 	*(u8 *)(mask + off) = 0xFF;
450*4882a593Smuzhiyun 	*fields |= DPAA2_ETH_DIST_IPPROTO;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
dpaa2_eth_prep_ext_rule(struct ethtool_flow_ext * ext_value,struct ethtool_flow_ext * ext_mask,void * key,void * mask,u64 * fields)455*4882a593Smuzhiyun static int dpaa2_eth_prep_ext_rule(struct ethtool_flow_ext *ext_value,
456*4882a593Smuzhiyun 				   struct ethtool_flow_ext *ext_mask,
457*4882a593Smuzhiyun 				   void *key, void *mask, u64 *fields)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	int off;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	if (ext_mask->vlan_etype)
462*4882a593Smuzhiyun 		return -EOPNOTSUPP;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (ext_mask->vlan_tci) {
465*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_VLAN, NH_FLD_VLAN_TCI);
466*4882a593Smuzhiyun 		*(__be16 *)(key + off) = ext_value->vlan_tci;
467*4882a593Smuzhiyun 		*(__be16 *)(mask + off) = ext_mask->vlan_tci;
468*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_VLAN;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	return 0;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
dpaa2_eth_prep_mac_ext_rule(struct ethtool_flow_ext * ext_value,struct ethtool_flow_ext * ext_mask,void * key,void * mask,u64 * fields)474*4882a593Smuzhiyun static int dpaa2_eth_prep_mac_ext_rule(struct ethtool_flow_ext *ext_value,
475*4882a593Smuzhiyun 				       struct ethtool_flow_ext *ext_mask,
476*4882a593Smuzhiyun 				       void *key, void *mask, u64 *fields)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	int off;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	if (!is_zero_ether_addr(ext_mask->h_dest)) {
481*4882a593Smuzhiyun 		off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA);
482*4882a593Smuzhiyun 		ether_addr_copy(key + off, ext_value->h_dest);
483*4882a593Smuzhiyun 		ether_addr_copy(mask + off, ext_mask->h_dest);
484*4882a593Smuzhiyun 		*fields |= DPAA2_ETH_DIST_ETHDST;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
dpaa2_eth_prep_cls_rule(struct ethtool_rx_flow_spec * fs,void * key,void * mask,u64 * fields)490*4882a593Smuzhiyun static int dpaa2_eth_prep_cls_rule(struct ethtool_rx_flow_spec *fs, void *key,
491*4882a593Smuzhiyun 				   void *mask, u64 *fields)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	int err;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	switch (fs->flow_type & 0xFF) {
496*4882a593Smuzhiyun 	case ETHER_FLOW:
497*4882a593Smuzhiyun 		err = dpaa2_eth_prep_eth_rule(&fs->h_u.ether_spec, &fs->m_u.ether_spec,
498*4882a593Smuzhiyun 					      key, mask, fields);
499*4882a593Smuzhiyun 		break;
500*4882a593Smuzhiyun 	case IP_USER_FLOW:
501*4882a593Smuzhiyun 		err = dpaa2_eth_prep_uip_rule(&fs->h_u.usr_ip4_spec,
502*4882a593Smuzhiyun 					      &fs->m_u.usr_ip4_spec, key, mask, fields);
503*4882a593Smuzhiyun 		break;
504*4882a593Smuzhiyun 	case TCP_V4_FLOW:
505*4882a593Smuzhiyun 		err = dpaa2_eth_prep_l4_rule(&fs->h_u.tcp_ip4_spec, &fs->m_u.tcp_ip4_spec,
506*4882a593Smuzhiyun 					     key, mask, IPPROTO_TCP, fields);
507*4882a593Smuzhiyun 		break;
508*4882a593Smuzhiyun 	case UDP_V4_FLOW:
509*4882a593Smuzhiyun 		err = dpaa2_eth_prep_l4_rule(&fs->h_u.udp_ip4_spec, &fs->m_u.udp_ip4_spec,
510*4882a593Smuzhiyun 					     key, mask, IPPROTO_UDP, fields);
511*4882a593Smuzhiyun 		break;
512*4882a593Smuzhiyun 	case SCTP_V4_FLOW:
513*4882a593Smuzhiyun 		err = dpaa2_eth_prep_l4_rule(&fs->h_u.sctp_ip4_spec,
514*4882a593Smuzhiyun 					     &fs->m_u.sctp_ip4_spec, key, mask,
515*4882a593Smuzhiyun 					     IPPROTO_SCTP, fields);
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 	default:
518*4882a593Smuzhiyun 		return -EOPNOTSUPP;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (err)
522*4882a593Smuzhiyun 		return err;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	if (fs->flow_type & FLOW_EXT) {
525*4882a593Smuzhiyun 		err = dpaa2_eth_prep_ext_rule(&fs->h_ext, &fs->m_ext, key, mask, fields);
526*4882a593Smuzhiyun 		if (err)
527*4882a593Smuzhiyun 			return err;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	if (fs->flow_type & FLOW_MAC_EXT) {
531*4882a593Smuzhiyun 		err = dpaa2_eth_prep_mac_ext_rule(&fs->h_ext, &fs->m_ext, key,
532*4882a593Smuzhiyun 						  mask, fields);
533*4882a593Smuzhiyun 		if (err)
534*4882a593Smuzhiyun 			return err;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return 0;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
dpaa2_eth_do_cls_rule(struct net_device * net_dev,struct ethtool_rx_flow_spec * fs,bool add)540*4882a593Smuzhiyun static int dpaa2_eth_do_cls_rule(struct net_device *net_dev,
541*4882a593Smuzhiyun 				 struct ethtool_rx_flow_spec *fs,
542*4882a593Smuzhiyun 				 bool add)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
545*4882a593Smuzhiyun 	struct device *dev = net_dev->dev.parent;
546*4882a593Smuzhiyun 	struct dpni_rule_cfg rule_cfg = { 0 };
547*4882a593Smuzhiyun 	struct dpni_fs_action_cfg fs_act = { 0 };
548*4882a593Smuzhiyun 	dma_addr_t key_iova;
549*4882a593Smuzhiyun 	u64 fields = 0;
550*4882a593Smuzhiyun 	void *key_buf;
551*4882a593Smuzhiyun 	int i, err;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
554*4882a593Smuzhiyun 	    fs->ring_cookie >= dpaa2_eth_queue_count(priv))
555*4882a593Smuzhiyun 		return -EINVAL;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	rule_cfg.key_size = dpaa2_eth_cls_key_size(DPAA2_ETH_DIST_ALL);
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	/* allocate twice the key size, for the actual key and for mask */
560*4882a593Smuzhiyun 	key_buf = kzalloc(rule_cfg.key_size * 2, GFP_KERNEL);
561*4882a593Smuzhiyun 	if (!key_buf)
562*4882a593Smuzhiyun 		return -ENOMEM;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/* Fill the key and mask memory areas */
565*4882a593Smuzhiyun 	err = dpaa2_eth_prep_cls_rule(fs, key_buf, key_buf + rule_cfg.key_size, &fields);
566*4882a593Smuzhiyun 	if (err)
567*4882a593Smuzhiyun 		goto free_mem;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	if (!dpaa2_eth_fs_mask_enabled(priv)) {
570*4882a593Smuzhiyun 		/* Masking allows us to configure a maximal key during init and
571*4882a593Smuzhiyun 		 * use it for all flow steering rules. Without it, we include
572*4882a593Smuzhiyun 		 * in the key only the fields actually used, so we need to
573*4882a593Smuzhiyun 		 * extract the others from the final key buffer.
574*4882a593Smuzhiyun 		 *
575*4882a593Smuzhiyun 		 * Program the FS key if needed, or return error if previously
576*4882a593Smuzhiyun 		 * set key can't be used for the current rule. User needs to
577*4882a593Smuzhiyun 		 * delete existing rules in this case to allow for the new one.
578*4882a593Smuzhiyun 		 */
579*4882a593Smuzhiyun 		if (!priv->rx_cls_fields) {
580*4882a593Smuzhiyun 			err = dpaa2_eth_set_cls(net_dev, fields);
581*4882a593Smuzhiyun 			if (err)
582*4882a593Smuzhiyun 				goto free_mem;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 			priv->rx_cls_fields = fields;
585*4882a593Smuzhiyun 		} else if (priv->rx_cls_fields != fields) {
586*4882a593Smuzhiyun 			netdev_err(net_dev, "No support for multiple FS keys, need to delete existing rules\n");
587*4882a593Smuzhiyun 			err = -EOPNOTSUPP;
588*4882a593Smuzhiyun 			goto free_mem;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		dpaa2_eth_cls_trim_rule(key_buf, fields);
592*4882a593Smuzhiyun 		rule_cfg.key_size = dpaa2_eth_cls_key_size(fields);
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	key_iova = dma_map_single(dev, key_buf, rule_cfg.key_size * 2,
596*4882a593Smuzhiyun 				  DMA_TO_DEVICE);
597*4882a593Smuzhiyun 	if (dma_mapping_error(dev, key_iova)) {
598*4882a593Smuzhiyun 		err = -ENOMEM;
599*4882a593Smuzhiyun 		goto free_mem;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	rule_cfg.key_iova = key_iova;
603*4882a593Smuzhiyun 	if (dpaa2_eth_fs_mask_enabled(priv))
604*4882a593Smuzhiyun 		rule_cfg.mask_iova = key_iova + rule_cfg.key_size;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	if (add) {
607*4882a593Smuzhiyun 		if (fs->ring_cookie == RX_CLS_FLOW_DISC)
608*4882a593Smuzhiyun 			fs_act.options |= DPNI_FS_OPT_DISCARD;
609*4882a593Smuzhiyun 		else
610*4882a593Smuzhiyun 			fs_act.flow_id = fs->ring_cookie;
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 	for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
613*4882a593Smuzhiyun 		if (add)
614*4882a593Smuzhiyun 			err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token,
615*4882a593Smuzhiyun 						i, fs->location, &rule_cfg,
616*4882a593Smuzhiyun 						&fs_act);
617*4882a593Smuzhiyun 		else
618*4882a593Smuzhiyun 			err = dpni_remove_fs_entry(priv->mc_io, 0,
619*4882a593Smuzhiyun 						   priv->mc_token, i,
620*4882a593Smuzhiyun 						   &rule_cfg);
621*4882a593Smuzhiyun 		if (err || priv->dpni_attrs.options & DPNI_OPT_SHARED_FS)
622*4882a593Smuzhiyun 			break;
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	dma_unmap_single(dev, key_iova, rule_cfg.key_size * 2, DMA_TO_DEVICE);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun free_mem:
628*4882a593Smuzhiyun 	kfree(key_buf);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	return err;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
dpaa2_eth_num_cls_rules(struct dpaa2_eth_priv * priv)633*4882a593Smuzhiyun static int dpaa2_eth_num_cls_rules(struct dpaa2_eth_priv *priv)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	int i, rules = 0;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	for (i = 0; i < dpaa2_eth_fs_count(priv); i++)
638*4882a593Smuzhiyun 		if (priv->cls_rules[i].in_use)
639*4882a593Smuzhiyun 			rules++;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return rules;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
dpaa2_eth_update_cls_rule(struct net_device * net_dev,struct ethtool_rx_flow_spec * new_fs,unsigned int location)644*4882a593Smuzhiyun static int dpaa2_eth_update_cls_rule(struct net_device *net_dev,
645*4882a593Smuzhiyun 				     struct ethtool_rx_flow_spec *new_fs,
646*4882a593Smuzhiyun 				     unsigned int location)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
649*4882a593Smuzhiyun 	struct dpaa2_eth_cls_rule *rule;
650*4882a593Smuzhiyun 	int err = -EINVAL;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	if (!priv->rx_cls_enabled)
653*4882a593Smuzhiyun 		return -EOPNOTSUPP;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	if (location >= dpaa2_eth_fs_count(priv))
656*4882a593Smuzhiyun 		return -EINVAL;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	rule = &priv->cls_rules[location];
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	/* If a rule is present at the specified location, delete it. */
661*4882a593Smuzhiyun 	if (rule->in_use) {
662*4882a593Smuzhiyun 		err = dpaa2_eth_do_cls_rule(net_dev, &rule->fs, false);
663*4882a593Smuzhiyun 		if (err)
664*4882a593Smuzhiyun 			return err;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 		rule->in_use = 0;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 		if (!dpaa2_eth_fs_mask_enabled(priv) &&
669*4882a593Smuzhiyun 		    !dpaa2_eth_num_cls_rules(priv))
670*4882a593Smuzhiyun 			priv->rx_cls_fields = 0;
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	/* If no new entry to add, return here */
674*4882a593Smuzhiyun 	if (!new_fs)
675*4882a593Smuzhiyun 		return err;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	err = dpaa2_eth_do_cls_rule(net_dev, new_fs, true);
678*4882a593Smuzhiyun 	if (err)
679*4882a593Smuzhiyun 		return err;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	rule->in_use = 1;
682*4882a593Smuzhiyun 	rule->fs = *new_fs;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun 
dpaa2_eth_get_rxnfc(struct net_device * net_dev,struct ethtool_rxnfc * rxnfc,u32 * rule_locs)687*4882a593Smuzhiyun static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
688*4882a593Smuzhiyun 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
691*4882a593Smuzhiyun 	int max_rules = dpaa2_eth_fs_count(priv);
692*4882a593Smuzhiyun 	int i, j = 0;
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	switch (rxnfc->cmd) {
695*4882a593Smuzhiyun 	case ETHTOOL_GRXFH:
696*4882a593Smuzhiyun 		/* we purposely ignore cmd->flow_type for now, because the
697*4882a593Smuzhiyun 		 * classifier only supports a single set of fields for all
698*4882a593Smuzhiyun 		 * protocols
699*4882a593Smuzhiyun 		 */
700*4882a593Smuzhiyun 		rxnfc->data = priv->rx_hash_fields;
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	case ETHTOOL_GRXRINGS:
703*4882a593Smuzhiyun 		rxnfc->data = dpaa2_eth_queue_count(priv);
704*4882a593Smuzhiyun 		break;
705*4882a593Smuzhiyun 	case ETHTOOL_GRXCLSRLCNT:
706*4882a593Smuzhiyun 		rxnfc->rule_cnt = 0;
707*4882a593Smuzhiyun 		rxnfc->rule_cnt = dpaa2_eth_num_cls_rules(priv);
708*4882a593Smuzhiyun 		rxnfc->data = max_rules;
709*4882a593Smuzhiyun 		break;
710*4882a593Smuzhiyun 	case ETHTOOL_GRXCLSRULE:
711*4882a593Smuzhiyun 		if (rxnfc->fs.location >= max_rules)
712*4882a593Smuzhiyun 			return -EINVAL;
713*4882a593Smuzhiyun 		rxnfc->fs.location = array_index_nospec(rxnfc->fs.location,
714*4882a593Smuzhiyun 							max_rules);
715*4882a593Smuzhiyun 		if (!priv->cls_rules[rxnfc->fs.location].in_use)
716*4882a593Smuzhiyun 			return -EINVAL;
717*4882a593Smuzhiyun 		rxnfc->fs = priv->cls_rules[rxnfc->fs.location].fs;
718*4882a593Smuzhiyun 		break;
719*4882a593Smuzhiyun 	case ETHTOOL_GRXCLSRLALL:
720*4882a593Smuzhiyun 		for (i = 0; i < max_rules; i++) {
721*4882a593Smuzhiyun 			if (!priv->cls_rules[i].in_use)
722*4882a593Smuzhiyun 				continue;
723*4882a593Smuzhiyun 			if (j == rxnfc->rule_cnt)
724*4882a593Smuzhiyun 				return -EMSGSIZE;
725*4882a593Smuzhiyun 			rule_locs[j++] = i;
726*4882a593Smuzhiyun 		}
727*4882a593Smuzhiyun 		rxnfc->rule_cnt = j;
728*4882a593Smuzhiyun 		rxnfc->data = max_rules;
729*4882a593Smuzhiyun 		break;
730*4882a593Smuzhiyun 	default:
731*4882a593Smuzhiyun 		return -EOPNOTSUPP;
732*4882a593Smuzhiyun 	}
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
dpaa2_eth_set_rxnfc(struct net_device * net_dev,struct ethtool_rxnfc * rxnfc)737*4882a593Smuzhiyun static int dpaa2_eth_set_rxnfc(struct net_device *net_dev,
738*4882a593Smuzhiyun 			       struct ethtool_rxnfc *rxnfc)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	int err = 0;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	switch (rxnfc->cmd) {
743*4882a593Smuzhiyun 	case ETHTOOL_SRXFH:
744*4882a593Smuzhiyun 		if ((rxnfc->data & DPAA2_RXH_SUPPORTED) != rxnfc->data)
745*4882a593Smuzhiyun 			return -EOPNOTSUPP;
746*4882a593Smuzhiyun 		err = dpaa2_eth_set_hash(net_dev, rxnfc->data);
747*4882a593Smuzhiyun 		break;
748*4882a593Smuzhiyun 	case ETHTOOL_SRXCLSRLINS:
749*4882a593Smuzhiyun 		err = dpaa2_eth_update_cls_rule(net_dev, &rxnfc->fs, rxnfc->fs.location);
750*4882a593Smuzhiyun 		break;
751*4882a593Smuzhiyun 	case ETHTOOL_SRXCLSRLDEL:
752*4882a593Smuzhiyun 		err = dpaa2_eth_update_cls_rule(net_dev, NULL, rxnfc->fs.location);
753*4882a593Smuzhiyun 		break;
754*4882a593Smuzhiyun 	default:
755*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	return err;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun int dpaa2_phc_index = -1;
762*4882a593Smuzhiyun EXPORT_SYMBOL(dpaa2_phc_index);
763*4882a593Smuzhiyun 
dpaa2_eth_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)764*4882a593Smuzhiyun static int dpaa2_eth_get_ts_info(struct net_device *dev,
765*4882a593Smuzhiyun 				 struct ethtool_ts_info *info)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun 	if (!dpaa2_ptp)
768*4882a593Smuzhiyun 		return ethtool_op_get_ts_info(dev, info);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
771*4882a593Smuzhiyun 				SOF_TIMESTAMPING_RX_HARDWARE |
772*4882a593Smuzhiyun 				SOF_TIMESTAMPING_RAW_HARDWARE;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	info->phc_index = dpaa2_phc_index;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
777*4882a593Smuzhiyun 			 (1 << HWTSTAMP_TX_ON) |
778*4882a593Smuzhiyun 			 (1 << HWTSTAMP_TX_ONESTEP_SYNC);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
781*4882a593Smuzhiyun 			   (1 << HWTSTAMP_FILTER_ALL);
782*4882a593Smuzhiyun 	return 0;
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun const struct ethtool_ops dpaa2_ethtool_ops = {
786*4882a593Smuzhiyun 	.get_drvinfo = dpaa2_eth_get_drvinfo,
787*4882a593Smuzhiyun 	.nway_reset = dpaa2_eth_nway_reset,
788*4882a593Smuzhiyun 	.get_link = ethtool_op_get_link,
789*4882a593Smuzhiyun 	.get_link_ksettings = dpaa2_eth_get_link_ksettings,
790*4882a593Smuzhiyun 	.set_link_ksettings = dpaa2_eth_set_link_ksettings,
791*4882a593Smuzhiyun 	.get_pauseparam = dpaa2_eth_get_pauseparam,
792*4882a593Smuzhiyun 	.set_pauseparam = dpaa2_eth_set_pauseparam,
793*4882a593Smuzhiyun 	.get_sset_count = dpaa2_eth_get_sset_count,
794*4882a593Smuzhiyun 	.get_ethtool_stats = dpaa2_eth_get_ethtool_stats,
795*4882a593Smuzhiyun 	.get_strings = dpaa2_eth_get_strings,
796*4882a593Smuzhiyun 	.get_rxnfc = dpaa2_eth_get_rxnfc,
797*4882a593Smuzhiyun 	.set_rxnfc = dpaa2_eth_set_rxnfc,
798*4882a593Smuzhiyun 	.get_ts_info = dpaa2_eth_get_ts_info,
799*4882a593Smuzhiyun };
800