diff options
-rw-r--r-- | src/solx_devfs.c | 116 |
1 files changed, 90 insertions, 26 deletions
diff --git a/src/solx_devfs.c b/src/solx_devfs.c index e184841..99ee1ac 100644 --- a/src/solx_devfs.c +++ b/src/solx_devfs.c @@ -22,7 +22,7 @@ * DEALINGS IN THE SOFTWARE. */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007, 2009 Sun Microsystems, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -68,6 +68,8 @@ #include "pciaccess.h" #include "pciaccess_private.h" +/* #define DEBUG */ + #define MAX_DEVICES 256 #define CELL_NUMS_1275 (sizeof(pci_regspec_t) / sizeof(uint_t)) @@ -85,12 +87,13 @@ typedef struct i_devnode { typedef struct nexus { int fd; - int domain; + int first_bus; + int last_bus; + const char *path; /* for errors/debugging; fd is all we need */ struct nexus *next; } nexus_t; static nexus_t *nexus_list = NULL; -static int num_domains = 0; static int xsvc_fd = -1; /* @@ -127,9 +130,6 @@ static int xsvc_fd = -1; # define U45_SB_CLASS_RID 0x06040000 #endif -#define DEBUGON 0 - - static int pci_device_solx_devfs_map_range(struct pci_device *dev, struct pci_device_mapping *map); @@ -174,12 +174,12 @@ static const struct pci_system_methods solx_devfs_methods = { }; static nexus_t * -find_nexus_for_domain( int domain ) +find_nexus_for_bus( int bus ) { nexus_t *nexus; for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) { - if (nexus->domain == domain) { + if ((bus >= nexus->first_bus) && (bus <= nexus->last_bus)) { return nexus; } } @@ -212,6 +212,7 @@ pci_system_solx_devfs_destroy( void ) for (nexus = nexus_list ; nexus != NULL ; nexus = next) { next = nexus->next; close(nexus->fd); + free(nexus->path); free(nexus); } nexus_list = NULL; @@ -443,7 +444,7 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) /* * Domain is peer bus?? */ - pci_base->domain = nexus->domain; + pci_base->domain = 0; pci_base->bus = prg_p->bus_no; pci_base->dev = prg_p->dev_no; pci_base->func = func; @@ -466,12 +467,20 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) pci_sys->devices[pci_sys->num_devices].header_type = GET_CONFIG_VAL_8(PCI_CONF_HEADER); -#if DEBUGON - fprintf(stderr, "busno = %x, devno = %x, funcno = %x\n", - prg_p->bus_no, prg_p->dev_no, func); +#ifdef DEBUG + fprintf(stderr, + "nexus = %s, busno = %x, devno = %x, funcno = %x\n", + nexus->path, prg_p->bus_no, prg_p->dev_no, func); #endif - pci_sys->num_devices++; + if (pci_sys->num_devices < (MAX_DEVICES - 1)) { + pci_sys->num_devices++; + } else { + (void) fprintf(stderr, + "Maximum number of PCI devices found," + " discarding additional devices\n"); + } + /* * Accommodate devices which state their @@ -495,17 +504,67 @@ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) { struct pci_system *pci_sys = (struct pci_system *) arg; - char *nexus_name; + const char *nexus_name; nexus_t *nexus; int fd; char nexus_path[MAXPATHLEN]; + di_prop_t prop; + const char *strings; + int *ints; + int numval; + int pci_node = 0; + int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); + +#ifdef DEBUG + nexus_name = di_devfs_minor_path(minor); + fprintf(stderr, "-- device name: %s\n", nexus_name); +#endif + + for (prop = di_prop_next(di_node, NULL); prop != NULL; + prop = di_prop_next(di_node, prop)) { + + const char *prop_name = di_prop_name(prop); + +#ifdef DEBUG + fprintf(stderr, " property: %s\n", prop_name); +#endif + + if (strcmp(prop_name, "device_type") == 0) { + numval = di_prop_strings(prop, &strings); + if (numval != 1 || strncmp(strings, "pci", 3) != 0) { + /* not a PCI node, bail */ + return (DI_WALK_CONTINUE); + } + pci_node = 1; + } + else if (strcmp(prop_name, "class-code") == 0) { + /* not a root bus node, bail */ + return (DI_WALK_CONTINUE); + } + else if (strcmp(prop_name, "bus-range") == 0) { + numval = di_prop_ints(prop, &ints); + if (numval == 2) { + first_bus = ints[0]; + last_bus = ints[1]; + } + } + } + +#ifdef __x86 /* sparc pci nodes don't have the device_type set */ + if (pci_node != 1) + return (DI_WALK_CONTINUE); +#endif + + /* we have a PCI root bus node. */ nexus = calloc(1, sizeof(nexus_t)); if (nexus == NULL) { (void) fprintf(stderr, "Error allocating memory for nexus: %s\n", strerror(errno)); - return DI_WALK_TERMINATE; + return (DI_WALK_TERMINATE); } + nexus->first_bus = first_bus; + nexus->last_bus = last_bus; nexus_name = di_devfs_minor_path(minor); if (nexus_name == NULL) { @@ -517,14 +576,20 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name); di_devfs_path_free(nexus_name); + nexus->path = strdup(nexus_path); + +#ifdef DEBUG + fprintf(stderr, "nexus = %s, bus-range = %d - %d\n", + nexus_path, first_bus, last_bus); +#endif if ((fd = open(nexus_path, O_RDWR)) >= 0) { nexus->fd = fd; - nexus->domain = num_domains++; if ((do_probe(nexus, pci_sys) != 0) && (errno != ENXIO)) { (void) fprintf(stderr, "Error probing node %s: %s\n", nexus_path, strerror(errno)); (void) close(fd); + free(nexus->path); free(nexus); } else { nexus->next = nexus_list; @@ -533,6 +598,7 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) } else { (void) fprintf(stderr, "Error opening %s: %s\n", nexus_path, strerror(errno)); + free(nexus->path); free(nexus); } @@ -553,9 +619,9 @@ do_probe(nexus_t *nexus, struct pci_system *pci_sys) pcitool_reg_t prg; uint32_t bus; uint8_t dev; - uint32_t last_bus = PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT; + uint32_t last_bus = nexus->last_bus; uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT; - uint8_t first_bus = 0; + uint8_t first_bus = nexus->first_bus; uint8_t first_dev = 0; int rval = 0; @@ -593,9 +659,6 @@ do_probe(nexus_t *nexus, struct pci_system *pci_sys) rval = 0; } } - if (pci_sys->num_devices > MAX_DEVICES) { - (void) fprintf(stderr, "pci devices reach maximum number\n"); - } return (rval); } @@ -634,7 +697,7 @@ find_target_node(di_node_t node, void *arg) len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®buf); if (len <= 0) { -#if DEBUGON +#ifdef DEBUG fprintf(stderr, "error = %x\n", errno); fprintf(stderr, "can not find assigned-address\n"); #endif @@ -808,7 +871,7 @@ pci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer ) .size = dev->rom_size, .flags = 0 }; - + err = pci_device_solx_devfs_map_range(dev, &prom); if (err == 0) { (void) bcopy(prom.memory, buffer, dev->rom_size); @@ -831,7 +894,7 @@ pci_device_solx_devfs_read( struct pci_device * dev, void * data, pcitool_reg_t cfg_prg; int err = 0; int i = 0; - nexus_t *nexus = find_nexus_for_domain(dev->domain); + nexus_t *nexus = find_nexus_for_bus(dev->bus); *bytes_read = 0; @@ -852,7 +915,8 @@ pci_device_solx_devfs_read( struct pci_device * dev, void * data, cfg_prg.offset = offset + i; if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) { - fprintf(stderr, "read bdf<%x,%x,%x,%llx> config space failure\n", + fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n", + nexus->path, cfg_prg.bus_no, cfg_prg.dev_no, cfg_prg.func_no, @@ -882,7 +946,7 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data, pcitool_reg_t cfg_prg; int err = 0; int cmd; - nexus_t *nexus = find_nexus_for_domain(dev->domain); + nexus_t *nexus = find_nexus_for_bus(dev->bus); if ( bytes_written != NULL ) { *bytes_written = 0; |