2016-10-18 10 views
3

В качестве теста первого уровня моего драйвера PCI я надеялся, что смогу получить доступ к области pci_iomap через /sys/bus/pci/devices/0000:01:00.0/ resource0 файл из моего пользовательского приложения. Страница man для mmap, образец программы, который я нашел, и другие сообщения, похоже, указывают на то, что пользовательский процесс доступа должен работать. Но некоторые статьи, похоже, указывают на то, что вызов mmap должен выполняться изнутри ядра через ioctl-аксессор.linux mmap доступ к области памяти PCI из пользовательского пространства

Вопрос: Должен ли mmap() файла ресурса PCI sysfs работать из прикладного пространства?

Когда я запускаю свой код, mmap возвращает то, что выглядит как действительный адрес, но при попытке доступа к виртуальному адресу появляется ошибка шины. Я считаю, что мое конечное устройство PCI-Xilinx AXI-моста, находящееся на FPGA, работает нормально, так как я могу R/W к нему через Windows PCIe utilty (Win Driver) Я нахожусь на процессоре NXP LS1021A ARM7 с Linux версии 3.12 0,37.

Благодаря Билл

Не то, что я хочу, чтобы кто-нибудь отлаживать код, но то, что я делаю лучше всего можно объяснить кодом, так что я включил его также. Приносим извинения, если вставленный код не отображается правильно. Надеюсь, это так.

я запускаю ниже код и получить корень @ ls1021aiot: ~ # pcimem /sys/bus/pci/devices/0000:01:00.0/resource0 0 ш

/SYS/автобус/PCI/устройства/0000: 01: 00.0/resource0 открыт. Смещение цели 0x0, размер страницы 4096 Карта маска 0xFFF mmap (0, 4096, 0x3, 0x1, 3, 0x0) mmap (0, 4096, 0x3, 0x1, 3, 0x0) Память PCI 4096 байт region to map_base 0x76fb5000. Доступ к карте памяти PCI 0x 76FB5000. Ошибка шины

/* 
* pcimem.c: Simple program to read/write from/to a pci device from userspace. 
* 
* Copyright (C) 2010, Bill Farrow ([email protected]) 
* 
* Based on the devmem2.c code 
* Copyright (C) 2000, Jan-Derk Bakker ([email protected]) 
* 
* This program is free software; you can redistribute it and/or modify 
* it under the terms of the GNU General Public License as published by 
* the Free Software Foundation; either version 2 of the License, or 
* (at your option) any later version. 
* 
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
* 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 
#include <signal.h> 
#include <fcntl.h> 
#include <ctype.h> 
#include <termios.h> 
#include <sys/types.h> 
#include <sys/mman.h> 
#include <linux/pci.h> 


#define PRINT_ERROR \ 
    do { \ 
     fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ 
     __LINE__, __FILE__, errno, strerror(errno)); exit(1); \ 
    } while(0) 

#define MAP_SIZE 4096UL 
#define MAP_MASK (MAP_SIZE - 1) 

int main(int argc, char **argv) { 
    int fd; 
    void *map_base, *virt_addr; 
    uint32_t read_result, writeval; 
    char *filename; 
    off_t target; 
    int access_type = 'w'; 

    if(argc < 3) { 
     // pcimem /sys/bus/pci/devices/0001\:00\:07.0/resource0 0x100 w 0x00 
     // argv[0] [1]           [2] [3] [4] 
     fprintf(stderr, "\nUsage:\t%s { sys file } { offset } [ type [ data ] ]\n" 
       "\tsys file: sysfs file for the pci resource to act on\n" 
       "\toffset : offset into pci memory region to act upon\n" 
       "\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n" 
       "\tdata : data to be written\n\n", 
       argv[0]); 
     exit(1); 
    } 
    filename = argv[1]; 
    target = strtoul(argv[2], 0, 0); 

    if(argc > 3) 
     access_type = tolower(argv[3][0]); 

    if((fd = open(filename, O_RDWR | O_SYNC)) == -1){ 
     PRINT_ERROR; 
    } 
    printf("%s opened.\n", filename); 
    printf("Target offset is 0x%x, page size is %ld map mask is 0x%lX\n", (int) target, sysconf(_SC_PAGE_SIZE), MAP_MASK); 
    fflush(stdout); 

    /* Map one page */ 
#if 0 
    //map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t) (target & ~MAP_MASK)); 
    //map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); 
