簡潔な答え:
はい。dma_unmap_single
マップされているすべてのバッファを使用する必要がありますdma_map_single
。
長い答え:
はい。すべての DMA トランザクションの最後に
呼び出す必要があります。dma_unmap_single
しかし、dma_map_single / dma_unmap_single
はコストのかかる操作であるため、(パケットが大きすぎない場合) DMA マップ バッファを再利用することを好む場合があるためdma_unmap_single
、DMA トランザクションの最後にを呼び出す代わりに、 を呼び出しdma_sync_single_for_cpu
て、 DMA マップ バッファを別のバッファに挿入してから を呼び出すことdma_sync_single_for_device
で、次の DMA トランザクションの前に、すでに DMA マップされているバッファをアンマップして再マップしなくても再利用できるようになりました。
パケットの大きさのしきい値はアーキテクチャ間で異なり、測定する必要があると思います。
measure_time(dma_sync_single_for_cpu + memcpy(packet_size) + dma_sync_single_for_device)
>?<
measure_time(dma_unmap_single + dma_map_single)
短い例:
if (frame_len < FRAME_LEN_THRESHOLD) {
skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
if (unlikely(!skb)) {
printk("packet dropped\n");
continue;
}
dma_sync_single_for_cpu(priv->device, rx_skbuff_dma[entry],
frame_len, DMA_FROM_DEVICE);
// same as memcpy
skb_copy_to_linear_data(skb, rx_skbuff[entry]->data, frame_len);
dma_sync_single_for_device(priv->device, rx_skbuff_dma[entry],
frame_len, DMA_FROM_DEVICE);
/* now we can reuse rx_skbuff_dma[entry].
no need to call dma_unmap_single */
} else {
skb = rx_skbuff[entry];
if (unlikely(!skb)) {
printk("packet dropped\n");
continue;
}
rx_skbuff[entry] = NULL;
dma_unmap_single(priv->device, rx_skbuff_dma[entry],
priv->dma_buffer_size, DMA_FROM_DEVICE);
/* if we want to use rx_skbuff_dma[entry] for another DMA transaction,
we will need to realocate a buffer and call dma_map_single */
}