]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
can: kvaser_usb: Add devlink support
authorJimmy Assarsson <extja@kvaser.com>
Fri, 25 Jul 2025 12:34:49 +0000 (14:34 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 25 Jul 2025 16:01:21 +0000 (18:01 +0200)
Add devlink support at device level.

Example output:
  $ devlink dev
  usb/1-1.3:1.0

  $ devlink dev info
  usb/1-1.3:1.0:
    driver kvaser_usb

Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://patch.msgid.link/20250725123452.41-9-extja@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/Kconfig
drivers/net/can/usb/kvaser_usb/Makefile
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c [new file with mode: 0644]

index 9dae0c71a2e1b8c3abb4b064a048c7ed2a3ace15..a7547a83120e841c920b58191fead9a96283a51c 100644 (file)
@@ -66,6 +66,7 @@ config CAN_GS_USB
 
 config CAN_KVASER_USB
        tristate "Kvaser CAN/USB interface"
+       select NET_DEVLINK
        help
          This driver adds support for Kvaser CAN/USB devices like Kvaser
          Leaf Light, Kvaser USBcan II and Kvaser Memorator Pro 5xHS.
index cf260044f0b9dc63f93264c28e4e35810d65a0d7..41b4a11555aaa70e76964738ea514866a7ee6020 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
-kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o
+kvaser_usb-y = kvaser_usb_core.o kvaser_usb_devlink.o kvaser_usb_leaf.o kvaser_usb_hydra.o
index 35c2cf3d44864ac2c2810dc01b46ee631517540b..d5f913ac9b440e6b21e7294e9af458f89116da1f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/usb.h>
+#include <net/devlink.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -226,6 +227,8 @@ struct kvaser_usb_dev_cfg {
 extern const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops;
 extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops;
 
+extern const struct devlink_ops kvaser_usb_devlink_ops;
+
 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,
index 2313fbc1a2c3f0c3113e9376251e1f119e743f2d..b9b2e120a5cd2e9912b860a4bdb06db5beec91ef 100644 (file)
@@ -914,6 +914,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
        struct kvaser_usb *dev;
+       struct devlink *devlink;
        int err;
        int i;
        const struct kvaser_usb_driver_info *driver_info;
@@ -923,17 +924,20 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        if (!driver_info)
                return -ENODEV;
 
-       dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
+       devlink = devlink_alloc(&kvaser_usb_devlink_ops, sizeof(*dev), &intf->dev);
+       if (!devlink)
                return -ENOMEM;
 
+       dev = devlink_priv(devlink);
        dev->intf = intf;
        dev->driver_info = driver_info;
        ops = driver_info->ops;
 
        err = ops->dev_setup_endpoints(dev);
-       if (err)
-               return dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)");
+       if (err) {
+               dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)");
+               goto free_devlink;
+       }
 
        dev->udev = interface_to_usbdev(intf);
 
@@ -944,50 +948,66 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        dev->card_data.ctrlmode_supported = 0;
        dev->card_data.capabilities = 0;
        err = ops->dev_init_card(dev);
-       if (err)
-               return dev_err_probe(&intf->dev, err,
-                                    "Failed to initialize card\n");
+       if (err) {
+               dev_err_probe(&intf->dev, err,
+                             "Failed to initialize card\n");
+               goto free_devlink;
+       }
 
        err = ops->dev_get_software_info(dev);
-       if (err)
-               return dev_err_probe(&intf->dev, err,
-                                    "Cannot get software info\n");
+       if (err) {
+               dev_err_probe(&intf->dev, err,
+                             "Cannot get software info\n");
+               goto free_devlink;
+       }
 
        if (ops->dev_get_software_details) {
                err = ops->dev_get_software_details(dev);
-               if (err)
-                       return dev_err_probe(&intf->dev, err,
-                                            "Cannot get software details\n");
+               if (err) {
+                       dev_err_probe(&intf->dev, err,
+                                     "Cannot get software details\n");
+                       goto free_devlink;
+               }
        }
 
-       if (WARN_ON(!dev->cfg))
-               return -ENODEV;
+       if (WARN_ON(!dev->cfg)) {
+               err = -ENODEV;
+               goto free_devlink;
+       }
 
        dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
 
        err = ops->dev_get_card_info(dev);
-       if (err)
-               return dev_err_probe(&intf->dev, err,
-                                    "Cannot get card info\n");
+       if (err) {
+               dev_err_probe(&intf->dev, err,
+                             "Cannot get card info\n");
+               goto free_devlink;
+       }
 
        if (ops->dev_get_capabilities) {
                err = ops->dev_get_capabilities(dev);
                if (err) {
-                       kvaser_usb_remove_interfaces(dev);
-                       return dev_err_probe(&intf->dev, err,
-                                            "Cannot get capabilities\n");
+                       dev_err_probe(&intf->dev, err,
+                                     "Cannot get capabilities\n");
+                       goto remove_interfaces;
                }
        }
 
        for (i = 0; i < dev->nchannels; i++) {
                err = kvaser_usb_init_one(dev, i);
-               if (err) {
-                       kvaser_usb_remove_interfaces(dev);
-                       return err;
-               }
+               if (err)
+                       goto remove_interfaces;
        }
+       devlink_register(devlink);
 
        return 0;
+
+remove_interfaces:
+       kvaser_usb_remove_interfaces(dev);
+free_devlink:
+       devlink_free(devlink);
+
+       return err;
 }
 
 static void kvaser_usb_disconnect(struct usb_interface *intf)
@@ -1000,6 +1020,8 @@ static void kvaser_usb_disconnect(struct usb_interface *intf)
                return;
 
        kvaser_usb_remove_interfaces(dev);
+       devlink_unregister(priv_to_devlink(dev));
+       devlink_free(priv_to_devlink(dev));
 }
 
 static struct usb_driver kvaser_usb_driver = {
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c
new file mode 100644 (file)
index 0000000..dbe7fa6
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/* kvaser_usb devlink functions
+ *
+ * Copyright (C) 2025 KVASER AB, Sweden. All rights reserved.
+ */
+#include "kvaser_usb.h"
+
+#include <net/devlink.h>
+
+const struct devlink_ops kvaser_usb_devlink_ops = {
+};