/*
* (C) Copyright IBM Corporation 2006
+ * Copyright (c) 2007, 2009, 2011, Oracle and/or its affiliates.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* DEALINGS IN THE SOFTWARE.
*/
/*
- * 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
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, and/or sell copies of the Software, and to permit persons
- * to whom the Software is furnished to do so, provided that the above
- * copyright notice(s) and this permission notice appear in all copies of
- * the Software and that both the above copyright notice(s) and this
- * permission notice appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
- * 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.
- *
- * Except as contained in this notice, the name of a copyright holder
- * shall not be used in advertising or otherwise to promote the sale, use
- * or other dealings in this Software without prior written authorization
- * of the copyright holder.
- */
-/*
* Solaris devfs interfaces
*/
/* #define DEBUG */
-#define MAX_DEVICES 256
+#define INITIAL_NUM_DEVICES 256
#define CELL_NUMS_1275 (sizeof(pci_regspec_t) / sizeof(uint_t))
typedef union {
int fd;
int first_bus;
int last_bus;
- const char *path; /* for errors/debugging; fd is all we need */
+ 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;
const void * data, pciaddr_t offset, pciaddr_t size,
pciaddr_t * bytes_written );
-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);
};
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;
}
}
next = nexus->next;
close(nexus->fd);
free(nexus->path);
+ free(nexus->dev_path);
free(nexus);
}
nexus_list = NULL;
{
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 ((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 ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
err = errno;
+ (void) fprintf(stderr, "di_init() failed: %s\n",
+ strerror(errno));
+ return (err);
}
- if (err != 0) {
- if (pci_sys != NULL) {
- free(pci_sys->devices);
- free(pci_sys);
- pci_sys = NULL;
- }
+ if ((devices = calloc(INITIAL_NUM_DEVICES,
+ sizeof (struct pci_device_private))) == NULL) {
+ err = errno;
+ di_fini(di_node);
+ return (err);
+ }
+
+ 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);
}
* 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;
* 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;
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
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
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;
- const 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];
di_prop_t prop;
- const char *strings;
+ char *strings;
int *ints;
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);
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 */
}
nexus->first_bus = first_bus;
nexus->last_bus = last_bus;
+ nexus->domain = domain;
nexus_name = di_devfs_minor_path(minor);
if (nexus_name == NULL) {
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",
if ((fd = open(nexus_path, O_RDWR)) >= 0) {
nexus->fd = fd;
- if ((do_probe(nexus, pci_sys) != 0) && (errno != ENXIO)) {
+ nexus->path = strdup(nexus_path);
+ 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;
} else {
(void) fprintf(stderr, "Error opening %s: %s\n",
nexus_path, strerror(errno));
- free(nexus->path);
free(nexus);
}
* 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;
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);
}
/*
int *regbuf = NULL;
int len = 0;
uint32_t busno, funcno, devno;
- i_devnode_t *devnode;
- void *prop = DI_PROP_NIL;
- int i;
-
- devnode = (i_devnode_t *)arg;
+ i_devnode_t *devnode = (i_devnode_t *)arg;
/*
* Test the property functions, only for testing
*/
/*
+ void *prop = DI_PROP_NIL;
+
(void) fprintf(stderr, "start of node 0x%x\n", node->nodeid);
while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) {
+ int i;
(void) fprintf(stderr, "name=%s: ", di_prop_name(prop));
len = 0;
if (!strcmp(di_prop_name(prop), "reg")) {
{
uint8_t config[256];
int err;
- di_node_t rnode;
- i_devnode_t args;
+ di_node_t rnode = DI_NODE_NIL;
+ i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
int *regbuf;
pci_regspec_t *reg;
int i;
pciaddr_t bytes;
int len = 0;
+ uint ent = 0;
err = pci_device_solx_devfs_read( dev, config, 0, 256, & bytes );
- args.node = DI_NODE_NIL;
if ( bytes >= 64 ) {
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;
dev->vendor_id = (uint16_t)config[0] + ((uint16_t)config[1] << 8);
dev->device_id = (uint16_t)config[2] + ((uint16_t)config[3] << 8);
* 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 {
args.func = dev->func;
(void) di_walk_node(rnode, DI_WALK_CLDFIRST,
(void *)&args, find_target_node);
- di_fini(rnode);
}
}
if (args.node != DI_NODE_NIL) {
}
if (len <= 0)
- return (err);
+ goto cleanup;
/*
}
/*
- * solaris has its own BAR index. To be sure that
- * Xorg has the same BAR number as solaris. ????
+ * Solaris has its own BAR index.
+ * Linux give two region slot for 64 bit address.
*/
for (i = 0; i < len; i = i + CELL_NUMS_1275) {
- int ent = i/CELL_NUMS_1275;
reg = (pci_regspec_t *)®buf[i];
+ ent = reg->pci_phys_hi & 0xff;
+ /*
+ * G35 broken in BAR0
+ */
+ ent = (ent - PCI_CONF_BASE0) >> 2;
+ if (ent >= 6) {
+ fprintf(stderr, "error ent = %d\n", ent);
+ break;
+ }
/*
* non relocatable resource is excluded
dev->regions[ent].is_prefetchable = 1;
}
+
+ /*
+ * We split the shift count 32 into two 16 to
+ * avoid the complaining of the compiler
+ */
+ dev->regions[ent].base_addr = reg->pci_phys_low +
+ ((reg->pci_phys_mid << 16) << 16);
+ dev->regions[ent].size = reg->pci_size_low +
+ ((reg->pci_size_hi << 16) << 16);
+
switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
case PCI_ADDR_IO:
dev->regions[ent].is_IO = 1;
break;
case PCI_ADDR_MEM64:
dev->regions[ent].is_64 = 1;
+ /*
+ * Skip one slot for 64 bit address
+ */
break;
}
-
- /*
- * We split the shift count 32 into two 16 to
- * avoid the complaining of the compiler
- */
- dev->regions[ent].base_addr = reg->pci_phys_low +
- ((reg->pci_phys_mid << 16) << 16);
- dev->regions[ent].size = reg->pci_size_low +
- ((reg->pci_size_hi << 16) << 16);
}
+ cleanup:
+ if (rnode != DI_NODE_NIL) {
+ di_fini(rnode);
+ }
return (err);
}
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;
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;