메모리 매핑된 I/O에 액세스하는 속도가 매우 느림

메모리 매핑된 I/O에 액세스하는 속도가 매우 느림

저는 Terasic-SoCKIT(fpga 및 arm cortex a9)를 가지고 있고 HPS에서 Linux를 실행하고 있습니다. "request_mem_region" 및 "ioremap" 함수를 사용하여 간단한 문자 드라이버를 작성하면서 메모리 매핑된 I/O에 액세스하려고 합니다.

메모리 매핑 IO는 데이터를 FPGA로 전송하는 데 사용할 수 있는 AXI 버스입니다. 각 쓰기에는 약 6us가 소요되며 내 애플리케이션의 경우 1us보다 작아야 합니다. 또한 드라이버는 몇 번의 쓰기 후에 매핑된 IO에 대한 쓰기를 중지합니다(FPGA의 데이터가 변경되는 것을 볼 수 없습니다. 드라이버의 버퍼가 가득 찼습니까?).

문제는 내가 뭔가를 놓치고 있는 걸까요, 아니면 쓰기가 가상 주소에서 실제 주소로 이루어지기 때문에 더 빠를 수 없다는 것입니다. 가상 주소에서 쓰는 속도가 느린 경우 속도를 높일 수 있는 방법이 있나요? ARM에 DMAC가 있다는 것을 알고 있지만 아직 살펴보지 않았습니다.

고마워요, 카르틱

죄송합니다. 사용자 공간 코드에서 시간을 측정하고 있다는 사실을 모두에게 알리지 못했습니다. 나중에 드라이버에 쓰는 데 걸린 시간을 나노초 단위로 확인했습니다. 그래서 대부분의 경우 사용자 공간에서 커널에 기록되는 것 같습니다.

그래서 더 자세히 읽고 ioremap()이 물리적 주소를 커널 가상 주소에 매핑하고 remap_pfn_range()가 물리적 주소/IO 메모리를 사용자 가상 공간에 매핑한다는 것을 알게 되었습니다(이것이 바로 제가 필요한 것입니다. 사용자 공간에서 IO 메모리에 쓰기). 나는 간단한 mmap 예제를 사용했습니다 -http://web.cecs.pdx.edu/~jrb/ui/linux/examples.dir/simple/simple.c커널 드라이버로. 다음 코드는 내 사용자 공간 코드입니다.

    using namespace std;
    #include <iostream>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdint.h>
    #include <ctime>


    #define PAGE_SIZE 4096
    #define HPS2FPGA_BRIDGE_BASE 0xc0000000
    #define BLINK_OFFSET 0x0

    volatile unsigned char *blink_mem;
    void *bridge_map;

    int main()
    {
        int fd, ret = EXIT_FAILURE;
        unsigned int i;
        unsigned char value;
        int dummy;
        off_t blink_base = HPS2FPGA_BRIDGE_BASE;
        clock_t start, stop;
        double duration;

        /* open the memory device file */
        fd = open("/dev/HPS2FPGA", O_RDWR|O_SYNC);
        if (fd < 0) {
            perror("open");
            exit(EXIT_FAILURE);
        }

        /* map the LWHPS2FPGA bridge into process memory */
        bridge_map = mmap(NULL, PAGE_SIZE, PROT_WRITE|PROT_READ|PROT_EXEC, MAP_SHARED,
                    fd, blink_base);
        if (bridge_map == MAP_FAILED) {
            perror("mmap");
            goto cleanup;
        }


        /* get the delay_ctrl peripheral's base address */
        blink_mem = (unsigned char *) (bridge_map + BLINK_OFFSET);

        start = clock();
        /* write the value */
        for(i = 0; i < 1000000; i++)
        {
            *blink_mem = i;
            dummy = *blink_mem;
        }
        stop = clock();
        duration = ( stop - start ) / (double) CLOCKS_PER_SEC;
        printf("%f", duration);

        if (munmap(bridge_map, PAGE_SIZE) < 0) {
            perror("munmap");
            goto cleanup;
        }

        ret = 0;

    cleanup:
        close(fd);
        return ret;
    }

