#define TX_EVENT_MM_MASK       GENMASK(31, 24)
 #define TX_EVENT_TXTS_MASK     GENMASK(15, 0)
 
+/* The ID and DLC registers are adjacent in M_CAN FIFO memory,
+ * and we can save a (potentially slow) bus round trip by combining
+ * reads and writes to them.
+ */
+struct id_and_dlc {
+       u32 id;
+       u32 dlc;
+};
+
 static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg)
 {
        return cdev->ops->read_reg(cdev, reg);
        struct m_can_classdev *cdev = netdev_priv(dev);
        struct canfd_frame *cf;
        struct sk_buff *skb;
-       u32 id, fgi, dlc;
+       struct id_and_dlc fifo_header;
+       u32 fgi;
        u32 timestamp = 0;
-       int i, err;
+       int err;
 
        /* calculate the fifo get index for where to read data */
        fgi = FIELD_GET(RXFS_FGI_MASK, rxfs);
-       err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DLC, &dlc, 1);
+       err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &fifo_header, 2);
        if (err)
                goto out_fail;
 
-       if (dlc & RX_BUF_FDF)
+       if (fifo_header.dlc & RX_BUF_FDF)
                skb = alloc_canfd_skb(dev, &cf);
        else
                skb = alloc_can_skb(dev, (struct can_frame **)&cf);
                return 0;
        }
 
-       if (dlc & RX_BUF_FDF)
-               cf->len = can_fd_dlc2len((dlc >> 16) & 0x0F);
+       if (fifo_header.dlc & RX_BUF_FDF)
+               cf->len = can_fd_dlc2len((fifo_header.dlc >> 16) & 0x0F);
        else
-               cf->len = can_cc_dlc2len((dlc >> 16) & 0x0F);
-
-       err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &id, 1);
-       if (err)
-               goto out_fail;
+               cf->len = can_cc_dlc2len((fifo_header.dlc >> 16) & 0x0F);
 
-       if (id & RX_BUF_XTD)
-               cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
+       if (fifo_header.id & RX_BUF_XTD)
+               cf->can_id = (fifo_header.id & CAN_EFF_MASK) | CAN_EFF_FLAG;
        else
-               cf->can_id = (id >> 18) & CAN_SFF_MASK;
+               cf->can_id = (fifo_header.id >> 18) & CAN_SFF_MASK;
 
-       if (id & RX_BUF_ESI) {
+       if (fifo_header.id & RX_BUF_ESI) {
                cf->flags |= CANFD_ESI;
                netdev_dbg(dev, "ESI Error\n");
        }
 
-       if (!(dlc & RX_BUF_FDF) && (id & RX_BUF_RTR)) {
+       if (!(fifo_header.dlc & RX_BUF_FDF) && (fifo_header.id & RX_BUF_RTR)) {
                cf->can_id |= CAN_RTR_FLAG;
        } else {
-               if (dlc & RX_BUF_BRS)
+               if (fifo_header.dlc & RX_BUF_BRS)
                        cf->flags |= CANFD_BRS;
 
-               for (i = 0; i < cf->len; i += 4) {
-                       err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DATA(i / 4), cf->data + i, 1);
-                       if (err)
-                               goto out_fail;
-               }
+               err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DATA(0),
+                                     cf->data, DIV_ROUND_UP(cf->len, 4));
+               if (err)
+                       goto out_fail;
        }
 
        /* acknowledge rx fifo 0 */
        stats->rx_packets++;
        stats->rx_bytes += cf->len;
 
-       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, dlc);
+       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
 
        m_can_receive_skb(cdev, skb, timestamp);