Skip to content

title: Kiến trúc DMA controller description: Kiến trúc phần cứng của DMA trong SoC: DMA controller chung và bus master DMA, các khối bên trong DMA controller, descriptor và scatter-gather, giao dịch AXI, cache coherency và các ví dụ PL330, AXI DMA, ZynqMP. tags: - soc - dma - axi - computer-architecture


Kiến trúc DMA controller

DMA (Direct Memory Access) là cơ chế để một khối phần cứng chép dữ liệu giữa bộ nhớ và ngoại vi, hoặc giữa hai vùng bộ nhớ, mà CPU không phải đọc ghi từng word. Trang này trình bày DMA ở mức kiến trúc chip, theo thứ tự: hai cách tổ chức DMA trong SoC, các khối bên trong một DMA controller, cách controller nhận yêu cầu từ ngoại vi, descriptor và scatter-gather, giao dịch trên bus AXI, cache coherency, các yếu tố quyết định hiệu năng, rồi ví dụ từ một số IP thực tế. Vị trí của DMA và IOMMU trong toàn bộ SoC nằm ở SoC / System. Cách driver Linux dùng DMA nằm ở DMA trong Linux kernel.

Hai cách tổ chức DMA

Trong SoC có hai cách để dữ liệu đi giữa thiết bị và bộ nhớ không qua CPU:

Hai cách tổ chức DMA trong SoC

Trái: DMA controller chung chép dữ liệu thay cho ngoại vi đơn giản. Phải: thiết bị có DMA engine riêng và tự phát giao dịch.
DMA controller chung (third-party) Bus master DMA (first-party)
Ai phát giao dịch bộ nhớ Một DMA controller dùng chung Chính thiết bị, qua DMA engine tích hợp
Thiết bị điển hình UART, SPI, I2C, I2S, ADC tốc độ thấp, chép bộ nhớ NIC, controller PCIe, USB, SATA, GPU, NPU
Giao diện của ngoại vi Chỉ cần slave port và FIFO, cộng đường request tới DMA controller Có master port riêng trên interconnect
Định dạng descriptor Do DMA controller quy định Do từng thiết bị quy định, thường là vòng descriptor (descriptor ring)
Ưu điểm Ngoại vi đơn giản, dùng chung một khối DMA cho nhiều ngoại vi Băng thông cao, thiết bị chủ động, không tranh kênh với ngoại vi khác

Hai cách thường cùng có mặt trên một SoC: ngoại vi tốc độ thấp dùng DMA controller chung, khối tốc độ cao có DMA riêng. Với thiết bị PCIe, phía máy chủ chỉ thấy thiết bị là bus master, còn bên trong card (ví dụ card FPGA) vẫn có một DMA engine.

Các khối bên trong DMA controller

Cấu trúc bên trong DMA controller

Các khối thường gặp trong một DMA controller.
Khối Chức năng
Giao diện slave Cho CPU đọc ghi thanh ghi cấu hình, thường là APB hoặc AXI-Lite
Kênh (channel) Mỗi kênh là một luồng truyền độc lập, có bộ thanh ghi riêng: địa chỉ nguồn, đích, độ dài, độ rộng truy cập, kích thước burst, con trỏ descriptor, trạng thái
Arbiter Chọn kênh được dùng bus khi nhiều kênh cùng hoạt động, theo round-robin hoặc mức ưu tiên
Khối nạp descriptor Đọc descriptor từ bộ nhớ và nạp vào thanh ghi của kênh, cho phép chạy chuỗi nhiều lần truyền
FIFO dữ liệu Đệm giữa phía đọc và phía ghi, cho phép đọc một burst lớn rồi ghi ra theo tốc độ phía đích
AXI master Phát giao dịch đọc ghi lên interconnect, quản lý burst và số giao dịch chờ (outstanding)
Request và handshake Nhận tín hiệu yêu cầu từ ngoại vi, báo lại khi đã xử lý
Logic ngắt Báo CPU khi một lần truyền hoặc một descriptor hoàn tất, hoặc khi có lỗi bus

Một lần truyền thường được mô tả bằng các tham số: địa chỉ nguồn và đích, chế độ tăng địa chỉ của từng phía (tăng dần với bộ nhớ, cố định với thanh ghi FIFO của ngoại vi), độ rộng mỗi lần truy cập, kích thước burst và tổng số byte.

Yêu cầu từ ngoại vi và flow control

Khi chép giữa bộ nhớ và ngoại vi, DMA controller không thể đọc hay ghi FIFO của ngoại vi tùy lúc: ghi khi FIFO phát đã đầy hoặc đọc khi FIFO thu còn rỗng sẽ làm mất dữ liệu. Vì vậy ngoại vi nối với DMA controller bằng đường request. Ngoại vi kích tín hiệu này khi FIFO đạt ngưỡng (còn đủ chỗ trống, hoặc đã có đủ dữ liệu), DMA controller thực hiện một burst rồi báo lại qua tín hiệu xác nhận.

