Register each CAN channel of the device as an devlink physical port. This makes it easier to get device information for a given network interface (i.e. can2). Example output: $ devlink dev usb/1-1.3:1.0 $ devlink port usb/1-1.3:1.0/0: type eth netdev can0 flavour physical port 0 splittable false usb/1-1.3:1.0/1: type eth netdev can1 flavour physical port 1 splittable false $ devlink port show can1 usb/1-1.3:1.0/1: type eth netdev can1 flavour physical port 0 splittable false $ devlink dev info usb/1-1.3:1.0: driver kvaser_usb serial_number 1020 versions: fixed: board.rev 1 board.id 7330130009653 running: fw 3.22.527 $ ethtool -i can1 driver: kvaser_usb version: 6.12.10-arch1-1 firmware-version: 3.22.527 expansion-rom-version: bus-info: 1-1.3:1.0 supports-statistics: no supports-test: no supports-eeprom-access: no supports-register-dump: no supports-priv-flags: no Reviewed-by: Vincent Mailhol Signed-off-by: Jimmy Assarsson --- Changes in v3: - Add tag Reviewed-by Vincent Mailhol Changes in v2: - Add two space indentation to terminal output. Suggested by Vincent Mailhol [1] [1] https://lore.kernel.org/linux-can/20250723083236.9-1-extja@kvaser.com/T/#m31ee4aad13ee29d5559b56fdce842609ae4f67c5 drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 4 +++ .../net/can/usb/kvaser_usb/kvaser_usb_core.c | 15 ++++++++--- .../can/usb/kvaser_usb/kvaser_usb_devlink.c | 25 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h index d5f913ac9b44..46a1b6907a50 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h @@ -131,6 +131,7 @@ struct kvaser_usb { struct kvaser_usb_net_priv { struct can_priv can; + struct devlink_port devlink_port; struct can_berr_counter bec; /* subdriver-specific data */ @@ -229,6 +230,9 @@ extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops; extern const struct devlink_ops kvaser_usb_devlink_ops; +int kvaser_usb_devlink_port_register(struct kvaser_usb_net_priv *priv); +void kvaser_usb_devlink_port_unregister(struct kvaser_usb_net_priv *priv); + void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv); int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index b9b2e120a5cd..90e77fa0ff4a 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -818,6 +818,7 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) if (ops->dev_remove_channel) ops->dev_remove_channel(priv); + kvaser_usb_devlink_port_unregister(priv); free_candev(priv->netdev); } } @@ -891,20 +892,28 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) if (ops->dev_init_channel) { err = ops->dev_init_channel(priv); if (err) - goto err; + goto candev_free; + } + + err = kvaser_usb_devlink_port_register(priv); + if (err) { + dev_err(&dev->intf->dev, "Failed to register devlink port\n"); + goto candev_free; } err = register_candev(netdev); if (err) { dev_err(&dev->intf->dev, "Failed to register CAN device\n"); - goto err; + goto unregister_devlink_port; } netdev_dbg(netdev, "device registered\n"); return 0; -err: +unregister_devlink_port: + kvaser_usb_devlink_port_unregister(priv); +candev_free: free_candev(netdev); dev->nets[channel] = NULL; return err; diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c index aa06bd1fa125..e838b82298ae 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c @@ -5,6 +5,7 @@ */ #include "kvaser_usb.h" +#include #include #define KVASER_USB_EAN_MSB 0x00073301 @@ -60,3 +61,27 @@ static int kvaser_usb_devlink_info_get(struct devlink *devlink, const struct devlink_ops kvaser_usb_devlink_ops = { .info_get = kvaser_usb_devlink_info_get, }; + +int kvaser_usb_devlink_port_register(struct kvaser_usb_net_priv *priv) +{ + int ret; + struct devlink_port_attrs attrs = { + .flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL, + .phys.port_number = priv->channel, + }; + devlink_port_attrs_set(&priv->devlink_port, &attrs); + + ret = devlink_port_register(priv_to_devlink(priv->dev), + &priv->devlink_port, priv->channel); + if (ret) + return ret; + + SET_NETDEV_DEVLINK_PORT(priv->netdev, &priv->devlink_port); + + return 0; +} + +void kvaser_usb_devlink_port_unregister(struct kvaser_usb_net_priv *priv) +{ + devlink_port_unregister(&priv->devlink_port); +} -- 2.49.0