Skip to content

Commit 6c30384

Browse files
vladimirolteankuba-moo
authored andcommitted
net: mscc: ocelot: register devlink ports
Add devlink integration into the mscc_ocelot switchdev driver. All physical ports (i.e. the unused ones as well) except the CPU port module at ocelot->num_phys_ports are registered with devlink, and that requires keeping the devlink_port structure outside struct ocelot_port_private, since the latter has a 1:1 mapping with a struct net_device (which does not exist for unused ports). Since we use devlink_port_type_eth_set to link the devlink port to the net_device, we can as well remove the .ndo_get_phys_port_name and .ndo_get_port_parent_id implementations, since devlink takes care of retrieving the port name and number automatically, once .ndo_get_devlink_port is implemented. Note that the felix DSA driver is already integrated with devlink by default, since that is a thing that the DSA core takes care of. This is the reason why these devlink stubs were put in ocelot_net.c and not in the common library. It is also the reason why ocelot::devlink is a pointer and not a full structure embedded inside struct ocelot: because the mscc_ocelot driver allocates that by itself (as the container of struct ocelot, in fact), but in the case of felix, it is DSA who allocates the devlink, and felix just propagates the pointer towards struct ocelot. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent c6c65d4 commit 6c30384

File tree

4 files changed

+148
-44
lines changed

4 files changed

+148
-44
lines changed

drivers/net/ethernet/mscc/ocelot.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,15 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
121121

122122
int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
123123
struct phy_device *phy);
124+
int ocelot_devlink_init(struct ocelot *ocelot);
125+
void ocelot_devlink_teardown(struct ocelot *ocelot);
126+
int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
127+
enum devlink_port_flavour flavour);
128+
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port);
124129

125130
extern struct notifier_block ocelot_netdevice_nb;
126131
extern struct notifier_block ocelot_switchdev_nb;
127132
extern struct notifier_block ocelot_switchdev_blocking_nb;
133+
extern const struct devlink_ops ocelot_devlink_ops;
128134

129135
#endif

drivers/net/ethernet/mscc/ocelot_net.c

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,43 @@
88
#include "ocelot.h"
99
#include "ocelot_vcap.h"
1010

11+
const struct devlink_ops ocelot_devlink_ops = {
12+
};
13+
14+
int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
15+
enum devlink_port_flavour flavour)
16+
{
17+
struct devlink_port *dlp = &ocelot->devlink_ports[port];
18+
int id_len = sizeof(ocelot->base_mac);
19+
struct devlink *dl = ocelot->devlink;
20+
struct devlink_port_attrs attrs = {};
21+
22+
memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
23+
attrs.switch_id.id_len = id_len;
24+
attrs.phys.port_number = port;
25+
attrs.flavour = flavour;
26+
27+
devlink_port_attrs_set(dlp, &attrs);
28+
29+
return devlink_port_register(dl, dlp, port);
30+
}
31+
32+
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port)
33+
{
34+
struct devlink_port *dlp = &ocelot->devlink_ports[port];
35+
36+
devlink_port_unregister(dlp);
37+
}
38+
39+
static struct devlink_port *ocelot_get_devlink_port(struct net_device *dev)
40+
{
41+
struct ocelot_port_private *priv = netdev_priv(dev);
42+
struct ocelot *ocelot = priv->port.ocelot;
43+
int port = priv->chip_port;
44+
45+
return &ocelot->devlink_ports[port];
46+
}
47+
1148
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
1249
struct flow_cls_offload *f,
1350
bool ingress)
@@ -525,20 +562,6 @@ static void ocelot_set_rx_mode(struct net_device *dev)
525562
__dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
526563
}
527564