Ngưỡng FIFO của ngoại vi và kích thước burst của kênh phải khớp nhau. Burst lớn hơn khoảng trống trong FIFO gây tràn, burst quá nhỏ làm tăng số lần request và giảm hiệu suất bus.

Một thông số khác là flow controller, bên quyết định khi nào lần truyền kết thúc:

Flow controller Cách hoạt động Dùng khi
DMA controller Phần mềm nạp trước tổng số byte, controller dừng khi đủ Độ dài biết trước, phần lớn trường hợp
Ngoại vi Ngoại vi báo kết thúc bằng tín hiệu riêng Độ dài không biết trước, ví dụ gói tin có độ dài thay đổi

Số đường request là tài nguyên cố định của một DMA controller. Trên SoC, bảng nối đường request với ngoại vi do nhà sản xuất quy định trong tài liệu tham khảo (TRM), và phần mềm phải dùng đúng số hiệu này khi cấu hình kênh.

Descriptor và scatter-gather

Ở chế độ đơn giản, CPU ghi tham số trực tiếp vào thanh ghi kênh rồi khởi động, mỗi lần truyền một vùng liền nhau. Buffer thực tế thường gồm nhiều đoạn rời nhau trong bộ nhớ vật lý, và mỗi lần CPU phải nạp lại sẽ tốn thời gian và tạo khoảng trống giữa các lần truyền. Scatter-gather giải quyết bằng chuỗi descriptor đặt trong bộ nhớ:

Chuỗi descriptor trong bộ nhớ

Kênh DMA lần lượt nạp từng descriptor và chép đoạn buffer tương ứng, đến khi gặp descriptor cuối.

Mỗi descriptor thường gồm địa chỉ nguồn, địa chỉ đích, độ dài, cờ điều khiển (ngắt khi xong, descriptor cuối) và con trỏ tới descriptor kế tiếp. Controller ghi lại trạng thái hoàn tất vào descriptor sau khi xử lý, để phần mềm biết đoạn nào đã xong mà không cần đọc thanh ghi.

Các biến thể thường gặp:

Dạng Mô tả
Linked list Mỗi descriptor trỏ tới descriptor kế tiếp, kết thúc bằng con trỏ rỗng hoặc cờ cuối
Vòng descriptor (ring) Mảng descriptor dùng vòng tròn, có bit sở hữu (ownership) cho biết descriptor đang thuộc phần mềm hay phần cứng. Dạng phổ biến ở NIC và các thiết bị bus master
Cyclic Chuỗi khép kín, controller chạy liên tục và báo ngắt sau mỗi đoạn. Dùng cho audio và các luồng liên tục
2D, strided Một descriptor mô tả nhiều dòng với bước nhảy giữa các dòng, dùng cho ảnh và video

Giao dịch trên bus AXI

DMA controller hiện đại thường có giao diện AXI master. Các thuộc tính của AXI ảnh hưởng trực tiếp tới cách DMA phát giao dịch:

Thuộc tính Ý nghĩa với DMA
Burst Một giao dịch gồm nhiều beat liên tiếp. Burst dài giảm chi phí địa chỉ trên mỗi byte. AXI4 cho phép burst INCR tới 256 beat
Loại burst INCR (địa chỉ tăng) cho bộ nhớ, FIXED (địa chỉ giữ nguyên) cho thanh ghi FIFO của ngoại vi
Ranh giới 4 KiB Một burst AXI không được vượt qua ranh giới 4 KiB, nên DMA tự cắt burst tại các ranh giới này
Kênh đọc và ghi tách rời DMA đọc nguồn và ghi đích song song
Outstanding transaction Phát nhiều giao dịch trước khi giao dịch đầu hoàn tất, để che độ trễ của DRAM
Thuộc tính cache và bảo mật (AxCACHE, AxPROT) Báo cho interconnect biết giao dịch có được cache không và thuộc vùng secure hay non-secure

Chi tiết về các bus AMBA và interconnect nằm ở SoC / System.

Cache coherency

CPU làm việc với dữ liệu qua cache, còn DMA đọc ghi qua interconnect tới DRAM. Nếu không có cơ chế đồng bộ, hai bên thấy dữ liệu khác nhau: DMA đọc bản cũ trong DRAM khi bản mới còn trong cache của CPU, hoặc CPU đọc bản cũ trong cache sau khi DMA đã ghi bản mới xuống DRAM.

