Re: [PATCH v4 4/5] net: can: flexcan: use CAN FD frames for Tx/Rx

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

 



On 08/12/2018 06:14 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
> 
> Cc: Oliver Hartkopp <socketcan@xxxxxxxxxxxx>
> Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx>
> ---
> 
> Notes:
>     V4:
>      - Based on Oliver's suggestion, used canfd_frame for both CAN 2.0 and
>        FD frames.
>      - Pass SKB to mailbox_read instead of can frame.
>      - introduced skb_overflow in rx_overload.
>     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      | 54 +++++++++++++++++++-------------
>  drivers/net/can/rx-offload.c   | 33 ++++++++++++++-----
>  include/linux/can/rx-offload.h |  6 +++-
>  3 files changed, 62 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index 3106134f3ba4..52c643d07f87 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -540,29 +540,31 @@ 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 canfd_frame *cfd = (struct canfd_frame *)skb->data;
>  	u32 can_id;
> -	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
> -	u8 can_dlc_dword, i;
> +	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (can_len2dlc(cfd->len) << 16);
> +	u8 can_len_dword, i;
>  
>  	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;
> +	if (cfd->can_id & CAN_EFF_FLAG) {
> +		can_id = cfd->can_id & CAN_EFF_MASK;
>  		ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
>  	} else {
> -		can_id = (cf->can_id & CAN_SFF_MASK) << 18;
> +		can_id = (cfd->can_id & CAN_SFF_MASK) << 18;
>  	}
>  
> -	if (cf->can_id & CAN_RTR_FLAG)
> -		ctrl |= FLEXCAN_MB_CNT_RTR;
> +	if (likely(!can_is_canfd_skb(skb))) {
> +		if (cfd->can_id & CAN_RTR_FLAG)
> +			ctrl |= FLEXCAN_MB_CNT_RTR;
> +	}
>  
> -	can_dlc_dword = DIV_ROUND_UP(cf->can_dlc, sizeof(u32));
> -	for (i = 0; i < can_dlc_dword; i++) {
> -		u32 data = be32_to_cpup((__be32 *)&cf->data[(i * sizeof(u32))]);
> +	can_len_dword = DIV_ROUND_UP(cfd->len, sizeof(u32));
> +	for (i = 0; i < can_len_dword; i++) {
> +		u32 data = be32_to_cpup((__be32 *)&cfd->data[(i * sizeof(u32))]);
>  		priv->write(data, &priv->tx_mb->data[i]);
>  	}
>  
> @@ -683,14 +685,15 @@ 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,
> +					 struct sk_buff *skb,
>  					 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 canfd_frame *cfd = (struct canfd_frame *)skb->data;
>  	u32 reg_ctrl, reg_id, reg_iflag1;
> -	u8 can_dlc_dword, i;
> +	u8 can_len_dword, i;
>  
>  	mb = flexcan_get_mb(priv, n);
>  
> @@ -725,18 +728,22 @@ 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;
> +		cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
>  	else
> -		cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
> +		cfd->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);
> +		cfd->can_id |= CAN_RTR_FLAG;
> +
> +	if (can_is_canfd_skb(skb))
> +		cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
> +	else
> +		cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
>  
> -	can_dlc_dword = DIV_ROUND_UP(cf->can_dlc, sizeof(u32));
> -	for (i = 0; i < can_dlc_dword; i++) {
> +	can_len_dword = DIV_ROUND_UP(cfd->len, sizeof(u32));
> +	for (i = 0; i < can_len_dword; i++) {
>  		__be32 data = cpu_to_be32(priv->read(&mb->data[i]));
> -		*(__be32 *)(cf->data + (i * sizeof(u32))) = data;
> +		*(__be32 *)(cfd->data + (i * sizeof(u32))) = data;
>  	}
>  
>  	/* mark as read */
> @@ -1150,10 +1157,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;
> +	}
>  	priv->mb_count = sizeof(priv->regs->mb[0]) / mb_size;
>  	priv->mb_count += sizeof(priv->regs->mb[1]) / mb_size;
>  
> diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
> index d94dae216820..1191fc23eb59 100644
> --- a/drivers/net/can/rx-offload.c
> +++ b/drivers/net/can/rx-offload.c
> @@ -55,11 +55,11 @@ 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 canfd_frame *cfd = (struct canfd_frame *)skb->data;
>  
>  		work_done++;
>  		stats->rx_packets++;
> -		stats->rx_bytes += cf->can_dlc;
> +		stats->rx_bytes += cfd->len;
>  		netif_receive_skb(skb);
>  	}
>  
> @@ -120,19 +120,23 @@ 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 *cfd;
>  	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, &cfd);
> +		else
> +			skb = alloc_can_skb(offload->dev,
> +					    (struct can_frame **)&cfd);
> +	}
>  
>  	if (!skb) {
> -		struct can_frame cf_overflow;
>  		u32 timestamp;
>  
> -		ret = offload->mailbox_read(offload, &cf_overflow,
> +		ret = offload->mailbox_read(offload, offload->skb_overflow,
>  					    &timestamp, n);
>  		if (ret)
>  			offload->dev->stats.rx_dropped++;
> @@ -141,7 +145,7 @@ 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);
> +	ret = offload->mailbox_read(offload, skb, &cb->timestamp, n);
>  	if (!ret) {
>  		kfree_skb(skb);
>  		return NULL;
> @@ -224,6 +228,8 @@ EXPORT_SYMBOL_GPL(can_rx_offload_irq_queue_err_skb);
>  
>  static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
>  {
> +	struct canfd_frame *cfd;
> +
>  	offload->dev = dev;
>  
>  	/* Limit queue len to 4x the weight (rounted to next power of two) */
> @@ -237,6 +243,15 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
>  	dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
>  		__func__, offload->skb_queue_len_max);
>  
> +	if (offload->fd_enable)
> +		offload->skb_overflow = alloc_canfd_skb(offload->dev, &cfd);
> +	else
> +		offload->skb_overflow = alloc_can_skb(offload->dev,
> +						      (struct can_frame **)&cfd);
> +
> +	if (unlikely(!offload->skb_overflow))
> +		return -ENOMEM;
> +
>  	return 0;
>  }
>  
> @@ -280,6 +295,8 @@ void can_rx_offload_del(struct can_rx_offload *offload)
>  {
>  	netif_napi_del(&offload->napi);
>  	skb_queue_purge(&offload->skb_queue);
> +	if (likely(offload->skb_overflow))

How can offload->skb_overflow be NULL?

> +		kfree_skb(offload->skb_overflow);


>  }
>  EXPORT_SYMBOL_GPL(can_rx_offload_del);
>  
> diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h
> index cb31683bbe15..fc290efa22d6 100644
> --- a/include/linux/can/rx-offload.h
> +++ b/include/linux/can/rx-offload.h
> @@ -23,10 +23,13 @@
>  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,
> +				     struct sk_buff *skb,
>  				     u32 *timestamp, unsigned int mb);
>  
>  	struct sk_buff_head skb_queue;
> +	struct sk_buff *skb_overflow;
> +
>  	u32 skb_queue_len_max;
>  
>  	unsigned int mb_first;
> @@ -34,6 +37,7 @@ struct can_rx_offload {
>  
>  	struct napi_struct napi;
>  
> +	bool fd_enable;
>  	bool inc;
>  };
>  
> 

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: 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