The
Linux pci interface provides a mechanism to access
the PCI bus address spaces from user programs.
Performing programmed I/O on pci devices on SGI
Linux systems involves the following steps: Examine /proc/bus/pci/devices and obtain offsets for the
base address registers (BARs) of the devices that you want to map. The
format of the lines is as follows (with field widths in the number of
hexadecimal characters shown, and line breaks added for readability): bus:2x (slotnumber<<3_|_fn):2x vend:8x bar0 bar1 bar2 bar3 ... |
For example: if ((fptr = fopen( "/proc/bus/pci/devices", "r")) == NULL) {
printf( "Unable to open /proc/bus/pci/devices\n" );
}
while(fgets(buf, sizeof(buf) - 1, fptr)) {
sscanf( buf, "%2x%2x %8x %*x %lx %lx %lx %lx %lx %lx %lx %lx %*lx %*lx %*lx %*lx %*lx %*lx",
&sbus, &sdevfn, &svend, &sbar[0], &sbar[1], &sbar[2], &sbar[3],
&sbar[4], &sbar[5], &sbar[6], &sbar[7]);
if(( sbus == bus ) && (sdevfn == devfn)) {
/* This is the bus, slot and function we're looking for,
* so save the base address register offset information. */
for(int i=0; i> 16;
device = svend & 0xffff;
}
}
fclose( fptr ); |
Open the appropriate device file for the bus,
slot, and function in which you are interested. The device files are named
as follows: /proc/bus/pci/bus/slot.function |
For example: memfile = (char*) malloc( 32 );
sprintf( memfile, "/proc/bus/pci/%02d/%02d.%d", bus, slot, function );
fd = open( memfile, O_RDWR ); |
Set the memory map state for the file to
MEM space using the PCIIOC_MMAP_IS_MEM request
to the ioctl() system call.
For example: ioctl(fd, PCIIOC_MMAP_IS_MEM); |
Map the opened file, using the offset obtained
in step 1 as the offset
parameter.
For example: tmpPtr = (char *) mmap( NULL, (size_t) len, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, (off_t) offset[bar]); |
For a complete example, see Appendix D, “Reading MAC Addresses Sample Program”.
For details about kernel-level PCI device drivers, see the Linux Device Driver Programmer's Guide-Porting to SGI Altix Systems,
|