Re: [PATCH v3 7/7] net: can: flexcan: use CAN FD frames for Tx/Rx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 08/01/2018 04:06 PM, Pankaj Bansal wrote:
> Use can FD frames for Tx/Rx operations. This would be needed in upcoming
> SOC LX2160A, which supports CAN FD protocol
> 
> Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx>
> ---
> 
> Notes:
>     V3:
>      - introduced fd_enable in rx_offload structure. This boolean indicates if
>        the FD mode is enabled or not.
>      - Based on fd_enable, send the CAN FD or CAN 2.0 frame to mailbox_read.
>      - in mailbox_read, detect the type of frame from fd_enable and fill the
>        values accordingly.
>      - in xmit function, detect the type of SKB received. if CAN FD SKB is
>        detected, tread its data as canfd_frame otherwise can_frame. Then fill
>        the values accordingly.
>     V2:
>      - No change
> 
>  drivers/net/can/flexcan.c      | 80 +++++++++++++++++++++++---------
>  drivers/net/can/rx-offload.c   | 35 +++++++++++---
>  include/linux/can/rx-offload.h |  4 +-
>  3 files changed, 89 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index c9edfc808f8f..52b0d19c80f0 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -540,30 +540,48 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
>  static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  {
>  	const struct flexcan_priv *priv = netdev_priv(dev);
> -	struct can_frame *cf = (struct can_frame *)skb->data;
> +	struct can_frame *cf;
> +	struct canfd_frame *cf_fd;

You can keep the assignment of cf and add cf_fd here.

>  	u32 can_id;
>  	u32 data;
> -	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
> -	u8 can_dlc_dword, i;
> +	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA;
> +	u8 can_dlc_dword, i, *pframe_data;
>  
>  	if (can_dropped_invalid_skb(dev, skb))
>  		return NETDEV_TX_OK;
>  
>  	netif_stop_queue(dev);
>  
> -	if (cf->can_id & CAN_EFF_FLAG) {
> -		can_id = cf->can_id & CAN_EFF_MASK;
> -		ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
> +	if (can_is_canfd_skb(skb)) {
> +		cf_fd = (struct canfd_frame *)skb->data;

VVV
> +		if (cf_fd->can_id & CAN_EFF_FLAG) {
> +			can_id = cf_fd->can_id & CAN_EFF_MASK;
> +			ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
> +		} else {
> +			can_id = (cf_fd->can_id & CAN_SFF_MASK) << 18;
> +		}
^^^

Is this code block the same for CAN-2.0 and CAN-FD frames? If so, please
don't copy-paste it.

> +
> +		ctrl |= (can_len2dlc(cf_fd->len) << 16);
> +		can_dlc_dword = (cf_fd->len + sizeof(u32) - 1) / sizeof(u32);
DIV_ROUND_UP
> +		pframe_data = cf_fd->data;

no need for pframe_data you can just use cf_fd->data, as it's compatible
with cf->data.

>  	} else {
> -		can_id = (cf->can_id & CAN_SFF_MASK) << 18;
> -	}
> +		cf = (struct can_frame *)skb->data;
> +		if (cf->can_id & CAN_EFF_FLAG) {
> +			can_id = cf->can_id & CAN_EFF_MASK;
> +			ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
> +		} else {
> +			can_id = (cf->can_id & CAN_SFF_MASK) << 18;
> +		}
> +		if (cf->can_id & CAN_RTR_FLAG)
> +			ctrl |= FLEXCAN_MB_CNT_RTR;
>  
> -	if (cf->can_id & CAN_RTR_FLAG)
> -		ctrl |= FLEXCAN_MB_CNT_RTR;
> +		ctrl |= (cf->can_dlc << 16);
> +		can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
DIV_ROUND_UP
> +		pframe_data = cf->data;
> +	}
>  
> -	can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
>  	for (i = 0; i < can_dlc_dword; i++) {
> -		data = be32_to_cpup((__be32 *)&cf->data[(i * sizeof(u32))]);
> +		data = be32_to_cpup((__be32 *)&pframe_data[(i * sizeof(u32))]);
>  		priv->write(data, &priv->tx_mb->data[i]);
>  	}
>  
> @@ -684,15 +702,18 @@ static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *off
>  }
>  
>  static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
> -					 struct can_frame *cf,
> +					 void *frame,
>  					 u32 *timestamp, unsigned int n)
>  {
>  	struct flexcan_priv *priv = rx_offload_to_priv(offload);
>  	struct flexcan_regs __iomem *regs = priv->regs;
>  	struct flexcan_mb __iomem *mb;
> +	struct can_frame *cf;
> +	struct canfd_frame *cf_fd;
>  	u32 reg_ctrl, reg_id, reg_iflag1;
>  	__be32 data;
> -	u8 can_dlc_dword, i;
> +	u8 can_dlc_dword, i, *pframe_data;
> +	canid_t can_id;
>  
>  	mb = flexcan_get_mb(priv, n);
>  
> @@ -727,18 +748,30 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
>  
>  	reg_id = priv->read(&mb->can_id);
>  	if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
> -		cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
> +		can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
>  	else
> -		cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
> +		can_id = (reg_id >> 18) & CAN_SFF_MASK;
>  
>  	if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
> -		cf->can_id |= CAN_RTR_FLAG;
> -	cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
> +		can_id |= CAN_RTR_FLAG;
> +
> +	if (offload->fd_enable) {
> +		cf_fd = (struct canfd_frame *)frame;
> +		cf_fd->can_id = can_id;
> +		cf_fd->len = can_dlc2len((reg_ctrl >> 16) & 0xf);
> +		can_dlc_dword = (cf_fd->len + sizeof(u32) - 1) / sizeof(u32);
DIV_ROUND_UP
> +		pframe_data = cf_fd->data;

Just use cf_fd->data, see above

> +	} else {
> +		cf = (struct can_frame *)frame;
> +		cf->can_id = can_id;
> +		cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
> +		can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
DIV_ROUND_UP
> +		pframe_data = cf->data;
> +	}
>  
> -	can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
>  	for (i = 0; i < can_dlc_dword; i++) {
>  		data = cpu_to_be32(priv->read(&mb->data[i]));
> -		*(__be32 *)(cf->data + (i * sizeof(u32))) = data;
> +		*(__be32 *)(pframe_data + (i * sizeof(u32))) = data;
>  	}
>  
>  	/* mark as read */
> @@ -1152,10 +1185,13 @@ static int flexcan_open(struct net_device *dev)
>  	if (err)
>  		goto out_close;
>  
> -	if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
> +		priv->offload.fd_enable = true;
>  		mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
> -	else
> +	} else {
> +		priv->offload.fd_enable = false;
>  		mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
> +	}
>  
>  	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
>  		priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP;
> diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
> index d94dae216820..18a23f919771 100644
> --- a/drivers/net/can/rx-offload.c
> +++ b/drivers/net/can/rx-offload.c
> @@ -55,11 +55,19 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
>  
>  	while ((work_done < quota) &&
>  	       (skb = skb_dequeue(&offload->skb_queue))) {
> -		struct can_frame *cf = (struct can_frame *)skb->data;
> +		struct can_frame *cf;
> +		struct canfd_frame *cf_fd;
> +
> +		if (can_is_canfd_skb(skb)) {
> +			cf_fd = (struct canfd_frame *)skb->data;
> +			stats->rx_bytes += cf_fd->len;
> +		} else {
> +			cf = (struct can_frame *)skb->data;
> +			stats->rx_bytes += cf->can_dlc;
> +		}
>  
>  		work_done++;
>  		stats->rx_packets++;
> -		stats->rx_bytes += cf->can_dlc;
>  		netif_receive_skb(skb);
>  	}
>  
> @@ -121,19 +129,29 @@ static struct sk_buff *can_rx_offload_offload_one(struct can_rx_offload *offload
>  	struct sk_buff *skb = NULL;
>  	struct can_rx_offload_cb *cb;
>  	struct can_frame *cf;
> +	struct canfd_frame *cf_fd;
>  	int ret;
>  
>  	/* If queue is full or skb not available, read to discard mailbox */
>  	if (likely(skb_queue_len(&offload->skb_queue) <=
> -		   offload->skb_queue_len_max))
> -		skb = alloc_can_skb(offload->dev, &cf);
> +		   offload->skb_queue_len_max)) {
> +		if (offload->fd_enable)
> +			skb = alloc_canfd_skb(offload->dev, &cf_fd);
> +		else
> +			skb = alloc_can_skb(offload->dev, &cf);
> +	}
>  
>  	if (!skb) {
>  		struct can_frame cf_overflow;
> +		struct canfd_frame cf_fd_overflow;
>  		u32 timestamp;
>  
> -		ret = offload->mailbox_read(offload, &cf_overflow,
> -					    &timestamp, n);
> +		if (offload->fd_enable)
> +			ret = offload->mailbox_read(offload, &cf_fd_overflow,
> +						    &timestamp, n);
> +		else
> +			ret = offload->mailbox_read(offload, &cf_overflow,
> +						    &timestamp, n);
>  		if (ret)
>  			offload->dev->stats.rx_dropped++;
>  
> @@ -141,7 +159,10 @@ static struct sk_buff *can_rx_offload_offload_one(struct can_rx_offload *offload
>  	}
>  
>  	cb = can_rx_offload_get_cb(skb);
> -	ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
> +	if (offload->fd_enable)
> +		ret = offload->mailbox_read(offload, cf_fd, &cb->timestamp, n);
> +	else
> +		ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
>  	if (!ret) {
>  		kfree_skb(skb);
>  		return NULL;
> diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h
> index cb31683bbe15..306a807ba93f 100644
> --- a/include/linux/can/rx-offload.h
> +++ b/include/linux/can/rx-offload.h
> @@ -23,7 +23,8 @@
>  struct can_rx_offload {
>  	struct net_device *dev;
>  
> -	unsigned int (*mailbox_read)(struct can_rx_offload *offload, struct can_frame *cf,
> +	unsigned int (*mailbox_read)(struct can_rx_offload *offload,
> +				     void *frame,
>  				     u32 *timestamp, unsigned int mb);
>  
>  	struct sk_buff_head skb_queue;
> @@ -34,6 +35,7 @@ struct can_rx_offload {
>  
>  	struct napi_struct napi;
>  
> +	bool fd_enable;
>  	bool inc;
>  };
>  
> 


-- 
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: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux