Als ersten Level-Test meines PCI-Treibers hoffte ich, dass ich über die /sys/bus/pci/devices/0000:01:00.0/ Zugriff auf die Region pci_iomap erhalten konnte resource0 Datei von meiner Benutzeranwendung. Die Manpage für mmap, das Beispielprogramm, das ich gefunden habe, und andere Posts scheinen anzuzeigen, dass der Benutzerprozesszugriff funktionieren sollte. Einige Artikel scheinen jedoch darauf hinzuweisen, dass der Aufruf von mmap über einen ioctl-Accessor vom Kernel aus erfolgen muss.linux mmap Zugriff auf PCI-Speicherbereich von User-Space-Anwendung
Meine Frage ist, sollte mmap() der PCI sysfs Ressourcendatei von Anwendungsraum funktionieren?
Wenn ich meinen Code mmap zurückgibt, was aussieht wie eine gültige Adresse, aber ich bekomme einen Busfehler, wenn ich versuche, auf die virtuelle Adresse zuzugreifen. Ich glaube mein Endgerät eine PCI zu Xilinx AXI Brücke, die auf dem FPGA funktioniert ok, da ich R/W über ein Windows-PCIe-Dienstprogramm (Win Driver) Ich bin auf einem NXP LS1021A ARM7-Prozessor mit Linux ver 3.12 .37.
Dank Bill
Nicht, dass ich jemand meinen Code debuggen wollen, aber was ich tue am besten durch den Code erklärt werden kann, so habe ich es auch eingeschlossen. Ich entschuldige mich, wenn der eingefügte Code nicht korrekt angezeigt wird. Hoffentlich tut es das.
ich den Code unten laufen und root @ ls1021aiot erhalten: ~ # pcimem /sys/bus/pci/devices/0000:01:00.0/resource0 0 w
/sys/bus/pci/devices/0000: 01: 00.0/Ressource0 geöffnet. Ziel-Offset ist 0x0, Seitengröße ist 4096 Kartenmaske ist 0xFFF mmap (0, 4096, 0x3, 0x1, 3, 0x0) mmap (0, 4096, 0x3, 0x1, 3, 0x0) PCI-Speicher zugeordnet 4096 Byte Region zu map_base 0x76fb5000. PCI-Speicherkartenzugriff 0x 76FB5000. Busfehler
/*
* 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;
}
Ich kompilierte meine Treiber und die pci_debug App für x86_64 (Linux 3.16.7) und sie funktionierten korrekt. Dies lässt mich glauben, dass ich etwas vermisse, was für den 32-Bit-Arm-Prozessor (40-Bit-interne Adressierung) erforderlich ist. Das PCI-Gerät ist in der Adressbasis 0x40_0000_0000 abgebildet. cat/proc/cpuinfo zeigt die lpae-Funktion an. –
Ich vergaß zu erwähnen, die pci_debug App für den ARM-Prozessor erfüllt Busfehler wie meine Test-App tat. Die mmap gibt void * zurück, zu dem ich einen Offset hinzufüge, ist dies in LPAE erlaubt? Ich werde weiter graben. Danke –