Add devlink integration into the mscc_ocelot switchdev driver. Only the probed interfaces are registered with devlink, because for convenience, struct devlink_port was included into struct ocelot_port_private, which is only initialized for the ports that are used.
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. Signed-off-by: Vladimir Oltean <vladimir.olt...@nxp.com> --- drivers/net/ethernet/mscc/ocelot.h | 4 + drivers/net/ethernet/mscc/ocelot_net.c | 92 ++++++++++++++++++++++ drivers/net/ethernet/mscc/ocelot_vsc7514.c | 7 ++ include/soc/mscc/ocelot.h | 1 + 4 files changed, 104 insertions(+) diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 8eae68e0fd0b..3fee5f565920 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -65,6 +65,8 @@ struct ocelot_port_private { struct phy *serdes; struct ocelot_port_tc tc; + + struct devlink_port devlink_port; }; struct ocelot_dump_ctx { @@ -106,6 +108,8 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target, struct phy_device *phy); +int ocelot_devlink_init(struct ocelot *ocelot); +void ocelot_devlink_teardown(struct ocelot *ocelot); extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index d3c03942546d..a11e5e7a0228 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -8,6 +8,98 @@ #include "ocelot.h" #include "ocelot_vcap.h" +struct ocelot_devlink_private { + struct ocelot *ocelot; +}; + +static const struct devlink_ops ocelot_devlink_ops = { +}; + +static int ocelot_port_devlink_init(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct devlink *dl = ocelot->devlink; + struct devlink_port_attrs attrs = {}; + struct ocelot_port_private *priv; + struct devlink_port *dlp; + + if (!ocelot_port) + return 0; + + priv = container_of(ocelot_port, struct ocelot_port_private, port); + dlp = &priv->devlink_port; + + attrs.phys.port_number = port; + + if (priv->dev) + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + else + attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED; + + devlink_port_attrs_set(dlp, &attrs); + + return devlink_port_register(dl, dlp, port); +} + +static void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct ocelot_port_private *priv; + struct devlink_port *dlp; + + if (!ocelot_port) + return; + + priv = container_of(ocelot_port, struct ocelot_port_private, port); + dlp = &priv->devlink_port; + + devlink_port_unregister(dlp); +} + +int ocelot_devlink_init(struct ocelot *ocelot) +{ + struct ocelot_devlink_private *dl_priv; + int port, err; + + ocelot->devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*dl_priv)); + if (!ocelot->devlink) + return -ENOMEM; + dl_priv = devlink_priv(ocelot->devlink); + dl_priv->ocelot = ocelot; + + err = devlink_register(ocelot->devlink, ocelot->dev); + if (err) + goto free_devlink; + + for (port = 0; port < ocelot->num_phys_ports; port++) { + err = ocelot_port_devlink_init(ocelot, port); + if (err) { + while (port-- > 0) + ocelot_port_devlink_teardown(ocelot, port); + goto unregister_devlink; + } + } + + return 0; + +unregister_devlink: + devlink_unregister(ocelot->devlink); +free_devlink: + devlink_free(ocelot->devlink); + return err; +} + +void ocelot_devlink_teardown(struct ocelot *ocelot) +{ + int port; + + for (port = 0; port < ocelot->num_phys_ports; port++) + ocelot_port_devlink_teardown(ocelot, port); + + devlink_unregister(ocelot->devlink); + devlink_free(ocelot->devlink); +} + int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv, struct flow_cls_offload *f, bool ingress) diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index ea55f4d20ecc..6512ddeafd50 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -1292,6 +1292,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev) } } + err = ocelot_devlink_init(ocelot); + if (err) { + mscc_ocelot_release_ports(ocelot); + goto out_put_ports; + } + register_netdevice_notifier(&ocelot_netdevice_nb); register_switchdev_notifier(&ocelot_switchdev_nb); register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); @@ -1307,6 +1313,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev) { struct ocelot *ocelot = platform_get_drvdata(pdev); + ocelot_devlink_teardown(ocelot); ocelot_deinit_timestamp(ocelot); mscc_ocelot_release_ports(ocelot); ocelot_deinit(ocelot); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index c6153c73dbfe..19ce7ea11163 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -599,6 +599,7 @@ struct ocelot_port { struct ocelot { struct device *dev; + struct devlink *devlink; const struct ocelot_ops *ops; struct regmap *targets[TARGET_MAX]; -- 2.25.1