/*
* (C) Copyright IBM Corporation 2006
+ * Copyright (c) 2007, 2009, 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 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
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
-#include <dirent.h>
#include <errno.h>
#include <sys/pci.h>
-#include <assert.h>
#include <libdevinfo.h>
#include "pci_tools.h"
#include "pciaccess.h"
#include "pciaccess_private.h"
+/* #define DEBUG */
+
#define MAX_DEVICES 256
-#define CELL_NUMS_1275 (sizeof(pci_regspec_t)/sizeof(uint_t))
+#define CELL_NUMS_1275 (sizeof(pci_regspec_t) / sizeof(uint_t))
typedef union {
uint8_t bytes[16 * sizeof (uint32_t)];
typedef struct nexus {
int fd;
- int domain;
+ int first_bus;
+ int last_bus;
+ 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;
/*
# 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);
};
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;
}
}
return NULL;
}
-static uint32_t
-get_config_hdr_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset,
- uint8_t size)
-{
- uint32_t value = 0;
-
- while (size-- > 0) {
- value = (value << 8) + config_hdr_p->bytes[offset + size];
- }
-
- return value;
-}
-
-#define GET_CONFIG_VAL_8(offset) \
- (config_hdr.bytes[offset])
+#define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset])
#define GET_CONFIG_VAL_16(offset) \
- (uint16_t)get_config_hdr_value(&config_hdr, offset, 2)
+ (uint16_t) (GET_CONFIG_VAL_8(offset) + (GET_CONFIG_VAL_8(offset+1) << 8))
#define GET_CONFIG_VAL_32(offset) \
- (uint32_t)get_config_hdr_value(&config_hdr, offset, 4)
+ (uint32_t) (GET_CONFIG_VAL_8(offset) + \
+ (GET_CONFIG_VAL_8(offset+1) << 8) + \
+ (GET_CONFIG_VAL_8(offset+2) << 16) + \
+ (GET_CONFIG_VAL_8(offset+3) << 24))
/*
* Release all the resources
pci_system_solx_devfs_destroy( void )
{
/*
- * the memory allocated in create routines
- * will be freed in pci_system_init
- * It is more reasonable to free them here
+ * The memory allocated for pci_sys & devices in create routines
+ * will be freed in pci_system_cleanup.
+ * Need to free system-specific allocations here.
*/
nexus_t *nexus, *next;
for (nexus = nexus_list ; nexus != NULL ; nexus = next) {
next = nexus->next;
close(nexus->fd);
+ free(nexus->path);
free(nexus);
}
nexus_list = NULL;
* Attempt to access PCI subsystem using Solaris's devfs interface.
* Solaris version
*/
-int
+_pci_hidden int
pci_system_solx_devfs_create( void )
{
int err = 0;
*/
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) {
+
+ if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
err = errno;
(void) fprintf(stderr, "di_init() failed: %s\n",
strerror(errno));
prg_p->data = 0;
prg_p->user_version = PCITOOL_USER_VERSION;
+ errno = 0;
if (((rval = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
(prg_p->data == 0xffffffff)) {
/*
* 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;
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
int fd;
char nexus_path[MAXPATHLEN];
+ di_prop_t prop;
+ 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) {
}
snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name);
+ di_devfs_path_free(nexus_name);
+
+#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++;
+ nexus->path = strdup(nexus_path);
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;
nexus_path, strerror(errno));
free(nexus);
}
- di_devfs_path_free(nexus_name);
return DI_WALK_CONTINUE;
}
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;
rval = 0;
}
}
- if (pci_sys->num_devices > MAX_DEVICES) {
- (void) fprintf(stderr, "pci devices reach maximum number\n");
- }
return (rval);
}
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")) {
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
{
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 =
* using libdevinfo
*/
if ((rnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
- (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
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);
- di_fini(rnode);
}
}
if (args.node != DI_NODE_NIL) {
/*
- * It will success for sure, because it was
+ * It will succeed for sure, because it was
* successfully called in find_target_node
*/
len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
}
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);
}
/*
- * Solaris version: read the ROM data
+ * Solaris version: read the VGA ROM data
*/
static int
pci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer )
{
- void *prom = MAP_FAILED;
+ int err;
+ struct pci_device_mapping prom = {
+ .base = 0xC0000,
+ .size = dev->rom_size,
+ .flags = 0
+ };
- if (xsvc_fd < 0) {
- if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) {
- (void) fprintf(stderr, "can not open xsvc driver\n");
+ err = pci_device_solx_devfs_map_range(dev, &prom);
+ if (err == 0) {
+ (void) bcopy(prom.memory, buffer, dev->rom_size);
- return (-1);
+ if (munmap(prom.memory, dev->rom_size) == -1) {
+ err = errno;
}
}
-
- prom = mmap(NULL, dev->rom_size,
- PROT_READ, MAP_SHARED,
- xsvc_fd, 0xC0000);
-
- if (prom == MAP_FAILED) {
- (void) fprintf(stderr, "map rom base =0xC0000 failed");
- return (-1);
- }
- (void) bcopy(prom, buffer, dev->rom_size);
-
- /*
- * Still used xsvc to do the user space mapping
- */
- return (0);
+ return err;
}
/*
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;
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,
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;
cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN;
break;
default:
- assert(0);
+ return EINVAL;
}
cfg_prg.bus_no = dev->bus;
cfg_prg.dev_no = dev->dev;
? (PROT_READ | PROT_WRITE) : PROT_READ;
int err = 0;
+ /*
+ * Still used xsvc to do the user space mapping
+ */
if (xsvc_fd < 0) {
if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) {
- (void) fprintf(stderr, "can not open xsvc driver\n");
- return errno;
+ err = errno;
+ (void) fprintf(stderr, "can not open /dev/xsvc: %s\n",
+ strerror(errno));
+ return err;
}
}
if (map->memory == MAP_FAILED) {
err = errno;
- (void) fprintf(stderr, "map rom region =%llx failed", map->base);
+ (void) fprintf(stderr, "map rom region =%llx failed: %s\n",
+ map->base, strerror(errno));
}
return err;