From: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> This patch adds the function can_skb_get_dll_len() which returns the length of a CAN frame on the data link layer, including Start-of-frame, Identifier, various other bits, the CRC, the End-of-frame, the Inter frame spacing and the actual data. Co-developed-by: Arunachalam Santhanam <arunachalam.santhanam@xxxxxxxxxxxx> Not-Signed-off-by: Arunachalam Santhanam <arunachalam.santhanam@xxxxxxxxxxxx> Co-developed-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> Not-Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> Co-developed-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> --- drivers/net/can/dev.c | 166 ++++++++++++++++++++++++++++++++++++++++ include/linux/can/dev.h | 3 + 2 files changed, 169 insertions(+) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index fa81e3067b3b..e11e3d95453b 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -81,6 +81,172 @@ u8 can_len2dll_len(u8 len) } EXPORT_SYMBOL_GPL(can_len2dll_len); +/* Size of a Classical CAN Standard Frame + * + * Name of Field Bits + * --------------------------------------------------------- + * Start-of-frame 1 + * Identifier 11 + * Remote transmission request (RTR) 1 + * Identifier extension bit (IDE) 1 + * Reserved bit (r0) 1 + * Data length code (DLC) 4 + * Data field 0...64 + * CRC 15 + * CRC delimiter 1 + * ACK slot 1 + * ACK delimiter 1 + * End-of-frame (EOF) 7 + * Inter frame spacing 3 + * + * rounded up and ignoring bitsuffing + */ +#define CAN_DLL_OVERHEAD_SFF DIV_ROUND_UP(47, 8) + +/* Size of a Classical CAN Extended Frame + * + * Name of Field Bits + * --------------------------------------------------------- + * Start-of-frame 1 + * Identifier A 11 + * Substitute remote request (SRR) 1 + * Identifier extension bit (IDE) 1 + * Identifier B 18 + * Remote transmission request (RTR) 1 + * Reserved bits (r1, r0) 2 + * Data length code (DLC) 4 + * Data field 0...64 + * CRC 15 + * CRC delimiter 1 + * ACK slot 1 + * ACK delimiter 1 + * End-of-frame (EOF) 7 + * Inter frame spacing 3 + * + * rounded up and ignoring bitsuffing + */ +#define CAN_DLL_OVERHEAD_EFF DIV_ROUND_UP(67, 8) + +/* Size of a CAN-FD Standard Frame + * + * Name of Field Bits + * --------------------------------------------------------- + * Start-of-frame 1 + * Identifier 11 + * Reserved bit (r1) 1 + * Identifier extension bit (IDE) 1 + * Flexible data rate format (FDF) 1 + * Reserved bit (r0) 1 + * Bit Rate Switch (BRS) 1 + * Error Status Indicator (ESI) 1 + * Data length code (DLC) 4 + * Data field 0...512 + * Stuff Bit Count (SBC) 4/5 0...16/20...64 + * CRC 17/21 0...16/20...64 + * CRC delimiter (CD) 1 + * ACK slot (AS) 1 + * ACK delimiter (AD) 1 + * End-of-frame (EOF) 7 + * Inter frame spacing 3 + * + * assuming CRC21, rounded up and ignoring bitsuffing + */ +#define CANFD_DLL_OVERHEAD_SFF DIV_ROUND_UP(61, 8) + +/* Size of a CAN-FD Extended Frame + * + * Name of Field Bits + * --------------------------------------------------------- + * Start-of-frame 1 + * Identifier A 11 + * Substitute remote request (SRR) 1 + * Identifier extension bit (IDE) 1 + * Identifier B 18 + * Reserved bit (r1) 1 + * Flexible data rate format (FDF) 1 + * Reserved bit (r0) 1 + * Bit Rate Switch (BRS) 1 + * Error Status Indicator (ESI) 1 + * Data length code (DLC) 4 + * Data field 0...512 + * Stuff Bit Count (SBC) 4/5 0...16/20...64 + * CRC 17/21 0...16/20...64 + * CRC delimiter (CD) 1 + * ACK slot (AS) 1 + * ACK delimiter (AD) 1 + * End-of-frame (EOF) 7 + * Inter frame spacing 3 + * + * assuming CRC21, rounded up and ignoring bitsuffing + */ +#define CANFD_DLL_OVERHEAD_EFF DIV_ROUND_UP(80, 8) + +/* Maximum size of a Classical CAN frame + * (rounded up and ignoring bitsuffing) + */ +#define CAN_DLL_LEN_MAX (CAN_DLL_OVERHEAD_EFF + CAN_MAX_DLEN) + +/* Maximum size of a CAN-FD frame (rough estimation because + * ES58X_SFF_BYTES() and ES58X_EFF_BYTES() macros are using the + * constant values for Classical CAN, not CAN-FD). + */ +#define CANFD_DLL_LEN_MAX (CANFD_DLL_OVERHEAD_EFF + CANFD_MAX_DLEN) + +/** + * can_skb_get_dll_len() - Calculate the CAN Data Link Layer length in + * bytes of a given skb. + * @skb: socket buffer of a CAN message. + * + * Do a rough calculation: bit stuffing is ignored and length in bits + * is rounded up to a length in bytes. + * + * Rationale: this function is to be used for the BQL functions + * (netdev_sent_queue() and netdev_completed_queue()) which expect a + * value in bytes. Just using skb->len is insufficient because it will + * return the constant value of CAN(FD)_MTU. Doing the bit stuffing + * calculation would be too expensive in term of computing resources + * for no noticeable gain. + * + * Remarks: + * a.) The payload of CAN FD frames with BRS flag are sent at a + * different bitrate. Currently, the can-utils canbusload tool does + * not support CAN-FD yet and so we could not run any benchmark to + * measure the impact. There might be possible improvement here. + * b.) The macro CAN_DLL_OVERHEAD_EFF and CAN_DLL_OVERHEAD_SFF are + * for classical CAN. Need to do the addition for CAN-FD (the value + * are expected to be close enough so the impact should be minimal or + * none). + * + * Return: length in bytes. + */ +unsigned int can_skb_get_dll_len(const struct sk_buff *skb) +{ + const struct canfd_frame *cf = (const struct canfd_frame *)skb->data; + u8 len; + + if (can_is_canfd_skb(skb)) + len = can_len2dll_len(cf->len); + else if (cf->can_id & CAN_RTR_FLAG) + len = 0; + else + len = cf->len; + + if (can_is_canfd_skb(skb)) { + if (cf->can_id & CAN_EFF_FLAG) + len += CANFD_DLL_OVERHEAD_EFF; + else + len += CANFD_DLL_OVERHEAD_SFF; + } else { + if (cf->can_id & CAN_EFF_FLAG) + len += CAN_DLL_OVERHEAD_EFF; + else + len += CAN_DLL_OVERHEAD_SFF; + } + + return len; +} +EXPORT_SYMBOL_GPL(can_skb_get_dll_len); + #ifdef CONFIG_CAN_CALC_BITTIMING #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 27c359a00203..affdee8f64c4 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -195,6 +195,9 @@ u8 can_len2dlc(u8 len); /* map the sanitized data length to an appropriate data link layer length */ u8 can_len2dll_len(u8 len); +/* get data link layer length of CAN/CAN-FD frame */ +unsigned int can_skb_get_dll_len(const struct sk_buff *skb); + struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max, unsigned int txqs, unsigned int rxqs); #define alloc_candev(sizeof_priv, echo_skb_max) \ -- 2.29.2