From: Siva Durga Prasad Paladugu Date: Thu, 29 Oct 2015 09:44:01 +0000 (+0530) Subject: qspi: zynqmp: Handle dma separately from zynqmp_qspi_genfifo_fill_rx X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6d9d76240a241b80a2053c9e47521dce70c950eb;p=thirdparty%2Fu-boot.git qspi: zynqmp: Handle dma separately from zynqmp_qspi_genfifo_fill_rx Define zynqmp_qspi_start_dma() to handle dma during qspi rx. The also solves the issue of stack corruption if prints were enabled in driver. The stack corruption is due to buffer allocated in else part using ALLOC_CACHE_ALIGN_BUFFER and using that buffer outside else part which will cause stack corruption as the ALLOC_CACHE_ALIGN_BUFFER allocates buffer from stack. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- diff --git a/drivers/spi/zynqmp_qspi.c b/drivers/spi/zynqmp_qspi.c index bb7372f82d0..3752fa178bd 100644 --- a/drivers/spi/zynqmp_qspi.c +++ b/drivers/spi/zynqmp_qspi.c @@ -83,6 +83,8 @@ #define SPI_XFER_ON_LOWER 1 #define SPI_XFER_ON_UPPER 2 +#define ZYNQMP_QSPI_DMA_ALIGN 0x4 + /* QSPI register offsets */ struct zynqmp_qspi_regs { u32 confr; /* 0x00 */ @@ -518,34 +520,15 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) return ret; } -static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) +static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, + u32 gen_fifo_cmd, u32 *buf) { - u32 gen_fifo_cmd; - u32 *buf; u32 addr; u32 size, len; u32 timeout = 10000000; u32 actuallen = priv->len; struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs; - gen_fifo_cmd = zynqmp_qspi_bus_select(priv); - gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_RX | - ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; - - if (last_cmd == QUAD_OUT_READ_CMD) - gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_QSPI; - else - gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; - - if (priv->stripe) - gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; - - if (!((unsigned long)priv->rx_buf & 0x3) && !(actuallen % 4)) { - buf = (u32 *)priv->rx_buf; - } else { - ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, 4)); - buf = (u32 *)tmp; - } writel((unsigned long)buf, &dma_regs->dmadst); writel(roundup(priv->len, 4), &dma_regs->dmasize); writel(ZYNQMP_QSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); @@ -589,6 +572,40 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) return 0; } +static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) +{ + u32 gen_fifo_cmd; + u32 *buf; + u32 actuallen = priv->len; + + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); + gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_RX | + ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; + + if (last_cmd == QUAD_OUT_READ_CMD) + gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_QSPI; + else + gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; + + if (priv->stripe) + gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; + + /* + * Check if receive buffer is aligned to 4 byte and length + * is multiples of four byte as we are using dma to receive. + */ + if (!((unsigned long)priv->rx_buf & (ZYNQMP_QSPI_DMA_ALIGN - 1)) && + !(actuallen % ZYNQMP_QSPI_DMA_ALIGN)) { + buf = (u32 *)priv->rx_buf; + return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); + } + + ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, + ZYNQMP_QSPI_DMA_ALIGN)); + buf = (u32 *)tmp; + return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); +} + static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv *priv) { int ret = 0;