简短的回答:
是的。您应该dma_unmap_single
使用映射的每个缓冲区dma_map_single
。
长答案:
也是的。
您应该dma_unmap_single
在每个 DMA 事务结束时调用。
但由于这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 */
}