提交 4a80eeba 编写于 作者: Q Quanyang Wang 提交者: Zheng Zengkai

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

stable inclusion
from stable-5.10.37
commit 5980a3b9c933408bc22b0e349b78c3ebd7cbf880
bugzilla: 51868
CVE: NA

--------------------------------

[ Upstream commit 126bdb60 ]

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: NQuanyang Wang <quanyang.wang@windriver.com>
Link: https://lore.kernel.org/r/20210416004652.2975446-6-quanyang.wang@windriver.comSigned-off-by: NMark Brown <broonie@kernel.org>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Acked-by: NWeilong Chen <chenweilong@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 c9b4c57c
...@@ -731,7 +731,7 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) ...@@ -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 * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation
* @xqspi: xqspi is a pointer to the GQSPI instance. * @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; u32 rx_bytes, rx_rem, config_reg;
dma_addr_t addr; dma_addr_t addr;
...@@ -745,7 +745,7 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) ...@@ -745,7 +745,7 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg); zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
xqspi->mode = GQSPI_MODE_IO; xqspi->mode = GQSPI_MODE_IO;
xqspi->dma_rx_bytes = 0; xqspi->dma_rx_bytes = 0;
return; return 0;
} }
rx_rem = xqspi->bytes_to_receive % 4; rx_rem = xqspi->bytes_to_receive % 4;
...@@ -753,8 +753,10 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) ...@@ -753,8 +753,10 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf, addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf,
rx_bytes, DMA_FROM_DEVICE); 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"); dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n");
return -ENOMEM;
}
xqspi->dma_rx_bytes = rx_bytes; xqspi->dma_rx_bytes = rx_bytes;
xqspi->dma_addr = addr; xqspi->dma_addr = addr;
...@@ -775,6 +777,8 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) ...@@ -775,6 +777,8 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
/* Write the number of bytes to transfer */ /* Write the number of bytes to transfer */
zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_SIZE_OFST, rx_bytes); 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, ...@@ -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 * @genfifoentry: genfifoentry is pointer to the variable in which
* GENFIFO mask is returned to calling function * 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) u32 genfifoentry)
{ {
zynqmp_qspi_setuprxdma(xqspi); int ret;
ret = zynqmp_qspi_setuprxdma(xqspi);
if (ret)
return ret;
zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry); zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry);
return 0;
} }
/** /**
...@@ -1029,8 +1039,11 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, ...@@ -1029,8 +1039,11 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
xqspi->rxbuf = (u8 *)op->data.buf.in; xqspi->rxbuf = (u8 *)op->data.buf.in;
xqspi->bytes_to_receive = op->data.nbytes; xqspi->bytes_to_receive = op->data.nbytes;
xqspi->bytes_to_transfer = 0; xqspi->bytes_to_transfer = 0;
zynqmp_qspi_read_op(xqspi, op->data.buswidth, err = zynqmp_qspi_read_op(xqspi, op->data.buswidth,
genfifoentry); genfifoentry);
if (err)
goto return_err;
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
zynqmp_gqspi_read zynqmp_gqspi_read
(xqspi, GQSPI_CONFIG_OFST) | (xqspi, GQSPI_CONFIG_OFST) |
...@@ -1152,6 +1165,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) ...@@ -1152,6 +1165,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_all; goto clk_dis_all;
} }
dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;
ctlr->mem_ops = &zynqmp_qspi_mem_ops; ctlr->mem_ops = &zynqmp_qspi_mem_ops;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册