1 /* Copyright 2014-2016 Freescale Semiconductor Inc.
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.
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
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.
33 #include "dpni.h" /* DPNI_LINK_OPT_* */
34 #include "dpaa2-eth.h"
36 /* To be kept in sync with DPNI statistics */
37 char dpaa2_ethtool_stats
[][ETH_GSTRING_LEN
] = {
51 "rx discarded frames",
52 "rx nobuffer discards",
53 "tx discarded frames",
54 "tx confirmed frames",
57 #define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats)
59 char dpaa2_ethtool_extras
[][ETH_GSTRING_LEN
] = {
67 "enqueue portal busy",
69 "dequeue portal busy",
70 "channel pull errors",
74 #define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras)
76 static void dpaa2_eth_get_drvinfo(struct net_device
*net_dev
,
77 struct ethtool_drvinfo
*drvinfo
)
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
));
88 dpaa2_eth_get_link_ksettings(struct net_device
*net_dev
,
89 struct ethtool_link_ksettings
*link_settings
)
91 struct dpni_link_state state
= {0};
93 struct dpaa2_eth_priv
*priv
= netdev_priv(net_dev
);
95 err
= dpni_get_link_state(priv
->mc_io
, 0, priv
->mc_token
, &state
);
97 netdev_err(net_dev
, "ERROR %d getting link state", err
);
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.
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
;
117 dpaa2_eth_set_link_ksettings(struct net_device
*net_dev
,
118 const struct ethtool_link_ksettings
*link_settings
)
120 struct dpni_link_cfg cfg
= {0};
121 struct dpaa2_eth_priv
*priv
= netdev_priv(net_dev
);
124 netdev_dbg(net_dev
, "Setting link parameters...");
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.
130 if (netif_running(net_dev
)) {
131 netdev_info(net_dev
, "Sorry, interface must be brought down first.\n");
135 cfg
.rate
= link_settings
->base
.speed
;
136 if (link_settings
->base
.autoneg
== AUTONEG_ENABLE
)
137 cfg
.options
|= DPNI_LINK_OPT_AUTONEG
;
139 cfg
.options
&= ~DPNI_LINK_OPT_AUTONEG
;
140 if (link_settings
->base
.duplex
== DUPLEX_HALF
)
141 cfg
.options
|= DPNI_LINK_OPT_HALF_DUPLEX
;
143 cfg
.options
&= ~DPNI_LINK_OPT_HALF_DUPLEX
;
145 err
= dpni_set_link_cfg(priv
->mc_io
, 0, priv
->mc_token
, &cfg
);
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
150 netdev_dbg(net_dev
, "ERROR %d setting link cfg", err
);
155 static void dpaa2_eth_get_strings(struct net_device
*netdev
, u32 stringset
,
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
;
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
;
175 static int dpaa2_eth_get_sset_count(struct net_device
*net_dev
, int sset
)
178 case ETH_SS_STATS
: /* ethtool_get_stats(), ethtool_get_drvinfo() */
179 return DPAA2_ETH_NUM_STATS
+ DPAA2_ETH_NUM_EXTRA_STATS
;
185 /** Fill in hardware counters, as returned by MC.
187 static void dpaa2_eth_get_ethtool_stats(struct net_device
*net_dev
,
188 struct ethtool_stats
*stats
,
194 union dpni_statistics dpni_stats
;
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
;
202 sizeof(u64
) * (DPAA2_ETH_NUM_STATS
+ DPAA2_ETH_NUM_EXTRA_STATS
));
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
,
209 netdev_warn(net_dev
, "dpni_get_stats(%d) failed", j
);
212 num_cnt
= sizeof(dpni_stats
.page_0
) / sizeof(u64
);
215 num_cnt
= sizeof(dpni_stats
.page_1
) / sizeof(u64
);
218 num_cnt
= sizeof(dpni_stats
.page_2
) / sizeof(u64
);
223 for (k
= 0; k
< num_cnt
; k
++)
224 *(data
+ i
++) = dpni_stats
.raw
.counter
[k
];
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
);
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
;
242 *(data
+ i
++) = portal_busy
;
243 *(data
+ i
++) = pull_err
;
244 *(data
+ i
++) = cdan
;
247 static int dpaa2_eth_get_rxnfc(struct net_device
*net_dev
,
248 struct ethtool_rxnfc
*rxnfc
, u32
*rule_locs
)
250 struct dpaa2_eth_priv
*priv
= netdev_priv(net_dev
);
252 switch (rxnfc
->cmd
) {
254 /* we purposely ignore cmd->flow_type for now, because the
255 * classifier only supports a single set of fields for all
258 rxnfc
->data
= priv
->rx_hash_fields
;
260 case ETHTOOL_GRXRINGS
:
261 rxnfc
->data
= dpaa2_eth_queue_count(priv
);
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
,