Unverified Commit 126bdb60 authored by Quanyang Wang's avatar Quanyang Wang Committed by Mark Brown
Browse files

spi: spi-zynqmp-gqspi: return -ENOMEM if dma_map_single fails



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: 1c26372e ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: default avatarQuanyang Wang <quanyang.wang@windriver.com>
Link: https://lore.kernel.org/r/20210416004652.2975446-6-quanyang.wang@windriver.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent a2c5bedb
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -733,7 +733,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;
@@ -747,7 +747,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;
@@ -755,8 +755,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;
@@ -777,6 +779,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;
}

/**
@@ -813,11 +817,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;
}

/**
@@ -1031,8 +1041,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) |
@@ -1159,6 +1172,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;