2013-06-12 7 views
6

자일링스의 Microblaze에서 full MMU를 사용하여 Linux 커널 3.3을 실행 중입니다. 내가하고있는 일은 내가 다음을 알아야한다는 것을 요구한다. 나는 텍스트 파일 (버퍼)을 만들고이 버퍼의 물리적 주소를 찾아야하고, 커널이이 파일을 메모리의 불연속 영역에 기록하는 것을 원하지 않는다.리눅스에서 버퍼의 실제 주소 얻기

미리 설정된 실제 메모리 주소에서 데이터를 스트리밍하는 DMA 엔진이 있기 때문에 필자가 필요로하는 이유 때문에이 정확한 메모리 위치에 버퍼 파일을 만들도록 Linux를 강제해야하므로이 데이터를 쓸 때 그 즉시 다른 하드웨어 코어로 DMA 엔진에 의해

자세한 내용 전송 파일 :.

내 시스템은 512MB의 DDR3 RAM은 자일링스의 '멀티 포트 메모리 컨트롤러 (MPMC) "를 통해 시스템에 연결이를 기본 주소 이 메모리 컨트롤러의 0x90000000입니다. 시스템의 모든 장치는 MicroBlaze를 포함하여이 컨트롤러를 통해 메모리에 액세스합니다. 내가 가지고있는 DMA 장치는 Native Perso 매우 낮은 수준에서 메모리와 통신하기위한 NPI (Nality Interface). 따라서 매우 빠른 성능을 제공합니다.

이 NPI DMA 장치는 원래 가상 메모리를 지원하지 않는 "xilkernel"이라는 매우 기본적인 임베디드 커널에서 사용되도록 설계되었지만 MMU는 MicroBlaze의 일부가 아니므로 프로그래머는 OS 코드가 어디에 있는지 볼 수있었습니다. DMA가 스트리밍되는 소스 주소로 0x91800000과 같은 실제 메모리 주소를 선택하면 프로그래머는 정확한 주소에 파일을 배치하고 시스템을 실행합니다.

대신에 Linux를 사용하도록 프로젝트를 마이그레이션해야 할 때 xilkernel 우리는이 문제에 직면 해 리눅스에서 블록 장치로 액세스 할 수있는 외부 저장 장치에 파일을 가지고 있으며 각 파일을 주 메모리 (DDR3 RAM)로 이동하고 DMA 스트림을 파일로 만들어야합니다. 현재 고정 주소의 DMA 스트림이지만 필요한 경우 일반화 할 수 있습니다.

+2

Linux 커널이 가상 메모리와 실제 메모리를 관리하는 방법을 설명하는 장을이 PDF에서 살펴보십시오. 다양한 시나리오에서 실제 메모리를 매핑하고 고정하는 방법에 대한 예제를 제공합니다. http://lwn.net/images/pdf/LDD3/ch15.pdf –

+1

@bromanous이 장치를 직접 개발했거나 수정할 수없는 타사 IP 코어입니까? 수정이 가능하면 tian_yufen이 말하는 표준 DMA 기능을 사용할 수 있도록 DMA 주소 소프트웨어를 구성 가능하게 설정하는 것이 좋습니다. –

+0

@BenjaminLeinweber, 예 DMA 코어의 소스 코드를 가지고 있으며 DMA 스트림이 일반 매개 변수로 사용되는 주소를 구성 할 수 있습니다. – bromanous

답변

5

DMA 컨트롤러와 인터페이스 할 버퍼를 처리하기 위해 특정 기능이 있습니다. 이러한 기능은 주소 변환뿐만 아니라 캐시 플러시 (전송하기 전에 메모리에 데이터 쓰기) 및 캐시 무효화 (수신하기 전에 캐시 무효화)와 같은 메모리와의 캐시 일관성을 처리합니다.

(1)에 버퍼를 할당 가상 어드레스와 물리 어드레스를 모두 얻을 다음 dma_handle 포인터 물리적 절약하면서

void *dma_alloc_coherent(struct device *dev, size_t size, 
         dma_addr_t *dma_handle, gfp_t flag) 

함수의 리턴 값이 할당 된 버퍼의 가상 주소,입니다 할당 된 버퍼의 주소.

(2) 하나의 버퍼 장치에 할당 전달할 :

