[PATCH v3 10/15] ata: ahci: fix zero-length DMA handling
Luca Lauro via B4 Relay <[email protected]> Sun, 02 Aug 2026 15:16:26 +0200
| Newsgroups | org.infradead.lists.barebox,org.kernel.feeds.b4-sent |
|---|---|
| Message-ID | <[email protected]> |
From: Luca Lauro <[email protected]> ata: ahci: fix zero-length DMA handling Commands without a data buffer must not trigger DMA setup. The previous code unconditionally programmed PRDT entries and attempted DMA mapping even when buf_len was zero, leading to invalid PRD tables and spurious DMA operations. This patch ensures that DMA mapping, PRDT setup and unmapping are only performed when buf_len > 0. Signed-off-by: Luca Lauro <[email protected]> --- drivers/ata/ahci.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0ac1a9dead..a080de236e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -198,30 +198,32 @@ static int ahci_io(struct ahci_port *ahci_port, u8 *fis, int fis_len, void *rbuf const void *wbuf, int buf_len) { u32 opts; - int sg_count; + int sg_count = 0; int ret; - void *buf; - dma_addr_t buf_dma; - enum dma_data_direction dma_dir; + void *buf = NULL; + dma_addr_t buf_dma = 0; + enum dma_data_direction dma_dir = DMA_NONE; if (!ahci_link_ok(ahci_port, 1)) return -EIO; - if (wbuf) { - buf = (void *)wbuf; - dma_dir = DMA_TO_DEVICE; - } else { - buf = rbuf; - dma_dir = DMA_FROM_DEVICE; - } + if (buf_len > 0) { + if (wbuf) { + buf = (void *)wbuf; + dma_dir = DMA_TO_DEVICE; + } else { + buf = rbuf; + dma_dir = DMA_FROM_DEVICE; + } - buf_dma = dma_map_single(ahci_port->ahci->dev, buf, buf_len, dma_dir); + buf_dma = dma_map_single(ahci_port->ahci->dev, buf, buf_len, dma_dir); + sg_count = ahci_fill_sg(ahci_port, buf_dma, buf_len); + } memcpy(ahci_port->cmd_tbl, fis, fis_len); - sg_count = ahci_fill_sg(ahci_port, buf_dma, buf_len); opts = (fis_len >> 2) | (sg_count << 16); - if (wbuf) + if (wbuf && buf_len > 0) opts |= CMD_LIST_OPTS_WRITE; ahci_fill_cmd_slot(ahci_port, opts); @@ -230,7 +232,8 @@ static int ahci_io(struct ahci_port *ahci_port, u8 *fis, int fis_len, void *rbuf ret = wait_on_timeout(WAIT_DATAIO, (ahci_port_read(ahci_port, PORT_CMD_ISSUE) & 0x1) == 0); - dma_unmap_single(ahci_port->ahci->dev, buf_dma, buf_len, dma_dir); + if (buf_len > 0) + dma_unmap_single(ahci_port->ahci->dev, buf_dma, buf_len, dma_dir); return ret; } -- 2.47.3