RE: [PATCH v2 1/4] net: can: flexcan: use CAN FD frames for Tx/Rx

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

 



> -----Original Message-----
> From: linux-can-owner@xxxxxxxxxxxxxxx <linux-can-owner@xxxxxxxxxxxxxxx>
> On Behalf Of Pankaj Bansal
> Sent: 2019年5月28日 17:55
> To: Wolfgang Grandegger <wg@xxxxxxxxxxxxxx>; Marc Kleine-Budde
> <mkl@xxxxxxxxxxxxxx>
> Cc: linux-can@xxxxxxxxxxxxxxx
> Subject: [PATCH v2 1/4] net: can: flexcan: use CAN FD frames for Tx/Rx
> 
> 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:
>     V2:
>     - No change
> 
>  drivers/net/can/flexcan.c      | 36 +++++++++++++++++++-------------
>  drivers/net/can/rx-offload.c   | 32 +++++++++++++++++++++-------
>  include/linux/can/rx-offload.h |  6 +++++-
>  3 files changed, 50 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index
> 44258cc871b3..931efffb8fa2 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -609,10 +609,10 @@ 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 data;
> -	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
> +	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (can_len2dlc(cfd->len) << 16);
>  	int i;
> 
>  	if (can_dropped_invalid_skb(dev, skb)) @@ -620,18 +620,18 @@ static
> netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
> 
>  	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)
> +	if (!can_is_canfd_skb(skb) && (cfd->can_id & CAN_RTR_FLAG))
>  		ctrl |= FLEXCAN_MB_CNT_RTR;
> 
> -	for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
> -		data = be32_to_cpup((__be32 *)&cf->data[i]);
> +	for (i = 0; i < can_len2dlc(cfd->len); i += sizeof(u32)) {
> +		data = be32_to_cpup((__be32 *)&cfd->data[i]);
>  		priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
>  	}
> 
> @@ -760,12 +760,13 @@ 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;
>  	int i;
> 
> @@ -802,17 +803,21 @@ 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;
> 
> -	for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
> +	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);
> +
> +	for (i = 0; i < cfd->len; i += sizeof(u32)) {
>  		__be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
> -		*(__be32 *)(cf->data + i) = data;
> +		*(__be32 *)(cfd->data + i) = data;
>  	}
> 
>  	/* mark as read */
> @@ -1262,6 +1267,7 @@ static int flexcan_open(struct net_device *dev)
>  	priv->reg_imask1_default = 0;
>  	priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
> 
> +	priv->offload.fd_enable = false;
>  	priv->offload.mailbox_read = flexcan_mailbox_read;
> 
>  	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
> { diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index
> 2ce4fa8698c7..556b280aa46c 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);
>  	}
> 
> @@ -122,19 +122,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);

[Joakinm Zhang]
Using alloc_canfd_skb() to allocate skb when FD mode enable, it is unreasonable.
When FD mode enabled, we also can transmit/receive classic frame, should use alloc_can_skb()
in this case. If you still use alloc_can_skb() in this case, it will cause failure for remote frame.
So it is more reasonable to allocate skb after we received the CAN frame.

> +	}
> 
>  	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++;
> @@ -143,7 +147,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;
> @@ -273,6 +277,8 @@ EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
> 
>  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) */
> @@ -286,6 +292,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;
>  }
> 
> @@ -329,6 +344,7 @@ void can_rx_offload_del(struct can_rx_offload
> *offload)  {
>  	netif_napi_del(&offload->napi);
>  	skb_queue_purge(&offload->skb_queue);
> +	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 8268811a697e..d01eb356692c 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;
>  };
> 
> --
> 2.17.1





[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