diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index d49634a..3add52e 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -53,9 +53,9 @@
 
 #define DRIVER_NAME		"mxs-spi"
 
-#define SSP_TIMEOUT		1000	/* 1000 ms */
+/* Use 10S timeout for very long transfers, it should suffice. */
+#define SSP_TIMEOUT		10000
 
-#define SG_NUM			4
 #define SG_MAXLEN		0xff00
 
 struct mxs_spi {
@@ -219,61 +219,94 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
 			    int *first, int *last, int write)
 {
 	struct mxs_ssp *ssp = &spi->ssp;
-	struct dma_async_tx_descriptor *desc;
-	struct scatterlist sg[SG_NUM];
+	struct dma_async_tx_descriptor *desc = NULL;
+	const bool vmalloced_buf = is_vmalloc_addr(buf);
+	const int desc_len = vmalloced_buf ? PAGE_SIZE : SG_MAXLEN;
+	const int sgs = DIV_ROUND_UP(len, desc_len);
 	int sg_count;
-	uint32_t pio = BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
-	int ret;
-
-	if (len > SG_NUM * SG_MAXLEN) {
-		dev_err(ssp->dev, "Data chunk too big for DMA\n");
+	int min, ret;
+	uint32_t ctrl0;
+	struct page *vm_page;
+	void *sg_buf;
+	struct {
+		uint32_t		pio[4];
+		struct scatterlist	sg;
+	} *dma_xfer;
+
+	if (!len)
 		return -EINVAL;
-	}
+
+	dma_xfer = kzalloc(sizeof(*dma_xfer) * sgs, GFP_KERNEL);
+	if (!dma_xfer)
+		return -ENOMEM;
 
 	INIT_COMPLETION(spi->c);
 
+	ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
+	ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
+
 	if (*first)
-		pio |= BM_SSP_CTRL0_LOCK_CS;
-	if (*last)
-		pio |= BM_SSP_CTRL0_IGNORE_CRC;
+		ctrl0 |= BM_SSP_CTRL0_LOCK_CS;
 	if (!write)
-		pio |= BM_SSP_CTRL0_READ;
-
-	if (ssp->devid == IMX23_SSP)
-		pio |= len;
-	else
-		writel(len, ssp->base + HW_SSP_XFER_SIZE);
-
-	/* Queue the PIO register write transfer. */
-	desc = dmaengine_prep_slave_sg(ssp->dmach,
-			(struct scatterlist *)&pio,
-			1, DMA_TRANS_NONE, 0);
-	if (!desc) {
-		dev_err(ssp->dev,
-			"Failed to get PIO reg. write descriptor.\n");
-		return -EINVAL;
-	}
+		ctrl0 |= BM_SSP_CTRL0_READ;
 
 	/* Queue the DMA data transfer. */
-	sg_init_table(sg, (len / SG_MAXLEN) + 1);
-	sg_count = 0;
-	while (len) {
-		sg_set_buf(&sg[sg_count++], buf, min(len, SG_MAXLEN));
-		len -= min(len, SG_MAXLEN);
-		buf += min(len, SG_MAXLEN);
-	}
-	dma_map_sg(ssp->dev, sg, sg_count,
-		write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-	desc = dmaengine_prep_slave_sg(ssp->dmach, sg, sg_count,
-			write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
-			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
-	if (!desc) {
-		dev_err(ssp->dev,
-			"Failed to get DMA data write descriptor.\n");
-		ret = -EINVAL;
-		goto err;
+	for (sg_count = 0; sg_count < sgs; sg_count++) {
+		min = min(len, desc_len);
+
+		/* Prepare the transfer descriptor. */
+		if ((sg_count + 1 == sgs) && *last)
+			ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
+
+		if (ssp->devid == IMX23_SSP)
+			ctrl0 |= min;
+
+		dma_xfer[sg_count].pio[0] = ctrl0;
+		dma_xfer[sg_count].pio[3] = min;
+
+		if (vmalloced_buf) {
+			vm_page = vmalloc_to_page(buf);
+			if (!vm_page) {
+				ret = -ENOMEM;
+				goto err_vmalloc;
+			}
+			sg_buf = page_address(vm_page) +
+				((size_t)buf & ~PAGE_MASK);
+		} else {
+			sg_buf = buf;
+		}
+
+		sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min);
+		ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
+			write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		len -= min;
+		buf += min;
+
+		/* Queue the PIO register write transfer. */
+		desc = dmaengine_prep_slave_sg(ssp->dmach,
+				(struct scatterlist *)dma_xfer[sg_count].pio,
+				(ssp->devid == IMX23_SSP) ? 1 : 4,
+				DMA_TRANS_NONE,
+				sg_count ? DMA_PREP_INTERRUPT : 0);
+		if (!desc) {
+			dev_err(ssp->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			ret = -EINVAL;
+			goto err_mapped;
+		}
+
+		desc = dmaengine_prep_slave_sg(ssp->dmach,
+				&dma_xfer[sg_count].sg, 1,
+				write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+		if (!desc) {
+			dev_err(ssp->dev,
+				"Failed to get DMA data write descriptor.\n");
+			ret = -EINVAL;
+			goto err_mapped;
+		}
 	}
 
 	/*
@@ -289,21 +322,23 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
 
 	ret = wait_for_completion_timeout(&spi->c,
 				msecs_to_jiffies(SSP_TIMEOUT));
-
 	if (!ret) {
 		dev_err(ssp->dev, "DMA transfer timeout\n");
 		ret = -ETIMEDOUT;
-		goto err;
+		goto err_vmalloc;
 	}
 
 	ret = 0;
 
-err:
-	for (--sg_count; sg_count >= 0; sg_count--) {
-		dma_unmap_sg(ssp->dev, &sg[sg_count], 1,
+err_vmalloc:
+	while (--sg_count >= 0) {
+err_mapped:
+		dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
 			write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	}
 
+	kfree(dma_xfer);
+
 	return ret;
 }
 