528-
static int ocelot_port_get_phys_port_name(struct net_device *dev,
529-
char *buf, size_t len)
530-
{
531-
struct ocelot_port_private *priv = netdev_priv(dev);
532-
int port = priv->chip_port;
533-
int ret;
534-
535-
ret = snprintf(buf, len, "p%d", port);
536-
if (ret >= len)
537-
return -EINVAL;
538-
539-
return 0;
540-
}
541-
542565
static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
543566
{
544567
struct ocelot_port_private *priv = netdev_priv(dev);
@@ -689,18 +712,6 @@ static int ocelot_set_features(struct net_device *dev,
689712
return 0;
690713
}
691714

692-
static int ocelot_get_port_parent_id(struct net_device *dev,
693-
struct netdev_phys_item_id *ppid)
694-
{
695-
struct ocelot_port_private *priv = netdev_priv(dev);
696-
struct ocelot *ocelot = priv->port.ocelot;
697-
698-
ppid->id_len = sizeof(ocelot->base_mac);
699-
memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
700-
701-
return 0;
702-
}
703-
704715
static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
705716
{
706717
struct ocelot_port_private *priv = netdev_priv(dev);
@@ -727,7 +738,6 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
727738
.ndo_stop = ocelot_port_stop,
728739
.ndo_start_xmit = ocelot_port_xmit,
729740
.ndo_set_rx_mode = ocelot_set_rx_mode,
730-
.ndo_get_phys_port_name = ocelot_port_get_phys_port_name,
731741
.ndo_set_mac_address = ocelot_port_set_mac_address,
732742
.ndo_get_stats64 = ocelot_get_stats64,
733743
.ndo_fdb_add = ocelot_port_fdb_add,
@@ -736,9 +746,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
736746
.ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid,
737747
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
738748
.ndo_set_features = ocelot_set_features,
739-
.ndo_get_port_parent_id = ocelot_get_port_parent_id,
740749
.ndo_setup_tc = ocelot_setup_tc,
741750
.ndo_do_ioctl = ocelot_ioctl,
751+
.ndo_get_devlink_port = ocelot_get_devlink_port,
742752
};
743753

744754
struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port)

drivers/net/ethernet/mscc/ocelot_vsc7514.c

Lines changed: 102 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,14 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
10511051
.enable = ocelot_ptp_enable,
10521052
};
10531053

1054+
static void mscc_ocelot_teardown_devlink_ports(struct ocelot *ocelot)
1055+
{
1056+
int port;
1057+
1058+
for (port = 0; port < ocelot->num_phys_ports; port++)
1059+
ocelot_port_devlink_teardown(ocelot, port);
1060+
}
1061+
10541062
static void mscc_ocelot_release_ports(struct ocelot *ocelot)
10551063
{
10561064
int port;
@@ -1078,28 +1086,44 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
10781086
{
10791087
struct ocelot *ocelot = platform_get_drvdata(pdev);
10801088
struct device_node *portnp;
1081-
int err;
1089+
bool *registered_ports;
1090+
int port, err;
1091+
u32 reg;
10821092

10831093
ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
10841094
sizeof(struct ocelot_port *), GFP_KERNEL);
10851095
if (!ocelot->ports)
10861096
return -ENOMEM;
10871097

1098+
ocelot->devlink_ports = devm_kcalloc(ocelot->dev,
1099+
ocelot->num_phys_ports,
1100+
sizeof(*ocelot->devlink_ports),
1101+
GFP_KERNEL);
1102+
if (!ocelot->devlink_ports)
1103+
return -ENOMEM;
1104+
1105+
registered_ports = kcalloc(ocelot->num_phys_ports, sizeof(bool),
1106+
GFP_KERNEL);
1107+
if (!registered_ports)
1108+
return -ENOMEM;
1109+
10881110
for_each_available_child_of_node(ports, portnp) {
10891111
struct ocelot_port_private *priv;
10901112
struct ocelot_port *ocelot_port;
10911113
struct device_node *phy_node;
1114+
struct devlink_port *dlp;
10921115
phy_interface_t phy_mode;
10931116
struct phy_device *phy;
10941117
struct regmap *target;
10951118
struct resource *res;
10961119
struct phy *serdes;
10971120
char res_name[8];
1098-
u32 port;
10991121

1100-
if (of_property_read_u32(portnp, "reg", &port))
1122+
if (of_property_read_u32(portnp, "reg", &reg))
11011123
continue;
11021124

1125+
port = reg;
1126+
11031127
snprintf(res_name, sizeof(res_name), "port%d", port);
11041128

11051129
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -1117,15 +1141,26 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11171141
if (!phy)
11181142
continue;
11191143

1144+
err = ocelot_port_devlink_init(ocelot, port,
1145+
DEVLINK_PORT_FLAVOUR_PHYSICAL);
1146+
if (err) {
1147+
of_node_put(portnp);
1148+
goto out_teardown;
1149+
}
1150+
11201151
err = ocelot_probe_port(ocelot, port, target, phy);
11211152
if (err) {
11221153
of_node_put(portnp);
1123-
return err;
1154+
goto out_teardown;
11241155
}
11251156

1157+
registered_ports[port] = true;
1158+
11261159
ocelot_port = ocelot->ports[port];
11271160
priv = container_of(ocelot_port, struct ocelot_port_private,
11281161
port);
1162+
dlp = &ocelot->devlink_ports[port];
1163+
devlink_port_type_eth_set(dlp, priv->dev);
11291164

11301165
of_get_phy_mode(portnp, &phy_mode);
11311166

@@ -1150,7 +1185,8 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11501185
"invalid phy mode for port%d, (Q)SGMII only\n",
11511186
port);
11521187
of_node_put(portnp);
1153-
return -EINVAL;
1188+
err = -EINVAL;
1189+
goto out_teardown;
11541190
}
11551191

