can: kvaser_usb: Add devlink port support

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 <mailhol.vincent@wanadoo.fr>
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://patch.msgid.link/20250725123452.41-11-extja@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Jimmy Assarsson 2025-07-25 14:34:51 +02:00 committed by Marc Kleine-Budde
parent 8720aed90c
commit aa6a5c995e
3 changed files with 41 additions and 3 deletions

View File

@ -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,

View File

@ -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;

View File

@ -5,6 +5,7 @@
*/
#include "kvaser_usb.h"
#include <linux/netdevice.h>
#include <net/devlink.h>
#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);
}