Skip to content

Commit d43a9d1

Browse files
committed
Merge branch 'dsa-master-ethtool-move'
Vivien Didelot says: ==================== net: dsa: move master ethtool code The DSA core overrides the master device's ethtool_ops structure so that it can inject statistics and such of its dedicated switch CPU port. This ethtool code is currently called on unnecessary conditions or before the master interface and its switch CPU port get wired up. This patchset fixes this. Similarly to slave.c where the DSA slave net_device is the entry point of the dsa_slave_* functions, this patchset also isolates the master's ethtool code in a new master.c file, where the DSA master net_device is the entry point of the dsa_master_* functions. This is a first step towards better control of the master device and support for multiple CPU ports. ==================== Tested-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 69e33b2 + f2f2356 commit d43a9d1

File tree

8 files changed

+136
-130
lines changed

8 files changed

+136
-130
lines changed

include/net/dsa.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ struct dsa_port {
188188
/*
189189
* Original copy of the master netdev ethtool_ops
190190
*/
191-
struct ethtool_ops ethtool_ops;
192191
const struct ethtool_ops *orig_ethtool_ops;
193192
};
194193

net/dsa/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# the core
22
obj-$(CONFIG_NET_DSA) += dsa_core.o
3-
dsa_core-y += dsa.o dsa2.o legacy.o port.o slave.o switch.o
3+
dsa_core-y += dsa.o dsa2.o legacy.o master.o port.o slave.o switch.o
44

55
# tagging formats
66
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o

net/dsa/dsa.c

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,6 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
112112
return ops;
113113
}
114114

115-
int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp)
116-
{
117-
struct dsa_switch *ds = cpu_dp->ds;
118-
struct net_device *master;
119-
struct ethtool_ops *cpu_ops;
120-
121-
master = cpu_dp->netdev;
122-
123-
cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL);
124-
if (!cpu_ops)
125-
return -ENOMEM;
126-
127-
memcpy(&cpu_dp->ethtool_ops, master->ethtool_ops,
128-
sizeof(struct ethtool_ops));
129-
cpu_dp->orig_ethtool_ops = master->ethtool_ops;
130-
memcpy(cpu_ops, &cpu_dp->ethtool_ops,
131-
sizeof(struct ethtool_ops));
132-
dsa_cpu_port_ethtool_init(cpu_ops);
133-
master->ethtool_ops = cpu_ops;
134-
135-
return 0;
136-
}
137-
138-
void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp)
139-
{
140-
cpu_dp->netdev->ethtool_ops = cpu_dp->orig_ethtool_ops;
141-
}
142-
143115
void dsa_cpu_dsa_destroy(struct dsa_port *port)
144116
{
145117
struct device_node *port_dn = port->dn;

net/dsa/dsa2.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,18 +433,17 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
433433
return err;
434434
}
435435

436-
if (dst->cpu_dp) {
437-
err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
438-
if (err)
439-
return err;
440-
}
441-
442436
/* If we use a tagging format that doesn't have an ethertype
443437
* field, make sure that all packets from this point on get
444438
* sent to the tag format's receive function.
445439
*/
446440
wmb();
447441
dst->cpu_dp->netdev->dsa_ptr = dst;
442+
443+
err = dsa_master_ethtool_setup(dst->cpu_dp->netdev);
444+
if (err)
445+
return err;
446+
448447
dst->applied = true;
449448

450449
return 0;
@@ -458,6 +457,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
458457
if (!dst->applied)
459458
return;
460459

460+
dsa_master_ethtool_restore(dst->cpu_dp->netdev);
461+
461462
dst->cpu_dp->netdev->dsa_ptr = NULL;
462463

463464
/* If we used a tagging format that doesn't have an ethertype
@@ -474,10 +475,7 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
474475
dsa_ds_unapply(dst, ds);
475476
}
476477

477-
if (dst->cpu_dp) {
478-
dsa_cpu_port_ethtool_restore(dst->cpu_dp);
479-
dst->cpu_dp = NULL;
480-
}
478+
dst->cpu_dp = NULL;
481479

482480
pr_info("DSA: tree %d unapplied\n", dst->tree);
483481
dst->applied = false;

net/dsa/dsa_priv.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ struct dsa_slave_priv {
9797
int dsa_cpu_dsa_setup(struct dsa_port *port);
9898
void dsa_cpu_dsa_destroy(struct dsa_port *dport);
9999
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
100-
int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp);
101-
void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp);
102100
bool dsa_schedule_work(struct work_struct *work);
103101

104102
/* legacy.c */
@@ -112,6 +110,10 @@ int dsa_legacy_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
112110
struct net_device *dev,
113111
const unsigned char *addr, u16 vid);
114112

