]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
Merge tag 'libnvdimm-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdim...
[karo-tx-linux.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                 default:
221                         break;
222                 }
223                 for (k = 0; k < num_cnt; k++)
224                         *(data + i++) = dpni_stats.raw.counter[k];
225         }
226
227         /* Print per-cpu extra stats */
228         for_each_online_cpu(k) {
229                 extras = per_cpu_ptr(priv->percpu_extras, k);
230                 for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
231                         *((__u64 *)data + i + j) += *((__u64 *)extras + j);
232         }
233         i += j;
234
235         for (j = 0; j < priv->num_channels; j++) {
236                 ch_stats = &priv->channel[j]->stats;
237                 cdan += ch_stats->cdan;
238                 portal_busy += ch_stats->dequeue_portal_busy;
239                 pull_err += ch_stats->pull_err;
240         }
241
242         *(data + i++) = portal_busy;
243         *(data + i++) = pull_err;
244         *(data + i++) = cdan;
245 }
246
247 static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
248                                struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
249 {
250         struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
251
252         switch (rxnfc->cmd) {
253         case ETHTOOL_GRXFH:
254                 /* we purposely ignore cmd->flow_type for now, because the
255                  * classifier only supports a single set of fields for all
256                  * protocols
257                  */
258                 rxnfc->data = priv->rx_hash_fields;
259                 break;
260         case ETHTOOL_GRXRINGS:
261                 rxnfc->data = dpaa2_eth_queue_count(priv);
262                 break;
263         default:
264                 return -EOPNOTSUPP;
265         }
266
267         return 0;
268 }
269
270 const struct ethtool_ops dpaa2_ethtool_ops = {
271         .get_drvinfo = dpaa2_eth_get_drvinfo,
272         .get_link = ethtool_op_get_link,
273         .get_link_ksettings = dpaa2_eth_get_link_ksettings,
274         .set_link_ksettings = dpaa2_eth_set_link_ksettings,
275         .get_sset_count = dpaa2_eth_get_sset_count,
276         .get_ethtool_stats = dpaa2_eth_get_ethtool_stats,
277         .get_strings = dpaa2_eth_get_strings,
278         .get_rxnfc = dpaa2_eth_get_rxnfc,
279 };