--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/lib/libpciaccess/sparc.patch Wed Dec 07 17:09:52 2011 -0800
@@ -0,0 +1,507 @@
+diff -ur old/src/solx_devfs.c new/src/solx_devfs.c
+--- src/solx_devfs.c Wed Sep 21 12:43:44 2011
++++ src/solx_devfs.c Tue Nov 15 12:23:53 2011
+@@ -66,6 +66,11 @@
+ char *path; /* for errors/debugging; fd is all we need */
+ char *dev_path;
+ struct nexus *next;
++#ifdef __sparc
++ struct pci_device **devlist;
++ volatile size_t num_allocated_elems;
++ volatile size_t num_devices;
++#endif
+ } nexus_t;
+
+ typedef struct probe_info {
+@@ -75,8 +80,14 @@
+ } probe_info_t;
+
+ static nexus_t *nexus_list = NULL;
++#if !defined(__sparc)
+ static int xsvc_fd = -1;
++#endif
+
++#ifdef __sparc
++static di_prom_handle_t di_phdl;
++#endif
++
+ /*
+ * Read config space in native processor endianness. Endian-neutral
+ * processing can then take place. On big endian machines, MSB and LSB
+@@ -91,6 +102,10 @@
+ # error "ISA is neither __sparc nor __x86"
+ #endif
+
++#ifdef __sparc
++#define MAPPING_DEV_PATH(dev) (((struct pci_device_private *) dev)->device_string)
++#endif
++
+ /*
+ * Identify problematic southbridges. These have device id 0x5249 and
+ * vendor id 0x10b9. Check for revision ID 0 and class code 060400 as well.
+@@ -156,7 +171,23 @@
+ .boot_vga = pci_device_solx_devfs_boot_vga
+ };
+
++#ifdef __sparc
+ static nexus_t *
++find_nexus_for_dev(struct pci_device *dev)
++{
++ nexus_t *nexus;
++ int i;
++
++ for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
++ for (i = 0; i < nexus->num_devices; i++) {
++ if (nexus->devlist[i] == dev)
++ return nexus;
++ }
++ }
++ return NULL;
++}
++#else
++static nexus_t *
+ find_nexus_for_bus( int domain, int bus )
+ {
+ nexus_t *nexus;
+@@ -169,6 +200,7 @@
+ }
+ return NULL;
+ }
++#endif
+
+ #define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset])
+ #define GET_CONFIG_VAL_16(offset) \
+@@ -198,14 +230,32 @@
+ close(nexus->fd);
+ free(nexus->path);
+ free(nexus->dev_path);
++#ifdef __sparc
++ {
++ struct pci_device *dev;
++ int i;
++
++ for (i = 0; i < nexus->num_devices; i++) {
++ dev = nexus->devlist[i];
++ if (MAPPING_DEV_PATH(dev))
++ di_devfs_path_free((char *) MAPPING_DEV_PATH(dev));
++ }
++ }
++ free(nexus->devlist);
++#endif
+ free(nexus);
+ }
+ nexus_list = NULL;
+
++#ifdef __sparc
++ if (di_phdl != DI_PROM_HANDLE_NIL)
++ (void) di_prom_fini(di_phdl);
++#else
+ if (xsvc_fd >= 0) {
+ close(xsvc_fd);
+ xsvc_fd = -1;
+ }
++#endif
+ }
+
+ /*
+@@ -238,10 +288,16 @@
+ return (err);
+ }
+
++#ifdef __sparc
++ if ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
++ (void) fprintf(stderr, "di_prom_init failed: %s\n", strerror(errno));
++#endif
++
+ pinfo.num_allocated_elems = INITIAL_NUM_DEVICES;
+ pinfo.num_devices = 0;
+- pinfo.devices = devices;
++ 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) {
+@@ -249,6 +305,7 @@
+ free(devices);
+ return (err);
+ }
++
+ pci_sys->methods = &solx_devfs_methods;
+ pci_sys->devices = pinfo.devices;
+ pci_sys->num_devices = pinfo.num_devices;
+@@ -372,6 +429,10 @@
+ else if (((errno != EFAULT) ||
+ (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
+ (prg_p->data != 0xffffffff)) {
++#ifdef __sparc
++/* on sparc, devices can be enumerated discontiguously. Do not quit */
++ rval = 0;
++#endif
+ break;
+ }
+
+@@ -438,6 +499,7 @@
+ pci_base->device_id = GET_CONFIG_VAL_16(PCI_CONF_DEVID);
+ pci_base->subvendor_id = GET_CONFIG_VAL_16(PCI_CONF_SUBVENID);
+ pci_base->subdevice_id = GET_CONFIG_VAL_16(PCI_CONF_SUBSYSID);
++ pci_base->irq = GET_CONFIG_VAL_8(PCI_CONF_ILINE);
+
+ pinfo->devices[pinfo->num_devices].header_type
+ = GET_CONFIG_VAL_8(PCI_CONF_HEADER);
+@@ -461,13 +523,32 @@
+ " discarding additional devices\n");
+ return (rval);
+ }
+- (void) memset(&new_devs[pinfo->num_devices], 0,
++ (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;
+- }
+-
++ }
++
++#ifdef __sparc
++ nexus->devlist[nexus->num_devices++] = pci_base;
++
++ if (nexus->num_devices == nexus->num_allocated_elems) {
++ struct pci_device **new_devs;
++ size_t new_num_elems = nexus->num_allocated_elems * 2;
++
++ new_devs = realloc(nexus->devlist,
++ new_num_elems * sizeof (struct pci_device *));
++ if (new_devs == NULL)
++ return (rval);
++ (void) memset(&new_devs[nexus->num_devices], 0,
++ nexus->num_allocated_elems *
++ sizeof (struct pci_device *));
++ nexus->num_allocated_elems = new_num_elems;
++ nexus->devlist = new_devs;
++ }
++#endif
++
+ /*
+ * Accommodate devices which state their
+ * multi-functionality only in their function 0 config
+@@ -502,7 +583,13 @@
+ int pci_node = 0;
+ int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
+ int domain = 0;
++#ifdef __sparc
++ int bus_range_found = 0;
++ int device_type_found = 0;
++ di_prom_prop_t prom_prop;
++#endif
+
++
+ #ifdef DEBUG
+ nexus_name = di_devfs_minor_path(minor);
+ fprintf(stderr, "-- device name: %s\n", nexus_name);
+@@ -519,11 +606,17 @@
+
+ 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);
++ if (numval == 1) {
++ if (strncmp(strings, "pci", 3) != 0)
++ /* not a PCI node, bail */
++ return (DI_WALK_CONTINUE);
++ else {
++ pci_node = 1;
++#ifdef __sparc
++ device_type_found = 1;
++#endif
++ }
+ }
+- pci_node = 1;
+ }
+ else if (strcmp(prop_name, "class-code") == 0) {
+ /* not a root bus node, bail */
+@@ -534,9 +627,12 @@
+ if (numval == 2) {
+ first_bus = ints[0];
+ last_bus = ints[1];
++#ifdef __sparc
++ bus_range_found = 1;
++#endif
+ }
+ }
+- else if (strcmp(prop_name, "pciseg") == 0) {
++ else if (strcmp(prop_name, "pciseg") == 0) {
+ numval = di_prop_ints(prop, &ints);
+ if (numval == 1) {
+ domain = ints[0];
+@@ -544,10 +640,30 @@
+ }
+ }
+
+-#ifdef __x86 /* sparc pci nodes don't have the device_type set */
++#ifdef __sparc
++ if ((!device_type_found) && di_phdl) {
++ numval = di_prom_prop_lookup_strings(di_phdl, di_node,
++ "device_type", &strings);
++ if (numval == 1) {
++ if (strncmp(strings, "pci", 3) != 0)
++ return (DI_WALK_CONTINUE);
++ else
++ pci_node = 1;
++ }
++ }
++
++ if ((!bus_range_found) && di_phdl) {
++ numval = di_prom_prop_lookup_ints(di_phdl, di_node,
++ "bus-range", &ints);
++ if (numval == 2) {
++ first_bus = ints[0];
++ last_bus = ints[1];
++ }
++ }
++#endif
++
+ if (pci_node != 1)
+ return (DI_WALK_CONTINUE);
+-#endif
+
+ /* we have a PCI root bus node. */
+ nexus = calloc(1, sizeof(nexus_t));
+@@ -560,6 +676,18 @@
+ nexus->last_bus = last_bus;
+ nexus->domain = domain;
+
++#ifdef __sparc
++ if ((nexus->devlist = calloc(INITIAL_NUM_DEVICES,
++ sizeof (struct pci_device *))) == NULL) {
++ (void) fprintf(stderr, "Error allocating memory for nexus devlist: %s\n",
++ strerror(errno));
++ free (nexus);
++ return (DI_WALK_TERMINATE);
++ }
++ nexus->num_allocated_elems = INITIAL_NUM_DEVICES;
++ nexus->num_devices = 0;
++#endif
++
+ nexus_name = di_devfs_minor_path(minor);
+ if (nexus_name == NULL) {
+ (void) fprintf(stderr, "Error getting nexus path: %s\n",
+@@ -692,6 +820,11 @@
+
+ len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®buf);
+
++#ifdef __sparc
++ if ((len <= 0) && di_phdl)
++ len = di_prom_prop_lookup_ints(di_phdl, node, "reg", ®buf);
++#endif
++
+ if (len <= 0) {
+ #ifdef DEBUG
+ fprintf(stderr, "error = %x\n", errno);
+@@ -721,8 +854,7 @@
+ static int
+ pci_device_solx_devfs_probe( struct pci_device * dev )
+ {
+- uint8_t config[256];
+- int err;
++ int err = 0;
+ di_node_t rnode = DI_NODE_NIL;
+ i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
+ int *regbuf;
+@@ -735,49 +867,43 @@
+ (struct pci_device_private *) dev;
+ nexus_t *nexus;
+
++#ifdef __sparc
++ if ( (nexus = find_nexus_for_dev(dev)) == NULL )
++#else
+ if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
++#endif
+ return ENODEV;
+
+- err = pci_device_solx_devfs_read( dev, config, 0, 256, & bytes );
+-
+- if ( bytes >= 64 ) {
+-
+- dev->vendor_id = (uint16_t)config[0] + ((uint16_t)config[1] << 8);
+- dev->device_id = (uint16_t)config[2] + ((uint16_t)config[3] << 8);
+- dev->device_class = (uint32_t)config[9] +
+- ((uint32_t)config[10] << 8) +
+- ((uint16_t)config[11] << 16);
+-
+- /*
+- * device class code is already there.
+- * see probe_dev function.
+- */
+- dev->revision = config[8];
+- dev->subvendor_id = (uint16_t)config[44] + ((uint16_t)config[45] << 8);
+- dev->subdevice_id = (uint16_t)config[46] + ((uint16_t)config[47] << 8);
+- dev->irq = config[60];
+-
+- priv->header_type = config[14];
+- /*
+- * starting to find if it is MEM/MEM64/IO
+- * using libdevinfo
+- */
+- if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
+- err = errno;
+- (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
+- } else {
+- args.bus = dev->bus;
+- args.dev = dev->dev;
+- args.func = dev->func;
+- (void) di_walk_node(rnode, DI_WALK_CLDFIRST,
+- (void *)&args, find_target_node);
+- }
++ /*
++ * starting to find if it is MEM/MEM64/IO
++ * using libdevinfo
++ */
++ if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
++ err = errno;
++ (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
++ } else {
++ args.bus = dev->bus;
++ args.dev = dev->dev;
++ args.func = dev->func;
++ (void) di_walk_node(rnode, DI_WALK_CLDFIRST,
++ (void *)&args, find_target_node);
+ }
++
+ if (args.node != DI_NODE_NIL) {
+ int *prop;
++#ifdef __sparc
++ di_minor_t minor;
++#endif
+
+ priv->is_primary = 0;
+
++#ifdef __sparc
++ if (minor = di_minor_next(args.node, DI_MINOR_NIL))
++ MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor);
++ else
++ MAPPING_DEV_PATH(dev) = NULL;
++#endif
++
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY,
+ args.node, "primary-controller", &prop) >= 1) {
+ if (prop[0])
+@@ -792,6 +918,12 @@
+ "assigned-addresses",
+ ®buf);
+
++#ifdef __sparc
++ if ((len <= 0) && di_phdl) {
++ len = di_prom_prop_lookup_ints(di_phdl, args.node,
++ "assigned-addresses", ®buf);
++ }
++#endif
+ }
+
+
+@@ -927,8 +1059,14 @@
+ pcitool_reg_t cfg_prg;
+ int err = 0;
+ int i = 0;
+- nexus_t *nexus = find_nexus_for_bus(dev->domain, dev->bus);
++ nexus_t *nexus;
+
++#ifdef __sparc
++ nexus = find_nexus_for_dev(dev);
++#else
++ nexus = find_nexus_for_bus(dev->domain, dev->bus);
++#endif
++
+ *bytes_read = 0;
+
+ if ( nexus == NULL ) {
+@@ -979,8 +1117,14 @@
+ pcitool_reg_t cfg_prg;
+ int err = 0;
+ int cmd;
+- nexus_t *nexus = find_nexus_for_bus(dev->domain, dev->bus);
++ nexus_t *nexus;
+
++#ifdef __sparc
++ nexus = find_nexus_for_dev(dev);
++#else
++ nexus = find_nexus_for_bus(dev->domain, dev->bus);
++#endif
++
+ if ( bytes_written != NULL ) {
+ *bytes_written = 0;
+ }
+@@ -993,15 +1137,19 @@
+ switch (size) {
+ case 1:
+ cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
++ cfg_prg.data = *((uint8_t *)data);
+ break;
+ case 2:
+ cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN;
++ cfg_prg.data = *((uint16_t *)data);
+ break;
+ case 4:
+ cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
++ cfg_prg.data = *((uint32_t *)data);
+ break;
+ case 8:
+ cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN;
++ cfg_prg.data = *((uint64_t *)data);
+ break;
+ default:
+ return EINVAL;
+@@ -1011,7 +1159,6 @@
+ cfg_prg.func_no = dev->func;
+ cfg_prg.barnum = 0;
+ cfg_prg.user_version = PCITOOL_USER_VERSION;
+- cfg_prg.data = *((uint64_t *)data);
+
+ /*
+ * Check if this device is bridge device.
+@@ -1048,6 +1195,24 @@
+ ? (PROT_READ | PROT_WRITE) : PROT_READ;
+ int err = 0;
+
++#ifdef __sparc
++ char map_dev[128];
++ int map_fd;
++
++ if (MAPPING_DEV_PATH(dev))
++ snprintf(map_dev, sizeof (map_dev), "%s%s", "/devices", MAPPING_DEV_PATH(dev));
++ else
++ strcpy (map_dev, "/dev/fb0");
++
++ if ((map_fd = open(map_dev, O_RDWR)) < 0) {
++ err = errno;
++ (void) fprintf(stderr, "can not open %s: %s\n", map_dev,
++ strerror(errno));
++ return err;
++ }
++
++ map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
++#else
+ /*
+ * Still used xsvc to do the user space mapping
+ */
+@@ -1061,6 +1226,8 @@
+ }
+
+ map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base);
++#endif
++
+ if (map->memory == MAP_FAILED) {
+ err = errno;
+
+@@ -1068,6 +1235,10 @@
+ map->base, strerror(errno));
+ }
+
++#ifdef __sparc
++ close (map_fd);
++#endif
++
+ return err;
+ }
+ static int pci_device_solx_devfs_boot_vga(struct pci_device *dev)