#define SJA1105_SIZE_RESET_CMD         4
 #define SJA1105_SIZE_SPI_MSG_HEADER    4
 #define SJA1105_SIZE_SPI_MSG_MAXLEN    (64 * 4)
-#define SJA1105_SIZE_SPI_TRANSFER_MAX  \
-       (SJA1105_SIZE_SPI_MSG_HEADER + SJA1105_SIZE_SPI_MSG_MAXLEN)
+
+struct sja1105_chunk {
+       u8      *buf;
+       size_t  len;
+       u64     reg_addr;
+};
 
 static void
 sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg)
        sja1105_pack(buf, &msg->address,    24,  4, size);
 }
 
+#define sja1105_hdr_xfer(xfers, chunk) \
+       ((xfers) + 2 * (chunk))
+#define sja1105_chunk_xfer(xfers, chunk) \
+       ((xfers) + 2 * (chunk) + 1)
+#define sja1105_hdr_buf(hdr_bufs, chunk) \
+       ((hdr_bufs) + (chunk) * SJA1105_SIZE_SPI_MSG_HEADER)
+
 /* If @rw is:
  * - SPI_WRITE: creates and sends an SPI write message at absolute
- *             address reg_addr, taking size_bytes from *packed_buf
+ *             address reg_addr, taking @len bytes from *buf
  * - SPI_READ:  creates and sends an SPI read message from absolute
- *             address reg_addr, writing size_bytes into *packed_buf
- *
- * This function should only be called if it is priorly known that
- * @size_bytes is smaller than SIZE_SPI_MSG_MAXLEN. Larger packed buffers
- * are chunked in smaller pieces by sja1105_xfer_long_buf below.
+ *             address reg_addr, writing @len bytes into *buf
  */
 int sja1105_xfer_buf(const struct sja1105_private *priv,
                     sja1105_spi_rw_mode_t rw, u64 reg_addr,
-                    void *packed_buf, size_t size_bytes)
+                    u8 *buf, size_t len)
 {
-       const int msg_len = size_bytes + SJA1105_SIZE_SPI_MSG_HEADER;
-       u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0};
-       u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0};
-       struct spi_device *spi = priv->spidev;
-       struct sja1105_spi_message msg = {0};
-       struct spi_transfer xfer = {
-               .tx_buf = tx_buf,
-               .rx_buf = rx_buf,
-               .len = msg_len,
+       struct sja1105_chunk chunk = {
+               .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN),
+               .reg_addr = reg_addr,
+               .buf = buf,
        };
-       struct spi_message m;
-       int rc;
-
-       if (msg_len > SJA1105_SIZE_SPI_TRANSFER_MAX)
-               return -ERANGE;
+       struct spi_device *spi = priv->spidev;
+       struct spi_transfer *xfers;
+       int num_chunks;
+       int rc, i = 0;
+       u8 *hdr_bufs;
 
-       msg.access = rw;
-       msg.address = reg_addr;
-       if (rw == SPI_READ)
-               msg.read_count = size_bytes / 4;
+       num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN);
 
-       sja1105_spi_message_pack(tx_buf, &msg);
+       /* One transfer for each message header, one for each message
+        * payload (chunk).
+        */
+       xfers = kcalloc(2 * num_chunks, sizeof(struct spi_transfer),
+                       GFP_KERNEL);
+       if (!xfers)
+               return -ENOMEM;
 
-       if (rw == SPI_WRITE)
-               memcpy(tx_buf + SJA1105_SIZE_SPI_MSG_HEADER,
-                      packed_buf, size_bytes);
+       /* Packed buffers for the num_chunks SPI message headers,
+        * stored as a contiguous array
+        */
+       hdr_bufs = kcalloc(num_chunks, SJA1105_SIZE_SPI_MSG_HEADER,
+                          GFP_KERNEL);
+       if (!hdr_bufs) {
+               kfree(xfers);
+               return -ENOMEM;
+       }
 
