Linux v6.18.37 · 개념과 코드 읽기

DMA, cache coherency와 IOMMU translation

이 코드는 어떤 문제를 푸나요?

장치가 메모리에 쓴 새 데이터보다 CPU 캐시에 남은 옛 데이터가 먼저 보이면 드라이버는 틀린 결과를 읽습니다. DMA 주소 변환과 캐시 소유권 전환은 별개 문제입니다. arm64의 캐시 관리, x86의 플랫폼 DMA/IOMMU 경로, RISC-V의 비일관성 처리 여부를 비교하고 대표로 arm64 CPU 재접근 함수를 읽습니다.

읽을 범위: v6.18.37 · arch/arm64/mm/dma-mapping.c · arch_sync_dma_for_cpu 23–32행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.

먼저 알아둘 개념

DMA 주소

장치에 주는 주소입니다. CPU 가상 주소와 다르며 IOMMU가 있으면 물리 주소와도 다를 수 있습니다.

비일관성 DMA

장치 쓰기가 CPU 캐시에 자동 반영되지 않는 환경입니다. CPU와 장치가 버퍼를 넘겨받을 때 DMA API의 동기화가 필요합니다.

IOMMU

장치가 보는 주소를 물리 메모리에 연결하고 접근 권한을 제한합니다. 이 기능이 CPU 캐시 동기화를 모두 대신하지는 않습니다.

처음 읽을 때

CPU 캐시·RAM·장치를 세 칸으로 그리고 장치가 쓴 뒤 CPU가 읽는 순서를 따라가십시오.

더 깊이 살펴볼 때

DMA_TO_DEVICE에서 CPU 측 invalidate를 생략하는 이유와 버퍼 정렬·거짓 공유 문제를 검토해 보십시오.

그림으로 보는 변화

한 DMA 버퍼에 대해 서로 다른 두 질문① 장치 주소는 어디를 가리키는가? ② 장치 사용 뒤 CPU는 어느 캐시 사본을 읽는가?

01 · 주소 경로

장치에 준 주소 → 접근 대상 메모리

DMA API가 반환한 주소는 장치가 사용합니다. CPU 가상 주소와 구별합니다.

  1. 장치에 전달한 DMA 주소이 값만 보고 원래 물리 주소와 숫자가 같다고 단정하지 않습니다.
  2. IOMMU 경로라면장치의 IOVA를 물리 페이지로 변환그 밖의 경로라면플랫폼 direct 경로 등으로 접근; 조건에 따라 bounce 가능
  3. 장치가 매핑된 메모리에 접근선택된 경로가 주소 연결을 정합니다. IOMMU 경로에서도 dev_use_swiotlb() 조건과 주소·크기 정렬에 따라 bounce 버퍼를 사용할 수 있습니다.

02 · 데이터 소유권·캐시 경로

장치 사용 완료 → CPU 재접근

비일관성 arm64 DMA에서 CPU가 버퍼를 다시 사용할 때, 이 글의 함수는 방향을 확인합니다.

  1. 장치의 버퍼 사용 완료CPU가 다시 읽기 전에 DMA API의 소유권·동기화 규칙을 따릅니다.
  2. arch_sync_dma_for_cpu의 방향 분기
    DMA_TO_DEVICE장치가 읽는 방향 · 이 함수는 CPU 측 invalidate 없이 반환
    DMA_FROM_DEVICE / DMA_BIDIRECTIONAL장치 쓰기가 가능한 방향 · 이 함수는 해당 CPU 캐시 범위를 invalidate
  3. CPU가 버퍼에 다시 접근필요한 캐시 처리를 거친 뒤 데이터를 봅니다.

두 레인은 서로 다른 판단입니다. IOMMU는 선택된 주소 변환 경로이고 캐시 동기화를 대신하지 않습니다. 캐시가 하드웨어로 일관되는 장치·플랫폼에서는 필요한 처리가 달라집니다. 주소 분기는 DMA 공통 경로 155–186행, 선택된 IOMMU 번역은 IOMMU 경로 835–863행을 바탕으로 합니다. IOMMU 매핑의 bounce·캐시 처리 조건 1198–1228행도 함께 확인하십시오. 캐시 경로의 분기는 arm64 고정 원문 23–32행의 arch_sync_dma_for_cpu를 설명하며, 주소 매핑 함수나 장치 완료를 이 함수가 수행한다는 뜻은 아닙니다.

DMA, cache coherency와 IOMMU translation의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 장치가 사용

장치가 허용된 DMA 주소로 버퍼에 접근합니다.

화살표는 장치의 읽기 또는 쓰기이며 CPU 포인터 역참조가 아닙니다.

2. CPU 소유권 회수

방향이 DMA_TO_DEVICE인지 확인합니다.

전송 방향은 필요한 캐시 작업을 고르는 조건입니다.

3. CPU가 다시 읽기

필요한 경우 CPU 캐시를 무효화해 새 데이터를 가져오게 합니다.

무효화는 버퍼 데이터를 0으로 지우는 작업이 아닙니다.

arch_sync_dma_for_cpu를 한 줄씩 읽기

줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.

void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
			   enum dma_data_direction dir)
{
	unsigned long start = (unsigned long)phys_to_virt(paddr);

	if (dir == DMA_TO_DEVICE)
		return;

	dcache_inval_poc(start, start + size);
}
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,

장치가 사용한 버퍼를 CPU가 다시 접근할 때 필요한 아키텍처 캐시 작업을 받습니다. paddr는 물리 주소, size는 바이트 범위입니다.

			   enum dma_data_direction dir)

dir는 전송 방향입니다. 장치가 읽었는지 썼는지에 따라 CPU에 낡은 캐시가 남을 가능성이 다릅니다.

	unsigned long start = (unsigned long)phys_to_virt(paddr);

캐시 유지보수 함수에 전달할 CPU 가상 주소를 물리 주소에서 구합니다. 이 값을 장치 DMA 주소와 혼동하지 않습니다.

	if (dir == DMA_TO_DEVICE)

장치로 보내기만 한 방향인지 확인합니다. DMA_TO_DEVICE에서는 장치가 버퍼의 새 내용을 작성하는 방향이 아닙니다.

		return;

이 경우 CPU 쪽 invalidate가 필요 없으므로 돌아갑니다.

	dcache_inval_poc(start, start + size);

그 외 방향은 해당 주소 구간의 CPU 캐시를 PoC 기준으로 무효화합니다. 장치가 갱신한 RAM 대신 낡은 CPU 사본을 읽지 않도록 하는 작업입니다.

함께 생각해 볼 질문

dma_map_single의 결과를 CPU가 역참조해도 됩니까?

아닙니다. 반환값은 장치에 전달할 DMA 주소입니다.

IOMMU가 있으면 cache sync는 없어도 됩니까?

아닙니다. 주소 보호와 캐시 일관성은 별도 성질입니다.

DMA_TO_DEVICE는 누가 읽는 방향입니까?

장치가 CPU 측에서 준비한 데이터를 읽는 방향입니다.

출처와 읽은 범위

Linux stable v6.18.37 · arch/arm64/mm/dma-mapping.c

해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고

맨 위로 ↑