* [RFC] CAN FD support part 1 - uncommented source
@ 2012-05-03 11:14 Oliver Hartkopp
2012-05-03 11:34 ` Wolfgang Grandegger
0 siblings, 1 reply; 11+ messages in thread
From: Oliver Hartkopp @ 2012-05-03 11:14 UTC (permalink / raw)
To: linux-can
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index f03d7a4..1b7e843 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -454,7 +454,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;
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index ea2d942..bddbafb 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
struct net_device_stats *stats = &dev->stats;
stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
+ stats->rx_bytes += can_dlc2len(cf->can_dlc);
- skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -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 += can_dlc2len(cf->can_dlc);
/* 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 += can_dlc2len(cf->can_dlc);
}
kfree_skb(skb);
return NETDEV_TX_OK;
@@ -133,14 +132,25 @@ 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)
+{
+ if (new_mtu == CAN_MTU || new_mtu == CANFD_MTU) {
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
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;
diff --git a/include/linux/can.h b/include/linux/can.h
index 9a19bcb..74052da 100644
--- a/include/linux/can.h
+++ b/include/linux/can.h
@@ -46,6 +46,9 @@ typedef __u32 canid_t;
*/
typedef __u32 can_err_mask_t;
+#define CAN_MAX_DLC 8
+#define CANFD_MAX_DLC 15
+
/**
* struct can_frame - basic CAN frame structure
* @can_id: the CAN ID of the frame and CAN_*_FLAG flags, see above.
@@ -58,6 +61,65 @@ struct can_frame {
__u8 data[8] __attribute__((aligned(8)));
};
+/*
+ * defined bits for canfd_frame.flags
+ *
+ * RX: HDR/EDL - info about received CAN FD frame
+ * ESI - bit from originating CAN controller
+ * TX: HDR/EDL - control per-frame settings if supported by CAN controller
+ * ESI - bit is set by local CAN controller
+ */
+#define CANFD_HDR 0x01 /* high data rate */
+#define CANFD_EDL 0x02 /* extended data length */
+#define CANFD_ESI 0x04 /* error state indicator */
+
+/**
+ * struct canfd_frame - CAN flexible data rate frame structure
+ * @can_id: the CAN ID of the frame and CAN_*_FLAG flags, see above.
+ * @can_dlc: the data length field of the CAN frame (data length code)
+ * @flags: additional flags for CAN FD
+ * @__res0: reserved / padding
+ * @__res1: reserved / padding
+ * @data: the CAN FD frame payload (up to 64 byte).
+ */
+struct canfd_frame {
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ __u8 can_dlc; /* CAN FD data length code: 0 .. 0xF */
+ __u8 flags; /* additional flags for CAN FD */
+ __u8 __res0; /* reserved / padding */
+ __u8 __res1; /* reserved / padding */
+ __u8 data[64] __attribute__((aligned(8)));
+};
+
+static const u8 dlc2len[16] = {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 */
+static inline u8 can_dlc2len (u8 can_dlc)
+{
+ return dlc2len[can_dlc & 0x0F];
+}
+
+static const u8 len2dlc[65] = {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 */
+static inline u8 can_len2dlc(u8 len)
+{
+ if (unlikely(len > 64))
+ return 0xF;
+
+ return len2dlc[len];
+}
+
/* particular protocols of the protocol family PF_CAN */
#define CAN_RAW 1 /* RAW sockets */
#define CAN_BCM 2 /* Broadcast Manager */
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 0ccc1cd..e6a3126 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -17,10 +17,10 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#define CAN_VERSION "20090105"
+#define CAN_VERSION "20120413"
/* 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
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 5d2efe7..082b664 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -61,7 +61,11 @@ 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))
+
+#define CAN_MTU (sizeof(struct can_frame))
+#define CANFD_MTU (sizeof(struct canfd_frame))
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
static inline int can_dropped_invalid_skb(struct net_device *dev,
@@ -69,13 +73,23 @@ static inline int can_dropped_invalid_skb(struct net_device *dev,
{
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;
- }
+ if (skb->protocol == htons(ETH_P_CAN)) {
+ if (skb->len != sizeof(struct can_frame) ||
+ cf->can_dlc > CAN_MAX_DLC)
+ goto inval_skb;
+ } else if (skb->protocol == htons(ETH_P_CANFD)) {
+ if (skb->len != sizeof(struct canfd_frame) ||
+ cf->can_dlc > CANFD_MAX_DLC)
+ goto inval_skb;
+ } else
+ goto inval_skb;
return 0;
+
+inval_skb:
+ kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return 1;
}
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h
index 781f3a3..5448c0f 100644
--- a/include/linux/can/raw.h
+++ b/include/linux/can/raw.h
@@ -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, /* use struct canfd_frame (default:off) */
};
#endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 56d907a..5c9c2b4 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -119,6 +119,7 @@
#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
+#define ETH_P_CANFD 0x00FD /* Controller Area Network FD */
/*
* This is an Ethernet frame header.
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 0ce2ad0..1b7f1f8 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -41,6 +41,7 @@
*/
#include <linux/module.h>
+#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
@@ -228,10 +229,20 @@ int can_send(struct sk_buff *skb, int loop)
struct can_frame *cf = (struct can_frame *)skb->data;
int err;
- if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
- kfree_skb(skb);
- return -EINVAL;
- }
+ if (skb->protocol == htons(ETH_P_CAN)) {
+ if (skb->len != sizeof(struct can_frame) ||
+ cf->can_dlc > CAN_MAX_DLC)
+ goto inval_skb;
+ } else if (skb->protocol == htons(ETH_P_CANFD)) {
+ if (skb->len != sizeof(struct canfd_frame) ||
+ cf->can_dlc > CANFD_MAX_DLC)
+ goto inval_skb;
+ } else
+ goto inval_skb;
+
+ /* make sure the CAN frame can pass the selected CAN netdevice */
+ if (skb->len > skb->dev->mtu)
+ goto inval_skb;
if (skb->dev->type != ARPHRD_CAN) {
kfree_skb(skb);
@@ -243,7 +254,6 @@ int can_send(struct sk_buff *skb, int loop)
return -ENETDOWN;
}
- skb->protocol = htons(ETH_P_CAN);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
@@ -300,6 +310,10 @@ int can_send(struct sk_buff *skb, int loop)
can_stats.tx_frames_delta++;
return 0;
+
+inval_skb:
+ kfree_skb(skb);
+ return -EINVAL;
}
EXPORT_SYMBOL(can_send);
@@ -632,24 +646,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
return matches;
}
-static int can_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+static void can_receive(struct sk_buff *skb, struct net_device *dev)
{
struct dev_rcv_lists *d;
- struct can_frame *cf = (struct can_frame *)skb->data;
int matches;
- if (!net_eq(dev_net(dev), &init_net))
- goto drop;
-
- if (WARN_ONCE(dev->type != ARPHRD_CAN ||
- skb->len != sizeof(struct can_frame) ||
- cf->can_dlc > 8,
- "PF_CAN: dropped non conform skbuf: "
- "dev type %d, len %d, can_dlc %d\n",
- dev->type, skb->len, cf->can_dlc))
- goto drop;
-
/* update statistics */
can_stats.rx_frames++;
can_stats.rx_frames_delta++;
@@ -673,7 +674,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
can_stats.matches++;
can_stats.matches_delta++;
}
+}
+
+static int can_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ if (!net_eq(dev_net(dev), &init_net))
+ goto drop;
+
+ if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+ skb->len != sizeof(struct can_frame) ||
+ cf->can_dlc > CAN_MAX_DLC,
+ "PF_CAN: dropped non conform CAN skbuf: "
+ "dev type %d, len %d, can_dlc %d\n",
+ dev->type, skb->len, cf->can_dlc))
+ goto drop;
+
+ can_receive(skb, dev);
+ return NET_RX_SUCCESS;
+
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct can_frame *cf = (struct can_frame *)skb->data;
+
+ if (!net_eq(dev_net(dev), &init_net))
+ goto drop;
+
+ if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+ skb->len != sizeof(struct canfd_frame) ||
+ cf->can_dlc > CANFD_MAX_DLC,
+ "PF_CAN: dropped non conform CAN FD skbuf: "
+ "dev type %d, len %d, can_dlc %d\n",
+ dev->type, skb->len, cf->can_dlc))
+ goto drop;
+
+ can_receive(skb, dev);
return NET_RX_SUCCESS;
drop:
@@ -811,6 +854,12 @@ static struct packet_type can_packet __read_mostly = {
.func = can_rcv,
};
+static struct packet_type canfd_packet __read_mostly = {
+ .type = cpu_to_be16(ETH_P_CANFD),
+ .dev = NULL,
+ .func = canfd_rcv,
+};
+
static const struct net_proto_family can_family_ops = {
.family = PF_CAN,
.create = can_create,
@@ -824,6 +873,10 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
static __init int can_init(void)
{
+ /* check for correct padding that can_dlc owns always the same position */
+ BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
+ offsetof(struct canfd_frame, can_dlc));
+
printk(banner);
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
@@ -846,6 +899,7 @@ static __init int can_init(void)
sock_register(&can_family_ops);
register_netdevice_notifier(&can_netdev_notifier);
dev_add_pack(&can_packet);
+ dev_add_pack(&canfd_packet);
return 0;
}
@@ -861,6 +915,7 @@ static __exit void can_exit(void)
/* protocol unregister */
dev_remove_pack(&can_packet);
+ dev_remove_pack(&canfd_packet);
unregister_netdevice_notifier(&can_netdev_notifier);
sock_unregister(PF_CAN);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 151b773..2060945 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -265,6 +265,7 @@ static void bcm_can_tx(struct bcm_op *op)
/* send with loopback */
skb->dev = dev;
skb->sk = op->sk;
+ skb->protocol = htons(ETH_P_CAN);
can_send(skb, 1);
/* update statistics */
@@ -1215,6 +1216,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
skb->dev = dev;
skb->sk = sk;
+ skb->protocol = htons(ETH_P_CAN);
err = can_send(skb, 1); /* send with loopback */
dev_put(dev);
diff --git a/net/can/raw.c b/net/can/raw.c
index cde1b4a..7d3864e 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -82,6 +82,7 @@ struct raw_sock {
struct notifier_block notifier;
int loopback;
int recv_own_msgs;
+ int fd_frames;
int count; /* number of active filters */
struct can_filter dfilter; /* default/single filter */
struct can_filter *filter; /* pointer to filter(s) */
@@ -119,6 +120,15 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
if (!ro->recv_own_msgs && oskb->sk == sk)
return;
+ /* only pass correct frames to the socket */
+ if (ro->fd_frames) {
+ if (oskb->protocol != htons(ETH_P_CANFD))
+ return;
+ } else {
+ if (oskb->protocol != htons(ETH_P_CAN))
+ return;
+ }
+
/* clone the given skb to be able to enqueue it into the rcv queue */
skb = skb_clone(oskb, GFP_ATOMIC);
if (!skb)
@@ -291,6 +301,7 @@ static int raw_init(struct sock *sk)
/* set default loopback behaviour */
ro->loopback = 1;
ro->recv_own_msgs = 0;
+ ro->fd_frames = 0;
/* set notifier */
ro->notifier.notifier_call = raw_notifier;
@@ -569,6 +580,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
break;
+ case CAN_RAW_FD_FRAMES:
+ if (optlen != sizeof(ro->fd_frames))
+ return -EINVAL;
+
+ if (copy_from_user(&ro->fd_frames, optval, optlen))
+ return -EFAULT;
+
+ break;
+
default:
return -ENOPROTOOPT;
}
@@ -627,6 +647,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
val = &ro->recv_own_msgs;
break;
+ case CAN_RAW_FD_FRAMES:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ val = &ro->fd_frames;
+ break;
+
default:
return -ENOPROTOOPT;
}
@@ -662,13 +688,24 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
} else
ifindex = ro->ifindex;
- if (size != sizeof(struct can_frame))
- return -EINVAL;
+ if (ro->fd_frames) {
+ if (size != sizeof(struct canfd_frame))
+ return -EINVAL;
+ } else {
+ if (size != sizeof(struct can_frame))
+ return -EINVAL;
+ }
dev = dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENXIO;
+ /* make sure the created CAN frame can pass the CAN netdevice */
+ if (size > dev->mtu) {
+ err = -EINVAL;
+ goto put_dev;
+ }
+
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
&err);
if (!skb)
@@ -684,6 +721,11 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
/* to be able to check the received tx sock reference in raw_rcv() */
skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
+ if (ro->fd_frames)
+ skb->protocol = htons(ETH_P_CANFD);
+ else
+ skb->protocol = htons(ETH_P_CAN);
+
skb->dev = dev;
skb->sk = sk;
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support part 1 - uncommented source
2012-05-03 11:14 [RFC] CAN FD support part 1 - uncommented source Oliver Hartkopp
@ 2012-05-03 11:34 ` Wolfgang Grandegger
2012-05-03 11:43 ` Oliver Hartkopp
0 siblings, 1 reply; 11+ messages in thread
From: Wolfgang Grandegger @ 2012-05-03 11:34 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: linux-can
On 05/03/2012 01:14 PM, Oliver Hartkopp wrote:
>
> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
>
> diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
> index f03d7a4..1b7e843 100644
> --- a/drivers/net/can/dev.c
> +++ b/drivers/net/can/dev.c
> @@ -454,7 +454,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;
> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
> index ea2d942..bddbafb 100644
> --- a/drivers/net/can/vcan.c
> +++ b/drivers/net/can/vcan.c
> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
> struct net_device_stats *stats = &dev->stats;
>
> stats->rx_packets++;
> - stats->rx_bytes += cf->can_dlc;
> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
Hm, I think "cf->can_dlc" should contain the *real* length. That would
simplify things a lot. The conversion is done when the corresponding DLC
registers are read or written.
Wolfgang.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support part 1 - uncommented source
2012-05-03 11:34 ` Wolfgang Grandegger
@ 2012-05-03 11:43 ` Oliver Hartkopp
2012-05-03 12:10 ` Wolfgang Grandegger
0 siblings, 1 reply; 11+ messages in thread
From: Oliver Hartkopp @ 2012-05-03 11:43 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: linux-can
On 03.05.2012 13:34, Wolfgang Grandegger wrote:
>> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
>> index ea2d942..bddbafb 100644
>> --- a/drivers/net/can/vcan.c
>> +++ b/drivers/net/can/vcan.c
>> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
>> struct net_device_stats *stats = &dev->stats;
>>
>> stats->rx_packets++;
>> - stats->rx_bytes += cf->can_dlc;
>> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
>
> Hm, I think "cf->can_dlc" should contain the *real* length. That would
> simplify things a lot. The conversion is done when the corresponding DLC
> registers are read or written.
I thought about this idea some time too.
My problem was that 'can_dlc' says
"CAN data length *code*"
And the dlc for CAN is already well defined.
From a todays view cf->len would indeed be a better expression :-/
We could generally think about a union of 'can_dlc' and 'len' though, where
can_dlc would not be part of struct canfd_frame but only the len value.
As you can see here, i also had the idea of providing both values:
https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869
But is was a bad design, as you have two APIs modifying one value - you
never know what to trust ... it was a sanity check hell.
Regards,
Oliver
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support part 1 - uncommented source
2012-05-03 11:43 ` Oliver Hartkopp
@ 2012-05-03 12:10 ` Wolfgang Grandegger
2012-05-03 12:18 ` [RFC] CAN FD support Kurt Van Dijck
0 siblings, 1 reply; 11+ messages in thread
From: Wolfgang Grandegger @ 2012-05-03 12:10 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: linux-can
On 05/03/2012 01:43 PM, Oliver Hartkopp wrote:
> On 03.05.2012 13:34, Wolfgang Grandegger wrote:
>
>>> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
>>> index ea2d942..bddbafb 100644
>>> --- a/drivers/net/can/vcan.c
>>> +++ b/drivers/net/can/vcan.c
>>> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
>>> struct net_device_stats *stats = &dev->stats;
>>>
>>> stats->rx_packets++;
>>> - stats->rx_bytes += cf->can_dlc;
>>> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
>>
>> Hm, I think "cf->can_dlc" should contain the *real* length. That would
>> simplify things a lot. The conversion is done when the corresponding DLC
>> registers are read or written.
>
>
> I thought about this idea some time too.
>
> My problem was that 'can_dlc' says
>
> "CAN data length *code*"
>
> And the dlc for CAN is already well defined.
>
>>From a todays view cf->len would indeed be a better expression :-/
Yes, definitely.
>
> We could generally think about a union of 'can_dlc' and 'len' though, where
> can_dlc would not be part of struct canfd_frame but only the len value.
Well, we do not need dlc in the struct, just len. The conversion
len->dlc needs just to be done once when register is read/written.
> As you can see here, i also had the idea of providing both values:
>
> https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869
>
> But is was a bad design, as you have two APIs modifying one value - you
> never know what to trust ... it was a sanity check hell.
If "cf->can_dlc", or however it is named, does not contain the real
length, we will end up in a dlc2len conversion nightmare. Be aware the
the struct is also used by the app.
Wolfgang.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 12:10 ` Wolfgang Grandegger
@ 2012-05-03 12:18 ` Kurt Van Dijck
2012-05-03 12:38 ` Oliver Hartkopp
0 siblings, 1 reply; 11+ messages in thread
From: Kurt Van Dijck @ 2012-05-03 12:18 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: Oliver Hartkopp, linux-can
On Thu, May 03, 2012 at 02:10:41PM +0200, Wolfgang Grandegger wrote:
> On 05/03/2012 01:43 PM, Oliver Hartkopp wrote:
> > On 03.05.2012 13:34, Wolfgang Grandegger wrote:
> >
> >>> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
> >>> index ea2d942..bddbafb 100644
> >>> --- a/drivers/net/can/vcan.c
> >>> +++ b/drivers/net/can/vcan.c
> >>> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
> >>> struct net_device_stats *stats = &dev->stats;
> >>>
> >>> stats->rx_packets++;
> >>> - stats->rx_bytes += cf->can_dlc;
> >>> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
> >>
> >> Hm, I think "cf->can_dlc" should contain the *real* length. That would
> >> simplify things a lot. The conversion is done when the corresponding DLC
> >> registers are read or written.
> >
> >
> > I thought about this idea some time too.
> >
> > My problem was that 'can_dlc' says
> >
> > "CAN data length *code*"
> >
> > And the dlc for CAN is already well defined.
> >
> >>From a todays view cf->len would indeed be a better expression :-/
>
> Yes, definitely.
>
> >
> > We could generally think about a union of 'can_dlc' and 'len' though, where
> > can_dlc would not be part of struct canfd_frame but only the len value.
>
> Well, we do not need dlc in the struct, just len. The conversion
> len->dlc needs just to be done once when register is read/written.
>
> > As you can see here, i also had the idea of providing both values:
> >
> > https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869
> >
> > But is was a bad design, as you have two APIs modifying one value - you
> > never know what to trust ... it was a sanity check hell.
>
> If "cf->can_dlc", or however it is named, does not contain the real
> length, we will end up in a dlc2len conversion nightmare. Be aware the
I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current
CAN frames have equal values for DLC & length!
> the struct is also used by the app.
>
> Wolfgang.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-can" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 12:18 ` [RFC] CAN FD support Kurt Van Dijck
@ 2012-05-03 12:38 ` Oliver Hartkopp
2012-05-03 12:43 ` Wolfgang Grandegger
2012-05-03 13:44 ` Marc Kleine-Budde
0 siblings, 2 replies; 11+ messages in thread
From: Oliver Hartkopp @ 2012-05-03 12:38 UTC (permalink / raw)
To: Wolfgang Grandegger, linux-can
On 03.05.2012 14:18, Kurt Van Dijck wrote:
> On Thu, May 03, 2012 at 02:10:41PM +0200, Wolfgang Grandegger wrote:
>> On 05/03/2012 01:43 PM, Oliver Hartkopp wrote:
>>> On 03.05.2012 13:34, Wolfgang Grandegger wrote:
>>>
>>>>> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
>>>>> index ea2d942..bddbafb 100644
>>>>> --- a/drivers/net/can/vcan.c
>>>>> +++ b/drivers/net/can/vcan.c
>>>>> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
>>>>> struct net_device_stats *stats = &dev->stats;
>>>>>
>>>>> stats->rx_packets++;
>>>>> - stats->rx_bytes += cf->can_dlc;
>>>>> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
>>>>
>>>> Hm, I think "cf->can_dlc" should contain the *real* length. That would
>>>> simplify things a lot. The conversion is done when the corresponding DLC
>>>> registers are read or written.
>>>
>>>
>>> I thought about this idea some time too.
>>>
>>> My problem was that 'can_dlc' says
>>>
>>> "CAN data length *code*"
>>>
>>> And the dlc for CAN is already well defined.
>>>
>>> >From a todays view cf->len would indeed be a better expression :-/
>>
>> Yes, definitely.
>>
>>>
>>> We could generally think about a union of 'can_dlc' and 'len' though, where
>>> can_dlc would not be part of struct canfd_frame but only the len value.
>>
>> Well, we do not need dlc in the struct, just len. The conversion
>> len->dlc needs just to be done once when register is read/written.
>>
>>> As you can see here, i also had the idea of providing both values:
>>>
>>> https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869
>>>
>>> But is was a bad design, as you have two APIs modifying one value - you
>>> never know what to trust ... it was a sanity check hell.
>>
>> If "cf->can_dlc", or however it is named, does not contain the real
>> length, we will end up in a dlc2len conversion nightmare. Be aware the
>
> I share this.
> I'd even prefer u16 over u8 even.
> No legacy issues exist when changing the meaning of can_dlc, since current
> CAN frames have equal values for DLC & length!
>
>> the struct is also used by the app.
Yes - that's the main problem IMO.
What about this binary compatible introduction of cf->len ...
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index bddbafb..366924e 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -74,7 +74,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
struct net_device_stats *stats = &dev->stats;
stats->rx_packets++;
- stats->rx_bytes += can_dlc2len(cf->can_dlc);
+ stats->rx_bytes += cf->len;
skb->pkt_type = PACKET_BROADCAST;
skb->dev = dev;
@@ -93,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 += can_dlc2len(cf->can_dlc);
+ stats->tx_bytes += cf->len;
/* set flag whether this packet has to be looped back */
loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -107,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 += can_dlc2len(cf->can_dlc);
+ stats->rx_bytes += cf->len;
}
kfree_skb(skb);
return NETDEV_TX_OK;
diff --git a/include/linux/can.h b/include/linux/can.h
index 74052da..b99f9f1 100644
--- a/include/linux/can.h
+++ b/include/linux/can.h
@@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
*/
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
- __u8 can_dlc; /* data length code: 0 .. 8 */
+ union {
+ __u8 can_dlc; /* data length code: 0 .. 8 */
+ __u8 len; /* data length: 0 .. 8 */
+ };
__u8 data[8] __attribute__((aligned(8)));
};
@@ -84,7 +87,7 @@ struct can_frame {
*/
struct canfd_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
- __u8 can_dlc; /* CAN FD data length code: 0 .. 0xF */
+ __u8 len; /* data length: 0 .. 64 */
__u8 flags; /* additional flags for CAN FD */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 1b7f1f8..9986d9c 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -875,7 +875,7 @@ static __init int can_init(void)
{
/* check for correct padding that can_dlc owns always the same position */
BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
- offsetof(struct canfd_frame, can_dlc));
+ offsetof(struct canfd_frame, len));
printk(banner);
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 12:38 ` Oliver Hartkopp
@ 2012-05-03 12:43 ` Wolfgang Grandegger
2012-05-03 13:00 ` Kurt Van Dijck
2012-05-03 13:44 ` Marc Kleine-Budde
1 sibling, 1 reply; 11+ messages in thread
From: Wolfgang Grandegger @ 2012-05-03 12:43 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: linux-can
On 05/03/2012 02:38 PM, Oliver Hartkopp wrote:
> On 03.05.2012 14:18, Kurt Van Dijck wrote:
>
>> On Thu, May 03, 2012 at 02:10:41PM +0200, Wolfgang Grandegger wrote:
>>> On 05/03/2012 01:43 PM, Oliver Hartkopp wrote:
>>>> On 03.05.2012 13:34, Wolfgang Grandegger wrote:
>>>>
>>>>>> diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
>>>>>> index ea2d942..bddbafb 100644
>>>>>> --- a/drivers/net/can/vcan.c
>>>>>> +++ b/drivers/net/can/vcan.c
>>>>>> @@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
>>>>>> struct net_device_stats *stats = &dev->stats;
>>>>>>
>>>>>> stats->rx_packets++;
>>>>>> - stats->rx_bytes += cf->can_dlc;
>>>>>> + stats->rx_bytes += can_dlc2len(cf->can_dlc);
>>>>>
>>>>> Hm, I think "cf->can_dlc" should contain the *real* length. That would
>>>>> simplify things a lot. The conversion is done when the corresponding DLC
>>>>> registers are read or written.
>>>>
>>>>
>>>> I thought about this idea some time too.
>>>>
>>>> My problem was that 'can_dlc' says
>>>>
>>>> "CAN data length *code*"
>>>>
>>>> And the dlc for CAN is already well defined.
>>>>
>>>> >From a todays view cf->len would indeed be a better expression :-/
>>>
>>> Yes, definitely.
>>>
>>>>
>>>> We could generally think about a union of 'can_dlc' and 'len' though, where
>>>> can_dlc would not be part of struct canfd_frame but only the len value.
>>>
>>> Well, we do not need dlc in the struct, just len. The conversion
>>> len->dlc needs just to be done once when register is read/written.
>>>
>>>> As you can see here, i also had the idea of providing both values:
>>>>
>>>> https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869
>>>>
>>>> But is was a bad design, as you have two APIs modifying one value - you
>>>> never know what to trust ... it was a sanity check hell.
>>>
>>> If "cf->can_dlc", or however it is named, does not contain the real
>>> length, we will end up in a dlc2len conversion nightmare. Be aware the
>>
>> I share this.
>> I'd even prefer u16 over u8 even.
>> No legacy issues exist when changing the meaning of can_dlc, since current
>> CAN frames have equal values for DLC & length!
>>
>>> the struct is also used by the app.
>
>
> Yes - that's the main problem IMO.
Furthermore, the user should be allowed to specify *any* lenght below
max, als 57 bytes. It's than up to the driver to do the necessary padding.
>
> What about this binary compatible introduction of cf->len ...
Looks good.
Wolfgang.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 12:43 ` Wolfgang Grandegger
@ 2012-05-03 13:00 ` Kurt Van Dijck
2012-05-03 13:13 ` Oliver Hartkopp
0 siblings, 1 reply; 11+ messages in thread
From: Kurt Van Dijck @ 2012-05-03 13:00 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: Oliver Hartkopp, linux-can
>
> Furthermore, the user should be allowed to specify *any* lenght below
> max, als 57 bytes. It's than up to the driver to do the necessary padding.
I think Oliver solved this (on af_can level?) with a table len2dlc (static in the header?)
>
> >
> > What about this binary compatible introduction of cf->len ...
>
> Looks good.
Yep, given 2 structs, this illustrates the contents very well!
Kurt
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 13:00 ` Kurt Van Dijck
@ 2012-05-03 13:13 ` Oliver Hartkopp
0 siblings, 0 replies; 11+ messages in thread
From: Oliver Hartkopp @ 2012-05-03 13:13 UTC (permalink / raw)
To: Wolfgang Grandegger, linux-can
On 03.05.2012 15:00, Kurt Van Dijck wrote:
>>
>> Furthermore, the user should be allowed to specify *any* lenght below
>> max, als 57 bytes. It's than up to the driver to do the necessary padding.
> I think Oliver solved this (on af_can level?) with a table len2dlc (static in the header?)
Yes - it was the only way not to make it clash when linking proc.o and
af_can.o together.
Btw. if we move this functionality to the driver, i would like to move it from
can.h into dev.c :-)
>
>>
>>>
>>> What about this binary compatible introduction of cf->len ...
>>
>> Looks good.
> Yep, given 2 structs, this illustrates the contents very well!
Fine.
One question:
What about omitting the union in struct can_frame modification and leave it as
it is since the first days of SocketCAN?
We can still check these offsets
BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
- offsetof(struct canfd_frame, can_dlc));
+ offsetof(struct canfd_frame, len));
and can (kernel) internally use struct canfd_frame as reference:
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct net_device_stats *stats = &dev->stats;
stats->rx_packets++;
stats->rx_bytes += cfd->len;
which would cover cf->can_dlc in the same way.
I wonder, if people would start to use can_frame.len once it is defined as
this would not be backward compatible code (but binary compatible).
Regards,
Oliver
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 12:38 ` Oliver Hartkopp
2012-05-03 12:43 ` Wolfgang Grandegger
@ 2012-05-03 13:44 ` Marc Kleine-Budde
2012-05-03 14:41 ` Oliver Hartkopp
1 sibling, 1 reply; 11+ messages in thread
From: Marc Kleine-Budde @ 2012-05-03 13:44 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: Wolfgang Grandegger, linux-can
[-- Attachment #1: Type: text/plain, Size: 1282 bytes --]
On 05/03/2012 02:38 PM, Oliver Hartkopp wrote:
[...]
>> I share this.
>> I'd even prefer u16 over u8 even.
>> No legacy issues exist when changing the meaning of can_dlc, since current
>> CAN frames have equal values for DLC & length!
>>
>>> the struct is also used by the app.
>
>
> Yes - that's the main problem IMO.
>
> What about this binary compatible introduction of cf->len ...
...but it's not 100% source compatible, due to a compiler bug in gcc.
You cannot use C99 initializers on anonymous unions in certain gcc versions.
[..]
> --- a/include/linux/can.h
> +++ b/include/linux/can.h
> @@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
> */
> struct can_frame {
> canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
> - __u8 can_dlc; /* data length code: 0 .. 8 */
> + union {
> + __u8 can_dlc; /* data length code: 0 .. 8 */
> + __u8 len; /* data length: 0 .. 8 */
> + };
> __u8 data[8] __attribute__((aligned(8)));
> };
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC] CAN FD support
2012-05-03 13:44 ` Marc Kleine-Budde
@ 2012-05-03 14:41 ` Oliver Hartkopp
0 siblings, 0 replies; 11+ messages in thread
From: Oliver Hartkopp @ 2012-05-03 14:41 UTC (permalink / raw)
To: Marc Kleine-Budde; +Cc: Wolfgang Grandegger, linux-can
On 03.05.2012 15:44, Marc Kleine-Budde wrote:
> On 05/03/2012 02:38 PM, Oliver Hartkopp wrote:
> [...]
>
>>> I share this.
>>> I'd even prefer u16 over u8 even.
>>> No legacy issues exist when changing the meaning of can_dlc, since current
>>> CAN frames have equal values for DLC & length!
>>>
>>>> the struct is also used by the app.
>>
>>
>> Yes - that's the main problem IMO.
>>
>> What about this binary compatible introduction of cf->len ...
>
> ...but it's not 100% source compatible, due to a compiler bug in gcc.
> You cannot use C99 initializers on anonymous unions in certain gcc versions.
ugh!
>
> [..]
>
>> --- a/include/linux/can.h
>> +++ b/include/linux/can.h
>> @@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
>> */
>> struct can_frame {
>> canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
>> - __u8 can_dlc; /* data length code: 0 .. 8 */
>> + union {
>> + __u8 can_dlc; /* data length code: 0 .. 8 */
>> + __u8 len; /* data length: 0 .. 8 */
>> + };
>> __u8 data[8] __attribute__((aligned(8)));
>> };
>
Thanks for the hint.
Indeed i left the struct can_frame as is now!
There's now can_frame.can_dlc and canfd_frame.len which both contains the real
length - even if can_frame.can_dlc is literally a data length *code* .
Btw. by having canfd_frame.len we indicate for CAN FD that we have a real
length here.
Regards,
Oliver
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2012-05-03 14:41 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-03 11:14 [RFC] CAN FD support part 1 - uncommented source Oliver Hartkopp
2012-05-03 11:34 ` Wolfgang Grandegger
2012-05-03 11:43 ` Oliver Hartkopp
2012-05-03 12:10 ` Wolfgang Grandegger
2012-05-03 12:18 ` [RFC] CAN FD support Kurt Van Dijck
2012-05-03 12:38 ` Oliver Hartkopp
2012-05-03 12:43 ` Wolfgang Grandegger
2012-05-03 13:00 ` Kurt Van Dijck
2012-05-03 13:13 ` Oliver Hartkopp
2012-05-03 13:44 ` Marc Kleine-Budde
2012-05-03 14:41 ` Oliver Hartkopp
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.