On 08/01/2018 04:06 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 > > Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx> > --- > > Notes: > 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 | 80 +++++++++++++++++++++++--------- > drivers/net/can/rx-offload.c | 35 +++++++++++--- > include/linux/can/rx-offload.h | 4 +- > 3 files changed, 89 insertions(+), 30 deletions(-) > > diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c > index c9edfc808f8f..52b0d19c80f0 100644 > --- a/drivers/net/can/flexcan.c > +++ b/drivers/net/can/flexcan.c > @@ -540,30 +540,48 @@ 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 can_frame *cf; > + struct canfd_frame *cf_fd; You can keep the assignment of cf and add cf_fd here. > u32 can_id; > u32 data; > - u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16); > - u8 can_dlc_dword, i; > + u32 ctrl = FLEXCAN_MB_CODE_TX_DATA; > + u8 can_dlc_dword, i, *pframe_data; > > 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; > - ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; > + if (can_is_canfd_skb(skb)) { > + cf_fd = (struct canfd_frame *)skb->data; VVV > + if (cf_fd->can_id & CAN_EFF_FLAG) { > + can_id = cf_fd->can_id & CAN_EFF_MASK; > + ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; > + } else { > + can_id = (cf_fd->can_id & CAN_SFF_MASK) << 18; > + } ^^^ Is this code block the same for CAN-2.0 and CAN-FD frames? If so, please don't copy-paste it. > + > + ctrl |= (can_len2dlc(cf_fd->len) << 16); > + can_dlc_dword = (cf_fd->len + sizeof(u32) - 1) / sizeof(u32); DIV_ROUND_UP > + pframe_data = cf_fd->data; no need for pframe_data you can just use cf_fd->data, as it's compatible with cf->data. > } else { > - can_id = (cf->can_id & CAN_SFF_MASK) << 18; > - } > + cf = (struct can_frame *)skb->data; > + if (cf->can_id & CAN_EFF_FLAG) { > + can_id = cf->can_id & CAN_EFF_MASK; > + ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; > + } else { > + can_id = (cf->can_id & CAN_SFF_MASK) << 18; > + } > + if (cf->can_id & CAN_RTR_FLAG) > + ctrl |= FLEXCAN_MB_CNT_RTR; > > - if (cf->can_id & CAN_RTR_FLAG) > - ctrl |= FLEXCAN_MB_CNT_RTR; > + ctrl |= (cf->can_dlc << 16); > + can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32); DIV_ROUND_UP > + pframe_data = cf->data; > + } > > - can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32); > for (i = 0; i < can_dlc_dword; i++) { > - data = be32_to_cpup((__be32 *)&cf->data[(i * sizeof(u32))]); > + data = be32_to_cpup((__be32 *)&pframe_data[(i * sizeof(u32))]); > priv->write(data, &priv->tx_mb->data[i]); > } > > @@ -684,15 +702,18 @@ 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, > + void *frame, > 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 can_frame *cf; > + struct canfd_frame *cf_fd; > u32 reg_ctrl, reg_id, reg_iflag1; > __be32 data; > - u8 can_dlc_dword, i; > + u8 can_dlc_dword, i, *pframe_data; > + canid_t can_id; > > mb = flexcan_get_mb(priv, n); > > @@ -727,18 +748,30 @@ 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; > + can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; > else > - cf->can_id = (reg_id >> 18) & CAN_SFF_MASK; > + 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); > + can_id |= CAN_RTR_FLAG; > + > + if (offload->fd_enable) { > + cf_fd = (struct canfd_frame *)frame; > + cf_fd->can_id = can_id; > + cf_fd->len = can_dlc2len((reg_ctrl >> 16) & 0xf); > + can_dlc_dword = (cf_fd->len + sizeof(u32) - 1) / sizeof(u32); DIV_ROUND_UP > + pframe_data = cf_fd->data; Just use cf_fd->data, see above > + } else { > + cf = (struct can_frame *)frame; > + cf->can_id = can_id; > + cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf); > + can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32); DIV_ROUND_UP > + pframe_data = cf->data; > + } > > - can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32); > for (i = 0; i < can_dlc_dword; i++) { > data = cpu_to_be32(priv->read(&mb->data[i])); > - *(__be32 *)(cf->data + (i * sizeof(u32))) = data; > + *(__be32 *)(pframe_data + (i * sizeof(u32))) = data; > } > > /* mark as read */ > @@ -1152,10 +1185,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; > + } > > if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { > priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP; > diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c > index d94dae216820..18a23f919771 100644 > --- a/drivers/net/can/rx-offload.c > +++ b/drivers/net/can/rx-offload.c > @@ -55,11 +55,19 @@ 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 can_frame *cf; > + struct canfd_frame *cf_fd; > + > + if (can_is_canfd_skb(skb)) { > + cf_fd = (struct canfd_frame *)skb->data; > + stats->rx_bytes += cf_fd->len; > + } else { > + cf = (struct can_frame *)skb->data; > + stats->rx_bytes += cf->can_dlc; > + } > > work_done++; > stats->rx_packets++; > - stats->rx_bytes += cf->can_dlc; > netif_receive_skb(skb); > } > > @@ -121,19 +129,29 @@ 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 *cf_fd; > 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, &cf_fd); > + else > + skb = alloc_can_skb(offload->dev, &cf); > + } > > if (!skb) { > struct can_frame cf_overflow; > + struct canfd_frame cf_fd_overflow; > u32 timestamp; > > - ret = offload->mailbox_read(offload, &cf_overflow, > - ×tamp, n); > + if (offload->fd_enable) > + ret = offload->mailbox_read(offload, &cf_fd_overflow, > + ×tamp, n); > + else > + ret = offload->mailbox_read(offload, &cf_overflow, > + ×tamp, n); > if (ret) > offload->dev->stats.rx_dropped++; > > @@ -141,7 +159,10 @@ 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); > + if (offload->fd_enable) > + ret = offload->mailbox_read(offload, cf_fd, &cb->timestamp, n); > + else > + ret = offload->mailbox_read(offload, cf, &cb->timestamp, n); > if (!ret) { > kfree_skb(skb); > return NULL; > diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h > index cb31683bbe15..306a807ba93f 100644 > --- a/include/linux/can/rx-offload.h > +++ b/include/linux/can/rx-offload.h > @@ -23,7 +23,8 @@ > 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, > + void *frame, > u32 *timestamp, unsigned int mb); > > struct sk_buff_head skb_queue; > @@ -34,6 +35,7 @@ struct can_rx_offload { > > struct napi_struct napi; > > + bool fd_enable; > bool inc; > }; > > -- 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