2017-11-03 25 views
1

openwrt 용 PCIE 장치 드라이버를 개발 중이며 last question에서 언급 한 타이머 인터럽트에서 io-memory에 액세스 할 때 데이터 버스 오류가 발생했습니다. 많은 연구 끝에 나는 그 이유를 발견했을지 모르지만 그것을 해결할 수는 없다. 아래는 내 문제입니다.PCIE 영역이 정렬되지 않았으며 일관성이 없습니다.

지난 주에 나는 시스템 시작시 pcie 영역 크기가 변경되었을 수도 있다는 것을 알았습니다. bar0의 영역 크기는 내 드라이버 (pci_resource_len에서 반환)에서 4096이고 영역 크기는 lspci -vv에서 4097이며 이는 Linux 커널의 페이지 크기를 나눕니다. pciutil의 소스 코드를 읽어 보면 lspci 명령이 /sys/devices/pci0000:00/0000:00:00.0/resouce 파일에서 pcie 정보를 가져 오는 것으로 나타났습니다. 따라서 모든 사용자 지정 구성 요소를 제거하고 라우터에서 원래 openwrt를 실행합니다. cat /sys/devices/pci0000:00/0000:00:00.0/resouce함으로써 결과의 첫 번째 행 (BAR0)는 I도 /proc/iomem의 내용을 확인 더욱이

0x0000000010008000 0x0000000010009000 0x0000000000040200 

이며 PCIE 관련된 콘텐츠

10000000-13ffffff : mem_base 
    10000000-13ffffff : PCI memory space 
     10000000-10007fff : 0000:00:00.0 
     10008000-10008fff : 0000:00:00.0 

는 그것은 그 슈퍼 이상이다 위의 두 파일에 표시된 bar0의 영역 크기가 다릅니다! PCIE의 메커니즘에 따르면 영역 크기는 항상 2의 제곱이어야합니다. 영역 크기는 어떻게 4097이됩니까?

답변

0

리눅스 커널의 소스 코드를 읽는 데 몇 주를 보낸 후, 나는 이것이 리눅스 커널 4.4.14의 버그라는 것을 알게되었다.

/sys/devices/pci0000:00/0000:00:00.0/resouce의 내용은 파일 drivers/pci/pci-sysfs.c에서 resource_show 함수를 통해 생성됩니다. 관련 코드는

for (i = 0; i < max; i++) { 
    struct resource *res = &pci_dev->resource[i]; 
    pci_resource_to_user(pci_dev, i, res, &start, &end); 
    str += sprintf(str, "0x%016llx 0x%016llx 0x%016llx\n", 
       (unsigned long long)start, 
       (unsigned long long)end, 
       (unsigned long long)res->flags); 
} 

실제로

static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, 
     const struct resource *rsrc, resource_size_t *start, 
     resource_size_t *end) 
{ 
    phys_addr_t size = resource_size(rsrc); 

    *start = fixup_bigphys_addr(rsrc->start, size); 
    *end = rsrc->start + size; 
} 
arch/mips/include/asm/pci.h에 위치한 호출 기능 pci_resource_to_user입니다

*end의 계산은 잘못하고

*end = rsrc->start + size - (size ? 1 : 0) 
에 의해 대체되어야한다