We need to use alloc_canfd_skb() for CAN FD frames and alloc_can_skb()
for CAN classic frames. So we have to alloc skb in flexcan_mailbox_read().

Signed-off-by: Joakim Zhang <qiangqing.zh...@nxp.com>

ChangeLog:
----------
V1->V2:
        *None
V2->V3:
        *Change the way to allocate skb
---
 drivers/net/can/flexcan.c      | 38 ++++++++++++++++++++--------------
 drivers/net/can/rx-offload.c   | 29 +++++++-------------------
 include/linux/can/rx-offload.h |  5 +++--
 3 files changed, 33 insertions(+), 39 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index e35083ff31ee..f742077e8f93 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -789,14 +789,15 @@ static inline struct flexcan_priv 
*rx_offload_to_priv(struct can_rx_offload *off
        return container_of(offload, struct flexcan_priv, offload);
 }
 
-static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
-                                        struct can_frame *cf,
-                                        u32 *timestamp, unsigned int n)
+static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, bool 
drop,
+                                        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;
        u32 reg_ctrl, reg_id, reg_iflag1;
+       struct can_frame *cf;
        int i;
 
        mb = flexcan_get_mb(priv, n);
@@ -827,22 +828,27 @@ static unsigned int flexcan_mailbox_read(struct 
can_rx_offload *offload,
                reg_ctrl = priv->read(&mb->can_ctrl);
        }
 
-       /* increase timstamp to full 32 bit */
-       *timestamp = reg_ctrl << 16;
+       if (!drop)
+               *skb = alloc_can_skb(offload->dev, &cf);
 
-       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;
-       else
-               cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+       if (*skb) {
+               /* increase timstamp to full 32 bit */
+               *timestamp = reg_ctrl << 16;
 
-       if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
-               cf->can_id |= CAN_RTR_FLAG;
-       cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+               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;
+               else
+                       cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
 
-       for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
-               __be32 data = cpu_to_be32(priv->read(&mb->data[i / 
sizeof(u32)]));
-               *(__be32 *)(cf->data + i) = data;
+               if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+                       cf->can_id |= CAN_RTR_FLAG;
+               cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+
+               for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
+                       __be32 data = cpu_to_be32(priv->read(&mb->data[i / 
sizeof(u32)]));
+                       *(__be32 *)(cf->data + i) = data;
+               }
        }
 
        /* mark as read */
diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
index 2ce4fa8698c7..632919484ff7 100644
--- a/drivers/net/can/rx-offload.c
+++ b/drivers/net/can/rx-offload.c
@@ -121,32 +121,19 @@ static int can_rx_offload_compare(struct sk_buff *a, 
struct sk_buff *b)
 static struct sk_buff *can_rx_offload_offload_one(struct can_rx_offload 
*offload, unsigned int n)
 {
        struct sk_buff *skb = NULL;
-       struct can_rx_offload_cb *cb;
-       struct can_frame *cf;
-       int ret;
+       u32 timestamp;
 
        /* 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);
+       bool drop = unlikely(skb_queue_len(&offload->skb_queue) >
+                            offload->skb_queue_len_max);
 
-       if (!skb) {
-               struct can_frame cf_overflow;
-               u32 timestamp;
+       if (offload->mailbox_read(offload, drop, &skb, &timestamp, n) && !skb)
+               offload->dev->stats.rx_dropped++;
 
-               ret = offload->mailbox_read(offload, &cf_overflow,
-                                           &timestamp, n);
-               if (ret)
-                       offload->dev->stats.rx_dropped++;
+       if (skb) {
+               struct can_rx_offload_cb *cb = can_rx_offload_get_cb(skb);
 
-               return NULL;
-       }
-
-       cb = can_rx_offload_get_cb(skb);
-       ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
-       if (!ret) {
-               kfree_skb(skb);
-               return NULL;
+               cb->timestamp = timestamp;
        }
 
        return skb;
diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h
index 8268811a697e..c54d80ef4314 100644
--- a/include/linux/can/rx-offload.h
+++ b/include/linux/can/rx-offload.h
@@ -23,8 +23,9 @@
 struct can_rx_offload {
        struct net_device *dev;
 
-       unsigned int (*mailbox_read)(struct can_rx_offload *offload, struct 
can_frame *cf,
-                                    u32 *timestamp, unsigned int mb);
+       unsigned int (*mailbox_read)(struct can_rx_offload *offload, bool drop,
+                                    struct sk_buff **skb, u32 *timestamp,
+                                    unsigned int mb);
 
        struct sk_buff_head skb_queue;
        u32 skb_queue_len_max;
-- 
2.17.1

Reply via email to