Hi libpciaccess devs, Please find attached a new module for review for GNU/Hurd access method. This has been a work in progress for quite some time. The corresponding server code has already been merged upstream in hurd to use this method as an arbiter for other processes to use the hurdish method. (it starts by using the x86 access method).
I also provide two patches to improve the x86 access method. In summary, these three patches provide: 0001) New access method for Hurd 0002) Better probe cmds for non-VGA PCI roms and regions on x86 and add a recursive scan-bus routine that uses the new probe cmds (it also splits the conf1 and conf2 methods into separate methods) 0003) Switch over to the new scan-bus routine in x86 method I wish to thank Joan Lledó for doing most of this work, I am following up to get this merged upstream into pciaccess. Cheers, Damien Zammit
>From e1d355652d389e7b155d9970a9437875a926a934 Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Sat, 10 Nov 2018 06:11:19 -0500 Subject: [PATCH libpciaccess 1/3] New module for the Hurd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This new module uses Hurd's RPCs for accessing the PCI configuration space. Direct access as in {read_write}_{8,16,32} functions is done by the old x86 module. Some x86 function prototypes are now declared in a new header for the Hurd module to use them, in order to duplicate as little code as possible. Author: Joan Lledó <joanlluisll...@gmail.com> Also-by: Damien Zammit <dam...@zamaudio.com> --- src/Makefile.am | 4 +- src/common_init.c | 4 +- src/hurd_pci.c | 496 ++++++++++++++++++++++++++++++++++++++++ src/pciaccess_private.h | 9 + src/x86_pci.c | 364 +++++++++++++++++------------ src/x86_pci.h | 88 +++++++ 6 files changed, 813 insertions(+), 152 deletions(-) create mode 100644 src/hurd_pci.c create mode 100644 src/x86_pci.h diff --git a/src/Makefile.am b/src/Makefile.am index 3a46a85..f222aa5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,12 +52,12 @@ VGA_ARBITER = common_vgaarb_stub.c endif if GNU -OS_SUPPORT = x86_pci.c +OS_SUPPORT = hurd_pci.c x86_pci.c x86_pci.h VGA_ARBITER = common_vgaarb_stub.c endif if CYGWIN -OS_SUPPORT = x86_pci.c +OS_SUPPORT = x86_pci.c x86_pci.h VGA_ARBITER = common_vgaarb_stub.c endif diff --git a/src/common_init.c b/src/common_init.c index f7b59bd..d83eb33 100644 --- a/src/common_init.c +++ b/src/common_init.c @@ -65,7 +65,9 @@ pci_system_init( void ) err = pci_system_openbsd_create(); #elif defined(__sun) err = pci_system_solx_devfs_create(); -#elif defined(__GNU__) || defined(__CYGWIN__) +#elif defined(__GNU__) + err = pci_system_hurd_create(); +#elif defined(__CYGWIN__) err = pci_system_x86_create(); #else # error "Unsupported OS" diff --git a/src/hurd_pci.c b/src/hurd_pci.c new file mode 100644 index 0000000..28bef16 --- /dev/null +++ b/src/hurd_pci.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2018, Damien Zammit + * Copyright (c) 2017, Joan Lledó + * Copyright (c) 2009, 2012 Samuel Thibault + * Heavily inspired from the freebsd, netbsd, and openbsd backends + * (C) Copyright Eric Anholt 2006 + * (C) Copyright IBM Corporation 2006 + * Copyright (c) 2008 Juan Romero Pardines + * Copyright (c) 2008 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <sys/mman.h> +#include <string.h> +#include <strings.h> +#include <hurd.h> +#include <hurd/pci.h> +#include <hurd/paths.h> + +#include "x86_pci.h" +#include "pciaccess.h" +#include "pciaccess_private.h" + +/* + * Hurd PCI access using RPCs. + * + * Some functions are shared with the x86 module to avoid repeating code. + */ + +/* Server path */ +#define _SERVERS_BUS_PCI _SERVERS_BUS "/pci" + +/* File names */ +#define FILE_CONFIG_NAME "config" +#define FILE_ROM_NAME "rom" + +/* Level in the fs tree */ +typedef enum { + LEVEL_NONE, + LEVEL_DOMAIN, + LEVEL_BUS, + LEVEL_DEV, + LEVEL_FUNC +} tree_level; + +struct pci_system_hurd { + struct pci_system system; +}; + +static int +pci_device_hurd_probe(struct pci_device *dev) +{ + uint8_t irq; + int err, i; + struct pci_bar regions[6]; + struct pci_xrom_bar rom; + struct pci_device_private *d; + size_t size; + char *buf; + + /* Many of the fields were filled in during initial device enumeration. + * At this point, we need to fill in regions, rom_size, and irq. + */ + + err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ); + if (err) + return err; + dev->irq = irq; + + /* Get regions */ + buf = (char *)®ions; + size = sizeof(regions); + d = (struct pci_device_private *)dev; + err = pci_get_dev_regions(d->device_port, &buf, &size); + if(err) + return err; + + if((char*)®ions != buf) + { + /* Sanity check for bogus server. */ + if(size > sizeof(regions)) + { + vm_deallocate(mach_task_self(), (vm_address_t) buf, size); + return EGRATUITOUS; + } + + memcpy(®ions, buf, size); + vm_deallocate(mach_task_self(), (vm_address_t) buf, size); + } + + for(i=0; i<6; i++) + { + if(regions[i].size == 0) + continue; + + dev->regions[i].base_addr = regions[i].base_addr; + dev->regions[i].size = regions[i].size; + dev->regions[i].is_IO = regions[i].is_IO; + dev->regions[i].is_prefetchable = regions[i].is_prefetchable; + dev->regions[i].is_64 = regions[i].is_64; + } + + /* Get rom info */ + buf = (char *)&rom; + size = sizeof(rom); + err = pci_get_dev_rom(d->device_port, &buf, &size); + if(err) + return err; + + if((char*)&rom != buf) + { + /* Sanity check for bogus server. */ + if(size > sizeof(rom)) + { + vm_deallocate(mach_task_self(), (vm_address_t) buf, size); + return EGRATUITOUS; + } + + memcpy(&rom, buf, size); + vm_deallocate(mach_task_self(), (vm_address_t) buf, size); + } + + d->rom_base = rom.base_addr; + dev->rom_size = rom.size; + + return 0; +} + +/* + * Read `nbytes' bytes from `reg' in device's configuretion space + * and store them in `buf'. + * + * It's assumed that `nbytes' bytes are allocated in `buf' + */ +static int +pciclient_cfg_read(mach_port_t device_port, int reg, char *buf, + size_t * nbytes) +{ + int err; + size_t nread; + char *data; + + data = buf; + nread = *nbytes; + err = pci_conf_read(device_port, reg, &data, &nread, *nbytes); + if (err) + return err; + + if (data != buf) { + if (nread > *nbytes) /* Sanity check for bogus server. */ { + vm_deallocate(mach_task_self(), (vm_address_t) data, nread); + return EGRATUITOUS; + } + + memcpy(buf, data, nread); + vm_deallocate(mach_task_self(), (vm_address_t)data, nread); + } + + *nbytes = nread; + + return 0; +} + +/* Write `nbytes' bytes from `buf' to `reg' in device's configuration space */ +static int +pciclient_cfg_write(mach_port_t device_port, int reg, char *buf, + size_t * nbytes) +{ + int err; + size_t nwrote; + + err = pci_conf_write(device_port, reg, buf, *nbytes, &nwrote); + + if (!err) + *nbytes = nwrote; + + return err; +} + +/* + * Read up to `size' bytes from `dev' configuration space to `data' starting + * at `offset'. Write the amount on read bytes in `bytes_read'. + */ +static int +pci_device_hurd_read(struct pci_device *dev, void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) +{ + int err; + struct pci_device_private *d; + + *bytes_read = 0; + d = (struct pci_device_private *)dev; + while (size > 0) { + size_t toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); + if (toread > size) + toread = size; + + err = pciclient_cfg_read(d->device_port, offset, (char*)data, + &toread); + if (err) + return err; + + offset += toread; + data = (char*)data + toread; + size -= toread; + *bytes_read += toread; + } + return 0; +} + +/* + * Write up to `size' bytes from `data' to `dev' configuration space starting + * at `offset'. Write the amount on written bytes in `bytes_written'. + */ +static int +pci_device_hurd_write(struct pci_device *dev, const void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) +{ + int err; + struct pci_device_private *d; + + *bytes_written = 0; + d = (struct pci_device_private *)dev; + while (size > 0) { + size_t towrite = 4; + if (towrite > size) + towrite = size; + if (towrite > 4 - (offset & 0x3)) + towrite = 4 - (offset & 0x3); + + err = pciclient_cfg_write(d->device_port, offset, (char*)data, + &towrite); + if (err) + return err; + + offset += towrite; + data = (const char*)data + towrite; + size -= towrite; + *bytes_written += towrite; + } + return 0; +} + +/* + * Copy the device's firmware in `buffer' + */ +static int +pci_device_hurd_read_rom(struct pci_device * dev, void * buffer) +{ + ssize_t rd; + int romfd; + char server[NAME_MAX]; + + snprintf(server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s", _SERVERS_BUS_PCI, + dev->domain, dev->bus, dev->dev, dev->func, FILE_ROM_NAME); + + romfd = open(server, O_RDONLY | O_CLOEXEC); + if (romfd == -1) + return errno; + + rd = read(romfd, buffer, dev->rom_size); + if (rd != dev->rom_size) { + close(romfd); + return errno; + } + + close(romfd); + + return 0; +} + +/* + * Each device has its own server where send RPC's to. + * + * Deallocate the port before destroying the device. + */ +static void +pci_device_hurd_destroy(struct pci_device *dev) +{ + struct pci_device_private *d = (struct pci_device_private*) dev; + + mach_port_deallocate (mach_task_self (), d->device_port); +} + +/* Walk through the FS tree to see what is allowed for us */ +static int +enum_devices(const char *parent, struct pci_device_private **device, + int domain, int bus, int dev, int func, tree_level lev) +{ + int err, ret; + DIR *dir; + struct dirent *entry; + char path[NAME_MAX]; + char server[NAME_MAX]; + uint32_t reg; + size_t toread; + mach_port_t device_port; + + dir = opendir(parent); + if (!dir) + return errno; + + while ((entry = readdir(dir)) != 0) { + snprintf(path, NAME_MAX, "%s/%s", parent, entry->d_name); + if (entry->d_type == DT_DIR) { + if (!strncmp(entry->d_name, ".", NAME_MAX) + || !strncmp(entry->d_name, "..", NAME_MAX)) + continue; + + errno = 0; + ret = strtol(entry->d_name, 0, 16); + if (errno) + return errno; + + /* + * We found a valid directory. + * Update the address and switch to the next level. + */ + switch (lev) { + case LEVEL_DOMAIN: + domain = ret; + break; + case LEVEL_BUS: + bus = ret; + break; + case LEVEL_DEV: + dev = ret; + break; + case LEVEL_FUNC: + func = ret; + break; + default: + return -1; + } + + err = enum_devices(path, device, domain, bus, dev, func, lev+1); + if (err == EPERM) + continue; + } + else { + if (strncmp(entry->d_name, FILE_CONFIG_NAME, NAME_MAX)) + /* We are looking for the config file */ + continue; + + /* We found an available virtual device, add it to our list */ + snprintf(server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s", + _SERVERS_BUS_PCI, domain, bus, dev, func, + entry->d_name); + device_port = file_name_lookup(server, 0, 0); + if (device_port == MACH_PORT_NULL) + return errno; + + toread = sizeof(reg); + err = pciclient_cfg_read(device_port, PCI_VENDOR_ID, (char*)®, + &toread); + if (err) + return err; + if (toread != sizeof(reg)) + return -1; + + (*device)->base.domain = domain; + (*device)->base.bus = bus; + (*device)->base.dev = dev; + (*device)->base.func = func; + (*device)->base.vendor_id = PCI_VENDOR(reg); + (*device)->base.device_id = PCI_DEVICE(reg); + + toread = sizeof(reg); + err = pciclient_cfg_read(device_port, PCI_CLASS, (char*)®, + &toread); + if (err) + return err; + if (toread != sizeof(reg)) + return -1; + + (*device)->base.device_class = reg >> 8; + (*device)->base.revision = reg & 0xFF; + + toread = sizeof(reg); + err = pciclient_cfg_read(device_port, PCI_SUB_VENDOR_ID, + (char*)®, &toread); + if (err) + return err; + if (toread != sizeof(reg)) + return -1; + + (*device)->base.subvendor_id = PCI_VENDOR(reg); + (*device)->base.subdevice_id = PCI_DEVICE(reg); + + (*device)->device_port = device_port; + + (*device)++; + } + } + + return 0; +} + +static const struct pci_system_methods hurd_pci_methods = { + .destroy = pci_system_x86_destroy, + .destroy_device = pci_device_hurd_destroy, + .read_rom = pci_device_hurd_read_rom, + .probe = pci_device_hurd_probe, + .map_range = pci_device_x86_map_range, + .unmap_range = pci_device_x86_unmap_range, + .read = pci_device_hurd_read, + .write = pci_device_hurd_write, + .fill_capabilities = pci_fill_capabilities_generic, + .open_legacy_io = pci_device_x86_open_legacy_io, + .close_io = pci_device_x86_close_io, + .read32 = pci_device_x86_read32, + .read16 = pci_device_x86_read16, + .read8 = pci_device_x86_read8, + .write32 = pci_device_x86_write32, + .write16 = pci_device_x86_write16, + .write8 = pci_device_x86_write8, + .map_legacy = pci_device_x86_map_legacy, + .unmap_legacy = pci_device_x86_unmap_legacy, +}; + +_pci_hidden int +pci_system_hurd_create(void) +{ + struct pci_device_private *device; + int err; + struct pci_system_hurd *pci_sys_hurd; + size_t ndevs; + mach_port_t pci_server_port; + + /* If we can open pci cfg io ports on hurd, + * we are the arbiter, therefore try x86 method first */ + err = pci_system_x86_create(); + if (!err) + return 0; + + pci_sys_hurd = calloc(1, sizeof(struct pci_system_hurd)); + if (pci_sys_hurd == NULL) { + x86_disable_io(); + return ENOMEM; + } + pci_sys = &pci_sys_hurd->system; + + pci_sys->methods = &hurd_pci_methods; + + pci_server_port = file_name_lookup(_SERVERS_BUS_PCI, 0, 0); + if (!pci_server_port) { + /* Fall back to x86 access method */ + return pci_system_x86_create(); + } + + /* The server gives us the number of available devices for us */ + err = pci_get_ndevs (pci_server_port, &ndevs); + if (err) { + mach_port_deallocate (mach_task_self (), pci_server_port); + /* Fall back to x86 access method */ + return pci_system_x86_create(); + } + mach_port_deallocate (mach_task_self (), pci_server_port); + + pci_sys->num_devices = ndevs; + pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); + if (pci_sys->devices == NULL) { + x86_disable_io(); + free(pci_sys_hurd); + pci_sys = NULL; + return ENOMEM; + } + + device = pci_sys->devices; + err = enum_devices(_SERVERS_BUS_PCI, &device, -1, -1, -1, -1, + LEVEL_DOMAIN); + if (err) + return pci_system_x86_create(); + + return 0; +} diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h index 2f05b29..10c9698 100644 --- a/src/pciaccess_private.h +++ b/src/pciaccess_private.h @@ -29,6 +29,9 @@ * \author Ian Romanick <i...@us.ibm.com> */ +#ifndef PCIACCESS_PRIVATE_H +#define PCIACCESS_PRIVATE_H + #if defined(__GNUC__) && (__GNUC__ >= 4) # define _pci_hidden __attribute__((visibility("hidden"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) @@ -150,6 +153,9 @@ struct pci_device_private { #ifdef __sun int is_primary; #endif +#ifdef __GNU__ + unsigned long device_port; +#endif }; @@ -189,5 +195,8 @@ extern int pci_system_netbsd_create( void ); extern int pci_system_openbsd_create( void ); extern void pci_system_openbsd_init_dev_mem( int ); extern int pci_system_solx_devfs_create( void ); +extern int pci_system_hurd_create( void ); extern int pci_system_x86_create( void ); extern void pci_io_cleanup( void ); + +#endif /* PCIACCESS_PRIVATE_H */ diff --git a/src/x86_pci.c b/src/x86_pci.c index 6b6a026..1be5f17 100644 --- a/src/x86_pci.c +++ b/src/x86_pci.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2018 Damien Zammit + * Copyright (c) 2017 Joan Lledó * Copyright (c) 2009, 2012 Samuel Thibault * Heavily inspired from the freebsd, netbsd, and openbsd backends * (C) Copyright Eric Anholt 2006 @@ -22,6 +24,8 @@ #include "config.h" #endif +#include "x86_pci.h" + #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -38,7 +42,7 @@ #include <sys/io.h> -static int +int x86_enable_io(void) { if (!ioperm(0, 0xffff, 1)) @@ -46,7 +50,7 @@ x86_enable_io(void) return errno; } -static int +int x86_disable_io(void) { if (!ioperm(0, 0xffff, 0)) @@ -207,34 +211,6 @@ outl(uint32_t value, uint16_t port) #endif -#define PCI_VENDOR(reg) ((reg) & 0xFFFF) -#define PCI_VENDOR_INVALID 0xFFFF - -#define PCI_VENDOR_ID 0x00 -#define PCI_SUB_VENDOR_ID 0x2c -#define PCI_VENDOR_ID_COMPAQ 0x0e11 -#define PCI_VENDOR_ID_INTEL 0x8086 - -#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF) -#define PCI_DEVICE_INVALID 0xFFFF - -#define PCI_CLASS 0x08 -#define PCI_CLASS_DEVICE 0x0a -#define PCI_CLASS_DISPLAY_VGA 0x0300 -#define PCI_CLASS_BRIDGE_HOST 0x0600 - -#define PCIC_DISPLAY 0x03 -#define PCIS_DISPLAY_VGA 0x00 - -#define PCI_HDRTYPE 0x0E -#define PCI_IRQ 0x3C - -struct pci_system_x86 { - struct pci_system system; - int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size); - int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size); -}; - static int pci_system_x86_conf1_probe(void) { @@ -408,62 +384,68 @@ pci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t } /* Check that this really looks like a PCI configuration. */ -static int -pci_system_x86_check(struct pci_system_x86 *pci_sys_x86) +static error_t +pci_system_x86_check (void) { int dev; uint16_t class, vendor; + struct pci_device tmpdev = { 0 }; /* Look on bus 0 for a device that is a host bridge, a VGA card, * or an intel or compaq device. */ + tmpdev.bus = 0; + tmpdev.func = 0; + class = 0; + vendor = 0; for (dev = 0; dev < 32; dev++) { - if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class))) - continue; - if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) - return 0; - if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor))) - continue; - if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) - return 0; + tmpdev.dev = dev; + if (pci_device_cfg_read_u16 (&tmpdev, &class, PCI_CLASS_DEVICE)) + continue; + if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) + return 0; + if (pci_device_cfg_read_u16 (&tmpdev, &vendor, PCI_VENDOR_ID)) + continue; + if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) + return 0; } return ENODEV; } static int -pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev) +pci_nfuncs(struct pci_device *dev, uint8_t *nfuncs) { uint8_t hdr; int err; + struct pci_device tmpdev = *dev; - err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr)); + tmpdev.func = 0; + + err = pci_device_cfg_read_u8 (&tmpdev, &hdr, PCI_HDRTYPE); if (err) return err; - return hdr & 0x80 ? 8 : 1; + *nfuncs = hdr & 0x80 ? 8 : 1; + return err; } /** - * Read a VGA rom using the 0xc0000 mapping. + * Read a PCI rom. */ -static int +static error_t pci_device_x86_read_rom(struct pci_device *dev, void *buffer) { void *bios; int memfd; - - if ((dev->device_class & 0x00ffff00) != - ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) { - return ENOSYS; - } + struct pci_device_private *d = (struct pci_device_private *)dev; memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC); if (memfd == -1) return errno; - bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000); + bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, d->rom_base); if (bios == MAP_FAILED) { close(memfd); return errno; @@ -635,7 +617,7 @@ pci_device_x86_unmap_range(struct pci_device *dev, #else -static int +int pci_device_x86_map_range(struct pci_device *dev, struct pci_device_mapping *map) { @@ -656,7 +638,7 @@ pci_device_x86_map_range(struct pci_device *dev, return 0; } -static int +int pci_device_x86_unmap_range(struct pci_device *dev, struct pci_device_mapping *map) { @@ -666,10 +648,33 @@ pci_device_x86_unmap_range(struct pci_device *dev, #endif static int -pci_device_x86_read(struct pci_device *dev, void *data, +pci_device_x86_read_conf1(struct pci_device *dev, void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) +{ + int err; + + *bytes_read = 0; + while (size > 0) { + int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); + if (toread > size) + toread = size; + + err = pci_system_x86_conf1_read(dev->bus, dev->dev, dev->func, offset, data, toread); + if (err) + return err; + + offset += toread; + data = (char*)data + toread; + size -= toread; + *bytes_read += toread; + } + return 0; +} + +static int +pci_device_x86_read_conf2(struct pci_device *dev, void *data, pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) { - struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys; int err; *bytes_read = 0; @@ -678,7 +683,7 @@ pci_device_x86_read(struct pci_device *dev, void *data, if (toread > size) toread = size; - err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread); + err = pci_system_x86_conf2_read(dev->bus, dev->dev, dev->func, offset, data, toread); if (err) return err; @@ -691,10 +696,9 @@ pci_device_x86_read(struct pci_device *dev, void *data, } static int -pci_device_x86_write(struct pci_device *dev, const void *data, +pci_device_x86_write_conf1(struct pci_device *dev, const void *data, pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) { - struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys; int err; *bytes_written = 0; @@ -705,7 +709,7 @@ pci_device_x86_write(struct pci_device *dev, const void *data, if (towrite > 4 - (offset & 0x3)) towrite = 4 - (offset & 0x3); - err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite); + err = pci_system_x86_conf1_write(dev->bus, dev->dev, dev->func, offset, data, towrite); if (err) return err; @@ -717,13 +721,39 @@ pci_device_x86_write(struct pci_device *dev, const void *data, return 0; } -static void +static int +pci_device_x86_write_conf2(struct pci_device *dev, const void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) +{ + int err; + + *bytes_written = 0; + while (size > 0) { + int towrite = 4; + if (towrite > size) + towrite = size; + if (towrite > 4 - (offset & 0x3)) + towrite = 4 - (offset & 0x3); + + err = pci_system_x86_conf2_write(dev->bus, dev->dev, dev->func, offset, data, towrite); + if (err) + return err; + + offset += towrite; + data = (const char*)data + towrite; + size -= towrite; + *bytes_written += towrite; + } + return 0; +} + +void pci_system_x86_destroy(void) { x86_disable_io(); } -static struct pci_io_handle * +struct pci_io_handle * pci_device_x86_open_legacy_io(struct pci_io_handle *ret, struct pci_device *dev, pciaddr_t base, pciaddr_t size) { @@ -736,7 +766,7 @@ pci_device_x86_open_legacy_io(struct pci_io_handle *ret, return ret; } -static void +void pci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle) { /* Like in the Linux case, do not disable I/O, as it may be opened several @@ -744,46 +774,46 @@ pci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle) /* x86_disable_io(); */ } -static uint32_t +uint32_t pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg) { return inl(reg + handle->base); } -static uint16_t +uint16_t pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg) { return inw(reg + handle->base); } -static uint8_t +uint8_t pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg) { return inb(reg + handle->base); } -static void +void pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data) { outl(data, reg + handle->base); } -static void +void pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data) { outw(data, reg + handle->base); } -static void +void pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data) { outb(data, reg + handle->base); } -static int +int pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size, unsigned map_flags, void **addr) { @@ -799,7 +829,7 @@ pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, return err; } -static int +int pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size) { @@ -812,14 +842,14 @@ pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, return pci_device_x86_unmap_range(dev, &map); } -static const struct pci_system_methods x86_pci_methods = { +static const struct pci_system_methods x86_pci_method_conf1 = { .destroy = pci_system_x86_destroy, .read_rom = pci_device_x86_read_rom, .probe = pci_device_x86_probe, .map_range = pci_device_x86_map_range, .unmap_range = pci_device_x86_unmap_range, - .read = pci_device_x86_read, - .write = pci_device_x86_write, + .read = pci_device_x86_read_conf1, + .write = pci_device_x86_write_conf1, .fill_capabilities = pci_fill_capabilities_generic, .open_legacy_io = pci_device_x86_open_legacy_io, .close_io = pci_device_x86_close_io, @@ -833,108 +863,144 @@ static const struct pci_system_methods x86_pci_methods = { .unmap_legacy = pci_device_x86_unmap_legacy, }; -static int pci_probe(struct pci_system_x86 *pci_sys_x86) +static const struct pci_system_methods x86_pci_method_conf2 = { + .destroy = pci_system_x86_destroy, + .read_rom = pci_device_x86_read_rom, + .probe = pci_device_x86_probe, + .map_range = pci_device_x86_map_range, + .unmap_range = pci_device_x86_unmap_range, + .read = pci_device_x86_read_conf2, + .write = pci_device_x86_write_conf2, + .fill_capabilities = pci_fill_capabilities_generic, + .open_legacy_io = pci_device_x86_open_legacy_io, + .close_io = pci_device_x86_close_io, + .read32 = pci_device_x86_read32, + .read16 = pci_device_x86_read16, + .read8 = pci_device_x86_read8, + .write32 = pci_device_x86_write32, + .write16 = pci_device_x86_write16, + .write8 = pci_device_x86_write8, + .map_legacy = pci_device_x86_map_legacy, + .unmap_legacy = pci_device_x86_unmap_legacy, +}; + +static int pci_probe(void) { + pci_sys->methods = &x86_pci_method_conf1; if (pci_system_x86_conf1_probe() == 0) { - pci_sys_x86->read = pci_system_x86_conf1_read; - pci_sys_x86->write = pci_system_x86_conf1_write; - if (pci_system_x86_check(pci_sys_x86) == 0) - return 0; + if (pci_system_x86_check() == 0) + return 1; } + pci_sys->methods = &x86_pci_method_conf2; if (pci_system_x86_conf2_probe() == 0) { - pci_sys_x86->read = pci_system_x86_conf2_read; - pci_sys_x86->write = pci_system_x86_conf2_write; - if (pci_system_x86_check(pci_sys_x86) == 0) - return 0; + if (pci_system_x86_check() == 0) + return 2; } - return ENODEV; + pci_sys->methods = NULL; + return 0; } _pci_hidden int pci_system_x86_create(void) { + uint8_t nfuncs = 0; + uint8_t bus, dev, func; + uint32_t reg = 0, ndevs; + struct pci_device tmpdev = { 0 }; struct pci_device_private *device; - int ret, bus, dev, ndevs, func, nfuncs; - struct pci_system_x86 *pci_sys_x86; - uint32_t reg; - - ret = x86_enable_io(); - if (ret) - return ret; - - pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86)); - if (pci_sys_x86 == NULL) { - x86_disable_io(); - return ENOMEM; - } - pci_sys = &pci_sys_x86->system; - - ret = pci_probe(pci_sys_x86); - if (ret) { - x86_disable_io(); - free(pci_sys_x86); - pci_sys = NULL; - return ret; - } + error_t err; + int confx; - pci_sys->methods = &x86_pci_methods; + err = x86_enable_io (); + if (err) + return err; ndevs = 0; for (bus = 0; bus < 256; bus++) { - for (dev = 0; dev < 32; dev++) { - nfuncs = pci_nfuncs(pci_sys_x86, bus, dev); - for (func = 0; func < nfuncs; func++) { - if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0) - continue; - if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || - PCI_VENDOR(reg) == 0) - continue; - ndevs++; - } - } + tmpdev.bus = bus; + for (dev = 0; dev < 32; dev++) { + tmpdev.dev = dev; + pci_nfuncs(&tmpdev, &nfuncs); + for (func = 0; func < nfuncs; func++) { + if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_VENDOR_ID)) + continue; + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || + PCI_VENDOR(reg) == 0) + continue; + ndevs++; + } + } + } + + pci_sys = calloc (1, sizeof (struct pci_system)); + if (pci_sys == NULL) + { + x86_disable_io (); + return ENOMEM; } pci_sys->num_devices = ndevs; pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); if (pci_sys->devices == NULL) { - x86_disable_io(); - free(pci_sys_x86); - pci_sys = NULL; - return ENOMEM; + x86_disable_io(); + free(pci_sys); + pci_sys = NULL; + return ENOMEM; + } + + confx = pci_probe (); + if (!confx) { + x86_disable_io (); + free (pci_sys); + pci_sys = NULL; + return ENODEV; } + else if (confx == 1) + pci_sys->methods = &x86_pci_method_conf1; + else + pci_sys->methods = &x86_pci_method_conf2; device = pci_sys->devices; for (bus = 0; bus < 256; bus++) { - for (dev = 0; dev < 32; dev++) { - nfuncs = pci_nfuncs(pci_sys_x86, bus, dev); - for (func = 0; func < nfuncs; func++) { - if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0) - continue; - if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || - PCI_VENDOR(reg) == 0) - continue; - device->base.domain = device->base.domain_16 = 0; - device->base.bus = bus; - device->base.dev = dev; - device->base.func = func; - device->base.vendor_id = PCI_VENDOR(reg); - device->base.device_id = PCI_DEVICE(reg); - - if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, ®, sizeof(reg)) != 0) - continue; - device->base.device_class = reg >> 8; - device->base.revision = reg & 0xFF; - - if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, ®, sizeof(reg)) != 0) - continue; - device->base.subvendor_id = PCI_VENDOR(reg); - device->base.subdevice_id = PCI_DEVICE(reg); - - device++; - } - } + tmpdev.bus = bus; + for (dev = 0; dev < 32; dev++) { + tmpdev.dev = dev; + err = pci_nfuncs(&tmpdev, &nfuncs); + if (err) { + x86_disable_io (); + free (pci_sys); + pci_sys = NULL; + return ENODEV; + } + for (func = 0; func < nfuncs; func++) { + tmpdev.func = func; + if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_VENDOR_ID)) + continue; + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || + PCI_VENDOR(reg) == 0) + continue; + device->base.domain = device->base.domain_16 = 0; + device->base.bus = bus; + device->base.dev = dev; + device->base.func = func; + device->base.vendor_id = PCI_VENDOR(reg); + device->base.device_id = PCI_DEVICE(reg); + + if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_CLASS)) + continue; + device->base.device_class = (reg >> 8) & 0xFF; + device->base.revision = reg & 0xFF; + + if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_SUB_VENDOR_ID)) + continue; + device->base.subvendor_id = PCI_VENDOR(reg); + device->base.subdevice_id = PCI_DEVICE(reg); + + device++; + } + } } return 0; diff --git a/src/x86_pci.h b/src/x86_pci.h new file mode 100644 index 0000000..22c9318 --- /dev/null +++ b/src/x86_pci.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017 Joan Lledó + * Copyright (c) 2009, 2012 Samuel Thibault + * Heavily inspired from the freebsd, netbsd, and openbsd backends + * (C) Copyright Eric Anholt 2006 + * (C) Copyright IBM Corporation 2006 + * Copyright (c) 2008 Juan Romero Pardines + * Copyright (c) 2008 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Macros and declarations used by both x86 and Hurd modules. */ + +#ifndef X86_PCI_H +#define X86_PCI_H + +#include "pciaccess.h" +#include "pciaccess_private.h" + +#define PCI_VENDOR(reg) ((reg) & 0xFFFF) +#define PCI_VENDOR_INVALID 0xFFFF + +#define PCI_VENDOR_ID 0x00 +#define PCI_SUB_VENDOR_ID 0x2c +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_INTEL 0x8086 + +#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF) +#define PCI_DEVICE_INVALID 0xFFFF + +#define PCI_CLASS 0x08 +#define PCI_CLASS_DEVICE 0x0a +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_BRIDGE_HOST 0x0600 + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 + +#define PCI_HDRTYPE 0x0E +#define PCI_HDRTYPE_DEVICE 0x00 +#define PCI_HDRTYPE_BRIDGE 0x01 +#define PCI_HDRTYPE_CARDBUS 0x02 +#define PCI_IRQ 0x3C + +#define PCI_BAR_ADDR_0 0x10 +#define PCI_XROMBAR_ADDR_00 0x30 +#define PCI_XROMBAR_ADDR_01 0x38 + +#define PCI_COMMAND 0x04 +#define PCI_SECONDARY_BUS 0x19 + +int x86_enable_io(void); +int x86_disable_io(void); +void pci_system_x86_destroy(void); +int pci_device_x86_map_range(struct pci_device *dev, + struct pci_device_mapping *map); +int pci_device_x86_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map); +struct pci_io_handle *pci_device_x86_open_legacy_io(struct pci_io_handle *ret, + struct pci_device *dev, pciaddr_t base, pciaddr_t size); +void pci_device_x86_close_io(struct pci_device *dev, + struct pci_io_handle *handle); +uint32_t pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg); +uint16_t pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg); +uint8_t pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg); +void pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg, + uint32_t data); +void pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg, + uint16_t data); +void pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg, + uint8_t data); +int pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, unsigned map_flags, void **addr); +int pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, + pciaddr_t size); + +#endif /* X86_PCI_H */ -- 2.17.1
>From 1dc02791dfef14b8639fa7c9dbac1eabfe6abe95 Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Sat, 10 Nov 2018 06:23:40 -0500 Subject: [PATCH libpciaccess 2/3] Add better probe cmds for non-VGA roms and regions on x86 Also add a recursive scan-bus routine that uses the new probe cmds. --- src/x86_pci.c | 344 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 285 insertions(+), 59 deletions(-) diff --git a/src/x86_pci.c b/src/x86_pci.c index 1be5f17..cdfc2ef 100644 --- a/src/x86_pci.c +++ b/src/x86_pci.c @@ -508,75 +508,301 @@ get_test_val_size( uint32_t testval ) return size; } -static int -pci_device_x86_probe(struct pci_device *dev) +/* Read BAR `reg_num' in `dev' and map the data if any */ +static error_t +pci_device_x86_region_probe (struct pci_device *dev, int reg_num) { - uint8_t irq, hdrtype; - int err, i, bar; + error_t err; + uint8_t offset; + uint32_t reg, addr, testval; + int memfd; - /* Many of the fields were filled in during initial device enumeration. - * At this point, we need to fill in regions, rom_size, and irq. - */ + offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; - err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ); + /* Get the base address */ + err = pci_device_cfg_read_u32 (dev, &addr, offset); if (err) - return err; - dev->irq = irq; + return err; - err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE); + /* Test write all ones to the register, then restore it. */ + reg = 0xffffffff; + err = pci_device_cfg_write_u32 (dev, reg, offset); if (err) - return err; + return err; + err = pci_device_cfg_read_u32 (dev, &testval, offset); + if (err) + return err; + err = pci_device_cfg_write_u32 (dev, addr, offset); + if (err) + return err; - bar = 0x10; - for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) { - uint32_t addr, testval; - - /* Get the base address */ - err = pci_device_cfg_read_u32(dev, &addr, bar); - if (err != 0) - continue; - - /* Test write all ones to the register, then restore it. */ - err = pci_device_cfg_write_u32(dev, 0xffffffff, bar); - if (err != 0) - continue; - pci_device_cfg_read_u32(dev, &testval, bar); - err = pci_device_cfg_write_u32(dev, addr, bar); - - if (addr & 0x01) - dev->regions[i].is_IO = 1; - if (addr & 0x04) - dev->regions[i].is_64 = 1; - if (addr & 0x08) - dev->regions[i].is_prefetchable = 1; - - /* Set the size */ - dev->regions[i].size = get_test_val_size(testval); - - /* Set the base address value */ - if (dev->regions[i].is_64) { - uint32_t top; - - err = pci_device_cfg_read_u32(dev, &top, bar + 4); - if (err != 0) - continue; - - dev->regions[i].base_addr = ((uint64_t)top << 32) | - get_map_base(addr); - bar += 4; - i++; - } else { - dev->regions[i].base_addr = get_map_base(addr); - } + if (addr & 0x01) + dev->regions[reg_num].is_IO = 1; + if (addr & 0x04) + dev->regions[reg_num].is_64 = 1; + if (addr & 0x08) + dev->regions[reg_num].is_prefetchable = 1; + + /* Set the size */ + dev->regions[reg_num].size = get_test_val_size (testval); + + /* Set the base address value */ + dev->regions[reg_num].base_addr = get_map_base (addr); + + if (dev->regions[reg_num].is_64) + { + err = pci_device_cfg_read_u32 (dev, &addr, offset + 4); + if (err) + return err; + + dev->regions[reg_num].base_addr |= ((uint64_t) addr << 32); + } + + if (dev->regions[reg_num].is_IO) + { + /* Enable the I/O Space bit */ + err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); + if (err) + return err; + + if (!(reg & 0x1)) + { + reg |= 0x1; + + err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); + if (err) + return err; + } + + /* Clear the map pointer */ + dev->regions[reg_num].memory = 0; + } + else if (dev->regions[reg_num].size > 0) + { + /* Enable the Memory Space bit */ + err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); + if (err) + return err; + + if (!(reg & 0x2)) + { + reg |= 0x2; + + err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); + if (err) + return err; + } + + /* Map the region in our space */ + memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); + if (memfd == -1) + return errno; + + dev->regions[reg_num].memory = + mmap (NULL, dev->regions[reg_num].size, PROT_READ | PROT_WRITE, 0, + memfd, dev->regions[reg_num].base_addr); + if (dev->regions[reg_num].memory == MAP_FAILED) + { + dev->regions[reg_num].memory = 0; + close (memfd); + return errno; + } + + close (memfd); + } + + return 0; +} + +/* Read the XROMBAR in `dev' and save the rom size and rom base */ +static error_t +pci_device_x86_probe_rom (struct pci_device *dev) +{ + error_t err; + uint8_t reg_8, xrombar_addr; + uint32_t reg, reg_back; + pciaddr_t rom_size; + pciaddr_t rom_base; + struct pci_device_private *d = (struct pci_device_private *)dev; + + /* First we need to know which type of header is this */ + err = pci_device_cfg_read_u8 (dev, ®_8, PCI_HDRTYPE); + if (err) + return err; + + /* Get the XROMBAR register address */ + switch (reg_8 & 0x3) + { + case PCI_HDRTYPE_DEVICE: + xrombar_addr = PCI_XROMBAR_ADDR_00; + break; + case PCI_HDRTYPE_BRIDGE: + xrombar_addr = PCI_XROMBAR_ADDR_01; + break; + default: + return -1; + } + + /* Get size and physical address */ + err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); + if (err) + return err; + + reg_back = reg; + reg = 0xFFFFF800; /* Base address: first 21 bytes */ + err = pci_device_cfg_write_u32 (dev, reg, xrombar_addr); + if (err) + return err; + err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); + if (err) + return err; + + rom_size = (~reg + 1); + rom_base = reg_back & reg; + + if (rom_size == 0) + return 0; + + /* Enable the address decoder and write the physical address back */ + reg_back |= 0x1; + err = pci_device_cfg_write_u32 (dev, reg_back, xrombar_addr); + if (err) + return err; + + /* Enable the Memory Space bit */ + err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); + if (err) + return err; + + if (!(reg & 0x2)) + { + reg |= 0x2; + + err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); + if (err) + return err; } - /* If it's a VGA device, set up the rom size for read_rom using the - * 0xc0000 mapping. - */ - if ((dev->device_class & 0x00ffff00) == - ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8))) + dev->rom_size = rom_size; + d->rom_base = rom_base; + + return 0; +} + +/* Configure BARs and ROM */ +static error_t +pci_device_x86_probe (struct pci_device *dev) +{ + error_t err; + uint8_t hdrtype; + int i; + + /* Probe BARs */ + err = pci_device_cfg_read_u8 (dev, &hdrtype, PCI_HDRTYPE); + if (err) + return err; + + for (i = 0; i < pci_device_x86_get_num_regions (hdrtype); i++) + { + err = pci_device_x86_region_probe (dev, i); + if (err) + return err; + + if (dev->regions[i].is_64) + /* Move the pointer one BAR ahead */ + i++; + } + + /* Probe ROM */ + pci_device_x86_probe_rom(dev); + + return 0; +} + +/* Recursively scan bus number `bus' */ +static error_t +pci_system_x86_scan_bus (uint8_t bus) +{ + error_t err; + uint8_t dev, func, nfuncs, hdrtype, secbus; + uint32_t reg; + struct pci_device_private *d, *devices; + struct pci_device scratchdev; + + scratchdev.bus = bus; + + for (dev = 0; dev < 32; dev++) { - dev->rom_size = 64 * 1024; + scratchdev.dev = dev; + scratchdev.func = 0; + err = pci_nfuncs (&scratchdev, &nfuncs); + if (err) + return err; + + for (func = 0; func < nfuncs; func++) + { + scratchdev.func = func; + err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_VENDOR_ID); + if (err) + return err; + + if (PCI_VENDOR (reg) == PCI_VENDOR_INVALID || PCI_VENDOR (reg) == 0) + continue; + + err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_CLASS); + if (err) + return err; + + err = pci_device_cfg_read_u8 (&scratchdev, &hdrtype, PCI_HDRTYPE); + if (err) + return err; + + devices = + realloc (pci_sys->devices, + (pci_sys->num_devices + 1) * sizeof (struct pci_device_private)); + if (!devices) + return ENOMEM; + + d = devices + pci_sys->num_devices; + memset (d, 0, sizeof (struct pci_device_private)); + + /* Fixed values as PCI express is still not supported */ + d->base.domain = 0; + d->base.bus = bus; + d->base.dev = dev; + d->base.func = func; + + d->base.device_class = reg >> 8; + + err = pci_device_x86_probe (&d->base); + if (err) + return err; + + pci_sys->devices = devices; + pci_sys->num_devices++; + + switch (hdrtype & 0x3) + { + case PCI_HDRTYPE_DEVICE: + break; + case PCI_HDRTYPE_BRIDGE: + case PCI_HDRTYPE_CARDBUS: + { + err = pci_device_cfg_read_u8 (&scratchdev, &secbus, PCI_SECONDARY_BUS); + if (err) + return err; + + err = pci_system_x86_scan_bus (secbus); + if (err) + return err; + + break; + } + default: + /* Unknown header, do nothing */ + break; + } + } } return 0; -- 2.17.1
>From 7263ba69531faf05bcaacb98c995159bf0b83f91 Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Sat, 10 Nov 2018 06:48:42 -0500 Subject: [PATCH libpciaccess 3/3] Use recursive scan bus Switch over to the new recursive scan bus routine for x86 --- src/x86_pci.c | 82 +++++++-------------------------------------------- 1 file changed, 11 insertions(+), 71 deletions(-) diff --git a/src/x86_pci.c b/src/x86_pci.c index cdfc2ef..786ee3c 100644 --- a/src/x86_pci.c +++ b/src/x86_pci.c @@ -1131,11 +1131,6 @@ static int pci_probe(void) _pci_hidden int pci_system_x86_create(void) { - uint8_t nfuncs = 0; - uint8_t bus, dev, func; - uint32_t reg = 0, ndevs; - struct pci_device tmpdev = { 0 }; - struct pci_device_private *device; error_t err; int confx; @@ -1143,23 +1138,6 @@ pci_system_x86_create(void) if (err) return err; - ndevs = 0; - for (bus = 0; bus < 256; bus++) { - tmpdev.bus = bus; - for (dev = 0; dev < 32; dev++) { - tmpdev.dev = dev; - pci_nfuncs(&tmpdev, &nfuncs); - for (func = 0; func < nfuncs; func++) { - if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_VENDOR_ID)) - continue; - if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || - PCI_VENDOR(reg) == 0) - continue; - ndevs++; - } - } - } - pci_sys = calloc (1, sizeof (struct pci_system)); if (pci_sys == NULL) { @@ -1167,17 +1145,9 @@ pci_system_x86_create(void) return ENOMEM; } - pci_sys->num_devices = ndevs; - pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); - if (pci_sys->devices == NULL) { - x86_disable_io(); - free(pci_sys); - pci_sys = NULL; - return ENOMEM; - } - confx = pci_probe (); - if (!confx) { + if (!confx) + { x86_disable_io (); free (pci_sys); pci_sys = NULL; @@ -1188,45 +1158,15 @@ pci_system_x86_create(void) else pci_sys->methods = &x86_pci_method_conf2; - device = pci_sys->devices; - for (bus = 0; bus < 256; bus++) { - tmpdev.bus = bus; - for (dev = 0; dev < 32; dev++) { - tmpdev.dev = dev; - err = pci_nfuncs(&tmpdev, &nfuncs); - if (err) { - x86_disable_io (); - free (pci_sys); - pci_sys = NULL; - return ENODEV; - } - for (func = 0; func < nfuncs; func++) { - tmpdev.func = func; - if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_VENDOR_ID)) - continue; - if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || - PCI_VENDOR(reg) == 0) - continue; - device->base.domain = device->base.domain_16 = 0; - device->base.bus = bus; - device->base.dev = dev; - device->base.func = func; - device->base.vendor_id = PCI_VENDOR(reg); - device->base.device_id = PCI_DEVICE(reg); - - if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_CLASS)) - continue; - device->base.device_class = (reg >> 8) & 0xFF; - device->base.revision = reg & 0xFF; - - if (pci_device_cfg_read_u32(&tmpdev, ®, PCI_SUB_VENDOR_ID)) - continue; - device->base.subvendor_id = PCI_VENDOR(reg); - device->base.subdevice_id = PCI_DEVICE(reg); - - device++; - } - } + /* Recursive scan */ + pci_sys->num_devices = 0; + err = pci_system_x86_scan_bus (0); + if (err) + { + x86_disable_io (); + free (pci_sys); + pci_sys = NULL; + return err; } return 0; -- 2.17.1
_______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel