| From 123e06b1aafa5d8fe079b2831d7b1d00040a2314 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 16 Apr 2021 08:46:52 +0800 |
| Subject: spi: spi-zynqmp-gqspi: return -ENOMEM if dma_map_single fails |
| |
| From: Quanyang Wang <quanyang.wang@windriver.com> |
| |
| [ Upstream commit 126bdb606fd2802454e6048caef1be3e25dd121e ] |
| |
| The spi controller supports 44-bit address space on AXI in DMA mode, |
| so set dma_addr_t width to 44-bit to avoid using a swiotlb mapping. |
| In addition, if dma_map_single fails, it should return immediately |
| instead of continuing doing the DMA operation which bases on invalid |
| address. |
| |
| This fixes the following crash which occurs in reading a big block |
| from flash: |
| |
| [ 123.633577] zynqmp-qspi ff0f0000.spi: swiotlb buffer is full (sz: 4194304 bytes), total 32768 (slots), used 0 (slots) |
| [ 123.644230] zynqmp-qspi ff0f0000.spi: ERR:rxdma:memory not mapped |
| [ 123.784625] Unable to handle kernel paging request at virtual address 00000000003fffc0 |
| [ 123.792536] Mem abort info: |
| [ 123.795313] ESR = 0x96000145 |
| [ 123.798351] EC = 0x25: DABT (current EL), IL = 32 bits |
| [ 123.803655] SET = 0, FnV = 0 |
| [ 123.806693] EA = 0, S1PTW = 0 |
| [ 123.809818] Data abort info: |
| [ 123.812683] ISV = 0, ISS = 0x00000145 |
| [ 123.816503] CM = 1, WnR = 1 |
| [ 123.819455] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000805047000 |
| [ 123.825887] [00000000003fffc0] pgd=0000000803b45003, p4d=0000000803b45003, pud=0000000000000000 |
| [ 123.834586] Internal error: Oops: 96000145 [#1] PREEMPT SMP |
| |
| Fixes: 1c26372e5aa9 ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework") |
| Signed-off-by: Quanyang Wang <quanyang.wang@windriver.com> |
| Link: https://lore.kernel.org/r/20210416004652.2975446-6-quanyang.wang@windriver.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/spi/spi-zynqmp-gqspi.c | 26 ++++++++++++++++++++------ |
| 1 file changed, 20 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c |
| index 2a0be16b2eb0..1dd2af9cc237 100644 |
| --- a/drivers/spi/spi-zynqmp-gqspi.c |
| +++ b/drivers/spi/spi-zynqmp-gqspi.c |
| @@ -731,7 +731,7 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) |
| * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation |
| * @xqspi: xqspi is a pointer to the GQSPI instance. |
| */ |
| -static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) |
| +static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) |
| { |
| u32 rx_bytes, rx_rem, config_reg; |
| dma_addr_t addr; |
| @@ -745,7 +745,7 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) |
| zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg); |
| xqspi->mode = GQSPI_MODE_IO; |
| xqspi->dma_rx_bytes = 0; |
| - return; |
| + return 0; |
| } |
| |
| rx_rem = xqspi->bytes_to_receive % 4; |
| @@ -753,8 +753,10 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) |
| |
| addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf, |
| rx_bytes, DMA_FROM_DEVICE); |
| - if (dma_mapping_error(xqspi->dev, addr)) |
| + if (dma_mapping_error(xqspi->dev, addr)) { |
| dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n"); |
| + return -ENOMEM; |
| + } |
| |
| xqspi->dma_rx_bytes = rx_bytes; |
| xqspi->dma_addr = addr; |
| @@ -775,6 +777,8 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) |
| |
| /* Write the number of bytes to transfer */ |
| zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_SIZE_OFST, rx_bytes); |
| + |
| + return 0; |
| } |
| |
| /** |
| @@ -811,11 +815,17 @@ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits, |
| * @genfifoentry: genfifoentry is pointer to the variable in which |
| * GENFIFO mask is returned to calling function |
| */ |
| -static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, |
| +static int zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, |
| u32 genfifoentry) |
| { |
| - zynqmp_qspi_setuprxdma(xqspi); |
| + int ret; |
| + |
| + ret = zynqmp_qspi_setuprxdma(xqspi); |
| + if (ret) |
| + return ret; |
| zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry); |
| + |
| + return 0; |
| } |
| |
| /** |
| @@ -1029,8 +1039,11 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, |
| xqspi->rxbuf = (u8 *)op->data.buf.in; |
| xqspi->bytes_to_receive = op->data.nbytes; |
| xqspi->bytes_to_transfer = 0; |
| - zynqmp_qspi_read_op(xqspi, op->data.buswidth, |
| + err = zynqmp_qspi_read_op(xqspi, op->data.buswidth, |
| genfifoentry); |
| + if (err) |
| + goto return_err; |
| + |
| zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, |
| zynqmp_gqspi_read |
| (xqspi, GQSPI_CONFIG_OFST) | |
| @@ -1152,6 +1165,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) |
| goto clk_dis_all; |
| } |
| |
| + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); |
| ctlr->bits_per_word_mask = SPI_BPW_MASK(8); |
| ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; |
| ctlr->mem_ops = &zynqmp_qspi_mem_ops; |
| -- |
| 2.30.2 |
| |