Streaming DMA Memindahkan Kepemilikan Buffer antara CPU dan Perangkat

Sebuah DMA buffer dapat menjadi memori yang valid bagi CPU dan perangkat, tetapi tetap memerlukan serah-terima yang ketat di antara keduanya. Streaming DMA mapping di Linux menyatakan serah-terima tersebut. Mapping API menyediakan alamat DMA yang terlihat oleh perangkat sekaligus memberi DMA layer titik untuk menjalankan cache maintenance, translasi alamat, atau bounce buffering yang spesifik terhadap arsitektur.

Perilaku ini paling terlihat pada sistem yang DMA perangkatnya tidak otomatis koheren dengan cache CPU. Namun, aturan kepemilikan tetap menjadi bagian dari DMA API portabel, termasuk pada mesin yang tidak memerlukan operasi cache tambahan.

Alamat DMA bukan pointer CPU

dma_map_single() menerima buffer yang dapat diakses CPU dan mengembalikan dma_addr_t. Nilai tersebut adalah alamat yang harus digunakan perangkat untuk transfer. Nilai itu bukan alamat virtual CPU dan tidak harus sama dengan alamat fisik yang menopang buffer.

IOMMU dapat menerjemahkan alamat DMA. DMA layer pada platform juga dapat menerapkan batas addressing atau mengalihkan transfer melalui bounce buffer ketika perangkat tidak dapat menjangkau memori asal secara langsung.

alamat virtual CPU
        |
        v
Linux DMA mapping layer
        |
        +--> cache maintenance bila diperlukan
        +--> IOMMU atau bounce mapping bila diperlukan
        |
        v
alamat DMA yang terlihat perangkat

Karena itu driver memberikan alamat DMA hasil mapping kepada hardware, bukan menurunkan bus address dari pointer CPU.

Direction menetapkan aliran data dan kewajiban cache

Streaming mapping membawa direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, atau DMA_BIDIRECTIONAL. Direction menyatakan arah aliran data dari sudut pandang memori.

Untuk DMA_TO_DEVICE, software menyelesaikan penulisan buffer sebelum menyerahkannya kepada perangkat. Untuk DMA_FROM_DEVICE, perangkat menulis data yang kemudian dipakai software. DMA_BIDIRECTIONAL mencakup buffer yang dapat membawa data ke kedua arah.

Direction bukan metadata dekoratif. Implementasi DMA dapat memakainya untuk memilih operasi cache dan permission akses. Direction yang tidak sesuai dengan akses perangkat dapat merusak correctness pada platform yang bergantung pada semantik tersebut.

Mapping menyerahkan kepemilikan kepada perangkat

Setelah streaming buffer di-map untuk akses perangkat, driver harus memperlakukan region terkait sesuai aturan kepemilikan DMA. Akses CPU pada saat yang salah dapat beradu dengan perangkat dan juga dapat menggagalkan cache maintenance yang dilakukan DMA layer.

Jalur transmit tipikal memiliki bentuk berikut:

CPU mengisi packet buffer
        |
        v
dma_map_single(..., DMA_TO_DEVICE)
        |
        v
perangkat memiliki interval transfer
        |
        v
DMA selesai
        |
        v
dma_unmap_single(...)
        |
        v
CPU dapat memakai ulang buffer

Mapping call bukan perintah untuk memulai DMA. Penulisan descriptor dan doorbell yang spesifik terhadap perangkat tetap memulai operasi hardware. Mapping membentuk kondisi sisi memori yang diperlukan operasi tersebut.

Mapping yang dipakai ulang memerlukan sinkronisasi eksplisit

Sebagian driver mempertahankan streaming mapping tetap aktif melewati beberapa pergantian kepemilikan, alih-alih melakukan unmap setelah setiap transfer. Dalam pola ini, dma_sync_single_for_cpu() dan dma_sync_single_for_device() menandai transisi.

Setelah dma_sync_single_for_cpu(), software dapat mengakses region yang dicakup sinkronisasi. Sebelum perangkat memakai region itu lagi, driver memanggil dma_sync_single_for_device() setelah modifikasi CPU terakhir.

fase perangkat
    |
dma_sync_single_for_cpu()
    |
fase CPU
    |
dma_sync_single_for_device()
    |
fase perangkat

Call tersebut dapat menjadi operasi cache maintenance pada arsitektur non-coherent. Pada platform coherent, pekerjaan cache dapat sedikit atau tidak ada, tetapi logika driver portabel tidak boleh mengasumsikan hasil tersebut.

Berbagi cache line dapat merusak data di sebelah buffer

Cache maintenance bekerja pada granularity cache line, bukan pada byte arbitrer. DMA buffer kecil yang berbagi cache line dengan data lain yang ditulis CPU menciptakan batas berbahaya pada sistem dengan DMA-incoherent cache.

Bayangkan receive buffer menempati sebagian line sementara field milik CPU berada pada bagian lain. Device write dan CPU cache writeback kemudian dapat menyentuh byte berbeda pada line yang sama. Tanpa isolasi yang sesuai, satu sisi dapat menimpa data yang dihasilkan sisi lain.

Dokumentasi DMA Linux karena itu menetapkan constraint alignment dan cache-line sharing untuk region DMA, terutama pada penggunaan DMA_FROM_DEVICE dan DMA_BIDIRECTIONAL. Unit aman bukan sekadar ukuran objek C; layout cache line di sekitarnya juga berpengaruh.

Coherent DMA memory memiliki kontrak berbeda

dma_alloc_coherent() menyediakan model mapping yang berbeda. Akses CPU dan perangkat ke coherent DMA memory diatur agar kedua sisi dapat melihat update satu sama lain tanpa explicit cache flushing pada setiap transisi kepemilikan.

Properti tersebut tidak menghapus kebutuhan ordering. CPU dapat melakukan reorder pada store, sehingga field descriptor yang harus terlihat dalam urutan tertentu tetap memerlukan memory barrier yang sesuai. Coherency menentukan apakah kedua agent dapat melihat update memori; ordering menentukan urutan update tersebut menjadi bermakna.

Streaming mapping umum dipakai untuk payload buffer yang berpindah melalui fase CPU dan perangkat yang terpisah. Coherent mapping umum dipakai untuk control structure berumur panjang seperti descriptor ring. Pilihan tepat tetap bergantung pada perangkat dan platform.

Kepemilikan terpisah dari penyelesaian transfer

DMA mapping tidak membuktikan bahwa hardware telah selesai memakai buffer. Completion berasal dari protocol perangkat: completion descriptor, status bit, interrupt, queue state yang di-poll, atau sinyal lain yang ditentukan perangkat.

Driver harus lebih dahulu memastikan bahwa perangkat telah menyelesaikan akses terkait. Setelah itu, driver dapat melakukan unmap pada streaming region atau menyinkronkannya kembali untuk akses CPU.

Pemisahan ini menjaga dua kontrak berbeda tetap jelas. Perangkat menentukan kapan transfernya selesai. DMA API menentukan cara memori menjadi valid bagi pemilik berikutnya pada batas CPU-perangkat.