Rule about streaming DMA mapping

From: Jia-Ju Bai
Date: Fri Jul 24 2020 - 10:52:47 EST


Hello,

From the book "Linux device drivers" (3rd edition), I find an interesting rule for streaming DMA mapping:

Once a buffer has been mapped, it belongs to the device, not the processor. Until
the buffer has been unmapped, the driver should not touch its contents in any
way. Only after dma_unmap_single has been called is it safe for the driver to
access the contents of the buffer (with one exception that we see shortly).
Among other things, this rule implies that a buffer being written to a device cannot
be mapped until it contains all the data to write.

I find some violations about this rule, and there are two examples in Linux-5.6:

=== EXAMPLE 1 ===
In vmxnet3_probe_device() in drivers/net/vmxnet3/vmxnet3_drv.c:
ÂÂÂ adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter,
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂÂ sizeof(struct vmxnet3_adapter),
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂÂ PCI_DMA_TODEVICE);
ÂÂÂ if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) {
ÂÂÂ ÂÂÂ dev_err(&pdev->dev, "Failed to map dma\n");
ÂÂÂ ÂÂÂ err = -EFAULT;
ÂÂÂ ÂÂÂ goto err_set_mask;
ÂÂÂ }
ÂÂÂ adapter->shared = dma_alloc_coherent(
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ &adapter->pdev->dev,
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ sizeof(struct Vmxnet3_DriverShared),
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ &adapter->shared_pa, GFP_KERNEL);
ÂÂÂ if (!adapter->shared) {
ÂÂÂ ÂÂÂ dev_err(&pdev->dev, "Failed to allocate memory\n");
ÂÂÂ ÂÂÂ err = -ENOMEM;
ÂÂÂ ÂÂÂ goto err_alloc_shared;
ÂÂÂ }

ÂÂÂ adapter->num_rx_queues = num_rx_queues;
ÂÂÂ adapter->num_tx_queues = num_tx_queues;
ÂÂÂ adapter->rx_buf_per_pkt = 1;

The variable "adapter" is mapped to streaming DMA, but its fields are used before this variable is unmapped.

=== EXAMPLE 2 ===
In queue_skb() in drivers/atm/idt77252.c:
ÂÂÂ IDT77252_PRV_PADDR(skb) = dma_map_single(&card->pcidev->dev, skb->data,
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂ Âskb->len, DMA_TO_DEVICE);

ÂÂÂ error = -EINVAL;

ÂÂÂ if (oam) {
ÂÂÂ ÂÂÂ if (skb->len != 52)
ÂÂÂ ÂÂÂ ÂÂÂ goto errout;

ÂÂÂ ÂÂÂ tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU;
ÂÂÂ ÂÂÂ tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
ÂÂÂ ÂÂÂ tbd->word_3 = 0x00000000;
ÂÂÂ ÂÂÂ tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
ÂÂÂ ÂÂÂ ÂÂÂ ÂÂÂÂÂ (skb->data[2] <<Â 8) | (skb->data[3] <<Â 0);

The array "skb->data" is mapped to streaming DMA, but its elements are used before this array is unmapped.

Because I am not familiar with streaming DMA mapping, I wonder whether these violations are real?
If they are real, what problems can they cause?

Thanks a lot :)


Best wishes,
Jia-Ju Bai