[RFC PATCH 14/14] !!! DO NOT MERGE !!! can: add dummyxl driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A dummy driver to test the CAN XL netlink.

I wrote this in less than one hour. I will drop this from the series
once this is not an RFC anymore.

To test:

  1. Apply this series, compile it and load the driver. Example:

       modprobe dummyxl

     From now on, I will assume that the can device name is
     can0. Adjust below commands accordingly to your setup.

  2. Apply the other series to the iproute2-next [1].

  3. Using the compiled ip tool, send the CAN bittiming and set the
     interface up. Example:

       ./ip/ip link set can0 up type can bitrate 500000 fd on dbitrate 2000000 xl on xl-dbitrate 8000000

  4. The kernel message log should show the bittiming parameters of
     the dummyxl driver. Like that:

       can0: CAN CC nominal bittiming:
       can0: 	bitrate: 500000
       can0: 	sample_point: 875
       can0: 	tq: 12
       can0: 	prop_seg: 69
       can0: 	phase_seg1: 70
       can0: 	phase_seg2: 20
       can0: 	sjw: 10
       can0: 	brp: 1
       can0:
       can0: CAN FD databittiming:
       can0: 	bitrate: 2000000
       can0: 	sample_point: 750
       can0: 	tq: 12
       can0: 	prop_seg: 14
       can0: 	phase_seg1: 15
       can0: 	phase_seg2: 10
       can0: 	sjw: 5
       can0: 	brp: 1
       can0: 	CAN FD TDC:
       can0: 		tdcv: 0
       can0: 		tdco: 30
       can0: 		tdcf: 0
       can0:
       can0: CAN XL databittiming:
       can0: 	bitrate: 8000000
       can0: 	sample_point: 700
       can0: 	tq: 12
       can0: 	prop_seg: 3
       can0: 	phase_seg1: 3
       can0: 	phase_seg2: 3
       can0: 	sjw: 1
       can0: 	brp: 1
       can0: 	CAN XL TDC:
       can0: 		tdcv: 0
       can0: 		tdco: 7
       can0: 		tdcf: 0
       can0:
       can0: dummyxl is up

  5. Use a recent version of can-utils [2] to generate some CAN
     traffic. For example:

       cangen -m can0

     should generate a mix of Classical CAN, CAN FD and CAN XL
     frames. The dummyxl drivers should then print in the kernel log
     that those frames were well received.

Voila, with this, you are now able to send CAN XL frames to a CAN XL
driver.

[1] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git
[2] https://github.com/linux-can/can-utils

Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
---
 drivers/net/can/Kconfig   |   8 ++
 drivers/net/can/Makefile  |   1 +
 drivers/net/can/dummyxl.c | 224 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+)
 create mode 100644 drivers/net/can/dummyxl.c

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index cf989bea9aa3..a8bc5f4e752f 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -124,6 +124,14 @@ config CAN_CAN327
 
 	  If this driver is built as a module, it will be called can327.
 
+config CAN_DUMMY_XL
+	tristate "Dummy CAN XL"
+	help
+	  A dummy module just to check the CAN XL netlink interface. Do not
+	  merge this.
+
+	  If this driver is built as a module, it will be called dummyxl.
+
 config CAN_FLEXCAN
 	tristate "Support for Freescale FLEXCAN based chips"
 	depends on OF || COLDFIRE || COMPILE_TEST
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index a71db2cfe990..ff8e00fa26e3 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CAN_CAN327)	+= can327.o
 obj-$(CONFIG_CAN_CC770)		+= cc770/
 obj-$(CONFIG_CAN_C_CAN)		+= c_can/
 obj-$(CONFIG_CAN_CTUCANFD)	+= ctucanfd/
+obj-$(CONFIG_CAN_DUMMY_XL)	+= dummyxl.o
 obj-$(CONFIG_CAN_FLEXCAN)	+= flexcan/
 obj-$(CONFIG_CAN_GRCAN)		+= grcan.o
 obj-$(CONFIG_CAN_IFI_CANFD)	+= ifi_canfd/
