6966962 libpciaccess should support multiple PCI segments
authorJohn Martin <John.M.Martin@Oracle.COM>
Sun, 27 Mar 2011 10:36:30 -0700
changeset 1099 5cae649c0908
parent 1098 1152221cb1e9
child 1100 2f03aaeee5fe
6966962 libpciaccess should support multiple PCI segments
open-src/lib/libpciaccess/Makefile
open-src/lib/libpciaccess/solx_devfs.c.domain.patch
--- a/open-src/lib/libpciaccess/Makefile	Sat Mar 26 10:54:02 2011 -0700
+++ b/open-src/lib/libpciaccess/Makefile	Sun Mar 27 10:36:30 2011 -0700
@@ -38,7 +38,8 @@
 SOURCE_PATCHES = \
 	pciaccess_private.h.patch \
 	scanpci.man.patch \
-	solx_devfs.c.patch
+	solx_devfs.c.patch \
+	solx_devfs.c.domain.patch
 
 # Library name
 LIBNAME=libpciaccess
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/lib/libpciaccess/solx_devfs.c.domain.patch	Sun Mar 27 10:36:30 2011 -0700
@@ -0,0 +1,332 @@
+diff -urp -x '*~' -x '*.orig' src/solx_devfs.c src/solx_devfs.c
+--- src/solx_devfs.c	2011-02-25 17:49:55.885702270 -0500
++++ src/solx_devfs.c	2011-03-01 07:39:45.657597520 -0500
+@@ -1,6 +1,6 @@
+ /*
+  * (C) Copyright IBM Corporation 2006
+- * Copyright (c) 2007, 2009, Oracle and/or its affiliates.
++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates.
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -43,7 +43,7 @@
+ 
+ /* #define DEBUG */
+ 
+-#define	MAX_DEVICES	256
++#define	INITIAL_NUM_DEVICES	256
+ #define	CELL_NUMS_1275	(sizeof(pci_regspec_t) / sizeof(uint_t))
+ 
+ typedef union {
+@@ -62,10 +62,18 @@ typedef struct nexus {
+     int fd;
+     int first_bus;
+     int last_bus;
++    int domain;
+     char *path;			/* for errors/debugging; fd is all we need */
++    char *dev_path;
+     struct nexus *next;
+ } nexus_t;
+ 
++typedef struct probe_info {
++    volatile size_t num_allocated_elems;
++    volatile size_t num_devices;
++    struct pci_device_private * volatile devices;
++} probe_info_t;
++
+ static nexus_t *nexus_list = NULL;
+ static int xsvc_fd = -1;
+ 
+@@ -120,10 +128,9 @@ static int pci_device_solx_devfs_write( 
+ 
+ static int pci_device_solx_devfs_boot_vga(struct pci_device *dev);
+ 
+-static int probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p,
+-		     struct pci_system *pci_sys);
++static int probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, probe_info_t *pinfo);
+ 
+-static int do_probe(nexus_t *nexus, struct pci_system *pci_sys);
++static int do_probe(nexus_t *nexus, probe_info_t *pinfo);
+ 
+ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg);
+ 
+@@ -150,12 +157,13 @@ static const struct pci_system_methods s
+ };
+ 
+ static nexus_t *
+-find_nexus_for_bus( int bus )
++find_nexus_for_bus( int domain, int bus )
+ {
+     nexus_t *nexus;
+ 
+     for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
+-	if ((bus >= nexus->first_bus) && (bus <= nexus->last_bus)) {
++	if ((domain == nexus->domain) &&
++	    (bus >= nexus->first_bus) && (bus <= nexus->last_bus)) {
+ 	    return nexus;
+ 	}
+     }
+@@ -189,6 +197,7 @@ pci_system_solx_devfs_destroy( void )
+ 	next = nexus->next;
+ 	close(nexus->fd);
+ 	free(nexus->path);
++	free(nexus->dev_path);
+ 	free(nexus);
+     }
+     nexus_list = NULL;
+@@ -208,48 +217,41 @@ pci_system_solx_devfs_create( void )
+ {
+     int err = 0;
+     di_node_t di_node;
+-
++    probe_info_t pinfo;
++    struct pci_device_private *devices;
+ 
+     if (nexus_list != NULL) {
+ 	return 0;
+     }
+ 
+-    /*
+-     * Only allow MAX_DEVICES exists
+-     * I will fix it later to get
+-     * the total devices first
+-     */
+-    if ((pci_sys = calloc(1, sizeof (struct pci_system))) != NULL) {
+-	pci_sys->methods = &solx_devfs_methods;
++    if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
++	err = errno;
++	(void) fprintf(stderr, "di_init() failed: %s\n",
++		       strerror(errno));
++	return (err);
++    }
+ 
+-	if ((pci_sys->devices =
+-	     calloc(MAX_DEVICES, sizeof (struct pci_device_private)))
+-	    != NULL) {
+-
+-	    if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
+-		err = errno;
+-		(void) fprintf(stderr, "di_init() failed: %s\n",
+-			       strerror(errno));
+-	    } else {
+-		(void) di_walk_minor(di_node, DDI_NT_REGACC, 0, pci_sys,
+-				     probe_nexus_node);
+-		di_fini(di_node);
+-	    }
+-	}
+-	else {
+-	    err = errno;
+-	}
+-    } else {
++    if ((devices = calloc(INITIAL_NUM_DEVICES,
++			sizeof (struct pci_device_private))) == NULL) {
+ 	err = errno;
++	di_fini(di_node);
++	return (err);
+     }
+ 
+-    if (err != 0) {
+-	if (pci_sys != NULL) {
+-	    free(pci_sys->devices);
+-	    free(pci_sys);
+-	    pci_sys = NULL;
+-	}
++    pinfo.num_allocated_elems = INITIAL_NUM_DEVICES;
++    pinfo.num_devices = 0;
++    pinfo.devices = devices; 
++    (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, &pinfo, probe_nexus_node);
++    di_fini(di_node);
++
++    if ((pci_sys = calloc(1, sizeof (struct pci_system))) == NULL) {
++	err = errno;
++	free(devices);
++	return (err);
+     }
++    pci_sys->methods = &solx_devfs_methods;
++    pci_sys->devices = pinfo.devices;
++    pci_sys->num_devices = pinfo.num_devices;
+ 
+     return (err);
+ }
+@@ -292,7 +294,7 @@ get_config_header(int fd, uint8_t bus_no
+  * Probe device's functions.  Modifies many fields in the prg_p.
+  */
+ static int
+-probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys)
++probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, probe_info_t *pinfo)
+ {
+     pci_conf_hdr_t	config_hdr;
+     boolean_t		multi_function_device;
+@@ -415,12 +417,9 @@ probe_dev(nexus_t *nexus, pcitool_reg_t 
+ 	     * function number.
+ 	     */
+ 
+-	    pci_base = &pci_sys->devices[pci_sys->num_devices].base;
++	    pci_base = &pinfo->devices[pinfo->num_devices].base;
+ 
+-	    /*
+-	     * Domain is peer bus??
+-	     */
+-	    pci_base->domain = 0;
++	    pci_base->domain = nexus->domain;
+ 	    pci_base->bus = prg_p->bus_no;
+ 	    pci_base->dev = prg_p->dev_no;
+ 	    pci_base->func = func;
+@@ -440,7 +439,7 @@ probe_dev(nexus_t *nexus, pcitool_reg_t 
+ 	    pci_base->subvendor_id 	= GET_CONFIG_VAL_16(PCI_CONF_SUBVENID);
+ 	    pci_base->subdevice_id 	= GET_CONFIG_VAL_16(PCI_CONF_SUBSYSID);
+ 
+-	    pci_sys->devices[pci_sys->num_devices].header_type
++	    pinfo->devices[pinfo->num_devices].header_type
+ 					= GET_CONFIG_VAL_8(PCI_CONF_HEADER);
+ 
+ #ifdef DEBUG
+@@ -449,15 +448,26 @@ probe_dev(nexus_t *nexus, pcitool_reg_t 
+ 		    nexus->path, prg_p->bus_no, prg_p->dev_no, func);
+ #endif
+ 
+-	    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");
+-	    }
+-
+-
++	    pinfo->num_devices++;
++	    if (pinfo->num_devices == pinfo->num_allocated_elems) {
++		struct pci_device_private *new_devs;
++		size_t new_num_elems = pinfo->num_allocated_elems * 2;
++
++		new_devs = realloc(pinfo->devices,
++			new_num_elems * sizeof (struct pci_device_private));
++		if (new_devs == NULL) {
++		    (void) fprintf(stderr,
++			           "Maximum number of PCI devices found,"
++			           " discarding additional devices\n");
++		    return (rval);
++		}
++		(void) memset(&new_devs[pinfo->num_devices], 0, 
++			pinfo->num_allocated_elems *
++			sizeof (struct pci_device_private));
++		pinfo->num_allocated_elems = new_num_elems;
++		pinfo->devices = new_devs;
++	    } 
++	
+ 	    /*
+ 	     * Accommodate devices which state their
+ 	     * multi-functionality only in their function 0 config
+@@ -479,8 +489,8 @@ probe_dev(nexus_t *nexus, pcitool_reg_t 
+ 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;
++    probe_info_t *pinfo = (probe_info_t *)arg;
++    char *nexus_name, *nexus_dev_path;
+     nexus_t *nexus;
+     int fd;
+     char nexus_path[MAXPATHLEN];
+@@ -491,6 +501,7 @@ probe_nexus_node(di_node_t di_node, di_m
+     int numval;
+     int pci_node = 0;
+     int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
++    int domain = 0;
+ 
+ #ifdef DEBUG
+     nexus_name = di_devfs_minor_path(minor);
+@@ -525,6 +536,12 @@ probe_nexus_node(di_node_t di_node, di_m
+ 		last_bus = ints[1];
+ 	    }
+ 	}
++	else if (strcmp(prop_name, "pciseg") == 0) { 
++	    numval = di_prop_ints(prop, &ints);
++	    if (numval == 1) {
++		domain = ints[0];
++	    }
++	}
+     }
+ 
+ #ifdef __x86  /* sparc pci nodes don't have the device_type set */
+@@ -541,6 +558,7 @@ probe_nexus_node(di_node_t di_node, di_m
+     }
+     nexus->first_bus = first_bus;
+     nexus->last_bus = last_bus;
++    nexus->domain = domain;
+ 
+     nexus_name = di_devfs_minor_path(minor);
+     if (nexus_name == NULL) {
+@@ -561,11 +579,15 @@ probe_nexus_node(di_node_t di_node, di_m
+     if ((fd = open(nexus_path, O_RDWR)) >= 0) {
+ 	nexus->fd = fd;
+ 	nexus->path = strdup(nexus_path);
+-	if ((do_probe(nexus, pci_sys) != 0) && (errno != ENXIO)) {
++	nexus_dev_path = di_devfs_path(di_node);
++	nexus->dev_path = strdup(nexus_dev_path);
++	di_devfs_path_free(nexus_dev_path);
++	if ((do_probe(nexus, pinfo) != 0) && (errno != ENXIO)) {
+ 	    (void) fprintf(stderr, "Error probing node %s: %s\n",
+ 			   nexus_path, strerror(errno));
+ 	    (void) close(fd);
+ 	    free(nexus->path);
++	    free(nexus->dev_path);
+ 	    free(nexus);
+ 	} else {
+ 	    nexus->next = nexus_list;
+@@ -589,7 +611,7 @@ probe_nexus_node(di_node_t di_node, di_m
+  * input_args contains commandline options as specified by the user.
+  */
+ static int
+-do_probe(nexus_t *nexus, struct pci_system *pci_sys)
++do_probe(nexus_t *nexus, probe_info_t *pinfo)
+ {
+     pcitool_reg_t prg;
+     uint32_t bus;
+@@ -623,7 +645,7 @@ do_probe(nexus_t *nexus, struct pci_syst
+ 
+ 	for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) {
+ 	    prg.dev_no = dev;
+-	    rval = probe_dev(nexus, &prg, pci_sys);
++	    rval = probe_dev(nexus, &prg, pinfo);
+ 	}
+ 
+ 	/*
+@@ -711,6 +733,10 @@ pci_device_solx_devfs_probe( struct pci_
+     uint ent = 0;
+     struct pci_device_private *priv =
+ 	    (struct pci_device_private *) dev;
++    nexus_t *nexus;
++
++    if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
++	return ENODEV;
+ 
+     err = pci_device_solx_devfs_read( dev, config, 0, 256, & bytes );
+ 
+@@ -736,7 +762,7 @@ pci_device_solx_devfs_probe( struct pci_
+ 	 * starting to find if it is MEM/MEM64/IO
+ 	 * using libdevinfo
+ 	 */
+-	if ((rnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
++	if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
+ 	    err = errno;
+ 	    (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
+ 	} else {
+@@ -905,7 +931,7 @@ pci_device_solx_devfs_read( struct pci_d
+     pcitool_reg_t cfg_prg;
+     int err = 0;
+     int i = 0;
+-    nexus_t *nexus = find_nexus_for_bus(dev->bus);
++    nexus_t *nexus = find_nexus_for_bus(dev->domain, dev->bus);
+ 
+     *bytes_read = 0;
+ 
+@@ -957,7 +983,7 @@ pci_device_solx_devfs_write( struct pci_
+     pcitool_reg_t cfg_prg;
+     int err = 0;
+     int cmd;
+-    nexus_t *nexus = find_nexus_for_bus(dev->bus);
++    nexus_t *nexus = find_nexus_for_bus(dev->domain, dev->bus);
+ 
+     if ( bytes_written != NULL ) {
+ 	*bytes_written = 0;