mmap에서 반환된 가상 주소 공간에 쓰고 있는데 해당 주소의 값을 읽어 쓰기를 확인할 수 있지만 FPGA의 값이 업데이트되는 것을 볼 수 없습니다.

사용자 가상공간에 쓸 때 물리주소는 어떻게 쓰나요? 실제 주소 공간이 실제로 기록되고 있는지 디버깅하고 확인할 수 있는 방법이 있습니까?

답변1

음, 이 질문의 주제는 다음과 같습니다....메모리 매핑된 I/O(올바르게 수행됨)는 액세스되는 하드웨어에 대해 프로세서가 수행하는 것만큼 빠르며 커널 모드와 달리 사용자 모드에서 수행하는 데 따른 오버헤드가 없습니다(예: 사용자 공간에서 "없음") 커널에 기록됨").

그러나 주소를 읽거나 쓸 때 어떤 일이 발생하는지 여전히 고려해야 합니다. 여기에 문제가 있습니다. 대부분의 아키텍처에는 가상에서 물리적으로, 물리적에서 장치로의 두 가지 매핑이 있습니다. 첫 번째는 가상 메모리 하드웨어에 설정되고 두 번째는 메모리 컨트롤러에 설정됩니다.

매핑을 제외한 모든 액세스는 일반적으로 다음을 통해 이루어집니다.은닉처하드웨어이므로 액세스를 캐시할지 여부를 결정해야 합니다. 액세스되는 기본 장치가 일종의 RAM인 경우 일반적으로 액세스를 캐시하려고 합니다. 다른 유형의 장치에서는 일반적으로 필요하지 않습니다.

고려해야 할 다른 사항(예: VM 매핑이 VM 하드웨어에 있는지 여부, 액세스 폭 및 기간, 우선 순위, 권한 등)이 있을 수 있지만 캐싱이 먼저입니다.

@Karthik의 경우에는 그렇지 않았기 때문에끄다캐시 유형에 따라 맵에 캐시되거나 전체 캐시에 캐시됩니다.철사주소에 쓸 때 쓰는 중이거나(write-through) 쓰기가 지연됩니다(write-back)(캐싱에 대한 세부 정보를 알고 싶다면 다음을 시도하세요).이것).

특정(후속) 질문에 대답하기 위해 가상 주소 매핑이 완료되고 캐시가 작업을 완료하면 액세스가 메모리 컨트롤러로 이동합니다. 하드웨어는 액세스할 버스 및/또는 장치를 결정하고 " 올바른 작동". 일반적으로 어설션과 관련된 하드웨어 "사물"칩 선택및/또는쓰기 가능신호, 일부 또는 전체를 복사할 수 있음물리적주소주소 라인, 어쩌면 일부타이밍 설정, 등.

...이 문제를 디버깅하는 가장 좋은 방법은분석기어떤 종류의 장치나 버스가 연결되어 있거나 너무 어렵거나 비용이 많이 드는 경우 메모리 컨트롤러에서 디버깅을 지원할 수도 있습니다.

blink_mem또 다른 사소하지만 중요한 점은 위 코드의 설명을 참고하세요.휘발성 물질유형 한정자는 매우 중요합니다. 주소에 대한 액세스를 파괴하지 않도록 컴파일러에 지시합니다. 이 외에도 메모리 액세스와 관련된 특수 파이프 명령도 알고 있어야 합니다(참조:아이오powerpc 교육 - 유머 감각이 있는 사람 :-)

마지막으로, 댓글에서 말한 내용을 다시 한번 말씀드리자면, 전화를 걸 때 이것이 질문에 대한 실제 답변이라는 것이 밝혀졌습니다.remap_pfn_range()닫다마지막 매개변수에 지정된 페이지 보호를 수정하여 캐시합니다(단백질) 사용pgprot_noncached()매크로. 또한 읽어보세요이것그리고이것특히이것. 건배!

관련 정보