File Index
Files and directories
Sign in
FILE

dummy_can.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/can/dummy_can.c C
  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
 19struct dummy_can {
 20	struct can_priv can;
 21	struct net_device *dev;
 22};
 23
 24static struct dummy_can *dummy_can;
 25
 26static 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
 38static 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
 50static 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
 59static 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
 71static 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
 80static 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
 89static 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
102static 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
109static 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
117static 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
139static 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
182static 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
200static 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
209static 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
222static 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
228static const struct ethtool_ops dummy_can_ethtool_ops = {
229	.get_ts_info = ethtool_op_get_ts_info,
230};
231
232static 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	dev->flags |= IFF_ECHO; /* enable echo handling */
245	priv = netdev_priv(dev);
246	priv->can.bittiming_const = &dummy_can_bittiming_const;
247	priv->can.bitrate_max = 20 * MEGA /* BPS */;
248	priv->can.clock.freq = 160 * MEGA /* Hz */;
249	priv->can.fd.data_bittiming_const = &dummy_can_fd_databittiming_const;
250	priv->can.fd.tdc_const = &dummy_can_fd_tdc_const;
251	priv->can.xl.data_bittiming_const = &dummy_can_xl_databittiming_const;
252	priv->can.xl.tdc_const = &dummy_can_xl_tdc_const;
253	priv->can.xl.pwm_const = &dummy_can_pwm_const;
254	priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
255		CAN_CTRLMODE_FD | CAN_CTRLMODE_TDC_AUTO |
256		CAN_CTRLMODE_RESTRICTED | CAN_CTRLMODE_XL |
257		CAN_CTRLMODE_XL_TDC_AUTO | CAN_CTRLMODE_XL_TMS;
258	priv->dev = dev;
259
260	ret = register_candev(priv->dev);
261	if (ret) {
262		free_candev(priv->dev);
263		return ret;
264	}
265
266	dummy_can = priv;
267	netdev_dbg(dev, "dummy-can ready\n");
268
269	return 0;
270}
271
272static void __exit dummy_can_exit(void)
273{
274	struct net_device *dev = dummy_can->dev;
275
276	netdev_dbg(dev, "dummy-can bye bye\n");
277	unregister_candev(dev);
278	free_candev(dev);
279}
280
281module_init(dummy_can_init);
282module_exit(dummy_can_exit);
283
284MODULE_DESCRIPTION("A dummy CAN driver, mainly to test the netlink interface");
285MODULE_LICENSE("GPL");
286MODULE_AUTHOR("Vincent Mailhol <mailhol@kernel.org>");
~/ Read-only file preview.