Skip to content

Commit e32036e

Browse files
vladimirolteandavem330
authored andcommitted
net: mscc: ocelot: add support for all sorts of standardized counters present in DSA
DSA is integrated with the new standardized ethtool -S --groups option, but the felix driver only exports unstructured statistics. Reuse the array of 64-bit statistics collected by ocelot_check_stats_work(), but just export select values from it. Since ocelot_check_stats_work() runs periodically to avoid 32-bit overflow, and the ethtool calling context is sleepable, we update the 64-bit stats one more time, to provide up-to-date values. The locking scheme with a mutex followed by a spinlock is a bit hard to digest, so we create and use a ocelot_port_stats_run() helper with a callback that populates the ethool stats group the caller is interested in. The exported stats are: ethtool -S swp0 --groups eth-phy ethtool -S swp0 --groups eth-mac ethtool -S swp0 --groups eth-ctrl ethtool -S swp0 --groups rmon ethtool --include-statistics --show-pause swp0 Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d3e75f1 commit e32036e

File tree

3 files changed

+241
-17
lines changed

3 files changed

+241
-17
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,47 @@ static void felix_get_stats64(struct dsa_switch *ds, int port,
10421042
ocelot_port_get_stats64(ocelot, port, stats);
10431043
}
10441044

1045+
static void felix_get_pause_stats(struct dsa_switch *ds, int port,
1046+
struct ethtool_pause_stats *pause_stats)
1047+
{
1048+
struct ocelot *ocelot = ds->priv;
1049+
1050+
ocelot_port_get_pause_stats(ocelot, port, pause_stats);
1051+
}
1052+
1053+
static void felix_get_rmon_stats(struct dsa_switch *ds, int port,
1054+
struct ethtool_rmon_stats *rmon_stats,
1055+
const struct ethtool_rmon_hist_range **ranges)
1056+
{
1057+
struct ocelot *ocelot = ds->priv;
1058+
1059+
ocelot_port_get_rmon_stats(ocelot, port, rmon_stats, ranges);
1060+
}
1061+
1062+
static void felix_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
1063+
struct ethtool_eth_ctrl_stats *ctrl_stats)
1064+
{
1065+
struct ocelot *ocelot = ds->priv;
1066+
1067+
ocelot_port_get_eth_ctrl_stats(ocelot, port, ctrl_stats);
1068+
}
1069+
1070+
static void felix_get_eth_mac_stats(struct dsa_switch *ds, int port,
1071+
struct ethtool_eth_mac_stats *mac_stats)
1072+
{
1073+
struct ocelot *ocelot = ds->priv;
1074+
1075+
ocelot_port_get_eth_mac_stats(ocelot, port, mac_stats);
1076+
}
1077+
1078+
static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port,
1079+
struct ethtool_eth_phy_stats *phy_stats)
1080+
{
1081+
struct ocelot *ocelot = ds->priv;
1082+
1083+
ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats);
1084+
}
1085+
10451086
static void felix_get_strings(struct dsa_switch *ds, int port,
10461087
u32 stringset, u8 *data)
10471088
{
@@ -1857,6 +1898,11 @@ const struct dsa_switch_ops felix_switch_ops = {
18571898
.teardown = felix_teardown,
18581899
.set_ageing_time = felix_set_ageing_time,
18591900
.get_stats64 = felix_get_stats64,
1901+
.get_pause_stats = felix_get_pause_stats,
1902+
.get_rmon_stats = felix_get_rmon_stats,
1903+
.get_eth_ctrl_stats = felix_get_eth_ctrl_stats,
1904+
.get_eth_mac_stats = felix_get_eth_mac_stats,
1905+
.get_eth_phy_stats = felix_get_eth_phy_stats,
18601906
.get_strings = felix_get_strings,
18611907
.get_ethtool_stats = felix_get_ethtool_stats,
18621908
.get_sset_count = felix_get_sset_count,

drivers/net/ethernet/mscc/ocelot_stats.c

Lines changed: 184 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Statistics for Ocelot switch family
33
*
44
* Copyright (c) 2017 Microsemi Corporation
5+
* Copyright 2022 NXP
56
*/
67
#include <linux/spinlock.h>
78
#include <linux/mutex.h>
@@ -101,37 +102,32 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
101102
}
102103
EXPORT_SYMBOL(ocelot_get_strings);
103104

104-
void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
105+
/* Update ocelot->stats for the given port and run the given callback */
106+
static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
107+
void (*cb)(struct ocelot *ocelot, int port,
108+
void *priv))
105109
{
106-
int i, err;
110+
int err;
107111

108112
mutex_lock(&ocelot->stat_view_lock);
109113

110-
/* check and update now */
111114
err = ocelot_port_update_stats(ocelot, port);
115+
if (err) {
116+
dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
117+
port, ERR_PTR(err));
118+
goto out_unlock;
119+
}
112120

113121
spin_lock(&ocelot->stats_lock);
114122

115123
ocelot_port_transfer_stats(ocelot, port);
116-
117-
/* Copy all supported counters */
118-
for (i = 0; i < OCELOT_NUM_STATS; i++) {
119-
int index = port * OCELOT_NUM_STATS + i;
120-
121-
if (ocelot->stats_layout[i].name[0] == '\0')
122-
continue;
123-
124-
*data++ = ocelot->stats[index];
125-
}
124+
cb(ocelot, port, priv);
126125

127126
spin_unlock(&ocelot->stats_lock);
128127

128+
out_unlock:
129129
mutex_unlock(&ocelot->stat_view_lock);
130-
131-
if (err)
132-
dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
133130
}
134-
EXPORT_SYMBOL(ocelot_get_ethtool_stats);
135131