11561192
serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
@@ -1164,20 +1200,54 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11641200
port);
11651201

11661202
of_node_put(portnp);
1167-
return err;
1203+
goto out_teardown;
11681204
}
11691205

11701206
priv->serdes = serdes;
11711207
}
11721208

1209+
/* Initialize unused devlink ports at the end */
1210+
for (port = 0; port < ocelot->num_phys_ports; port++) {
1211+
if (registered_ports[port])
1212+
continue;
1213+
1214+
err = ocelot_port_devlink_init(ocelot, port,
1215+
DEVLINK_PORT_FLAVOUR_UNUSED);
1216+
if (err) {
1217+
while (port-- >= 0) {
1218+
if (!registered_ports[port])
1219+
continue;
1220+
ocelot_port_devlink_teardown(ocelot, port);
1221+
}
1222+
1223+
goto out_teardown;
1224+
}
1225+
}
1226+
1227+
kfree(registered_ports);
1228+
11731229
return 0;
1230+
1231+
out_teardown:
1232+
/* Unregister the network interfaces */
1233+
mscc_ocelot_release_ports(ocelot);
1234+
/* Tear down devlink ports for the registered network interfaces */
1235+
for (port = 0; port < ocelot->num_phys_ports; port++) {
1236+
if (!registered_ports[port])
1237+
continue;
1238+
1239+
ocelot_port_devlink_teardown(ocelot, port);
1240+
}
1241+
kfree(registered_ports);
1242+
return err;
11741243
}
11751244

11761245
static int mscc_ocelot_probe(struct platform_device *pdev)
11771246
{
11781247
struct device_node *np = pdev->dev.of_node;
11791248
int err, irq_xtr, irq_ptp_rdy;
11801249
struct device_node *ports;
1250+
struct devlink *devlink;
11811251
struct ocelot *ocelot;
11821252
struct regmap *hsio;
11831253
unsigned int i;
@@ -1201,10 +1271,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12011271
if (!np && !pdev->dev.platform_data)
12021272
return -ENODEV;
12031273

1204-
ocelot = devm_kzalloc(&pdev->dev, sizeof(*ocelot), GFP_KERNEL);
1205-
if (!ocelot)
1274+
devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot));
1275+
if (!devlink)
12061276
return -ENOMEM;
12071277

