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