diff --git a/drivers/net/can/dummyxl.c b/drivers/net/can/dummyxl.c
new file mode 100644
index 000000000000..9f6a2991b0ec
--- /dev/null
+++ b/drivers/net/can/dummyxl.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (c) 2024 Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/units.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/skb.h>
+
+struct dummyxl {
+	struct can_priv can;
+	struct net_device *dev;
+};
+
+static struct dummyxl *dummyxl;
+
+static const struct can_bittiming_const dummyxl_bittiming_const = {
+	.name = "dummyxl nominal",
+	.tseg1_min = 2,
+	.tseg1_max = 256,
+	.tseg2_min = 2,
+	.tseg2_max = 128,
+	.sjw_max = 128,
+	.brp_min = 1,
+	.brp_max = 512,
+	.brp_inc = 1
+};
+
+static const struct can_bittiming_const dummyxl_fd_databittiming_const = {
+	.name = "dummyxl FD",
+	.tseg1_min = 2,
+	.tseg1_max = 256,
+	.tseg2_min = 2,
+	.tseg2_max = 128,
+	.sjw_max = 128,
+	.brp_min = 1,
+	.brp_max = 512,
+	.brp_inc = 1
+};
+
+static const struct can_tdc_const dummyxl_fd_tdc_const = {
+	.tdcv_min = 0,
+	.tdcv_max = 0, /* Manual mode not supported. */
+	.tdco_min = 0,
+	.tdco_max = 127,
+	.tdcf_min = 0,
+	.tdcf_max = 127
+};
+
+static const struct can_bittiming_const dummyxl_xl_databittiming_const = {
+	.name = "dummyxl XL",
+	.tseg1_min = 2,
+	.tseg1_max = 256,
+	.tseg2_min = 2,
+	.tseg2_max = 128,
+	.sjw_max = 128,
+	.brp_min = 1,
+	.brp_max = 512,
+	.brp_inc = 1
+};
+
+static const struct can_tdc_const dummyxl_xl_tdc_const = {
+	.tdcv_min = 0,
+	.tdcv_max = 0, /* Manual mode not supported. */
+	.tdco_min = 0,
+	.tdco_max = 127,
+	.tdcf_min = 0,
+	.tdcf_max = 127
+};
+
+static void dummyxl_print_bittiming(struct net_device *dev, struct can_bittiming *bt)
+{
+	netdev_info(dev, "\tbitrate: %u\n", bt->bitrate);
+	netdev_info(dev, "\tsample_point: %u\n", bt->sample_point);
+	netdev_info(dev, "\ttq: %u\n", bt->tq);
+	netdev_info(dev, "\tprop_seg: %u\n", bt->prop_seg);
+	netdev_info(dev, "\tphase_seg1: %u\n", bt->phase_seg1);
+	netdev_info(dev, "\tphase_seg2: %u\n", bt->phase_seg2);
+	netdev_info(dev, "\tsjw: %u\n", bt->sjw);
+	netdev_info(dev, "\tbrp: %u\n", bt->brp);
+}
+
+static void dummyxl_print_tdc(struct net_device *dev, struct can_tdc *tdc)
+{
+	netdev_info(dev, "\t\ttdcv: %u\n", tdc->tdcv);
+	netdev_info(dev, "\t\ttdco: %u\n", tdc->tdco);
+	netdev_info(dev, "\t\ttdcf: %u\n", tdc->tdcf);
+}
+
+static int dummyxl_netdev_open(struct net_device *dev)
+{
+	struct dummyxl *priv = netdev_priv(dev);
+	struct can_priv *can_priv = &priv->can;
+	int ret;
+
+	netdev_info(dev, "CAN CC nominal bittiming:\n");
+	dummyxl_print_bittiming(dev, &can_priv->bittiming);
+	netdev_info(dev, "\n");
+
+	if (can_priv->ctrlmode & CAN_CTRLMODE_FD) {
+		netdev_info(dev, "CAN FD databittiming:\n");
+		dummyxl_print_bittiming(dev, &can_priv->fd.data_bittiming);
+		if (can_fd_tdc_is_enabled(can_priv)) {
+			netdev_info(dev, "\tCAN FD TDC:\n");
+			dummyxl_print_tdc(dev, &can_priv->fd.tdc);
+		} else {
+			netdev_info(dev, "\tCAN FD TDC is off\n");
+		}
+	} else {
+		netdev_info(dev, "CAN FD is off\n");
+	}
+	netdev_info(dev, "\n");
+
+	if (can_priv->ctrlmode & CAN_CTRLMODE_XL) {
+		netdev_info(dev, "CAN XL databittiming:\n");
+		dummyxl_print_bittiming(dev, &can_priv->xl.data_bittiming);
+		if (can_xl_tdc_is_enabled(can_priv)) {
+			netdev_info(dev, "\tCAN XL TDC:\n");
+			dummyxl_print_tdc(dev, &can_priv->xl.tdc);
+		} else {
+			netdev_info(dev, "\tCAN XL TDC is off\n");
+		}
+	} else {
+		netdev_info(dev, "CAN XL is off\n");
+	}
+	netdev_info(dev, "\n");
+
+	ret = open_candev(dev);
+	if (ret)
+		return ret;
+	netif_start_queue(dev);
+	netdev_info(dev, "dummyxl is up\n");
+
+	return 0;
+}
+
+static int dummyxl_netdev_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	close_candev(dev);
+	netdev_info(dev, "dummyxl is down\n");
+
+	return 0;
+}
+
+static netdev_tx_t dummyxl_start_xmit(struct sk_buff *skb,
+				      struct net_device *dev)
+{
+	if (can_is_canxl_skb(skb))
+		netdev_info(dev, "Received CAN XL skb\n");
+	else if (can_is_canfd_skb(skb))
+		netdev_info(dev, "Received CAN FD skb\n");
+	else if (can_is_can_skb(skb))
+		netdev_info(dev, "Received Classical CAN skb\n");
+	else
+		netdev_info(dev, "Received an odd skb?!\n");
+	kfree_skb(skb);
+	dev->stats.tx_dropped++;
+
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops dummyxl_netdev_ops = {
+	.ndo_open = dummyxl_netdev_open,
+	.ndo_stop = dummyxl_netdev_close,
+	.ndo_start_xmit = dummyxl_start_xmit,
+};
+
+static int __init dummyxl_init(void)
+{
+	struct net_device *dev;
+	struct dummyxl *priv;
+	int ret;
+
+	dev = alloc_candev(sizeof(struct dummyxl), 0);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->netdev_ops = &dummyxl_netdev_ops;
+	priv = netdev_priv(dev);
+	priv->can.bittiming_const = &dummyxl_bittiming_const;
+	priv->can.bitrate_max = 8 * MEGA /* BPS */;
+	priv->can.clock.freq = 80 * MEGA /* Hz */;
+	priv->can.fd.data_bittiming_const = &dummyxl_fd_databittiming_const;
+	priv->can.fd.tdc_const = &dummyxl_fd_tdc_const;
+	priv->can.xl.data_bittiming_const = &dummyxl_xl_databittiming_const;
+	priv->can.xl.tdc_const = &dummyxl_xl_tdc_const;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+		CAN_CTRLMODE_FD | CAN_CTRLMODE_TDC_AUTO |
+		CAN_CTRLMODE_XL | CAN_CTRLMODE_XL_TDC_AUTO;
+	priv->dev = dev;
+
+	ret = register_candev(priv->dev);
+	if (ret) {
+		free_candev(priv->dev);
+		return ret;
+	}
+
+	dummyxl = priv;
+	netdev_info(dev, "dummyxl OK\n");
+
+	return 0;
+}
+
+static void __exit dummyxl_exit(void)
+{
+	struct net_device *dev = dummyxl->dev;
+
+	netdev_info(dev, "dummyxl bye bye\n");
+	unregister_candev(dev);
+	free_candev(dev);
+}
+
+module_init(dummyxl_init);
+module_exit(dummyxl_exit);
+
+MODULE_DESCRIPTION("A dummy module just to check the CAN XL netlink interface");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>");
-- 
2.45.2





[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux