diff mbox series

[SPI,for-next,2/3] spi: mchp-pci1xxxx: DMA Read support for copying data into SPI Buf

Message ID 20231215114748.152319-3-thangaraj.s@microchip.com
State New
Headers show
Series DMA Support for SPI in PCI1xxxx | expand

Commit Message

Thangaraj Samynathan Dec. 15, 2023, 11:47 a.m. UTC
pci1xxxx_spi_transfer_with_dma is registered as transfer_one callback
when DMA can be supported. This function adds DMA read operation which
copies the data from host cpu buffer to SPI Tx Buffer.
On DMA Read Completion interrupt, SPI transaction is initiated in isr.
Helper functions pci1xxxx_spi_setup, pci1xxxx_spi_setup_dma_read and
pci1xxxx_start_spi_xfer are added for starting spi transfer, setting up
spi and dma read operation. In the existing implementation, codes are
replaced with helper wherever applicable.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 drivers/spi/spi-pci1xxxx.c | 225 +++++++++++++++++++++++++++++++++----
 1 file changed, 204 insertions(+), 21 deletions(-)

Comments

kernel test robot Dec. 16, 2023, 10:44 a.m. UTC | #1
Hi Thangaraj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on broonie-spi/for-next]
[also build test WARNING on linus/master v6.7-rc5 next-20231215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Thangaraj-Samynathan/spi-mchp-pci1xxxx-Add-support-for-DMA-in-SPI/20231215-195133
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link:    https://lore.kernel.org/r/20231215114748.152319-3-thangaraj.s%40microchip.com
patch subject: [PATCH SPI for-next 2/3] spi: mchp-pci1xxxx: DMA Read support for copying data into SPI Buf
config: arc-randconfig-r132-20231216 (https://download.01.org/0day-ci/archive/20231216/202312161832.s8L4PtmO-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20231216/202312161832.s8L4PtmO-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312161832.s8L4PtmO-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/spi/spi-pci1xxxx.c:321:22: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void *base @@     got void [noderef] __iomem * @@
   drivers/spi/spi-pci1xxxx.c:321:22: sparse:     expected void *base
   drivers/spi/spi-pci1xxxx.c:321:22: sparse:     got void [noderef] __iomem *
   drivers/spi/spi-pci1xxxx.c:323:22: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void *base @@     got void [noderef] __iomem * @@
   drivers/spi/spi-pci1xxxx.c:323:22: sparse:     expected void *base
   drivers/spi/spi-pci1xxxx.c:323:22: sparse:     got void [noderef] __iomem *
>> drivers/spi/spi-pci1xxxx.c:325:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:325:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:325:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c:326:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:326:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:326:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c:327:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:327:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:327:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c:328:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:328:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:328:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c:330:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:330:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:330:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c:332:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/spi/spi-pci1xxxx.c:332:9: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/spi/spi-pci1xxxx.c:332:9: sparse:     got void *
   drivers/spi/spi-pci1xxxx.c: note: in included file (through include/linux/mmzone.h, include/linux/gfp.h, include/linux/xarray.h, ...):
   include/linux/page-flags.h:242:46: sparse: sparse: self-comparison always evaluates to false

vim +321 drivers/spi/spi-pci1xxxx.c

   314	
   315	static void pci1xxxx_spi_setup_dma_read(struct pci1xxxx_spi_internal *p,
   316						dma_addr_t dma_addr, u32 len)
   317	{
   318		void *base;
   319	
   320		if (!p->hw_inst)
 > 321			base = p->parent->dma_offset_bar + SPI_DMA_CH0_RD_BASE;
   322		else
   323			base = p->parent->dma_offset_bar + SPI_DMA_CH1_RD_BASE;
   324	
 > 325		writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET);
   326		writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET);
   327		writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_SAR_LO_OFFSET);
   328		writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_SAR_HI_OFFSET);
   329		/* Updated SPI Command Registers */
   330		writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
   331		       base + SPI_DMA_CH_DAR_LO_OFFSET);
   332		writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
   333		       base + SPI_DMA_CH_DAR_HI_OFFSET);
   334	}
   335