#endif 
    printf("mmap(%d, %ld, 0x%x, 0x%x, %d, 0x%x)\n", 0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (int) (target & ~MAP_MASK)); 
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (target & ~MAP_MASK)); 
    if(map_base == (void *) -1){ 
     printf("PCI Memory mapped ERROR.\n"); 
     PRINT_ERROR; 
     close(fd); 
     return 1; 
    } 

    printf("mmap(%d, %ld, 0x%x, 0x%x, %d, 0x%x)\n", 0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (int) (target & ~MAP_MASK)); 
    printf("PCI Memory mapped %ld byte region to map_base 0x%08lx.\n", MAP_SIZE, (unsigned long) map_base); 
    fflush(stdout); 

    virt_addr = map_base + (target & MAP_MASK); 
    printf("PCI Memory mapped access 0x %08X.\n", (uint32_t) virt_addr); 
    switch(access_type) { 
     case 'b': 
       read_result = *((uint8_t *) virt_addr); 
       break; 
     case 'h': 
       read_result = *((uint16_t *) virt_addr); 
       break; 
     case 'w': 
       read_result = *((uint32_t *) virt_addr); 
         printf("READ Value at offset 0x%X (%p): 0x%X\n", (int) target, virt_addr, read_result); 
       break; 
     default: 
       fprintf(stderr, "Illegal data type '%c'.\n", access_type); 
       exit(2); 
    } 
    fflush(stdout); 

    if(argc > 4) { 
     writeval = strtoul(argv[4], 0, 0); 
     switch(access_type) { 
       case 'b': 
         *((uint8_t *) virt_addr) = writeval; 
         read_result = *((uint8_t *) virt_addr); 
         break; 
       case 'h': 
         *((uint16_t *) virt_addr) = writeval; 
         read_result = *((uint16_t *) virt_addr); 
         break; 
       case 'w': 
         *((uint32_t *) virt_addr) = writeval; 
         read_result = *((uint32_t *) virt_addr); 
         break; 
     } 
     printf("Written 0x%X; readback 0x%X\n", writeval, read_result); 
     fflush(stdout); 
    } 

    if(munmap(map_base, MAP_SIZE) == -1) { PRINT_ERROR;} 
    close(fd); 
    return 0; 
} 
+0

Я скомпилировал оба моих драйвера и приложение pci_debug для x86_64 (linux 3.16.7), и они работали правильно. Это оставляет мне поверить, что мне не хватает чего-то необходимого для 32-битного процессора (40-битная внутренняя адресация). Устройство PCI отображается в базу адресов 0x40_0000_0000. cat/proc/cpuinfo показывает функцию lpae. –

+0

Я забыл упомянуть приложение pci_debug, выполненное для ошибок шины процессора ARM, таких как мое тестовое приложение. Mmap возвращает void *, к которому я добавляю смещение, это разрешено в LPAE? Я продолжаю копать. Thanks –

ответ

2

Вы посмотрите на pci_debug программный код может, доступный here. Если у вас ошибка шины, возможно, это проблема с дизайном FPGA. Ваша шина IP AXI принимает доступ на 32 бита/16 бит/8бит? Обязательно получите доступ к памяти с правильным адресом (если адрес 32бит должен делиться на 4, если 16 бит на 2).

+0

Thanks Fabien. Это полезный инструмент. Я видел ошибку шины, используя ее так же, как и с моим тестовым приложением. Я собираюсь перестроить драйвер и тестовое приложение и попробовать подключить PCI-карту к системе Intel. Когда я получаю ошибку шины, я не думаю, что пакеты TLP фактически отправляются на шину PCI. В какой-то момент у нас был PCI-анализатор. На мой взгляд, это будет оправдывать ядро ​​IP AXI. Согласитесь? –

+0

По-прежнему не найдено исправления. Я закончил тем, что просто написал драйвер IOCT и использовал процедуры чтения и записи в пространстве ядра для доступа к pci_iomap() –

2

Все еще не нашли исправления для этого на процессоре NXP LS1021A, но я тестировал его на машине x86_64 и там mmap работал с той же целью PCIe Edge. У процессора NXP ARMv7 у меня есть 40-битное внутреннее устройство адресного пространства, но это 32-битный процессор. Это должно представлять особый случай для таблиц виртуальных адресов, которые не обрабатываются правильно. Два корневых устройства PCIe отображаются в более высокое адресное пространство. Я закончил тем, что просто написал драйвер IOCTL и использовал процедуры чтения и записи в пространстве ядра для доступа к указателю pci_iomap(), который я кэшировал при проверке устройства. NXP предложил предложение, которое я цитирую ниже, но у меня все еще есть ошибка шины. Если они когда-нибудь разрешат это, я обновлю.

«Что касается ттар. Вот ответ от команды разработчиков. использование mmap64() для отображения 40 бит phy_address к 32 virt_addr или продолжать использовать ММАП но добавить„-D_FILE_OFFSET_BITS = 64“при компиляции.»

ОБНОВЛЕНИЕ. Я получил новую версию инструментальной цепочки от NXP, и в нем была доступна mmap64. Я считаю, что поддержка mmap64 необходимо использовать только в 32-битных системах, если вы хотите получить доступ к файлам и смещениям более крупных> 4 ГБ файлов. Заменив вызовы на mmap с помощью mmap64, тесты, которые я использовал, теперь работают правильно.

 Смежные вопросы

  • Нет связанных вопросов^_^