dma_addr_t dma_map_single(struct device *dev, void *ptr, 
          size_t size, 
          enum dma_data_direction dir) 

반환 값은 버퍼의 물리 어드레스이고, 파라미터 DIR은 DMA_TO_DEVICE이다 PTR 버퍼의 가상 주소이고; 장치로부터

(3)를 수신하는 한 완충액 :

void dma_unmap_single(struct device *dev, dma_addr_t addr, 
          size_t size, 
          enum dma_data_direction dir) 

파라미터 DIR은 DMA_FROM_DEVICE이다.

참고 : dma와 관련된 세 가지 기능을 사용하려면 dma_map_ops가있는 특정 버스에 장치를 등록해야합니다. 그렇지 않으면이 세 가지 기능을 사용할 수 없습니다.

+2

OP의 질문에 대한 대답이 아닙니다. OP는 메모리의 고정 된 위치에 dma 버퍼를 생성하려고합니다. 이러한 API 중 어느 것도이를 수행 할 수 없습니다. –

4

는 그 정확한 메모리 위치이 불가능

로 버퍼 파일을 생성하도록 강제 할 필요가있다. (실제로 XY 질문을 만들었습니다.)

"사전 설정 실제 메모리 주소에서 데이터를 스트리밍하는"하드웨어가 있으므로의 경우 Linux 커널이이 메모리 영역을 일부로 사용하지 않도록해야합니다. 그 메모리 풀 이 메모리 영역을 사용하지 않으려면 을으로 부팅 할 때 커널에 알릴 필요가 있습니다. 커널이 제어하는 ​​메모리 공간의 일부가되면이 특정 물리적 메모리 영역에서 버퍼를 "회수하거나"할당 할 수 없습니다.

메모리 영역을 제외하는 가장 일반적인 방법은 커널 명령 줄에서 memmap= 매개 변수를 사용하는 것입니다.

memmap=nn[KMG]$ss[KMG] 
     [KNL,ACPI] Mark specific memory as reserved. 
     Region of memory to be used, from ss to ss+nn. 
     Example: Exclude memory from 0x18690000-0x1869ffff 
       memmap=64K$0x18690000 
       or 
       memmap=0x10000$0x18690000 

ATAG가있는 ARM과 같은 일부 아키텍처는 물리적 메모리의 영역을 예약하는 데 덜 눈에 잘 띄고보다 안전한 방법을 제공합니다.

그런데 어떻게하면이 메모리 영역의 주소와 크기를 장치 드라이버에 제공해야합니다. 명령 줄을 구문 분석하거나, #define을 사용하여 하드 코드 된 (엄지 손가락으로 아래로 내려) 결과를 얻을 수 있습니다.

드라이버는 request_mem_region()을 호출하여 메모리 영역 사용을 선언해야합니다.
드라이버는 ioreamp()을 호출하여이 메모리 영역을 가상 주소 공간에 매핑 할 수 있습니다.

드라이버가 제공되었거나 이미 실제 주소를 알고 있기 때문에 완료되었습니다. 실제 메모리가 할당되었으므로 메모리는 연속적입니다. 이 메모리 영역에서 캐싱을 사용하지 않도록 MMU를 구성해야합니다. 메모리 영역은 "DMA 가능"이됩니다.

+2

+1 질문에 대한 직접적인 대답. 또 다른 비슷한 방법은 장치가 메모리의 맨 위를 사용하고 실제로 mem = boot 매개 변수를 사용하는 것보다 적은 메모리가 있다고 Linux에 알리는 것입니다. 예를 들어 64MB의 메모리가있는 경우 mem = 63M을 전달하여 0x3F00000부터 시작하여 장치의 메가를 예약 할 수 있습니다. –

+0

@sawdust "이 메모리 영역에서 캐싱을 사용하지 않도록 MMU를 구성해야합니다"라는 방법을 이해하지 못했지만 MicroBlaze 조정 매개 변수를 살펴 보았습니다. memmap을 충분히 설정하지 않습니까? – bromanous

+1

@bromanous - 나는 그것을 완전성을위한 사후 검토로 포함시켰다. 아마도 명시 적으로 할 일이 없을 것입니다. 다행히'memmap ='명세와 arch/board/proc에 대한'ioremap()'호출은 그 메모리 영역에 대한 적절한 속성을 설정할 것이다. – sawdust