drivers/spi/spi-dw-dma.c
Source file repositories/reference/linux-study-clean/drivers/spi/spi-dw-dma.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/spi/spi-dw-dma.c- Extension
.c- Size
- 17983 bytes
- Lines
- 712
- Domain
- Driver Families
- Bucket
- drivers/spi
- Inferred role
- Driver Families: exported/initcall integration point
- Status
- integration implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/completion.hlinux/dma-mapping.hlinux/dmaengine.hlinux/irqreturn.hlinux/jiffies.hlinux/module.hlinux/pci.hlinux/platform_data/dma-dw.hlinux/spi/spi.hlinux/types.hspi-dw.h
Detected Declarations
function Copyrightfunction dw_spi_dma_maxburst_initfunction dw_spi_dma_caps_initfunction dw_spi_dma_init_mfldfunction dw_spi_dma_init_genericfunction dw_spi_dma_exitfunction dw_spi_dma_transfer_handlerfunction dw_spi_dma_convert_widthfunction dw_spi_can_dmafunction dw_spi_dma_waitfunction dw_spi_dma_tx_busyfunction dw_spi_dma_wait_tx_donefunction dw_spi_dma_tx_donefunction dw_spi_dma_config_txfunction dw_spi_dma_submit_txfunction dw_spi_dma_rx_busyfunction dw_spi_dma_wait_rx_donefunction dw_spi_dma_rx_donefunction dw_spi_dma_config_rxfunction dw_spi_dma_submit_rxfunction dw_spi_dma_setupfunction dw_spi_dma_transfer_allfunction dw_spi_dma_transfer_onefunction dw_spi_dma_transferfunction dw_spi_dma_stopfunction dw_spi_dma_setup_mfldfunction dw_spi_dma_setup_generic
Annotated Snippet
if (!tx_len) {
tx_sg = !tx_sg ? &xfer->tx_sg.sgl[0] : sg_next(tx_sg);
sg_dma_address(&tx_tmp) = sg_dma_address(tx_sg);
tx_len = sg_dma_len(tx_sg);
}
/* Fetch next Rx DMA data chunk */
if (!rx_len) {
rx_sg = !rx_sg ? &xfer->rx_sg.sgl[0] : sg_next(rx_sg);
sg_dma_address(&rx_tmp) = sg_dma_address(rx_sg);
rx_len = sg_dma_len(rx_sg);
}
len = min(tx_len, rx_len);
sg_dma_len(&tx_tmp) = len;
sg_dma_len(&rx_tmp) = len;
/* Submit DMA Tx transfer */
ret = dw_spi_dma_submit_tx(dws, &tx_tmp, 1);
if (ret)
break;
/* Submit DMA Rx transfer */
ret = dw_spi_dma_submit_rx(dws, &rx_tmp, 1);
if (ret)
break;
/* Rx must be started before Tx due to SPI instinct */
dma_async_issue_pending(dws->rxchan);
dma_async_issue_pending(dws->txchan);
/*
* Here we only need to wait for the DMA transfer to be
* finished since SPI controller is kept enabled during the
* procedure this loop implements and there is no risk to lose
* data left in the Tx/Rx FIFOs.
*/
ret = dw_spi_dma_wait(dws, len, xfer->effective_speed_hz);
if (ret)
break;
reinit_completion(&dws->dma_completion);
sg_dma_address(&tx_tmp) += len;
sg_dma_address(&rx_tmp) += len;
tx_len -= len;
rx_len -= len;
}
dw_writel(dws, DW_SPI_DMACR, 0);
return ret;
}
static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
{
unsigned int nents;
int ret;
nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents);
/*
* Execute normal DMA-based transfer (which submits the Rx and Tx SG
* lists directly to the DMA engine at once) if either full hardware
* accelerated SG list traverse is supported by both channels, or the
* Tx-only SPI transfer is requested, or the DMA engine is capable to
* handle both SG lists on hardware accelerated basis.
*/
if (!dws->dma_sg_burst || !xfer->rx_buf || nents <= dws->dma_sg_burst)
ret = dw_spi_dma_transfer_all(dws, xfer);
else
ret = dw_spi_dma_transfer_one(dws, xfer);
if (ret)
return ret;
if (dws->ctlr->cur_msg->status == -EINPROGRESS) {
ret = dw_spi_dma_wait_tx_done(dws, xfer);
if (ret)
return ret;
}
if (xfer->rx_buf && dws->ctlr->cur_msg->status == -EINPROGRESS)
ret = dw_spi_dma_wait_rx_done(dws);
return ret;
}
static void dw_spi_dma_stop(struct dw_spi *dws)
Annotation
- Immediate include surface: `linux/completion.h`, `linux/dma-mapping.h`, `linux/dmaengine.h`, `linux/irqreturn.h`, `linux/jiffies.h`, `linux/module.h`, `linux/pci.h`, `linux/platform_data/dma-dw.h`.
- Detected declarations: `function Copyright`, `function dw_spi_dma_maxburst_init`, `function dw_spi_dma_caps_init`, `function dw_spi_dma_init_mfld`, `function dw_spi_dma_init_generic`, `function dw_spi_dma_exit`, `function dw_spi_dma_transfer_handler`, `function dw_spi_dma_convert_width`, `function dw_spi_can_dma`, `function dw_spi_dma_wait`.
- Atlas domain: Driver Families / drivers/spi.
- Implementation status: integration implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.