-       spi_message_init(&m);
-       spi_message_add_tail(&xfer, &m);
+       for (i = 0; i < num_chunks; i++) {
+               struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i);
+               struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i);
+               u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i);
+               struct sja1105_spi_message msg;
+
+               /* Populate the transfer's header buffer */
+               msg.address = chunk.reg_addr;
+               msg.access = rw;
+               if (rw == SPI_READ)
+                       msg.read_count = chunk.len / 4;
+               else
+                       /* Ignored */
+                       msg.read_count = 0;
+               sja1105_spi_message_pack(hdr_buf, &msg);
+               hdr_xfer->tx_buf = hdr_buf;
+               hdr_xfer->len = SJA1105_SIZE_SPI_MSG_HEADER;
+
+               /* Populate the transfer's data buffer */
+               if (rw == SPI_READ)
+                       chunk_xfer->rx_buf = chunk.buf;
+               else
+                       chunk_xfer->tx_buf = chunk.buf;
+               chunk_xfer->len = chunk.len;
+
+               /* Calculate next chunk */
+               chunk.buf += chunk.len;
+               chunk.reg_addr += chunk.len / 4;
+               chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf),
+                                 SJA1105_SIZE_SPI_MSG_MAXLEN);
+
+               /* De-assert the chip select after each chunk. */
+               if (chunk.len)
+                       chunk_xfer->cs_change = 1;
+       }
 
-       rc = spi_sync(spi, &m);
-       if (rc < 0) {
+       rc = spi_sync_transfer(spi, xfers, 2 * num_chunks);
+       if (rc < 0)
                dev_err(&spi->dev, "SPI transfer failed: %d\n", rc);
-               return rc;
-       }
 
-       if (rw == SPI_READ)
-               memcpy(packed_buf, rx_buf + SJA1105_SIZE_SPI_MSG_HEADER,
-                      size_bytes);
+       kfree(hdr_bufs);
+       kfree(xfers);
 
-       return 0;
+       return rc;
 }
 
 /* If @rw is:
        return rc;
 }
 
-/* Should be used if a @packed_buf larger than SJA1105_SIZE_SPI_MSG_MAXLEN
- * must be sent/received. Splitting the buffer into chunks and assembling
- * those into SPI messages is done automatically by this function.
- */
-static int sja1105_xfer_long_buf(const struct sja1105_private *priv,
-                                sja1105_spi_rw_mode_t rw, u64 base_addr,
-                                void *packed_buf, u64 buf_len)
-{
-       struct chunk {
-               void *buf_ptr;
-               int len;
-               u64 spi_address;
-       } chunk;
-       int distance_to_end;
-       int rc;
-
-       /* Initialize chunk */
-       chunk.buf_ptr = packed_buf;
-       chunk.spi_address = base_addr;
-       chunk.len = min_t(int, buf_len, SJA1105_SIZE_SPI_MSG_MAXLEN);
-
-       while (chunk.len) {
-               rc = sja1105_xfer_buf(priv, rw, chunk.spi_address,
-                                     chunk.buf_ptr, chunk.len);
-               if (rc < 0)
-                       return rc;
-
-               chunk.buf_ptr += chunk.len;
-               chunk.spi_address += chunk.len / 4;
-               distance_to_end = (uintptr_t)(packed_buf + buf_len -
-                                             chunk.buf_ptr);
-               chunk.len = min(distance_to_end, SJA1105_SIZE_SPI_MSG_MAXLEN);
-       }
-
-       return 0;
-}
-
 /* Back-ported structure from UM11040 Table 112.
  * Reset control register (addr. 100440h)
  * In the SJA1105 E/T, only warm_rst and cold_rst are
                /* Wait for the switch to come out of reset */
                usleep_range(1000, 5000);
                /* Upload the static config to the device */
-               rc = sja1105_xfer_long_buf(priv, SPI_WRITE, regs->config,
-                                          config_buf, buf_len);
+               rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->config,
+                                     config_buf, buf_len);
                if (rc < 0) {
                        dev_err(dev, "Failed to upload config, retrying...\n");
                        continue;