[PATCH v6 5/6] net: can: flexcan: use CAN FD frames for Tx/Rx

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

 



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:
    V6:
     - No Change
    V5:
     - removed likely from xmit
     - removed if condition when free skb_overflow in rx_offload delete
    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   | 32 ++++++++++++++-----
 include/linux/can/rx-offload.h |  6 +++-
 3 files changed, 61 insertions(+), 31 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f6bbcfdd4d46..dcb86dfa799c 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -536,29 +536,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 (!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]);
 	}
 
@@ -679,14 +681,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);
 
@@ -721,18 +724,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 */
@@ -1151,10 +1158,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;
 		priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
-	else
+	} else {
+		priv->offload.fd_enable = false;
 		priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
+	}
 	priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
 			 (sizeof(priv->regs->mb[1]) / priv->mb_size);
 
diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
index d94dae216820..f681a7b914f5 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,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 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;
 };
 
-- 
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