This is a cleaned up version of my previous patch. It fixes a bug by sorting the device array by B/D/F for all backends. (It assumes only domain 0000 exists and I think that assumption is also made elsewhere).
--- src/common_init.c | 37 ++++++++++++++++ src/hurd_pci.c | 108 +++++++++++++++++++++++++++------------------- 2 files changed, 101 insertions(+), 44 deletions(-) diff --git a/src/common_init.c b/src/common_init.c index 1940cff..14f0c6b 100644 --- a/src/common_init.c +++ b/src/common_init.c @@ -40,6 +40,40 @@ _pci_hidden struct pci_system * pci_sys; +static int +sort_devices(void) +{ + int bus, dev, func; + struct pci_device_private *sorted; + struct pci_device_private *device; + struct pci_device_private *tmpdev; + + sorted = calloc(pci_sys->num_devices, sizeof(struct pci_device_private)); + if (!sorted) { + return ENOMEM; + } + + tmpdev = sorted; + + for (bus = 0; bus < 256; bus++) { + for (dev = 0; dev < 32; dev++) { + for (func = 0; func < 8; func++) { + device = (struct pci_device_private *) + pci_device_find_by_slot(0, bus, dev, func); + if (device) { + *tmpdev = *device; + tmpdev++; + } + } + } + } + if (pci_sys->devices) { + free(pci_sys->devices); + pci_sys->devices = sorted; + } + return 0; +} + /** * Initialize the PCI subsystem for access. * @@ -72,6 +106,9 @@ pci_system_init( void ) #else # error "Unsupported OS" #endif + if (!err) { + err = sort_devices(); + } return err; } diff --git a/src/hurd_pci.c b/src/hurd_pci.c index ada7af8..ad6883a 100644 --- a/src/hurd_pci.c +++ b/src/hurd_pci.c @@ -33,9 +33,12 @@ #include <sys/mman.h> #include <string.h> #include <strings.h> +#include <mach.h> #include <hurd.h> #include <hurd/pci.h> #include <hurd/paths.h> +#include <hurd/fs.h> +#include <device/device.h> #include "x86_pci.h" #include "pciaccess.h" @@ -302,26 +305,52 @@ pci_device_hurd_destroy(struct pci_device *dev) mach_port_deallocate (mach_task_self (), d->device_port); } +static struct dirent * +simple_readdir(mach_port_t port, uint32_t *first_entry) +{ + struct dirent *e; + char *data; + int nentries = 0; + vm_size_t size; + + dir_readdir (port, &data, &size, *first_entry, 1, 0, &nentries); + + if (nentries == 0) { + return NULL; + } + + *first_entry = *first_entry + 1; + e = (struct dirent *)(data+4); + return e; +} + /* Walk through the FS tree to see what is allowed for us */ static int -enum_devices(const char *parent, int domain, - int bus, int dev, int func, tree_level lev) +enum_devices(mach_port_t pci_port, mach_port_t cwd_port, const char *parent, int domain, + int bus, int dev, int func, tree_level lev) { int err, ret; - DIR *dir; - struct dirent *entry; + struct dirent *entry = NULL; char path[NAME_MAX]; char server[NAME_MAX]; - uint32_t reg; + uint32_t reg, count = 0; size_t toread; mach_port_t device_port; struct pci_device_private *d, *devices; - dir = opendir(parent); - if (!dir) - return errno; + if (pci_port == MACH_PORT_NULL) { + return EGRATUITOUS; + } else { + if (lev > LEVEL_FUNC + 1) { + return 0; + } + cwd_port = file_name_lookup_under (pci_port, parent, O_DIRECTORY | O_RDWR | O_EXEC, 0); + if (cwd_port == MACH_PORT_NULL) { + return 0; + } + } - while ((entry = readdir(dir)) != 0) { + while ((entry = simple_readdir(cwd_port, &count)) != NULL) { snprintf(path, NAME_MAX, "%s/%s", parent, entry->d_name); if (entry->d_type == DT_DIR) { if (!strncmp(entry->d_name, ".", NAME_MAX) @@ -331,7 +360,6 @@ enum_devices(const char *parent, int domain, errno = 0; ret = strtol(entry->d_name, 0, 16); if (errno) { - closedir(dir); return errno; } @@ -353,16 +381,12 @@ enum_devices(const char *parent, int domain, func = ret; break; default: - if (closedir(dir) < 0) - return errno; - return -1; + return 0; } - err = enum_devices(path, domain, bus, dev, func, lev+1); + err = enum_devices(pci_port, cwd_port, path, domain, bus, dev, func, lev+1); if (err && err != EPERM && err != EACCES) { - if (closedir(dir) < 0) - return errno; - return err; + return 0; } } else { if (strncmp(entry->d_name, FILE_CONFIG_NAME, NAME_MAX)) @@ -370,34 +394,27 @@ enum_devices(const char *parent, int domain, 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, + snprintf(server, NAME_MAX, "./%04x/%02x/%02x/%01u/%s", + domain, bus, dev, func, entry->d_name); - device_port = file_name_lookup(server, 0, 0); + device_port = file_name_lookup_under(pci_port, server, O_RDWR, 0); if (device_port == MACH_PORT_NULL) { - closedir(dir); - return errno; + return 0; } toread = sizeof(reg); err = pciclient_cfg_read(device_port, PCI_VENDOR_ID, (char*)®, &toread); if (err) { - if (closedir(dir) < 0) - return errno; return err; } if (toread != sizeof(reg)) { - if (closedir(dir) < 0) - return errno; return -1; } devices = realloc(pci_sys->devices, (pci_sys->num_devices + 1) * sizeof(struct pci_device_private)); if (!devices) { - if (closedir(dir) < 0) - return errno; return ENOMEM; } @@ -415,13 +432,9 @@ enum_devices(const char *parent, int domain, err = pciclient_cfg_read(device_port, PCI_CLASS, (char*)®, &toread); if (err) { - if (closedir(dir) < 0) - return errno; return err; } if (toread != sizeof(reg)) { - if (closedir(dir) < 0) - return errno; return -1; } @@ -432,13 +445,9 @@ enum_devices(const char *parent, int domain, err = pciclient_cfg_read(device_port, PCI_SUB_VENDOR_ID, (char*)®, &toread); if (err) { - if (closedir(dir) < 0) - return errno; return err; } if (toread != sizeof(reg)) { - if (closedir(dir) < 0) - return errno; return -1; } @@ -452,9 +461,6 @@ enum_devices(const char *parent, int domain, } } - if (closedir(dir) < 0) - return errno; - return 0; } @@ -489,6 +495,8 @@ pci_system_hurd_create(void) { int err; struct pci_system_hurd *pci_sys_hurd; + mach_port_t device_master; + mach_port_t root, pci_server_port = MACH_PORT_NULL; if (&netfs_server_name && netfs_server_name && !strcmp(netfs_server_name, "pci-arbiter")) { @@ -513,12 +521,24 @@ pci_system_hurd_create(void) pci_sys->methods = &hurd_pci_methods; pci_sys->num_devices = 0; - err = enum_devices(_SERVERS_BUS_PCI, -1, -1, -1, -1, LEVEL_DOMAIN); + + if (! (err = get_privileged_ports (NULL, &device_master)) && (device_master != MACH_PORT_NULL)) { + err = device_open (device_master, D_READ|D_WRITE, "pci", &pci_server_port); + if (err) { + pci_system_cleanup(); + return err; + } + root = file_name_lookup_under (pci_server_port, ".", O_DIRECTORY | O_RDWR | O_EXEC, 0); + if (!root) { + pci_system_cleanup(); + return errno; + } + err = enum_devices(pci_server_port, root, ".", -1, -1, -1, -1, LEVEL_DOMAIN); + } + if (err) { - /* There was an error, but we don't know which devices have been - * initialized correctly, so call cleanup to free whatever is allocated */ - pci_system_cleanup(); - return err; + pci_system_cleanup(); + return err; } return 0; -- 2.30.0