113+
/* master.c */
114+
int dsa_master_ethtool_setup(struct net_device *dev);
115+
void dsa_master_ethtool_restore(struct net_device *dev);
116+
115117
/* port.c */
116118
int dsa_port_set_state(struct dsa_port *dp, u8 state,
117119
struct switchdev_trans *trans);
@@ -139,7 +141,6 @@ int dsa_port_vlan_del(struct dsa_port *dp,
139141
/* slave.c */
140142
extern const struct dsa_device_ops notag_netdev_ops;
141143
void dsa_slave_mii_bus_init(struct dsa_switch *ds);
142-
void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops);
143144
int dsa_slave_create(struct dsa_port *port, const char *name);
144145
void dsa_slave_destroy(struct net_device *slave_dev);
145146
int dsa_slave_suspend(struct net_device *slave_dev);

net/dsa/legacy.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,6 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
206206
netdev_err(master, "[%d] : can't configure CPU and DSA ports\n",
207207
index);
208208

209-
ret = dsa_cpu_port_ethtool_setup(ds->dst->cpu_dp);
210-
if (ret)
211-
return ret;
212-
213209
return 0;
214210
}
215211

@@ -606,7 +602,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
606602
wmb();
607603
dev->dsa_ptr = dst;
608604

609-
return 0;
605+
return dsa_master_ethtool_setup(dst->cpu_dp->netdev);
610606
}
611607

612608
static int dsa_probe(struct platform_device *pdev)
@@ -671,6 +667,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
671667
{
672668
int i;
673669

670+
dsa_master_ethtool_restore(dst->cpu_dp->netdev);
671+
674672
dst->cpu_dp->netdev->dsa_ptr = NULL;
675673

676674
/* If we used a tagging format that doesn't have an ethertype
@@ -686,8 +684,6 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
686684
dsa_switch_destroy(ds);
687685
}
688686

689-
dsa_cpu_port_ethtool_restore(dst->cpu_dp);
690-
691687
dev_put(dst->cpu_dp->netdev);
692688
}
693689

net/dsa/master.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Handling of a master device, switching frames via its switch fabric CPU port
3+
*
4+
* Copyright (c) 2017 Savoir-faire Linux Inc.
5+
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*/
12+
13+
#include "dsa_priv.h"
14+
15+
static void dsa_master_get_ethtool_stats(struct net_device *dev,
16+
struct ethtool_stats *stats,
17+
uint64_t *data)
18+
{
19+
struct dsa_switch_tree *dst = dev->dsa_ptr;
20+
struct dsa_port *port = dst->cpu_dp;
21+
struct dsa_switch *ds = port->ds;
22+
const struct ethtool_ops *ops = port->orig_ethtool_ops;
23+
int count = 0;
24+
25+
if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
26+
count = ops->get_sset_count(dev, ETH_SS_STATS);
27+
ops->get_ethtool_stats(dev, stats, data);
28+
}
29+
30+
if (ds->ops->get_ethtool_stats)
31+
ds->ops->get_ethtool_stats(ds, port->index, data + count);
32+
}
33+
34+
static int dsa_master_get_sset_count(struct net_device *dev, int sset)
35+
{
36+
struct dsa_switch_tree *dst = dev->dsa_ptr;
37+
struct dsa_port *port = dst->cpu_dp;
38+
struct dsa_switch *ds = port->ds;
39+
const struct ethtool_ops *ops = port->orig_ethtool_ops;
40+
int count = 0;
41+
42+
if (ops && ops->get_sset_count)
43+
count += ops->get_sset_count(dev, sset);
44+
45+
if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
46+
count += ds->ops->get_sset_count(ds);
47+
48+
return count;
49+
}
50+
51+
static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset,
52+
uint8_t *data)
53+
{
54+
struct dsa_switch_tree *dst = dev->dsa_ptr;
55+
struct dsa_port *port = dst->cpu_dp;
56+
struct dsa_switch *ds = port->ds;
57+
const struct ethtool_ops *ops = port->orig_ethtool_ops;
58+
int len = ETH_GSTRING_LEN;
59+
int mcount = 0, count;
60+
unsigned int i;
61+
uint8_t pfx[4];
62+
uint8_t *ndata;
63+
64+
snprintf(pfx, sizeof(pfx), "p%.2d", port->index);
65+
/* We do not want to be NULL-terminated, since this is a prefix */
66+
pfx[sizeof(pfx) - 1] = '_';
67+
68+
if (ops && ops->get_sset_count && ops->get_strings) {
69+
mcount = ops->get_sset_count(dev, ETH_SS_STATS);
70+
ops->get_strings(dev, stringset, data);
71+
}
72+
73+
if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
74+
ndata = data + mcount * len;
75+
/* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
76+
* the output after to prepend our CPU port prefix we
77+
* constructed earlier
78+
*/
79+
ds->ops->get_strings(ds, port->index, ndata);
80+
count = ds->ops->get_sset_count(ds);
81+
for (i = 0; i < count; i++) {
82+
memmove(ndata + (i * len + sizeof(pfx)),
83+
ndata + i * len, len - sizeof(pfx));
84+
memcpy(ndata + i * len, pfx, sizeof(pfx));
85+
}
86+
}
87+
}
88+
89+
int dsa_master_ethtool_setup(struct net_device *dev)
90+
{
91+
struct dsa_switch_tree *dst = dev->dsa_ptr;
92+
struct dsa_port *port = dst->cpu_dp;
93+
struct dsa_switch *ds = port->ds;
94+
struct ethtool_ops *ops;
95+
96+
ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL);
97+
if (!ops)
98+
return -ENOMEM;
99+
100+
port->orig_ethtool_ops = dev->ethtool_ops;
101+
if (port->orig_ethtool_ops)
102+
memcpy(ops, port->orig_ethtool_ops, sizeof(*ops));
103+
104+
ops->get_sset_count = dsa_master_get_sset_count;
105+
ops->get_ethtool_stats = dsa_master_get_ethtool_stats;
106+
ops->get_strings = dsa_master_get_strings;
107+
108+
dev->ethtool_ops = ops;
109+
110+
return 0;
111+
}
112+
113+
void dsa_master_ethtool_restore(struct net_device *dev)
114+
{
115+
struct dsa_switch_tree *dst = dev->dsa_ptr;
116+
struct dsa_port *port = dst->cpu_dp;
117+
118+
dev->ethtool_ops = port->orig_ethtool_ops;
119+
port->orig_ethtool_ops = NULL;
120+
}

