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, > ×tamp, 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