Thangaraj Samynathan Dec. 20, 2023, 6:55 a.m. UTC | #2
Hi Mark,
Thanks for your comments. Will send the updated patch shortly.
On Fri, 2023-12-15 at 13:29 +0000, Mark Brown wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you
> know the content is safe
diff mbox series

Patch

diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c
index 95b1255e62cd..824885ada9b6 100644
--- a/drivers/spi/spi-pci1xxxx.c
+++ b/drivers/spi/spi-pci1xxxx.c
@@ -5,6 +5,7 @@ 
 //          Kumaravel Thiagarajan <Kumaravel.Thiagarajan@microchip.com>
 
 
+#include <linux/bitfield.h>
 #include <linux/dma-mapping.h>
 #include <linux/iopoll.h>
 #include <linux/irq.h>
@@ -12,6 +13,7 @@ 
 #include <linux/msi.h>
 #include <linux/pci_regs.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
 #include <linux/spi/spi.h>
 #include <linux/delay.h>
 
@@ -37,6 +39,7 @@ 
 #define	SPI_MST_CTL_MODE_SEL		(BIT(2))
 #define	SPI_MST_CTL_GO			(BIT(0))
 
+#define SPI_PERI_ADDR_BASE		(0x160000)
 #define SPI_SYSTEM_ADDR_BASE		(0x2000)
 #define	SPI_MST1_ADDR_BASE		(0x800)
 
@@ -48,22 +51,49 @@ 
 #define DEV_REV_MASK			(GENMASK(7, 0))
 
 #define SPI_SYSLOCK			BIT(4)
+#define SPI0				(0)
+#define SPI1				(1)
 
 /* DMA Related Registers */
 #define SPI_DMA_ADDR_BASE		(0x1000)
 #define SPI_DMA_GLOBAL_WR_ENGINE_EN	(SPI_DMA_ADDR_BASE + 0x0C)
 #define SPI_DMA_GLOBAL_RD_ENGINE_EN	(SPI_DMA_ADDR_BASE + 0x2C)
+#define SPI_DMA_RD_DOORBELL_REG		(SPI_DMA_ADDR_BASE + 0x30)
 #define SPI_DMA_INTR_IMWR_WDONE_LOW	(SPI_DMA_ADDR_BASE + 0x60)
 #define SPI_DMA_INTR_IMWR_WDONE_HIGH	(SPI_DMA_ADDR_BASE + 0x64)
 #define SPI_DMA_INTR_IMWR_WABORT_LOW	(SPI_DMA_ADDR_BASE + 0x68)
 #define SPI_DMA_INTR_IMWR_WABORT_HIGH	(SPI_DMA_ADDR_BASE + 0x6C)
 #define SPI_DMA_INTR_WR_IMWR_DATA	(SPI_DMA_ADDR_BASE + 0x70)
+#define SPI_DMA_INTR_RD_STS		(SPI_DMA_ADDR_BASE + 0xA0)
+#define SPI_DMA_RD_INT_MASK		(SPI_DMA_ADDR_BASE + 0xA8)
+#define SPI_DMA_INTR_RD_CLR		(SPI_DMA_ADDR_BASE + 0xAC)
+#define SPI_DMA_ERR_RD_STS		(SPI_DMA_ADDR_BASE + 0xB8)
 #define SPI_DMA_INTR_IMWR_RDONE_LOW	(SPI_DMA_ADDR_BASE + 0xCC)
 #define SPI_DMA_INTR_IMWR_RDONE_HIGH	(SPI_DMA_ADDR_BASE + 0xD0)
 #define SPI_DMA_INTR_IMWR_RABORT_LOW	(SPI_DMA_ADDR_BASE + 0xD4)
 #define SPI_DMA_INTR_IMWR_RABORT_HIGH	(SPI_DMA_ADDR_BASE + 0xD8)
 #define SPI_DMA_INTR_RD_IMWR_DATA	(SPI_DMA_ADDR_BASE + 0xDC)
 