136132
int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
137133
{
@@ -148,6 +144,177 @@ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
148144
}
149145
EXPORT_SYMBOL(ocelot_get_sset_count);
150146

147+
static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
148+
void *priv)
149+
{
150+
u64 *data = priv;
151+
int i;
152+
153+
/* Copy all supported counters */
154+
for (i = 0; i < OCELOT_NUM_STATS; i++) {
155+
int index = port * OCELOT_NUM_STATS + i;
156+
157+
if (ocelot->stats_layout[i].name[0] == '\0')
158+
continue;
159+
160+
*data++ = ocelot->stats[index];
161+
}
162+
}
163+
164+
void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
165+
{
166+
ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
167+
}
168+
EXPORT_SYMBOL(ocelot_get_ethtool_stats);
169+
170+
static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
171+
{
172+
u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
173+
struct ethtool_pause_stats *pause_stats = priv;
174+
175+
pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
176+
pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
177+
}
178+
179+
void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
180+
struct ethtool_pause_stats *pause_stats)
181+
{
182+
ocelot_port_stats_run(ocelot, port, pause_stats,
183+
ocelot_port_pause_stats_cb);
184+
}
185+
EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
186+
187+
static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
188+
{ 64, 64 },
189+
{ 65, 127 },
190+
{ 128, 255 },
191+
{ 256, 511 },
192+
{ 512, 1023 },
193+
{ 1024, 1526 },
194+
{ 1527, 65535 },
195+
{},
196+
};
197+
198+
static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
199+
{
200+
u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
201+
struct ethtool_rmon_stats *rmon_stats = priv;
202+
203+
rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
204+
rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
205+
rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
206+
rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
207+
208+
rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
209+
rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
210+
rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
211+
rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
212+
rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
213+
rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
214+
rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
215+
216+
rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
217+
rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
218+
rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
219+
rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_128_255];
220+
rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_256_511];
221+
rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_512_1023];
222+
rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1024_1526];
223+
}
224+
225+
void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
226+
struct ethtool_rmon_stats *rmon_stats,
227+
const struct ethtool_rmon_hist_range **ranges)
228+
{
229+
*ranges = ocelot_rmon_ranges;
230+
231+
ocelot_port_stats_run(ocelot, port, rmon_stats,
232+
ocelot_port_rmon_stats_cb);
233+
}
234+
EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
235+
236+
static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
237+
{
238+
u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
239+
struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
240+
241+
ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
242+
}
243+
244+
void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
245+
struct ethtool_eth_ctrl_stats *ctrl_stats)
246+
{
247+
ocelot_port_stats_run(ocelot, port, ctrl_stats,
248+
ocelot_port_ctrl_stats_cb);
249+
}
250+
EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
251+
252+
static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
253+
{
254+
u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
255+
struct ethtool_eth_mac_stats *mac_stats = priv;
256+
257+
mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
258+
mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
259+
s[OCELOT_STAT_TX_65_127] +
260+
s[OCELOT_STAT_TX_128_255] +
261+
s[OCELOT_STAT_TX_256_511] +
262+
s[OCELOT_STAT_TX_512_1023] +
263+
s[OCELOT_STAT_TX_1024_1526] +
264+
s[OCELOT_STAT_TX_1527_MAX];
265+
mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
266+
mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
267+
s[OCELOT_STAT_RX_GREEN_PRIO_1] +
268+
s[OCELOT_STAT_RX_GREEN_PRIO_2] +
269+
s[OCELOT_STAT_RX_GREEN_PRIO_3] +
270+
s[OCELOT_STAT_RX_GREEN_PRIO_4] +
271+
s[OCELOT_STAT_RX_GREEN_PRIO_5] +
272+
s[OCELOT_STAT_RX_GREEN_PRIO_6] +
273+
s[OCELOT_STAT_RX_GREEN_PRIO_7] +
274+
s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
275+
s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
276+
s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
277+
s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
278+
s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
279+
s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
280+
s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
281+
s[OCELOT_STAT_RX_YELLOW_PRIO_7];
282+
mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
283+
mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
284+
mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
285+
mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
286+
mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
287+
/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
288+
* counted individually.
289+
*/
290+
mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
291+
mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
292+
}
293+
294+
void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
295+
struct ethtool_eth_mac_stats *mac_stats)
296+
{
297+
ocelot_port_stats_run(ocelot, port, mac_stats,
298+
ocelot_port_mac_stats_cb);
299+
}
300+
EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
301+
302+
static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
303+
{
304+
u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
305+
struct ethtool_eth_phy_stats *phy_stats = priv;
306+
307+
phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
308+
}
309+
310+
void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
311+
struct ethtool_eth_phy_stats *phy_stats)
312+
{
313+
ocelot_port_stats_run(ocelot, port, phy_stats,
314+
ocelot_port_phy_stats_cb);
315+
}
316+
EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
317+
151318
void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
152319
struct rtnl_link_stats64 *stats)
153320
{

include/soc/mscc/ocelot.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,17 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data);
10451045
int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset);
10461046
void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
10471047
struct rtnl_link_stats64 *stats);
1048+
void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
1049+
struct ethtool_pause_stats *pause_stats);
1050+
void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
1051+
struct ethtool_rmon_stats *rmon_stats,
1052+
const struct ethtool_rmon_hist_range **ranges);
1053+
void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
1054+
struct ethtool_eth_ctrl_stats *ctrl_stats);
1055+
void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
1056+
struct ethtool_eth_mac_stats *mac_stats);
1057+
void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
1058+
struct ethtool_eth_phy_stats *phy_stats);
10481059
int ocelot_get_ts_info(struct ocelot *ocelot, int port,
10491060
struct ethtool_ts_info *info);
10501061
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);

0 commit comments

Comments
 (0)