Skip to content

Commit 0c73c52

Browse files
ffainellidavem330
authored andcommitted
net: dsa: Initialize CPU port ethtool ops per tree
Now that we can properly support multiple distinct trees in the system, using a global variable: dsa_cpu_port_ethtool_ops is getting clobbered as soon as the second switch tree gets probed, and we don't want that. We need to move this to be dynamically allocated, and since we can't really be comparing addresses anymore to determine first time initialization versus any other times, just move this to dsa.c and dsa2.c where the remainder of the dst/ds initialization happens. The operations teardown restores the master netdev's ethtool_ops to its original ethtool_ops pointer (typically within the Ethernet driver) Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent af42192 commit 0c73c52

File tree

5 files changed

+50
-10
lines changed

5 files changed

+50
-10
lines changed

include/net/dsa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct dsa_switch_tree {
116116
* Original copy of the master netdev ethtool_ops
117117
*/
118118
struct ethtool_ops master_ethtool_ops;
119+
const struct ethtool_ops *master_orig_ethtool_ops;
119120

120121
/*
121122
* The switch and port to which the CPU is attached.

net/dsa/dsa.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,41 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
266266
return ops;
267267
}
268268

269+
int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds)
270+
{
271+
struct net_device *master;
272+
struct ethtool_ops *cpu_ops;
273+
274+
master = ds->dst->master_netdev;
275+
if (ds->master_netdev)
276+
master = ds->master_netdev;
277+
278+
cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL);
279+
if (!cpu_ops)
280+
return -ENOMEM;
281+
282+
memcpy(&ds->dst->master_ethtool_ops, master->ethtool_ops,
283+
sizeof(struct ethtool_ops));
284+
ds->dst->master_orig_ethtool_ops = master->ethtool_ops;
285+
memcpy(cpu_ops, &ds->dst->master_ethtool_ops,
286+
sizeof(struct ethtool_ops));
287+
dsa_cpu_port_ethtool_init(cpu_ops);
288+
master->ethtool_ops = cpu_ops;
289+
290+
return 0;
291+
}
292+
293+
void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds)
294+
{
295+
struct net_device *master;
296+
297+
master = ds->dst->master_netdev;
298+
if (ds->master_netdev)
299+
master = ds->master_netdev;
300+
301+
master->ethtool_ops = ds->dst->master_orig_ethtool_ops;
302+
}
303+
269304
static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
270305
{
271306
struct dsa_switch_driver *drv = ds->drv;
@@ -379,6 +414,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
379414
ret = 0;
380415
}
381416

417+
ret = dsa_cpu_port_ethtool_setup(ds);
418+
if (ret)
419+
return ret;
420+
382421
#ifdef CONFIG_NET_DSA_HWMON
383422
/* If the switch provides a temperature sensor,
384423
* register with hardware monitoring subsystem.
@@ -963,6 +1002,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
9631002
dsa_switch_destroy(ds);
9641003
}
9651004

1005+
dsa_cpu_port_ethtool_restore(dst->ds[0]);
1006+
9661007
dev_put(dst->master_netdev);
9671008
}
9681009

net/dsa/dsa2.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
394394
return err;
395395
}
396396

397+
err = dsa_cpu_port_ethtool_setup(dst->ds[0]);
398+
if (err)
399+
return err;
400+
397401
/* If we use a tagging format that doesn't have an ethertype
398402
* field, make sure that all packets from this point on get
399403
* sent to the tag format's receive function.
@@ -429,6 +433,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
429433
dsa_ds_unapply(dst, ds);
430434
}
431435

436+
dsa_cpu_port_ethtool_restore(dst->ds[0]);
437+
432438
pr_info("DSA: tree %d unapplied\n", dst->tree);
433439
dst->applied = false;
434440
}

net/dsa/dsa_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
5454
struct device_node *port_dn, int port);
5555
void dsa_cpu_dsa_destroy(struct device_node *port_dn);
5656
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
57+
int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds);
58+
void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds);
5759

5860
/* slave.c */
5961
extern const struct dsa_device_ops notag_netdev_ops;

net/dsa/slave.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
892892
.get_eee = dsa_slave_get_eee,
893893
};
894894

895-
static struct ethtool_ops dsa_cpu_port_ethtool_ops;
896-
897895
static const struct net_device_ops dsa_slave_netdev_ops = {
898896
.ndo_open = dsa_slave_open,
899897
.ndo_stop = dsa_slave_close,
@@ -1126,14 +1124,6 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
11261124

11271125
slave_dev->features = master->vlan_features;
11281126
slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
1129-
if (master->ethtool_ops != &dsa_cpu_port_ethtool_ops) {
1130-
memcpy(&dst->master_ethtool_ops, master->ethtool_ops,
1131-
sizeof(struct ethtool_ops));
1132-
memcpy(&dsa_cpu_port_ethtool_ops, &dst->master_ethtool_ops,
1133-
sizeof(struct ethtool_ops));
1134-
dsa_cpu_port_ethtool_init(&dsa_cpu_port_ethtool_ops);
1135-
master->ethtool_ops = &dsa_cpu_port_ethtool_ops;
1136-
}
11371127
eth_hw_addr_inherit(slave_dev, master);
11381128
slave_dev->priv_flags |= IFF_NO_QUEUE;
11391129
slave_dev->netdev_ops = &dsa_slave_netdev_ops;

0 commit comments

Comments
 (0)