+#define SPI_DMA_CH0_RD_BASE		(SPI_DMA_ADDR_BASE + 0x300)
+#define SPI_DMA_CH1_RD_BASE		(SPI_DMA_ADDR_BASE + 0x500)
+
+#define SPI_DMA_CH_CTL1_OFFSET		(0x00)
+#define SPI_DMA_CH_XFER_LEN_OFFSET	(0x08)
+#define SPI_DMA_CH_SAR_LO_OFFSET	(0x0C)
+#define SPI_DMA_CH_SAR_HI_OFFSET	(0x10)
+#define SPI_DMA_CH_DAR_LO_OFFSET	(0x14)
+#define SPI_DMA_CH_DAR_HI_OFFSET	(0x18)
+
+#define SPI_DMA_CH0_DONE_INT		BIT(0)
+#define SPI_DMA_CH1_DONE_INT		BIT(1)
+#define SPI_DMA_CH0_ABORT_INT		BIT(16)
+#define SPI_DMA_CH1_ABORT_INT		BIT(17)
+#define SPI_DMA_DONE_INT_MASK		(SPI_DMA_CH0_DONE_INT | SPI_DMA_CH1_DONE_INT)
+#define SPI_DMA_ABORT_INT_MASK		(SPI_DMA_CH0_ABORT_INT | SPI_DMA_CH1_ABORT_INT)
+#define DMA_CH_CONTROL_LIE		BIT(3)
+#define DMA_CH_CONTROL_RIE		BIT(4)
+#define DMA_INTR_EN			(DMA_CH_CONTROL_RIE | DMA_CH_CONTROL_LIE)
+
 /* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */
 
 #define	SPI_MST_CMD_BUF_OFFSET(x)		(((x) * SPI_MST1_ADDR_BASE) + 0x00)
@@ -82,6 +112,7 @@ 
 #define PCI1XXXX_SPI_TIMEOUT			(msecs_to_jiffies(100))
 #define SYSLOCK_RETRY_CNT			(1000)
 #define SPI_DMA_ENGINE_EN			(0x1)
+#define SPI_DMA_ENGINE_DIS			(0x0)
 
 #define SPI_INTR		BIT(8)
 #define SPI_FORCE_CE		BIT(4)
@@ -95,6 +126,7 @@ 
 struct pci1xxxx_spi_internal {
 	u8 hw_inst;
 	bool spi_xfer_in_progress;
+	bool dma_aborted_rd;
 	int irq;
 	struct completion spi_xfer_done;
 	struct spi_controller *spi_host;
@@ -111,6 +143,8 @@  struct pci1xxxx_spi {
 	u8 dev_rev;
 	void __iomem *reg_base;
 	void __iomem *dma_offset_bar;
+	/* lock to safely access the DMA registers in isr */
+	spinlock_t dma_reg_lock;
 	bool can_dma;
 	struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances);
 };
@@ -220,6 +254,7 @@  static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int irq)
 	if (ret)
 		return ret;
 
+	spin_lock_init(&spi_bus->dma_reg_lock);
 	get_cached_msi_msg(irq, &msi);
 	writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN);
 	writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
@@ -277,6 +312,53 @@  static u8 pci1xxxx_get_clock_div(u32 hz)
 	return val;
 }
 
+static void pci1xxxx_spi_setup_dma_read(struct pci1xxxx_spi_internal *p,
+					dma_addr_t dma_addr, u32 len)
+{
+	void *base;
+
+	if (!p->hw_inst)
+		base = p->parent->dma_offset_bar + SPI_DMA_CH0_RD_BASE;
+	else
+		base = p->parent->dma_offset_bar + SPI_DMA_CH1_RD_BASE;
+
+	writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET);
+	writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET);
+	writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_SAR_LO_OFFSET);
+	writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_SAR_HI_OFFSET);
+	/* Updated SPI Command Registers */
+	writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
+	       base + SPI_DMA_CH_DAR_LO_OFFSET);
+	writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
+	       base + SPI_DMA_CH_DAR_HI_OFFSET);
+}
+
+static void pci1xxxx_spi_setup(struct pci1xxxx_spi *par, u8 hw_inst, u32 mode,
+			       u8 clkdiv, u32 len)
+{
+	u32 regval;
+
+	regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+	regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK |
+		    SPI_MST_CTL_SPEED_MASK);
+
+	if (mode == SPI_MODE_3)
+		regval |= SPI_MST_CTL_MODE_SEL;
+
+	regval |= FIELD_PREP(SPI_MST_CTL_CMD_LEN_MASK, len);
+	regval |= FIELD_PREP(SPI_MST_CTL_SPEED_MASK, clkdiv);
+	writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+}
+
+static void pci1xxxx_start_spi_xfer(struct pci1xxxx_spi_internal *p, u8 hw_inst)
+{
+	u32 regval;
+
+	regval = readl(p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+	regval |= SPI_MST_CTL_GO;
+	writel(regval, p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+}
+
 static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
 				     struct spi_device *spi, struct spi_transfer *xfer)
 {
@@ -317,26 +399,8 @@  static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
 			memcpy_toio(par->reg_base + SPI_MST_CMD_BUF_OFFSET(p->hw_inst),
 				    &tx_buf[bytes_transfered], len);
 			bytes_transfered += len;
-			regval = readl(par->reg_base +
-				       SPI_MST_CTL_REG_OFFSET(p->hw_inst));
-			regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK |
-				    SPI_MST_CTL_SPEED_MASK);
-
-			if (mode == SPI_MODE_3)
-				regval |= SPI_MST_CTL_MODE_SEL;
-			else
-				regval &= ~SPI_MST_CTL_MODE_SEL;
-
-			regval |= (clkdiv << 5);
-			regval &= ~SPI_MST_CTL_CMD_LEN_MASK;
-			regval |= (len << 8);
-			writel(regval, par->reg_base +
-			       SPI_MST_CTL_REG_OFFSET(p->hw_inst));
-			regval = readl(par->reg_base +
-				       SPI_MST_CTL_REG_OFFSET(p->hw_inst));
-			regval |= SPI_MST_CTL_GO;
-			writel(regval, par->reg_base +
-			       SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+			pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len);
+			pci1xxxx_start_spi_xfer(p, p->hw_inst);
 
 			/* Wait for DMA_TERM interrupt */
 			result = wait_for_completion_timeout(&p->spi_xfer_done,
@@ -356,10 +420,105 @@  static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
 	return 0;
 }
 
+static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
+					  struct spi_device *spi,
+					  struct spi_transfer *xfer)
+{
+	struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr);
+	struct pci1xxxx_spi *par = p->parent;
+	struct device *dev = &par->dev->dev;
+	dma_addr_t tx_dma_addr = 0;
+	u64 bytes_transfered = 0;
+	u64 bytes_recvd = 0;
+	int loop_count;
+	int ret = 0;
+	u32 regval;
+	u8 *rx_buf;
+	u8 clkdiv;
+	u32 len;
+	u32 i;
+
+	p->spi_xfer_in_progress = true;
+	clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz);
+	rx_buf = xfer->rx_buf;
+	regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+	writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+
+	if (!xfer->tx_buf) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	tx_dma_addr = dma_map_single(dev, (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
+	if (dma_mapping_error(NULL, tx_dma_addr)) {
+		tx_dma_addr = 0;
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	loop_count = DIV_ROUND_UP(xfer->len, SPI_MAX_DATA_LEN);
+	len = SPI_MAX_DATA_LEN;
+	pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len);
+	for (i = 0; i < loop_count; i++) {
+		if ((i == loop_count - 1) && (xfer->len % SPI_MAX_DATA_LEN != 0)) {
+			len = xfer->len % SPI_MAX_DATA_LEN;
+			pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len);
+		}
+
+		pci1xxxx_spi_setup_dma_read(p, (tx_dma_addr + bytes_transfered), len);
+
+		writel(p->hw_inst, par->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
+
+		reinit_completion(&p->spi_xfer_done);
+		/* Wait for DMA_TERM interrupt */
+		ret = wait_for_completion_timeout(&p->spi_xfer_done, PCI1XXXX_SPI_TIMEOUT);
+		if (!ret) {
+			ret = -ETIMEDOUT;
+			if (p->dma_aborted_rd) {
+				writel(SPI_DMA_ENGINE_DIS,
+				       par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
+
+				/*
+				 * DMA ENGINE reset takes time if any TLP
+				 * completeion in progress, should wait
+				 * till DMA Engine reset is completed.
+				 */
+				ret = readl_poll_timeout(par->dma_offset_bar +
+							 SPI_DMA_GLOBAL_RD_ENGINE_EN, regval,
+							 (regval == 0x0), 0, USEC_PER_MSEC);
+				if (ret) {
+					ret = -ECANCELED;
+					goto error;
+				}
+				writel(SPI_DMA_ENGINE_EN,
+				       par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
+				p->dma_aborted_rd = false;
+				ret = -ECANCELED;
+			}
+			goto error;
+		}
+		bytes_transfered += len;
+		if (rx_buf) {
+			memcpy_fromio(&rx_buf[bytes_recvd], par->reg_base +
+				      SPI_MST_RSP_BUF_OFFSET(p->hw_inst), len);
+			bytes_recvd += len;
+		}
+		ret = 0;
+	}
+
+error:
+	p->spi_xfer_in_progress = false;
+	if (tx_dma_addr)
+		dma_unmap_single(dev, tx_dma_addr, xfer->len, DMA_TO_DEVICE);
+
+	return ret;
+}
+
 static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
 {
 	struct pci1xxxx_spi_internal *p = dev;
 	irqreturn_t spi_int_fired = IRQ_NONE;
+	unsigned long flags;
 	u32 regval;
 
 	/* Clear the SPI GO_BIT Interrupt */
@@ -372,6 +531,26 @@  static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
 
 	writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
 
+	if (!p->parent->can_dma)
+		return spi_int_fired;
+
+	spin_lock_irqsave(&p->parent->dma_reg_lock, flags);
+	/* Clear the DMA RD INT and start spi xfer*/
+	regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_RD_STS);
+	if (regval & SPI_DMA_DONE_INT_MASK) {
+		if (regval & SPI_DMA_CH0_DONE_INT)
+			pci1xxxx_start_spi_xfer(p, SPI0);
+		if (regval & SPI_DMA_CH1_DONE_INT)
+			pci1xxxx_start_spi_xfer(p, SPI1);
+		spi_int_fired = IRQ_HANDLED;
+	}
+	if (regval & SPI_DMA_ABORT_INT_MASK) {
+		p->dma_aborted_rd = true;
+		spi_int_fired = IRQ_HANDLED;
+	}
+	writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR);
+	spin_unlock_irqrestore(&p->parent->dma_reg_lock, flags);
+
 	return spi_int_fired;
 }
 
@@ -495,7 +674,11 @@  static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
 		spi_host->num_chipselect = SPI_CHIP_SEL_COUNT;
 		spi_host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_RX_DUAL |
 				      SPI_TX_DUAL | SPI_LOOP;
-		spi_host->transfer_one = pci1xxxx_spi_transfer_one;
+		if (spi_bus->can_dma)
+			spi_host->transfer_one = pci1xxxx_spi_transfer_with_dma;
+		else
+			spi_host->transfer_one = pci1xxxx_spi_transfer_one;
+
 		spi_host->set_cs = pci1xxxx_spi_set_cs;
 		spi_host->bits_per_word_mask = SPI_BPW_MASK(8);
 		spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ;