Skip to content

Commit 816cf43

Browse files
vincent-mailholmarckleinebudde
authored andcommitted
can: add dummy_can driver
During the development of CAN XL, we found the need of creating a dummy CAN XL driver in order to test the new netlink interface. While this code was initially intended to be some throwaway, it received some positive feedback. Add the dummy_can driver. This driver acts similarly to the vcan interface in the sense that it will echo back any packet it receives. The difference is that it exposes a set on bittiming parameters as a real device would and thus must be configured as if it was a real physical interface. The driver comes with a debug mode. If debug message are enabled (for example by enabling CONFIG_CAN_DEBUG_DEVICES), it will print in the kernel log all the bittiming values, similar to what a: ip --details link show can0 would do. This driver is mostly intended for debugging and testing, but some developers also may want to look at it as a simple reference implementation. Signed-off-by: Vincent Mailhol <mailhol@kernel.org> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20251126-canxl-v8-15-e7e3eb74f889@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent f5de373 commit 816cf43

File tree

3 files changed

+303
-0
lines changed

3 files changed

+303
-0
lines changed

drivers/net/can/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,23 @@ config CAN_CAN327
124124

125125
If this driver is built as a module, it will be called can327.
126126

127+
config CAN_DUMMY
128+
tristate "Dummy CAN"
129+
help
130+
A dummy CAN module supporting Classical CAN, CAN FD and CAN XL. It
131+
exposes bittiming values which can be configured through the netlink
132+
interface.
133+
134+
The module will simply echo any frame sent to it. If debug messages
135+
are activated, it prints all the CAN bittiming information in the
136+
kernel log. Aside from that it does nothing.
137+
138+
This is convenient for testing the CAN netlink interface. Most of the
139+
users will never need this. If unsure, say NO.
140+
141+
To compile this driver as a module, choose M here: the module will be
142+
called dummy-can.
143+
127144
config CAN_FLEXCAN
128145
tristate "Support for Freescale FLEXCAN based chips"
129146
depends on OF || COLDFIRE || COMPILE_TEST

drivers/net/can/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ obj-$(CONFIG_CAN_CAN327) += can327.o
2121
obj-$(CONFIG_CAN_CC770) += cc770/
2222
obj-$(CONFIG_CAN_C_CAN) += c_can/
2323
obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/
24+
obj-$(CONFIG_CAN_DUMMY) += dummy_can.o
2425
obj-$(CONFIG_CAN_FLEXCAN) += flexcan/
2526
obj-$(CONFIG_CAN_GRCAN) += grcan.o
2627
obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/

drivers/net/can/dummy_can.c

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/* Copyright (c) 2025 Vincent Mailhol <mailhol@kernel.org> */
4+
5+
#include <linux/array_size.h>
6+
#include <linux/errno.h>
7+
#include <linux/init.h>
8+
#include <linux/kernel.h>
9+
#include <linux/module.h>
10+
#include <linux/netdevice.h>
11+
#include <linux/units.h>
12+
#include <linux/string_choices.h>
13+
14+
#include <linux/can.h>
15+
#include <linux/can/bittiming.h>
16+
#include <linux/can/dev.h>
17+
#include <linux/can/skb.h>
18+
19+
struct dummy_can {
20+
struct can_priv can;
21+
struct net_device *dev;
22+
};
23+
24+
static struct dummy_can *dummy_can;
25+
26+
static const struct can_bittiming_const dummy_can_bittiming_const = {
27+
.name = "dummy_can CC",
28+
.tseg1_min = 2,
29+
.tseg1_max = 256,
30+
.tseg2_min = 2,
31+
.tseg2_max = 128,
32+
.sjw_max = 128,
33+
.brp_min = 1,
34+
.brp_max = 512,
35+
.brp_inc = 1
36+
};
37+
38+
static const struct can_bittiming_const dummy_can_fd_databittiming_const = {
39+
.name = "dummy_can FD",
40+
.tseg1_min = 2,
41+
.tseg1_max = 256,
42+
.tseg2_min = 2,
43+
.tseg2_max = 128,
44+
.sjw_max = 128,
45+
.brp_min = 1,
46+
.brp_max = 512,
47+
.brp_inc = 1
48+
};
49+
50+
static const struct can_tdc_const dummy_can_fd_tdc_const = {
51+
.tdcv_min = 0,
52+
.tdcv_max = 0, /* Manual mode not supported. */
53+
.tdco_min = 0,
54+
.tdco_max = 127,
55+
.tdcf_min = 0,
56+
.tdcf_max = 127
57+
};
58+
59+
static const struct can_bittiming_const dummy_can_xl_databittiming_const = {
60+
.name = "dummy_can XL",
61+
.tseg1_min = 2,
62+
.tseg1_max = 256,
63+
.tseg2_min = 2,
64+
.tseg2_max = 128,
65+
.sjw_max = 128,
66+
.brp_min = 1,
67+
.brp_max = 512,
68+
.brp_inc = 1
69+
};
70+
71+
static const struct can_tdc_const dummy_can_xl_tdc_const = {
72+
.tdcv_min = 0,
73+
.tdcv_max = 0, /* Manual mode not supported. */
74+
.tdco_min = 0,
75+
.tdco_max = 127,
76+
.tdcf_min = 0,
77+
.tdcf_max = 127
78+
};
79+
80+
static const struct can_pwm_const dummy_can_pwm_const = {
81+
.pwms_min = 1,
82+
.pwms_max = 8,
83+
.pwml_min = 2,
84+
.pwml_max = 24,
85+
.pwmo_min = 0,
86+
.pwmo_max = 16,
87+
};
88+
89+
static void dummy_can_print_bittiming(struct net_device *dev,
90+
struct can_bittiming *bt)
91+
{
92+
netdev_dbg(dev, "\tbitrate: %u\n", bt->bitrate);
93+
netdev_dbg(dev, "\tsample_point: %u\n", bt->sample_point);
94+
netdev_dbg(dev, "\ttq: %u\n", bt->tq);
95+
netdev_dbg(dev, "\tprop_seg: %u\n", bt->prop_seg);
96+
netdev_dbg(dev, "\tphase_seg1: %u\n", bt->phase_seg1);
97+
netdev_dbg(dev, "\tphase_seg2: %u\n", bt->phase_seg2);
98+
netdev_dbg(dev, "\tsjw: %u\n", bt->sjw);
99+
netdev_dbg(dev, "\tbrp: %u\n", bt->brp);
100+
}
101+
102+
static void dummy_can_print_tdc(struct net_device *dev, struct can_tdc *tdc)
103+
{
104+
netdev_dbg(dev, "\t\ttdcv: %u\n", tdc->tdcv);
105+
netdev_dbg(dev, "\t\ttdco: %u\n", tdc->tdco);
106+
netdev_dbg(dev, "\t\ttdcf: %u\n", tdc->tdcf);
107+
}
108+
109+
static void dummy_can_print_pwm(struct net_device *dev, struct can_pwm *pwm,
110+
struct can_bittiming *dbt)
111+
{
112+
netdev_dbg(dev, "\t\tpwms: %u\n", pwm->pwms);
113+
netdev_dbg(dev, "\t\tpwml: %u\n", pwm->pwml);
114+
netdev_dbg(dev, "\t\tpwmo: %u\n", pwm->pwmo);
115+
}
116+
117+
static void dummy_can_print_ctrlmode(struct net_device *dev)
118+
{
119+
struct dummy_can *priv = netdev_priv(dev);
120+
struct can_priv *can_priv = &priv->can;
121+
unsigned long supported = can_priv->ctrlmode_supported;
122+
u32 enabled = can_priv->ctrlmode;
123+
124+
netdev_dbg(dev, "Control modes:\n");
125+
netdev_dbg(dev, "\tsupported: 0x%08x\n", (u32)supported);
126+
netdev_dbg(dev, "\tenabled: 0x%08x\n", enabled);
127+
128+
if (supported) {
129+
int idx;
130+
131+
netdev_dbg(dev, "\tlist:");
132+
for_each_set_bit(idx, &supported, BITS_PER_TYPE(u32))
133+
netdev_dbg(dev, "\t\t%s: %s\n",
134+
can_get_ctrlmode_str(BIT(idx)),
135+
enabled & BIT(idx) ? "on" : "off");
136+
}
137+
}
138+
139+
static void dummy_can_print_bittiming_info(struct net_device *dev)
140+
{
141+
struct dummy_can *priv = netdev_priv(dev);
142+
struct can_priv *can_priv = &priv->can;
143+
144+
netdev_dbg(dev, "Clock frequency: %u\n", can_priv->clock.freq);
145+
netdev_dbg(dev, "Maximum bitrate: %u\n", can_priv->bitrate_max);
146+
netdev_dbg(dev, "MTU: %u\n", dev->mtu);
147+
netdev_dbg(dev, "\n");
148+
149+
dummy_can_print_ctrlmode(dev);
150+
netdev_dbg(dev, "\n");
151+
152+
netdev_dbg(dev, "Classical CAN nominal bittiming:\n");
153+
dummy_can_print_bittiming(dev, &can_priv->bittiming);
154+
netdev_dbg(dev, "\n");
155+
156+
if (can_priv->ctrlmode & CAN_CTRLMODE_FD) {
157+
netdev_dbg(dev, "CAN FD databittiming:\n");
158+
dummy_can_print_bittiming(dev, &can_priv->fd.data_bittiming);
159+
if (can_fd_tdc_is_enabled(can_priv)) {
160+
netdev_dbg(dev, "\tCAN FD TDC:\n");
161+
dummy_can_print_tdc(dev, &can_priv->fd.tdc);
162+
}
163+
}
164+
netdev_dbg(dev, "\n");
165+
166+
if (can_priv->ctrlmode & CAN_CTRLMODE_XL) {
167+
netdev_dbg(dev, "CAN XL databittiming:\n");
168+
dummy_can_print_bittiming(dev, &can_priv->xl.data_bittiming);
169+
if (can_xl_tdc_is_enabled(can_priv)) {
170+
netdev_dbg(dev, "\tCAN XL TDC:\n");
171+
dummy_can_print_tdc(dev, &can_priv->xl.tdc);
172+
}
173+
if (can_priv->ctrlmode & CAN_CTRLMODE_XL_TMS) {
174+
netdev_dbg(dev, "\tCAN XL PWM:\n");
175+
dummy_can_print_pwm(dev, &can_priv->xl.pwm,
176+
&can_priv->xl.data_bittiming);
177+
}
178+
}
179+
netdev_dbg(dev, "\n");
180+
}
181+
182+
static int dummy_can_netdev_open(struct net_device *dev)
183+
{
184+
int ret;
185+
struct can_priv *priv = netdev_priv(dev);
186+
187+
dummy_can_print_bittiming_info(dev);
188+
netdev_dbg(dev, "error-signalling is %s\n",
189+
str_enabled_disabled(!can_dev_in_xl_only_mode(priv)));
190+
191+
ret = open_candev(dev);
192+
if (ret)
193+
return ret;
194+
netif_start_queue(dev);
195+
netdev_dbg(dev, "dummy-can is up\n");
196+
197+
return 0;
198+
}
199+
200+
static int dummy_can_netdev_close(struct net_device *dev)
201+
{
202+
netif_stop_queue(dev);
203+
close_candev(dev);
204+
netdev_dbg(dev, "dummy-can is down\n");
205+
206+
return 0;
207+
}
208+
209+
static netdev_tx_t dummy_can_start_xmit(struct sk_buff *skb,
210+
struct net_device *dev)
211+
{
212+
if (can_dev_dropped_skb(dev, skb))
213+
return NETDEV_TX_OK;
214+
215+
can_put_echo_skb(skb, dev, 0, 0);
216+
dev->stats.tx_packets++;
217+
dev->stats.tx_bytes += can_get_echo_skb(dev, 0, NULL);
218+
219+
return NETDEV_TX_OK;
220+
}
221+
222+
static const struct net_device_ops dummy_can_netdev_ops = {
223+
.ndo_open = dummy_can_netdev_open,
224+
.ndo_stop = dummy_can_netdev_close,
225+
.ndo_start_xmit = dummy_can_start_xmit,
226+
};
227+
228+
static const struct ethtool_ops dummy_can_ethtool_ops = {
229+
.get_ts_info = ethtool_op_get_ts_info,
230+
};
231+
232+
static int __init dummy_can_init(void)
233+
{
234+
struct net_device *dev;
235+
struct dummy_can *priv;
236+
int ret;
237+
238+
dev = alloc_candev(sizeof(*priv), 1);
239+
if (!dev)
240+
return -ENOMEM;
241+
242+
dev->netdev_ops = &dummy_can_netdev_ops;
243+
dev->ethtool_ops = &dummy_can_ethtool_ops;
244+
priv = netdev_priv(dev);
245+
priv->can.bittiming_const = &dummy_can_bittiming_const;
246+
priv->can.bitrate_max = 20 * MEGA /* BPS */;
247+
priv->can.clock.freq = 160 * MEGA /* Hz */;
248+
priv->can.fd.data_bittiming_const = &dummy_can_fd_databittiming_const;
249+
priv->can.fd.tdc_const = &dummy_can_fd_tdc_const;
250+
priv->can.xl.data_bittiming_const = &dummy_can_xl_databittiming_const;
251+
priv->can.xl.tdc_const = &dummy_can_xl_tdc_const;
252+
priv->can.xl.pwm_const = &dummy_can_pwm_const;
253+
priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
254+
CAN_CTRLMODE_FD | CAN_CTRLMODE_TDC_AUTO |
255+
CAN_CTRLMODE_RESTRICTED | CAN_CTRLMODE_XL |
256+
CAN_CTRLMODE_XL_TDC_AUTO | CAN_CTRLMODE_XL_TMS;
257+
priv->dev = dev;
258+
259+
ret = register_candev(priv->dev);
260+
if (ret) {
261+
free_candev(priv->dev);
262+
return ret;
263+
}
264+
265+
dummy_can = priv;
266+
netdev_dbg(dev, "dummy-can ready\n");
267+
268+
return 0;
269+
}
270+
271+
static void __exit dummy_can_exit(void)
272+
{
273+
struct net_device *dev = dummy_can->dev;
274+
275+
netdev_dbg(dev, "dummy-can bye bye\n");
276+
unregister_candev(dev);
277+
free_candev(dev);
278+
}
279+
280+
module_init(dummy_can_init);
281+
module_exit(dummy_can_exit);
282+
283+
MODULE_DESCRIPTION("A dummy CAN driver, mainly to test the netlink interface");
284+
MODULE_LICENSE("GPL");
285+
MODULE_AUTHOR("Vincent Mailhol <mailhol@kernel.org>");

0 commit comments

Comments
 (0)