Cách Phần cứng Phần mềm
Không coherent DMA đi thẳng tới bộ nhớ, không kiểm tra cache của CPU Phải clean cache trước khi DMA đọc và invalidate cache trước khi CPU đọc dữ liệu DMA vừa ghi
IO coherent DMA nối vào cổng coherent của interconnect (ví dụ ACE-Lite trên hệ Arm). Giao dịch của DMA được snoop vào cache của CPU Không cần thao tác cache
Bộ nhớ không cache Vùng buffer được đánh dấu không cache trong page table Không cần thao tác cache, nhưng CPU truy cập vùng này chậm

IO coherent chỉ là một chiều: DMA thấy được cache của CPU, nhưng DMA không có cache được CPU snoop. Trên SoC có cả cổng coherent và không coherent (ví dụ cổng HP và HPC của ZynqMP nối PL với PS), việc khai báo đúng thiết bị nào đi qua cổng nào ảnh hưởng trực tiếp tới phần mềm. Linux dùng property dma-coherent trong Device Tree để biết điều này, xem DMA trong Linux kernel. Nền tảng về coherence giữa các core nằm ở Cache.

IOMMU và bảo mật

DMA có quyền đọc ghi bộ nhớ nên là một rủi ro bảo mật: thiết bị lỗi hoặc firmware độc hại có thể ghi vào bất kỳ vùng nào. IOMMU (SMMU trên Arm) đặt giữa thiết bị và interconnect, dịch địa chỉ của thiết bị và chặn truy cập ngoài vùng được cấp, xem SoC / System. Mỗi master được IOMMU nhận diện bằng một mã luồng (stream ID trên SMMU), nên một DMA controller chung với nhiều kênh có thể chỉ có một mã, tức các kênh dùng chung một không gian địa chỉ.

Trên hệ có TrustZone, giao dịch DMA mang thuộc tính secure hoặc non-secure. Một số DMA controller có kênh và thanh ghi riêng cho từng vùng, để phần mềm non-secure không dùng DMA đọc được bộ nhớ secure.

Yếu tố quyết định hiệu năng

Yếu tố Ảnh hưởng
Độ rộng bus và tần số Giới hạn trên của băng thông: số byte mỗi beat nhân tần số clock của giao diện
Kích thước burst Burst ngắn tăng tỉ lệ chi phí địa chỉ và làm DRAM kém hiệu quả
Số outstanding transaction Không đủ outstanding thì độ trễ DRAM làm kênh chờ, băng thông giảm dù bus còn trống
Căn chỉnh địa chỉ Địa chỉ không căn theo độ rộng bus hoặc theo cache line tạo thêm giao dịch nhỏ
Kích thước đoạn trong scatter-gather Đoạn quá nhỏ làm chi phí nạp descriptor chiếm phần lớn thời gian
Tranh chấp interconnect DMA dùng chung đường tới DRAM với CPU, GPU và các master khác
Ngắt Ngắt sau mỗi đoạn nhỏ làm tăng tải CPU. Gom ngắt (interrupt coalescing) giảm tải nhưng tăng độ trễ

Ví dụ IP thực tế

IP Kiểu Đặc điểm chính
Arm CoreLink DMA-330 (PL330) DMA controller chung Tới 8 kênh, tới 32 giao diện request từ ngoại vi. Mỗi kênh chạy một chương trình gồm các lệnh DMA riêng (nạp, lưu, vòng lặp, chờ request) thay cho descriptor dạng bảng. Dùng làm DMA của PS trên Zynq-7000
AMD Xilinx AXI DMA IP trong FPGA, chép giữa AXI4-Stream và bộ nhớ Hai kênh MM2S (bộ nhớ ra stream) và S2MM (stream vào bộ nhớ). Có chế độ đơn giản dùng thanh ghi và chế độ scatter-gather dùng descriptor trong bộ nhớ
ZynqMP GDMA và ADMA DMA controller chung trong PS Hai khối, mỗi khối 8 kênh: GDMA ở miền full-power, ADMA ở miền low-power
DMA engine của NIC, NVMe Bus master Vòng descriptor trong bộ nhớ máy chủ, bit sở hữu, nhiều hàng đợi

Driver Linux cho các IP này dùng framework dmaengine (DMA controller chung) hoặc DMA API trực tiếp (bus master), xem DMA trong Linux kernel.

Liên quan

  • DMA trong Linux kernel: DMA API, dmaengine, CMA và IOMMU từ góc nhìn của driver.
  • SoC / System: interconnect, interrupt controller và IOMMU trong toàn bộ SoC.
  • Cache: cache coherence giữa các core.
  • Xilinx IPCore: IP core của Xilinx dùng trong thiết kế FPGA.

Tài liệu tham khảo