GNU Linux-libre 4.14.251-gnu1
[releases.git] / drivers / staging / fsl-dpaa2 / ethernet / dpaa2-ethtool.c
1 /* Copyright 2014-2016 Freescale Semiconductor Inc.
2  * Copyright 2016 NXP
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above copyright
9  *       notice, this list of conditions and the following disclaimer in the
10  *       documentation and/or other materials provided with the distribution.
11  *     * Neither the name of Freescale Semiconductor nor the
12  *       names of its contributors may be used to endorse or promote products
13  *       derived from this software without specific prior written permission.
14  *
15  *
16  * ALTERNATIVELY, this software may be distributed under the terms of the
17  * GNU General Public License ("GPL") as published by the Free Software
18  * Foundation, either version 2 of that License or (at your option) any
19  * later version.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "dpni.h"       /* DPNI_LINK_OPT_* */
34 #include "dpaa2-eth.h"
35
36 /* To be kept in sync with DPNI statistics */
37 static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {
38         "[hw] rx frames",
39         "[hw] rx bytes",
40         "[hw] rx mcast frames",
41         "[hw] rx mcast bytes",
42         "[hw] rx bcast frames",
43         "[hw] rx bcast bytes",
44         "[hw] tx frames",
45         "[hw] tx bytes",
46         "[hw] tx mcast frames",
47         "[hw] tx mcast bytes",
48         "[hw] tx bcast frames",
49         "[hw] tx bcast bytes",
50         "[hw] rx filtered frames",
51         "[hw] rx discarded frames",
52         "[hw] rx nobuffer discards",
53         "[hw] tx discarded frames",
54         "[hw] tx confirmed frames",
55 };
56
57 #define DPAA2_ETH_NUM_STATS     ARRAY_SIZE(dpaa2_ethtool_stats)
58
59 static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = {
60         /* per-cpu stats */
61         "[drv] tx conf frames",
62         "[drv] tx conf bytes",
63         "[drv] tx sg frames",
64         "[drv] tx sg bytes",
65         "[drv] rx sg frames",
66         "[drv] rx sg bytes",
67         "[drv] enqueue portal busy",
68         /* Channel stats */
69         "[drv] dequeue portal busy",
70         "[drv] channel pull errors",
71         "[drv] cdan",
72 };
73
74 #define DPAA2_ETH_NUM_EXTRA_STATS       ARRAY_SIZE(dpaa2_ethtool_extras)
75
76 static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
77                                   struct ethtool_drvinfo *drvinfo)
78 {
79         strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
80         strlcpy(drvinfo->version, dpaa2_eth_drv_version,
81                 sizeof(drvinfo->version));
82         strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
83         strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
84                 sizeof(drvinfo->bus_info));
85 }
86
87 static int
88 dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
89                              struct ethtool_link_ksettings *link_settings)
90 {
91         struct dpni_link_state state = {0};
92         int err = 0;
93         struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
94
95         err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
96         if (err) {
97                 netdev_err(net_dev, "ERROR %d getting link state\n", err);
98                 goto out;
99         }
100
101         /* At the moment, we have no way of interrogating the DPMAC
102          * from the DPNI side - and for that matter there may exist
103          * no DPMAC at all. So for now we just don't report anything
104          * beyond the DPNI attributes.
105          */
106         if (state.options & DPNI_LINK_OPT_AUTONEG)
107                 link_settings->base.autoneg = AUTONEG_ENABLE;
108         if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX))
109                 link_settings->base.duplex = DUPLEX_FULL;
110         link_settings->base.speed = state.rate;
111
112 out:
113         return err;
114 }
115
116 static int
117 dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
118                              const struct ethtool_link_ksettings *link_settings)
119 {
120         struct dpni_link_cfg cfg = {0};
121         struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
122         int err = 0;
123
124         netdev_dbg(net_dev, "Setting link parameters...");
125
126         /* Due to a temporary MC limitation, the DPNI must be down
127          * in order to be able to change link settings. Taking steps to let
128          * the user know that.
129          */
130         if (netif_running(net_dev)) {
131                 netdev_info(net_dev, "Sorry, interface must be brought down first.\n");
132                 return -EACCES;
133         }
134
135         cfg.rate = link_settings->base.speed;
136         if (link_settings->base.autoneg == AUTONEG_ENABLE)
137                 cfg.options |= DPNI_LINK_OPT_AUTONEG;
138         else
139                 cfg.options &= ~DPNI_LINK_OPT_AUTONEG;
140         if (link_settings->base.duplex  == DUPLEX_HALF)
141                 cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX;
142         else
143                 cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
144
145         err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
146         if (err)
147                 /* ethtool will be loud enough if we return an error; no point
148                  * in putting our own error message on the console by default
149                  */
150                 netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err);
151
152         return err;
153 }
154
155 static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
156                                   u8 *data)
157 {
158         u8 *p = data;
159         int i;
160
161         switch (stringset) {
162         case ETH_SS_STATS:
163                 for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) {
164                         strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
165                         p += ETH_GSTRING_LEN;
166                 }
167                 for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
168                         strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
169                         p += ETH_GSTRING_LEN;
170                 }
171                 break;
172         }
173 }
174
175 static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
176 {
177         switch (sset) {
178         case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
179                 return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
180         default:
181                 return -EOPNOTSUPP;
182         }
183 }
184
185 /** Fill in hardware counters, as returned by MC.
186  */
187 static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
188                                         struct ethtool_stats *stats,
189                                         u64 *data)
190 {
191         int i = 0;
192         int j, k, err;
193         int num_cnt;
194         union dpni_statistics dpni_stats;
195         u64 cdan = 0;
196         u64 portal_busy = 0, pull_err = 0;
197         struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
198         struct dpaa2_eth_drv_stats *extras;
199         struct dpaa2_eth_ch_stats *ch_stats;
200
201         memset(data, 0,
202                sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
203
204         /* Print standard counters, from DPNI statistics */
205         for (j = 0; j <= 2; j++) {
206                 err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
207                                           j, &dpni_stats);
208                 if (err != 0)
209                         netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j);
210                 switch (j) {
211                 case 0:
212                         num_cnt = sizeof(dpni_stats.page_0) / sizeof(u64);
213                         break;
214                 case 1:
215                         num_cnt = sizeof(dpni_stats.page_1) / sizeof(u64);
216                         break;
217                 case 2:
218                         num_cnt = sizeof(dpni_stats.page_2) / sizeof(u64);
219                         break;
220                 }
221                 for (k = 0; k < num_cnt; k++)
222                         *(data + i++) = dpni_stats.raw.counter[k];
223         }
224
225         /* Print per-cpu extra stats */
226         for_each_online_cpu(k) {
227                 extras = per_cpu_ptr(priv->percpu_extras, k);
228                 for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
229                         *((__u64 *)data + i + j) += *((__u64 *)extras + j);
230         }
231         i += j;
232
233         for (j = 0; j < priv->num_channels; j++) {
234                 ch_stats = &priv->channel[j]->stats;
235                 cdan += ch_stats->cdan;
236                 portal_busy += ch_stats->dequeue_portal_busy;
237                 pull_err += ch_stats->pull_err;
238         }
239
240         *(data + i++) = portal_busy;
241         *(data + i++) = pull_err;
242         *(data + i++) = cdan;
243 }
244
245 static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
246                                struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
247 {
248         struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
249
250         switch (rxnfc->cmd) {
251         case ETHTOOL_GRXFH:
252                 /* we purposely ignore cmd->flow_type for now, because the
253                  * classifier only supports a single set of fields for all
254                  * protocols
255                  */
256                 rxnfc->data = priv->rx_hash_fields;
257                 break;
258         case ETHTOOL_GRXRINGS:
259                 rxnfc->data = dpaa2_eth_queue_count(priv);
260                 break;
261         default:
262                 return -EOPNOTSUPP;
263         }
264
265         return 0;
266 }
267
268 const struct ethtool_ops dpaa2_ethtool_ops = {
269         .get_drvinfo = dpaa2_eth_get_drvinfo,
270         .get_link = ethtool_op_get_link,
271         .get_link_ksettings = dpaa2_eth_get_link_ksettings,
272         .set_link_ksettings = dpaa2_eth_set_link_ksettings,
273         .get_sset_count = dpaa2_eth_get_sset_count,
274         .get_ethtool_stats = dpaa2_eth_get_ethtool_stats,
275         .get_strings = dpaa2_eth_get_strings,
276         .get_rxnfc = dpaa2_eth_get_rxnfc,
277 };