I have been trying out the new IO interface routines (pci_device_open_io, etc.) in libpciaccess with a view that they might solve the problem of MMIO on idiosyncratic architectures such as the old Alphas.

In short, those routines do not work, at least not in the Linux sysfs implementation.

In that implementation libpciaccess opens the sysfs PCI resource file as a file then reads and writes (via pread and pwrite) are performed on the resource file for IO byte, word and longword access.

The trouble with this implementation is that reading and writing the PCI resource files in the Linux sysfs does not appear to be supported by the kernel. Only memory mapping the resource files is supported.

If I modify the read I/O routines in the file linux-sysfs.c to report any IO errors as in:

static uint32_t
pci_device_linux_sysfs_read32(struct pci_io_handle *handle, uint32_t port)
{
    uint32_t ret;

    if (pread(handle->fd, &ret, 4, port) != 4) {
        fprintf(stderr, "ERROR: pread failed %d (%s)\n",errno, strerror(errno));
    }

    return ret;
}

then error number 5 (Input/output error) is returned. Oh, In that routine I have also modified the offset passed to pread() to be port only as the offset should be from the start of the resource file, not the start of memory, methinks.

I test on amd64 architecture a Radeon RV710 card, in particular the resource at bar 2 which is a 65535 byte region of IO ports. Interestingly the PCI config reports this resource as memory but it is obviously IO ports by the way the radeon video driver uses it. So for my tests I modified pci_device_open_io() in libpciaccess to allow access to PCI resources indicated as memory.

I attach my test code.  I run it as so:

./test-libpci 2:00.0 2 7200 ff

where 2:00.0 is the Radeon card, 2 is the bar, and it will access ports at 0x7200 through to 0x72ff (which might be recognised by some to be the default range the radeonhd project's rhd_dump utility dumps). The utility prints that memory range using the pci_device_map_range() and direct memory access first, then prints it out using pci_device_open_io() and pci_io_read32(). Output is:

Found bar 2 at 0xfdde0000 of size 65536.

7200:        0        0        0        0
7210:        0        0        0        0
7220:        0        0        0        0
7230:        0        0  65a2000        0
7240:        0        0        0        0
7250:        0        0        0        0
7260:        0        0        0        0
7270:        0        0        0        0
7280:        0        0        0        0
7290:        0        4        0        0
72a0:        0        0        0        0
72b0:        0        0        0       40
72c0:        0        0        0        0
72d0:        0        0        0        0
72e0:        0        0        0        0
72f0:        0        0        0        0

ERROR: pread failed 5 (Input/output error)
ERROR: pread failed 5 (Input/output error)
ERROR: pread failed 5 (Input/output error)
ERROR: pread failed 5 (Input/output error)
7200:     7f7a     7f7a     7f7a     7f7a

And so on with more pread errors.

Cheers
Michael.

/* 
   For testing libpciaccess routines
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <pciaccess.h>


int main(int argc, char *argv[]) 
{
    struct pci_device *device = NULL;
    void *io;
    int bus, dev, func;
    int bar;
    unsigned int start, size;
    int j;

    if (argc != 5) {
	printf("Usage: test-libpci bus:dev.func bar start size\n");
	printf("WARNING: be careful what you use this on!\n");
	return 1;
    }
    
    j = sscanf(argv[1], "%x:%x.%x", &bus, &dev, &func);
    if (j != 3) {
	j = sscanf(argv[1], "%x:%x:%x", &bus, &dev, &func);
	if (j != 3) {
	    j = sscanf(argv[1], "%d:%d.%d", &bus, &dev, &func);
	    if (j != 3) {
		j = sscanf(argv[1], "%d:%d:%d", &bus, &dev, &func);
	    }
	}
    }
    if (j != 3) {
	fprintf(stderr, "ERROR: Can't parse pci tag: %s\n", argv[1]);
	return 1;
    }

    bar = -1;
    sscanf(argv[2], "%d", &bar);
    if (bar < 0 || bar > 5) {
	fprintf(stderr, "ERROR: Invalid bar: %s\n", argv[2]);
	return 1;
    }

    start = -1;
    sscanf(argv[3], "%x", &start);
    if (start < 0) {
	fprintf(stderr, "ERROR: Invalid start value: %s\n", argv[3]);
	return 1;
    }

    size = -1;
    sscanf(argv[4], "%x", &size);
    if (size < 0) {
	fprintf(stderr, "ERROR: Invalid size value: %s\n", argv[4]);
	return 1;
    }

    if ((j = pci_system_init())) {
        fprintf(stderr, "ERROR: pciaccess failed to initialise PCI bus"
                        " (error %d)\n", j);
        return 1;
    }

    if ((device = pci_device_find_by_slot(0, bus, dev, func)) == NULL) {
	fprintf(stderr, "ERROR: Unable to find PCI device at %02X:%02X.%02X.\n",
		bus, dev, func);
	return 1;
    }

    pci_device_probe(device);

    if (device->regions[bar].base_addr == 0) {
	fprintf(stderr, "ERROR: Failed to find required resource on PCI card.\n");
        return 1;
    }
    
    printf("Found bar %d at %p of size %u.\n", bar, 
	   (void *)device->regions[bar].base_addr, 
	   (unsigned int)device->regions[bar].size);
    if ((start + size) > device->regions[bar].size) {
	fprintf(stderr, "ERROR: Requested start+size extends past end of bar.\n");
	return 1;
    }

    /* Read bar as memory */

    if ((j = pci_device_map_range(device,device->regions[bar].base_addr,
                                         device->regions[bar].size,
                                         PCI_DEV_MAP_FLAG_WRITABLE, &io))) {
        fprintf(stderr, "ERROR: Couldn't map bar as memory: %s.\n", strerror(j));
        return 1;
    }

    for (j = (start/4)*4; j < start+size; j+=4) {
	if (j % 16 == 0) {
	    printf("\n%4x:", j);
	}
	printf(" %8x", *((unsigned int *)(((char *)io) + j)));
    }
    printf("\n");

    pci_device_unmap_range(device, io, device->regions[bar].size);

    /* Read bar as I/O */

    if ((io = pci_device_open_io(device, device->regions[bar].base_addr,
				 device->regions[bar].size)) == NULL) {
        fprintf(stderr, "ERROR: Couldn't map bar as IO.\n");
        return 1;
    }

    for (j = (start/4)*4; j < start+size; j+=4) {
	if (j % 16 == 0) {
	    printf("\n%4x:", j);
	}
	printf(" %8x", pci_io_read32(io, j));
    }
    printf("\n");

    /*     pci_device_close_io(device, io); */

    pci_system_cleanup();

    return 0;
}
_______________________________________________
xorg-devel mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to