net/dsa/slave.c

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -567,79 +567,6 @@ static void dsa_slave_get_strings(struct net_device *dev,
567567
}
568568
}
569569

570-
static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev,
571-
struct ethtool_stats *stats,
572-
uint64_t *data)
573-
{
574-
struct dsa_switch_tree *dst = dev->dsa_ptr;
575-
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
576-
struct dsa_switch *ds = cpu_dp->ds;
577-
s8 cpu_port = cpu_dp->index;
578-
int count = 0;
579-
580-
if (cpu_dp->ethtool_ops.get_sset_count) {
581-
count = cpu_dp->ethtool_ops.get_sset_count(dev, ETH_SS_STATS);
582-
cpu_dp->ethtool_ops.get_ethtool_stats(dev, stats, data);
583-
}
584-
585-
if (ds->ops->get_ethtool_stats)
586-
ds->ops->get_ethtool_stats(ds, cpu_port, data + count);
587-
}
588-
589-
static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset)
590-
{
591-
struct dsa_switch_tree *dst = dev->dsa_ptr;
592-
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
593-
struct dsa_switch *ds = cpu_dp->ds;
594-
int count = 0;
595-
596-
if (cpu_dp->ethtool_ops.get_sset_count)
597-
count += cpu_dp->ethtool_ops.get_sset_count(dev, sset);
598-
599-
if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
600-
count += ds->ops->get_sset_count(ds);
601-
602-
return count;
603-
}
604-
605-
static void dsa_cpu_port_get_strings(struct net_device *dev,
606-
uint32_t stringset, uint8_t *data)
607-
{
608-
struct dsa_switch_tree *dst = dev->dsa_ptr;
609-
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
610-
struct dsa_switch *ds = cpu_dp->ds;
611-
s8 cpu_port = cpu_dp->index;
612-
int len = ETH_GSTRING_LEN;
613-
int mcount = 0, count;
614-
unsigned int i;
615-
uint8_t pfx[4];
616-
uint8_t *ndata;
617-
618-
snprintf(pfx, sizeof(pfx), "p%.2d", cpu_port);
619-
/* We do not want to be NULL-terminated, since this is a prefix */
620-
pfx[sizeof(pfx) - 1] = '_';
621-
622-
if (cpu_dp->ethtool_ops.get_sset_count) {
623-
mcount = cpu_dp->ethtool_ops.get_sset_count(dev, ETH_SS_STATS);
624-
cpu_dp->ethtool_ops.get_strings(dev, stringset, data);
625-
}
626-
627-
if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
628-
ndata = data + mcount * len;
629-
/* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
630-
* the output after to prepend our CPU port prefix we
631-
* constructed earlier
632-
*/
633-
ds->ops->get_strings(ds, cpu_port, ndata);
634-
count = ds->ops->get_sset_count(ds);
635-
for (i = 0; i < count; i++) {
636-
memmove(ndata + (i * len + sizeof(pfx)),
637-
ndata + i * len, len - sizeof(pfx));
638-
memcpy(ndata + i * len, pfx, sizeof(pfx));
639-
}
640-
}
641-
}
642-
643570
static void dsa_slave_get_ethtool_stats(struct net_device *dev,
644571
struct ethtool_stats *stats,
645572
uint64_t *data)
@@ -976,13 +903,6 @@ static void dsa_slave_get_stats64(struct net_device *dev,
976903
}
977904
}
978905

979-
void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops)
980-
{
981-
ops->get_sset_count = dsa_cpu_port_get_sset_count;
982-
ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats;
983-
ops->get_strings = dsa_cpu_port_get_strings;
984-
}
985-
986906
static int dsa_slave_get_rxnfc(struct net_device *dev,
987907
struct ethtool_rxnfc *nfc, u32 *rule_locs)
988908
{

0 commit comments

Comments
 (0)