CAN FD support
Subsystems (3)
Oliver Hartkopp
maintainerRFC v5 1/1 CAN FD support
Hi all,
since RFC v4 - see http://marc.info/?l=linux-can&m=133708871921901&w=2 from 2012-05-15 - i cleaned up some details and added the support of simultaneous CAN and CANFD frame handling inside the networking code after some discussion with Kurt. Sometimes code needs to be implemented to see that there is a more elegant solution out there when removing that code again ;-)
If you also feel fine with this patch i would finally create a patchset of four patches, like
- adding new structures and constants
- adding CAN FD support in af_can.c
- adding CAN FD support in raw.c
- adding CAN FD support in vcan.c
for the upcoming net-next bound for Linux 3.6 .
Some words about the basic concepts of this CAN FD support for Linux CAN networking. In general the new CAN FD controllers support two different bitrates for the arbitration phase and the payload phase of the CAN FD frame and up to 64 bytes of payload. This extended payload length breaks all the kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight bytes of payload (struct can_frame) like the CAN_RAW socket.
This patch enables the CAN network layer to handle CAN FD frames and 'legacy' CAN frames following ISO 11898-1 and updates the virtual CAN driver (vcan) to be able to develop and test userspace applications and CAN network drivers.
Main concepts:
1. Introduction of a new data structure canfd_frame with 64 bytes of payload:
The struct canfd_frame and the existing struct can_frame have the CAN ID and the payload length at the same offset inside their structures. This allows to change the internal processing of the payload length to a plain length handling with values from 0 .. 64 instead of the 'data length code' which was a 1:1 mapping in the legacy CAN frames anyway.
The data length to DLC mapping is only performed inside the CAN drivers, preferably with the new helper functions can_dlc2len() and can_len2dlc().
2. The CAN netdevice drivers can be distinguished by the maximum transfer unit (MTU), which presents the length of the struct can(fd)_frame:
MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => 'legacy' CAN device
MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable dev
CAN FD capable devices can also handle and send legacy CAN frames.
3. The internal socket buffers (skbuffs) that contain CAN frames are split in two different ethernet frame types to distinguish the frame types e.g. for networking tools using AF_PACKET:
ETH_P_CAN (val 0x000C): skbuffs containing a struct can_frame
ETH_P_CANFD (val 0x000D): skbuffs containing a struct canfd_frame
Inside the CAN network layer the different CAN frame types are distinguished by the skbuffs length (skb->len) and not by the ETH_P_CAN(FD) protocol tags.
4. CAN FD support in CAN_RAW sockets can be enabled with a new socket option CAN_RAW_FD_FRAMES which is off by default. When the new socket option is not supported by the CAN_RAW socket (e.g. on older kernels), switching the CAN_RAW_FD_FRAMES option returns the error -ENOPROTOOPT.
Once CAN_RAW_FD_FRAMES is enabled the application can send both CAN frames and CAN FD frames. OTOH the application has to handle CAN and CAN FD frames when reading from the socket. E.g. when reading with size CANFD_MTU returns CAN_MTU bytes that have been received from the socket a legacy CAN frame has been read into the provided CAN FD structure. As this frame has a payload length <= 8 and has a similar layout the CAN data can be used inside the struct canfd_frame as-is.
As long as the payload length is <=8 the received CAN frames from CAN FD capable CAN devices can be received and read by legacy sockets too. When user-generated CAN FD frames have a payload length <=8 these can be send by legacy CAN network interfaces too.
CAN_RAW_FD_FRAMES enabled: CAN_MTU and CANFD_MTU are allowed CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default)
Sending CAN FD frames with payload length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
I hope this description makes the review of the following patch easier. I did some conversions to some of the can-utils for private testing:
https://gitorious.org/~hartkopp/linux-can/hartkopps-can-utils
The following diff was generated by 'git diff fb7944b' on the repository
https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next
Regards,
Oliver
drivers/net/can/dev.c | 35 +++++++++++++- drivers/net/can/vcan.c | 27 ++++++++-- include/linux/can.h | 55 ++++++++++++++++++++-- include/linux/can/core.h | 4 - include/linux/can/dev.h | 33 ++++++++++--- include/linux/can/raw.h | 3 - include/linux/if_ether.h | 3 - net/can/af_can.c | 116 ++++++++++++++++++++++++++++++++++++----------- net/can/raw.c | 50 ++++++++++++++++++-- 9 files changed, 271 insertions(+), 55 deletions(-)
---
drivers/net/can/dev.c +34 -1
@@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC);MODULE_LICENSE ("GPL v2" );MODULE_AUTHOR ("Wolfgang Grandegger <[email protected]>" ); +/* CAN DLC to real data length conversion helpers */ + +static const u8 dlc2len[] = {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 , +8 ,12 ,16 ,20 ,24 ,32 ,48 ,64 }; + +/* get data length from can_dlc with sanitized can_dlc */ +u8 can_dlc2len (u8 can_dlc) +{ +return dlc2len[can_dlc &0x0F ]; +} +EXPORT_SYMBOL_GPL (can_dlc2len); + +static const u8 len2dlc[] = {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,/* 0 - 8 */ +9 ,9 ,9 ,9 ,/* 9 - 12 */ +10 ,10 ,10 ,10 ,/* 13 - 16 */ +11 ,11 ,11 ,11 ,/* 17 - 20 */ +12 ,12 ,12 ,12 ,/* 21 - 24 */ +13 ,13 ,13 ,13 ,13 ,13 ,13 ,13 ,/* 25 - 32 */ +14 ,14 ,14 ,14 ,14 ,14 ,14 ,14 ,/* 33 - 40 */ +14 ,14 ,14 ,14 ,14 ,14 ,14 ,14 ,/* 41 - 48 */ +15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,/* 49 - 56 */ +15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 };/* 57 - 64 */ + +/* map the sanitized data length to an appropriate data length code */ +u8 can_len2dlc (u8 len) +{ +if (unlikely (len >64 )) +return 0xF ; + +return len2dlc[len]; +} +EXPORT_SYMBOL_GPL (can_len2dlc); +#ifdef CONFIG_CAN_CALC_BITTIMING #define CAN_CALC_MAX_ERROR 50/* in one-tenth of a percent */
@@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);static void can_setup (struct net_device *dev) { dev->type =ARPHRD_CAN ; - dev->mtu =sizeof (struct can_frame ); + dev->mtu =CAN_MTU ; dev->hard_header_len =0 ; dev->addr_len =0 ; dev->tx_queue_len =10 ;
drivers/net/can/vcan.c +20 -7
@@ -70,13 +70,12 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");static void vcan_rx (struct sk_buff *skb,struct net_device *dev) { -struct can_frame *cf = (struct can_frame *)skb->data; +struct canfd_frame *cfd = (struct canfd_frame *)skb->data;struct net_device_stats *stats = &dev->stats; stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; + stats->rx_bytes += cfd->len; - skb->protocol =htons (ETH_P_CAN ); skb->pkt_type =PACKET_BROADCAST ; skb->dev = dev; skb->ip_summed =CHECKSUM_UNNECESSARY ;
@@ -86,7 +85,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)static netdev_tx_t vcan_tx (struct sk_buff *skb,struct net_device *dev) { -struct can_frame *cf = (struct can_frame *)skb->data; +struct canfd_frame *cfd = (struct canfd_frame *)skb->data;struct net_device_stats *stats = &dev->stats;int loop;
@@ -94,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)return NETDEV_TX_OK ; stats->tx_packets++; - stats->tx_bytes += cf->can_dlc; + stats->tx_bytes += cfd->len;/* set flag whether this packet has to be looped back */ loop = skb->pkt_type ==PACKET_LOOPBACK ;
@@ -108,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)* CAN core already did the echo for us */ stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; + stats->rx_bytes += cfd->len; }kfree_skb (skb);return NETDEV_TX_OK ;
@@ -133,14 +132,28 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)return NETDEV_TX_OK ; } +static int vcan_change_mtu (struct net_device *dev,int new_mtu) +{ +/* Do not allow changing the MTU while running */ +if (dev->flags &IFF_UP ) +return -EBUSY ; + +if (new_mtu !=CAN_MTU && new_mtu !=CANFD_MTU ) +return -EINVAL ; + + dev->mtu = new_mtu; +return 0 ; +} +static const struct net_device_ops vcan_netdev_ops = { .ndo_start_xmit = vcan_tx, + .ndo_change_mtu = vcan_change_mtu, };static void vcan_setup (struct net_device *dev) { dev->type =ARPHRD_CAN ; - dev->mtu =sizeof (struct can_frame ); + dev->mtu =CAN_MTU ; dev->hard_header_len =0 ; dev->addr_len =0 ; dev->tx_queue_len =0 ;
include/linux/can.h +51 -4
69 lines not on this page · raw message
include/linux/can/core.h +2 -2
@@ -17,10 +17,10 @@#include <linux/skbuff.h> #include <linux/netdevice.h> -#define CAN_VERSION "20090105" +#define CAN_VERSION "20120528"/* increment this number each time you change some user-space interface */ -#define CAN_ABI_VERSION "8" +#define CAN_ABI_VERSION "9"#define CAN_VERSION_STRING "rev " CAN_VERSION " abi " CAN_ABI_VERSION
include/linux/can/dev.h +25 -8
@@ -61,23 +61,40 @@ struct can_priv {* To be used in the CAN netdriver receive path to ensure conformance with * ISO 11898-1 Chapter 8.4.2.3 (DLC field) */ -#define get_can_dlc (i) (min_t(__u8, (i), 8)) +#define get_can_dlc (i) (min_t(__u8, (i), CAN_MAX_DLC)) +#define get_canfd_dlc (i) (min_t(__u8, (i), CANFD_MAX_DLC))/* Drop a given socketbuffer if it does not contain a valid CAN frame. */ static inline int can_dropped_invalid_skb (struct net_device *dev,struct sk_buff *skb) { -const struct can_frame *cf = (struct can_frame *)skb->data; - -if (unlikely (skb->len !=sizeof (*cf) || cf->can_dlc >8 )) { -kfree_skb (skb); - dev->stats.tx_dropped++; -return 1 ; - } +const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + +if (skb->protocol ==htons (ETH_P_CAN )) { +if (unlikely (skb->len !=CAN_MTU || + cfd->len >CAN_MAX_DLEN )) + goto inval_skb; + }else if (skb->protocol ==htons (ETH_P_CANFD )) { +if (unlikely (skb->len !=CANFD_MTU || + cfd->len >CANFD_MAX_DLEN )) + goto inval_skb; + }else + goto inval_skb;return 0 ; + +inval_skb: +kfree_skb (skb); + dev->stats.tx_dropped++; +return 1 ; } +/* get data length from can_dlc with sanitized can_dlc */ +u8 can_dlc2len (u8 can_dlc); + +/* map the sanitized data length to an appropriate data length code */ +u8 can_len2dlc (u8 len); +struct net_device *alloc_candev (int sizeof_priv,unsigned int echo_skb_max);void free_candev (struct net_device *dev);
include/linux/can/raw.h +2 -1
@@ -23,7 +23,8 @@ enum {CAN_RAW_FILTER =1 ,/* set 0 .. n can_filter(s) */ CAN_RAW_ERR_FILTER ,/* set filter for error frames */ CAN_RAW_LOOPBACK ,/* local loopback (default:on) */ -CAN_RAW_RECV_OWN_MSGS /* receive my own msgs (default:off) */ +CAN_RAW_RECV_OWN_MSGS ,/* receive my own msgs (default:off) */ + CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ };#endif
include/linux/if_ether.h +2 -1
@@ -105,7 +105,8 @@#define ETH_P_WAN_PPP 0x0007/* Dummy type for WAN PPP frames*/ #define ETH_P_PPP_MP 0x0008/* Dummy type for PPP MP frames */ #define ETH_P_LOCALTALK 0x0009/* Localtalk pseudo type */ -#define ETH_P_CAN 0x000C/* Controller Area Network */ +#define ETH_P_CAN 0x000C/* Controller Area Network (CAN)*/ +#define ETH_P_CANFD 0x000D/* CAN FD 64 byte payload frames*/ #define ETH_P_PPPTALK 0x0010/* Dummy type for Atalk over PPP*/ #define ETH_P_TR_802_2 0x0011/* 802.2 frames */ #define ETH_P_MOBITEX 0x0015/* Mobitex ([email protected]) */
net/can/af_can.c +89 -27
190 lines not on this page · raw message
net/can/raw.c +46 -4
101 lines not on this page · raw message
Quoted 11 lines · Oliver Hartkopp
Hi all,
since RFC v4 - see http://marc.info/?l=linux-can&m=133708871921901&w=2 from 2012-05-15 - i cleaned up some details and added the support of simultaneous CAN and CANFD frame handling inside the networking code after some discussion with Kurt. Sometimes code needs to be implemented to see that there is a more elegant solution out there when removing that code again ;-)
If you also feel fine with this patch i would finally create a patchset of four patches, like
Quoted 6 lines
- adding new structures and constants
- adding CAN FD support inaf_can.c
- adding CAN FD support inraw.c
- adding CAN FD support invcan.cfor the upcoming net-next bound for Linux 3.6 .
Do you have already CAN FD hardware for testing? If not, do we really want to have this patchset mainline.
More later...
Wolfgang.
Oliver Hartkopp
maintainerQuoted 17 lines · Wolfgang Grandegger
Quoted 16 lines · Oliver Hartkopp
Hi all,
since RFC v4 - see http://marc.info/?l=linux-can&m=133708871921901&w=2 from 2012-05-15 - i cleaned up some details and added the support of simultaneous CAN and CANFD frame handling inside the networking code after some discussion with Kurt. Sometimes code needs to be implemented to see that there is a more elegant solution out there when removing that code again ;-)
If you also feel fine with this patch i would finally create a patchset of four patches, like
- adding new structures and constants
- adding CAN FD support inaf_can.c
- adding CAN FD support inraw.c
- adding CAN FD support invcan.c
Quoted 4 lines
Quoted 1 line
for the upcoming net-next bound for Linux 3.6 .
Do you have already CAN FD hardware for testing? If not, do we really want to have this patchset mainline.
Yes. There's a good reason for this patchset.
As you might remember from the old days ...
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=history;f=drivers/net/can/Kconfig
2009-05-18 Wolfgang Grandegger can: CAN Network device driver and Netlink interface blob | commitdiff | diff to current
2008-01-28 Oliver Hartkopp [CAN]: Add virtual CAN netdevice driver blob | commitdiff | diff to current
it was nearly 16 month the PF_CAN infrastructure was part of the mainline kernel until the first 'real' CAN drivers have been added to the tree. Meanwhile the driver development inside and outside the tree had a stable environment for APIs and testing.
Same situation here. The CAN FD patches just provide a CAN FD capable infrastructure with new data structures and extended userspace API which allows to develop both drivers and CAN FD applications.
So when the patches go the usual way, they are released in Linux 3.6 somewhere in November/December this year - together with the first announced real CAN FD hardware silicon. Btw. i assume that the first FPGA based CAN controllers will be available for tests earlier.
So hitting this net-next window to provide CAN FD support in the netlayer infrastructure is not too fast but right in time :-)
Quoted 1 line
More later...
Reviews are welcome.
Please check the different postings and discussions up to v5 before.
Regards,
Oliver
Quoted 31 lines · Oliver Hartkopp
Quoted 17 lines · Wolfgang Grandegger
Quoted 16 lines · Oliver Hartkopp
Hi all,
since RFC v4 - see http://marc.info/?l=linux-can&m=133708871921901&w=2 from 2012-05-15 - i cleaned up some details and added the support of simultaneous CAN and CANFD frame handling inside the networking code after some discussion with Kurt. Sometimes code needs to be implemented to see that there is a more elegant solution out there when removing that code again ;-)
If you also feel fine with this patch i would finally create a patchset of four patches, like
- adding new structures and constants
- adding CAN FD support inaf_can.c
- adding CAN FD support inraw.c
- adding CAN FD support invcan.cQuoted 4 lines
Quoted 1 line
for the upcoming net-next bound for Linux 3.6 .
Do you have already CAN FD hardware for testing? If not, do we really want to have this patchset mainline.
Yes. There's a good reason for this patchset.
As you might remember from the old days ...
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=history;f=drivers/net/can/Kconfig
Quoted 8 lines
2009-05-18 Wolfgang Grandegger can: CAN Network device driver and Netlink interface blob | commitdiff | diff to current
2008-01-28 Oliver Hartkopp [CAN]: Add virtual CAN netdevice driver blob | commitdiff | diff to current
it was nearly 16 month the
PF_CANinfrastructure was part of the mainline kernel until the first 'real' CAN drivers have been added to the tree. Meanwhile the driver development inside and outside the tree had a stable environment for APIs and testing.
Ah, I forgot, the vcan driver allows to test the CAN FD interface as well, basically ==> the code is tested to some extend which calms me down ;).
Quoted 9 lines
Same situation here. The CAN FD patches just provide a CAN FD capable infrastructure with new data structures and extended userspace API which allows to develop both drivers and CAN FD applications.
So when the patches go the usual way, they are released in Linux 3.6 somewhere in November/December this year - together with the first announced real CAN FD hardware silicon. Btw. i assume that the first FPGA based CAN controllers will be available for tests earlier.
Quoted 8 lines
So hitting this net-next window to provide CAN FD support in the netlayer infrastructure is not too fast but right in time :-)
Quoted 1 line
More later...
Reviews are welcome.
Please check the different postings and discussions up to v5 before.
Well, I'm just back from holiday...
Wolfgang.
Oliver Hartkopp
maintainerQuoted 11 lines · Wolfgang Grandegger
Quoted 4 lines · Oliver Hartkopp
it was nearly 16 month the
PF_CANinfrastructure was part of the mainline kernel until the first 'real' CAN drivers have been added to the tree. Meanwhile the driver development inside and outside the tree had a stable environment for APIs and testing.Ah, I forgot, the vcan driver allows to test the CAN FD interface as well, basically ==> the code is tested to some extend which calms me down ;).
Yes. After some development and also removal of new ugly code it looks pretty simple and clear now. And it was also easy to test (using new applications with the older kernel too).
Especially it allowed some simplifications in the kernel code and the adaption of userspace applications was amazingly simple. See my commits in hartkopps-can-utils ...
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
More later...
Reviews are welcome.
Please check the different postings and discussions up to v5 before.Well, I'm just back from holiday...
Welcome back :-)
Oliver