1278+
ocelot = devlink_priv(devlink);
1279+
ocelot->devlink = priv_to_devlink(ocelot);
12081280
platform_set_drvdata(pdev, ocelot);
12091281
ocelot->dev = &pdev->dev;
12101282

@@ -1221,7 +1293,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12211293
ocelot->targets[io_target[i].id] = NULL;
12221294
continue;
12231295
}
1224-
return PTR_ERR(target);
1296+
err = PTR_ERR(target);
1297+
goto out_free_devlink;
12251298
}
12261299

12271300
ocelot->targets[io_target[i].id] = target;
@@ -1230,24 +1303,25 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12301303
hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
12311304
if (IS_ERR(hsio)) {
12321305
dev_err(&pdev->dev, "missing hsio syscon\n");
1233-
return PTR_ERR(hsio);
1306+
err = PTR_ERR(hsio);
1307+
goto out_free_devlink;
12341308
}
12351309

12361310
ocelot->targets[HSIO] = hsio;
12371311

12381312
err = ocelot_chip_init(ocelot, &ocelot_ops);
12391313
if (err)
1240-
return err;
1314+
goto out_free_devlink;
12411315

12421316
irq_xtr = platform_get_irq_byname(pdev, "xtr");
12431317
if (irq_xtr < 0)
1244-
return -ENODEV;
1318+
goto out_free_devlink;
12451319

12461320
err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
12471321
ocelot_xtr_irq_handler, IRQF_ONESHOT,
12481322
"frame extraction", ocelot);
12491323
if (err)
1250-
return err;
1324+
goto out_free_devlink;
12511325

12521326
irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
12531327
if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
@@ -1256,7 +1330,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12561330
IRQF_ONESHOT, "ptp ready",
12571331
ocelot);
12581332
if (err)
1259-
return err;
1333+
goto out_free_devlink;
12601334

12611335
/* Both the PTP interrupt and the PTP bank are available */
12621336
ocelot->ptp = 1;
@@ -1265,7 +1339,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12651339
ports = of_get_child_by_name(np, "ethernet-ports");
12661340
if (!ports) {
12671341
dev_err(ocelot->dev, "no ethernet-ports child node found\n");
1268-
return -ENODEV;
1342+
err = -ENODEV;
1343+
goto out_free_devlink;
12691344
}
12701345

12711346
ocelot->num_phys_ports = of_get_child_count(ports);
@@ -1280,10 +1355,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12801355
if (err)
12811356
goto out_put_ports;
12821357

1283-
err = mscc_ocelot_init_ports(pdev, ports);
1358+
err = devlink_register(devlink, ocelot->dev);
12841359
if (err)
12851360
goto out_ocelot_deinit;
12861361

1362+
err = mscc_ocelot_init_ports(pdev, ports);
1363+
if (err)
1364+
goto out_ocelot_devlink_unregister;
1365+
12871366
if (ocelot->ptp) {
12881367
err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
12891368
if (err) {
@@ -1303,10 +1382,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
13031382

13041383
return 0;
13051384

1385+
out_ocelot_devlink_unregister:
1386+
devlink_unregister(devlink);
13061387
out_ocelot_deinit:
13071388
ocelot_deinit(ocelot);
13081389
out_put_ports:
13091390
of_node_put(ports);
1391+
out_free_devlink:
1392+
devlink_free(devlink);
13101393
return err;
13111394
}
13121395

@@ -1316,10 +1399,13 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
13161399

13171400
ocelot_deinit_timestamp(ocelot);
13181401
mscc_ocelot_release_ports(ocelot);
1402+
mscc_ocelot_teardown_devlink_ports(ocelot);
1403+
devlink_unregister(ocelot->devlink);
13191404
ocelot_deinit(ocelot);
13201405
unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
13211406
unregister_switchdev_notifier(&ocelot_switchdev_nb);
13221407
unregister_netdevice_notifier(&ocelot_netdevice_nb);
1408+
devlink_free(ocelot->devlink);
13231409

13241410
return 0;
13251411
}

0 commit comments

Comments
 (0)