diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2012-03-09 21:02:11 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2012-03-09 21:02:11 +0000 |
commit | fdaa6ab556a8914edcb6dbe9da49821fd6c48b3e (patch) | |
tree | c6d814653ce0456e948c23f20800af1df73da128 /lib/libpciaccess/src | |
parent | 79db6e4960cdb7facb6143b780c692265fc09c88 (diff) |
Update to libpciaccess 0.13. Tested by shadchin@
Diffstat (limited to 'lib/libpciaccess/src')
-rw-r--r-- | lib/libpciaccess/src/Makefile.am | 5 | ||||
-rw-r--r-- | lib/libpciaccess/src/Makefile.in | 33 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_bridge.c | 10 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_capability.c | 10 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_device_name.c | 35 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_init.c | 12 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_interface.c | 92 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_io.c | 13 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_iterator.c | 30 | ||||
-rw-r--r-- | lib/libpciaccess/src/freebsd_pci.c | 14 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_devmem.c | 18 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_devmem.h | 2 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_sysfs.c | 179 | ||||
-rw-r--r-- | lib/libpciaccess/src/netbsd_pci.c | 2 | ||||
-rw-r--r-- | lib/libpciaccess/src/openbsd_pci.c | 157 | ||||
-rw-r--r-- | lib/libpciaccess/src/pciaccess_private.h | 15 | ||||
-rw-r--r-- | lib/libpciaccess/src/solx_devfs.c | 667 |
17 files changed, 888 insertions, 406 deletions
diff --git a/lib/libpciaccess/src/Makefile.am b/lib/libpciaccess/src/Makefile.am index 2cf8a028f..13a7d94b8 100644 --- a/lib/libpciaccess/src/Makefile.am +++ b/lib/libpciaccess/src/Makefile.am @@ -1,4 +1,4 @@ -# +# # (C) Copyright IBM Corporation 2006 # All Rights Reserved. # @@ -43,6 +43,7 @@ endif if OPENBSD OS_SUPPORT = openbsd_pci.c +# VGA Arbiter code is included in openbsd_pci.c endif if SOLARIS @@ -69,4 +70,4 @@ libpciaccess_la_SOURCES = common_bridge.c \ libpciaccess_la_LIBADD = $(PCIACCESS_LIBS) -libpciaccess_la_LDFLAGS = -version-number 0:10:8 -no-undefined +libpciaccess_la_LDFLAGS = -version-number 0:11:0 -no-undefined diff --git a/lib/libpciaccess/src/Makefile.in b/lib/libpciaccess/src/Makefile.in index fbf6a3f1a..0154ed51f 100644 --- a/lib/libpciaccess/src/Makefile.in +++ b/lib/libpciaccess/src/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -# +# # (C) Copyright IBM Corporation 2006 # All Rights Reserved. # @@ -63,7 +63,9 @@ subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_define_dir.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(install_sh) -d @@ -135,6 +137,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BASE_CFLAGS = @BASE_CFLAGS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ @@ -142,24 +145,20 @@ CHANGELOG_CMD = @CHANGELOG_CMD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CWARNFLAGS = @CWARNFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ FILE_MAN_DIR = @FILE_MAN_DIR@ FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ FREEBSD_FALSE = @FREEBSD_FALSE@ @@ -172,6 +171,7 @@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -180,21 +180,27 @@ LIB_MAN_DIR = @LIB_MAN_DIR@ LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ LINUX_FALSE = @LINUX_FALSE@ LINUX_TRUE = @LINUX_TRUE@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SUBSTS = @MAN_SUBSTS@ MISC_MAN_DIR = @MISC_MAN_DIR@ MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ NETBSD_FALSE = @NETBSD_FALSE@ NETBSD_TRUE = @NETBSD_TRUE@ +NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENBSD_FALSE = @OPENBSD_FALSE@ OPENBSD_TRUE = @OPENBSD_TRUE@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -216,13 +222,11 @@ STRICT_CFLAGS = @STRICT_CFLAGS@ STRIP = @STRIP@ VERSION = @VERSION@ XORG_MAN_PAGE = @XORG_MAN_PAGE@ +ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -271,6 +275,7 @@ lib_LTLIBRARIES = libpciaccess.la @LINUX_TRUE@OS_SUPPORT = linux_sysfs.c linux_devmem.c linux_devmem.h @NETBSD_TRUE@OS_SUPPORT = netbsd_pci.c @OPENBSD_TRUE@OS_SUPPORT = openbsd_pci.c +# VGA Arbiter code is included in openbsd_pci.c @SOLARIS_TRUE@OS_SUPPORT = solx_devfs.c pci_tools.h @FREEBSD_TRUE@VGA_ARBITER = common_vgaarb_stub.c @GNU_TRUE@VGA_ARBITER = common_vgaarb_stub.c @@ -290,7 +295,7 @@ libpciaccess_la_SOURCES = common_bridge.c \ $(OS_SUPPORT) libpciaccess_la_LIBADD = $(PCIACCESS_LIBS) -libpciaccess_la_LDFLAGS = -version-number 0:10:8 -no-undefined +libpciaccess_la_LDFLAGS = -version-number 0:11:0 -no-undefined all: all-am .SUFFIXES: diff --git a/lib/libpciaccess/src/common_bridge.c b/lib/libpciaccess/src/common_bridge.c index 871c1f66c..4a067b937 100644 --- a/lib/libpciaccess/src/common_bridge.c +++ b/lib/libpciaccess/src/common_bridge.c @@ -25,7 +25,7 @@ /** * \file common_bridge.c * Support routines used to process PCI header information for bridges. - * + * * \author Ian Romanick <idr@us.ibm.com> */ @@ -75,7 +75,7 @@ read_bridge_info( struct pci_device_private * priv ) info = malloc(sizeof(*info)); if (info != NULL) { - pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, + pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 0x40 - 0x18, & bytes ); info->primary_bus = buf[0x18]; @@ -239,7 +239,7 @@ pci_device_get_pcmcia_bridge_info( struct pci_device * dev ) /** * Determine the primary, secondary, and subordinate buses for a bridge - * + * * Determines the IDs of the primary, secondary, and subordinate buses for * a specified bridge. Not all bridges directly store this information * (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but @@ -252,7 +252,7 @@ pci_device_get_pcmcia_bridge_info( struct pci_device * dev ) * \return * On success, zero is returned. If \c dev is not a bridge, \c ENODEV is * returned. - * + * * \bug * Host bridges are handled the same way as PCI-to-ISA bridges. This is * almost certainly not correct. @@ -265,7 +265,7 @@ pci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus, /* If the device isn't a bridge, return an error. */ - + if (((dev->device_class >> 16) & 0x0ff) != 0x06) { return ENODEV; } diff --git a/lib/libpciaccess/src/common_capability.c b/lib/libpciaccess/src/common_capability.c index 3963db1cc..488743dd6 100644 --- a/lib/libpciaccess/src/common_capability.c +++ b/lib/libpciaccess/src/common_capability.c @@ -25,7 +25,7 @@ /** * \file common_capability.c * Platform independent PCI capability related routines. - * + * * In addition to including the interface glue for \c pci_device_get_agp_info, * this file also contains a generic implementation of that function. * @@ -51,7 +51,7 @@ * Once more than just the AGP capability is supported, the body of each of * the cases in the capability processing loop should probably be broken out * into its own function. - * + * * \todo * Once more than just the AGP capability is supported, some care will need * to be taken in partial failure cases. If, say, the first capability is @@ -79,7 +79,7 @@ pci_fill_capabilities_generic( struct pci_device * dev ) if ( (status & 0x0010) == 0 ) { return ENOSYS; } - + err = pci_device_cfg_read_u8( dev, & cap_offset, 52 ); if ( err ) { return err; @@ -101,7 +101,7 @@ pci_fill_capabilities_generic( struct pci_device * dev ) if ( err ) { return err; } - + switch ( cap_id ) { case 2: { struct pci_agp_info * agp_info; @@ -187,7 +187,7 @@ pci_device_get_agp_info( struct pci_device * dev ) if ( dev == NULL ) { return NULL; } - + if ( dev_priv->agp == NULL ) { (void) (*pci_sys->methods->fill_capabilities)( dev ); } diff --git a/lib/libpciaccess/src/common_device_name.c b/lib/libpciaccess/src/common_device_name.c index 896a8a311..b2765dd2c 100644 --- a/lib/libpciaccess/src/common_device_name.c +++ b/lib/libpciaccess/src/common_device_name.c @@ -69,7 +69,7 @@ pci_id_file_open(void) #define pci_id_file_gets(l, s, f) gzgets(f, l, s) #define pci_id_file_close(f) gzclose(f) #else -typedef FILE pci_id_file; +typedef FILE * pci_id_file; #define pci_id_file_open() fopen(PCIIDS_PATH "/pci.ids", "r") #define pci_id_file_gets(l, s, f) fgets(l, s, f) #define pci_id_file_close(f) fclose(f) @@ -77,7 +77,7 @@ typedef FILE pci_id_file; /** * Node for sorting vendor IDs. - * + * * Each structure forms an internal node of an n-way tree. Each node selects * \c pci_id_node::bits number of bits from the vendor ID. Starting from the * root of the tree, a slice of the low-order bits of the vendor ID are @@ -86,7 +86,7 @@ typedef FILE pci_id_file; * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID * have been used), the \c pci_id_node::children is actually an array of * pointers to \c pci_id_leaf structures. - * + * * \todo * Determine if there is a cleaner way (in the source code) to have the * \c children array change type based on whether the node is internal or @@ -105,7 +105,7 @@ struct pci_id_node { struct pci_id_leaf { uint16_t vendor; const char * vendor_name; - + size_t num_devices; struct pci_device_leaf * devices; }; @@ -122,7 +122,7 @@ _pci_hidden struct pci_id_node * tree = NULL; /** * Get a pointer to the leaf node for a vendor ID. - * + * * If the vendor ID does not exist in the tree, it is added. */ static struct pci_id_leaf * @@ -159,7 +159,7 @@ insert( uint16_t vendor ) n->children[ idx ] = child; } else { - struct pci_id_leaf * leaf = + struct pci_id_leaf * leaf = calloc( 1, sizeof( struct pci_id_leaf ) ); leaf->vendor = vendor; @@ -177,9 +177,9 @@ insert( uint16_t vendor ) /** * Populate a vendor node with all the devices associated with that vendor - * + * * \param vend Vendor node that is to be filled from the pci.ids file. - * + * * \todo * The parsing in this function should be more rhobust. There are some error * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled @@ -189,7 +189,7 @@ insert( uint16_t vendor ) static void populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) { - pci_id_file * f; + pci_id_file f; char buf[128]; unsigned vendor = PCI_MATCH_ANY; @@ -202,7 +202,7 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) } f = pci_id_file_open(); - + /* If the pci.ids file could not be opened, there's nothing we can do. */ if (f == NULL) { @@ -223,14 +223,14 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) break; } } - + if ( !isxdigit( buf[ num_tabs + 0 ] ) || !isxdigit( buf[ num_tabs + 1 ] ) || !isxdigit( buf[ num_tabs + 2 ] ) || !isxdigit( buf[ num_tabs + 3 ] ) ) { continue; } - + new_line = strchr( buf, '\n' ); if ( new_line != NULL ) { *new_line = '\0'; @@ -263,13 +263,13 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) struct pci_device_leaf * d; struct pci_device_leaf * dev; struct pci_device_leaf * last_dev; - + d = realloc( vend->devices, (vend->num_devices + 1) * sizeof( struct pci_device_leaf ) ); if ( d == NULL ) { - return; + goto cleanup; } last_dev = & d[ vend->num_devices - 1 ]; @@ -279,7 +279,7 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) if ( num_tabs == 1 ) { dev->id.vendor_id = vend->vendor; - dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ], + dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 ); dev->id.subvendor_id = PCI_MATCH_ANY; dev->id.subdevice_id = PCI_MATCH_ANY; @@ -295,13 +295,14 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 ); - dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ], + dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ], NULL, 16 ); dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] ); } } } - + + cleanup: pci_id_file_close( f ); } diff --git a/lib/libpciaccess/src/common_init.c b/lib/libpciaccess/src/common_init.c index 89c56ad98..5e91c2765 100644 --- a/lib/libpciaccess/src/common_init.c +++ b/lib/libpciaccess/src/common_init.c @@ -39,7 +39,7 @@ _pci_hidden struct pci_system * pci_sys; /** * Initialize the PCI subsystem for access. - * + * * \return * Zero on success or an errno value on failure. In particular, if no * platform-specific initializers are available, \c ENOSYS will be returned. @@ -51,7 +51,7 @@ int pci_system_init( void ) { int err = ENOSYS; - + #ifdef linux err = pci_system_linux_sysfs_create(); #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) @@ -79,7 +79,7 @@ pci_system_init_dev_mem(int fd) /** * Shutdown all access to the PCI subsystem. - * + * * \sa pci_system_init */ void @@ -103,7 +103,7 @@ pci_system_cleanup( void ) free( (char *) pci_sys->devices[i].device_string ); free( (char *) pci_sys->devices[i].agp ); - + pci_sys->devices[i].device_string = NULL; pci_sys->devices[i].agp = NULL; @@ -111,7 +111,7 @@ pci_system_cleanup( void ) (*pci_sys->methods->destroy_device)( & pci_sys->devices[i].base ); } } - + free( pci_sys->devices ); pci_sys->devices = NULL; pci_sys->num_devices = 0; @@ -121,7 +121,7 @@ pci_system_cleanup( void ) if ( pci_sys->methods->destroy != NULL ) { (*pci_sys->methods->destroy)(); } - + free( pci_sys ); pci_sys = NULL; } diff --git a/lib/libpciaccess/src/common_interface.c b/lib/libpciaccess/src/common_interface.c index 4af772ac3..6dccf8eaf 100644 --- a/lib/libpciaccess/src/common_interface.c +++ b/lib/libpciaccess/src/common_interface.c @@ -86,14 +86,14 @@ /** * Read a device's expansion ROM. - * + * * Reads the device's expansion ROM and stores the data in the memory pointed * to by \c buffer. The buffer must be at least \c pci_device::rom_size * bytes. * * \param dev Device whose expansion ROM is to be read. * \param buffer Memory in which to store the ROM. - * + * * \return * Zero on success or an \c errno value on failure. */ @@ -125,7 +125,7 @@ pci_device_is_boot_vga( struct pci_device * dev ) /** * Probe a PCI device to determine if a kernel driver is attached. - * + * * \param dev Device to query * \return * Zero if no driver attached, 1 if attached kernel drviver @@ -140,14 +140,14 @@ pci_device_has_kernel_driver( struct pci_device * dev ) /** * Probe a PCI device to learn information about the device. - * + * * Probes a PCI device to learn various information about the device. Before * calling this function, the only public fields in the \c pci_device * structure that have valid values are \c pci_device::domain, * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func. - * + * * \param dev Device to be probed. - * + * * \return * Zero on success or an \c errno value on failure. */ @@ -173,7 +173,7 @@ pci_device_probe( struct pci_device * dev ) * \param dev Device whose memory region is to be mapped. * \param region Region, on the range [0, 5], that is to be mapped. * \param write_enable Map for writing (non-zero). - * + * * \return * Zero on success or an \c errno value on failure. * @@ -194,7 +194,7 @@ pci_device_map_region(struct pci_device * dev, unsigned region, if (dev->regions[region].memory != NULL) { return 0; } - + return pci_device_map_range(dev, dev->regions[region].base_addr, dev->regions[region].size, map_flags, &dev->regions[region].memory); @@ -213,7 +213,7 @@ pci_device_map_region(struct pci_device * dev, unsigned region, * \param size Size of the range to be mapped. * \param write_enable Map for writing (non-zero). * \param addr Location to store the mapped address. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -241,7 +241,7 @@ int pci_device_map_memory_range(struct pci_device *dev, * \param size Size of the range to be mapped. * \param map_flags Flag bits controlling how the mapping is accessed. * \param addr Location to store the mapped address. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -335,7 +335,7 @@ pci_device_map_range(struct pci_device *dev, pciaddr_t base, * * \param dev Device whose memory region is to be mapped. * \param region Region, on the range [0, 5], that is to be mapped. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -374,7 +374,7 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region ) * \param dev Device whose memory is to be unmapped. * \param memory Pointer to the base of the mapped range. * \param size Size, in bytes, of the range to be unmapped. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -398,7 +398,7 @@ pci_device_unmap_memory_range(struct pci_device *dev, void *memory, * \param dev Device whose memory is to be unmapped. * \param memory Pointer to the base of the mapped range. * \param size Size, in bytes, of the range to be unmapped. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -429,17 +429,17 @@ pci_device_unmap_range(struct pci_device *dev, void *memory, return ENOENT; } - + err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]); if (!err) { const unsigned entries_to_move = (devp->num_mappings - i) - 1; - + if (entries_to_move > 0) { (void) memmove(&devp->mappings[i], &devp->mappings[i + 1], entries_to_move * sizeof(devp->mappings[0])); } - + devp->num_mappings--; devp->mappings = realloc(devp->mappings, (sizeof(devp->mappings[0]) * devp->num_mappings)); @@ -474,7 +474,7 @@ pci_device_unmap_range(struct pci_device *dev, void *memory, */ int pci_device_cfg_read( struct pci_device * dev, void * data, - pciaddr_t offset, pciaddr_t size, + pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read ) { pciaddr_t scratch; @@ -484,7 +484,7 @@ pci_device_cfg_read( struct pci_device * dev, void * data, } return pci_sys->methods->read( dev, data, offset, size, - (bytes_read == NULL) + (bytes_read == NULL) ? & scratch : bytes_read ); } @@ -495,7 +495,7 @@ pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data, { pciaddr_t bytes; int err = pci_device_cfg_read( dev, data, offset, 1, & bytes ); - + if ( (err == 0) && (bytes != 1) ) { err = ENXIO; } @@ -510,7 +510,7 @@ pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data, { pciaddr_t bytes; int err = pci_device_cfg_read( dev, data, offset, 2, & bytes ); - + if ( (err == 0) && (bytes != 2) ) { err = ENXIO; } @@ -561,7 +561,7 @@ pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data, */ int pci_device_cfg_write( struct pci_device * dev, const void * data, - pciaddr_t offset, pciaddr_t size, + pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_written ) { pciaddr_t scratch; @@ -571,7 +571,7 @@ pci_device_cfg_write( struct pci_device * dev, const void * data, } return pci_sys->methods->write( dev, data, offset, size, - (bytes_written == NULL) + (bytes_written == NULL) ? & scratch : bytes_written ); } @@ -590,7 +590,7 @@ pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data, return err; } - + int pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data, @@ -627,7 +627,7 @@ pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data, int -pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, +pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, uint32_t data, pciaddr_t offset ) { uint32_t temp; @@ -654,3 +654,47 @@ pci_device_enable(struct pci_device *dev) if (pci_sys->methods->enable) pci_sys->methods->enable(dev); } + +/** + * Map the legacy memory space for the PCI domain containing \c dev. + * + * \param dev Device whose memory region is to be mapped. + * \param base Base address of the range to be mapped. + * \param size Size of the range to be mapped. + * \param map_flags Flag bits controlling how the mapping is accessed. + * \param addr Location to store the mapped address. + * + * \returns + * Zero on success or an \c errno value on failure. + */ +int +pci_device_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size, + unsigned map_flags, void **addr) +{ + if (base > 0x100000 || base + size > 0x100000) + return EINVAL; + + if (!pci_sys->methods->map_legacy) + return ENOSYS; + + return pci_sys->methods->map_legacy(dev, base, size, map_flags, addr); +} + +/** + * Unmap the legacy memory space for the PCI domain containing \c dev. + * + * \param dev Device whose memory region is to be unmapped. + * \param addr Location of the mapped address. + * \param size Size of the range to be unmapped. + * + * \returns + * Zero on success or an \c errno value on failure. + */ +int +pci_device_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size) +{ + if (!pci_sys->methods->unmap_legacy) + return ENOSYS; + + return pci_sys->methods->unmap_legacy(dev, addr, size); +} diff --git a/lib/libpciaccess/src/common_io.c b/lib/libpciaccess/src/common_io.c index 58628b442..5b35e07d9 100644 --- a/lib/libpciaccess/src/common_io.c +++ b/lib/libpciaccess/src/common_io.c @@ -64,10 +64,15 @@ delete_io_handle(struct pci_io_handle *handle) } } - new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios - 1)); - if (new) - ios = new; num_ios--; + if (num_ios) { + new = realloc(ios, sizeof(struct pci_io_handle) * num_ios); + if (new) + ios = new; + } else { + free(ios); + ios = NULL; + } } _pci_hidden void @@ -109,7 +114,7 @@ pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size) ret = new_io_handle(); if (!ret) return NULL; - + if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) { delete_io_handle(ret); return NULL; diff --git a/lib/libpciaccess/src/common_iterator.c b/lib/libpciaccess/src/common_iterator.c index 83cade326..ccf656d20 100644 --- a/lib/libpciaccess/src/common_iterator.c +++ b/lib/libpciaccess/src/common_iterator.c @@ -25,7 +25,7 @@ /** * \file common_iterator.c * Platform independent iterator support routines. - * + * * \author Ian Romanick <idr@us.ibm.com> */ @@ -37,7 +37,7 @@ /** * Track device iteration state - * + * * \private */ struct pci_device_iterator { @@ -69,7 +69,7 @@ struct pci_device_iterator * pci_slot_match_iterator_create( const struct pci_slot_match * match ) { struct pci_device_iterator * iter; - + if ( pci_sys == NULL ) { return NULL; } @@ -105,7 +105,7 @@ struct pci_device_iterator * pci_id_match_iterator_create( const struct pci_id_match * match ) { struct pci_device_iterator * iter; - + if ( pci_sys == NULL ) { return NULL; } @@ -130,9 +130,9 @@ pci_id_match_iterator_create( const struct pci_id_match * match ) /** * Destroy an iterator previously created with \c pci_iterator_create. - * + * * \param iter Iterator to be destroyed. - * + * * \sa pci_device_next, pci_iterator_create */ void @@ -146,9 +146,9 @@ pci_iterator_destroy( struct pci_device_iterator * iter ) /** * Iterate to the next PCI device. - * + * * \param iter Device iterator returned by \c pci_device_iterate. - * + * * \return * A pointer to a \c pci_device, or \c NULL when all devices have been * iterated. @@ -172,7 +172,7 @@ pci_device_next( struct pci_device_iterator * iter ) case match_slot: { while ( iter->next_index < pci_sys->num_devices ) { - struct pci_device_private * const temp = + struct pci_device_private * const temp = & pci_sys->devices[ iter->next_index ]; iter->next_index++; @@ -184,13 +184,13 @@ pci_device_next( struct pci_device_iterator * iter ) break; } } - + break; } case match_id: { while ( iter->next_index < pci_sys->num_devices ) { - struct pci_device_private * const temp = + struct pci_device_private * const temp = & pci_sys->devices[ iter->next_index ]; iter->next_index++; @@ -198,13 +198,13 @@ pci_device_next( struct pci_device_iterator * iter ) && PCI_ID_COMPARE( iter->match.id.device_id, temp->base.device_id ) && PCI_ID_COMPARE( iter->match.id.subvendor_id, temp->base.subvendor_id ) && PCI_ID_COMPARE( iter->match.id.subdevice_id, temp->base.subdevice_id ) - && ((temp->base.device_class & iter->match.id.device_class_mask) + && ((temp->base.device_class & iter->match.id.device_class_mask) == iter->match.id.device_class) ) { d = temp; break; } } - + break; } } @@ -218,8 +218,8 @@ pci_device_find_by_slot( uint32_t domain, uint32_t bus, uint32_t dev, uint32_t func ) { struct pci_device_iterator iter; - - + + iter.next_index = 0; iter.mode = match_slot; iter.match.slot.domain = domain; diff --git a/lib/libpciaccess/src/freebsd_pci.c b/lib/libpciaccess/src/freebsd_pci.c index 4a2dcf143..d11535d83 100644 --- a/lib/libpciaccess/src/freebsd_pci.c +++ b/lib/libpciaccess/src/freebsd_pci.c @@ -90,10 +90,10 @@ struct freebsd_pci_system { /** * Map a memory region for a device using /dev/mem. - * + * * \param dev Device whose memory region is to be mapped. * \param map Parameters of the mapping that is to be created. - * + * * \return * Zero on success or an \c errno value on failure. */ @@ -101,7 +101,7 @@ static int pci_device_freebsd_map_range(struct pci_device *dev, struct pci_device_mapping *map) { - const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? (PROT_READ | PROT_WRITE) : PROT_READ; struct mem_range_desc mrd; struct mem_range_op mro; @@ -200,7 +200,7 @@ pci_device_freebsd_read( struct pci_device * dev, void * data, io.pi_reg = offset; io.pi_width = toread; - if ( ioctl( freebsd_pci_sys->pcidev, PCIOCREAD, &io ) < 0 ) + if ( ioctl( freebsd_pci_sys->pcidev, PCIOCREAD, &io ) < 0 ) return errno; memcpy(data, &io.pi_data, toread ); @@ -241,7 +241,7 @@ pci_device_freebsd_write( struct pci_device * dev, const void * data, io.pi_width = towrite; memcpy( &io.pi_data, data, towrite ); - if ( ioctl( freebsd_pci_sys->pcidev, PCIOCWRITE, &io ) < 0 ) + if ( ioctl( freebsd_pci_sys->pcidev, PCIOCWRITE, &io ) < 0 ) return errno; offset += towrite; @@ -365,7 +365,7 @@ pci_device_freebsd_probe( struct pci_device * dev ) for (i = 0; i < pci_device_freebsd_get_num_regions( dev ); i++) { bar.pbi_reg = PCIR_BAR(i); - if ( ioctl( freebsd_pci_sys->pcidev, PCIOCGETBAR, &bar ) < 0 ) + if ( ioctl( freebsd_pci_sys->pcidev, PCIOCGETBAR, &bar ) < 0 ) continue; if (PCI_BAR_IO(bar.pbi_base)) @@ -440,7 +440,7 @@ pci_device_freebsd_get_region_info( struct pci_device * dev, int region, /* * We are going to be doing evil things to the registers here - * so disable them via the command register first. + * so disable them via the command register first. */ err = pci_device_cfg_read_u16( dev, &cmd, PCIR_COMMAND ); if (err != 0) diff --git a/lib/libpciaccess/src/linux_devmem.c b/lib/libpciaccess/src/linux_devmem.c index 271e53f84..10e3bde05 100644 --- a/lib/libpciaccess/src/linux_devmem.c +++ b/lib/libpciaccess/src/linux_devmem.c @@ -25,7 +25,7 @@ /** * \file linux_devmem.c * Access PCI subsystem using Linux's the old /dev/mem interface. - * + * * \note * This is currently just a skeleton. It only includes the /dev/mem based * function for reading the device ROM. @@ -52,11 +52,11 @@ /** * Read a device's expansion ROM using /dev/mem. - * + * * \note * This function could probably be used, as-is, on other platforms that have * a /dev/mem interface. - * + * * \bugs * Before using the VGA special case code, this function should check that * VGA access are routed to the device. Right? @@ -94,7 +94,7 @@ pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) rom_size = priv->base.rom_size; PCI_ROM = 1; } - + /* Enable the device's ROM. @@ -106,15 +106,15 @@ pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) } if ((rom_base_tmp & 0x000000001) == 0) { - err = pci_device_cfg_write_u32(& priv->base, + err = pci_device_cfg_write_u32(& priv->base, rom_base_tmp | 1, 48); if (err) { return err; } } } - - + + /* Read the portion of /dev/mem that corresponds to the device's ROM. */ fd = open("/dev/mem", O_RDONLY, 0); @@ -125,7 +125,7 @@ pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) size_t bytes; for (bytes = 0; bytes < rom_size; /* empty */) { - const ssize_t got = pread(fd, buffer, rom_size - bytes, + const ssize_t got = pread(fd, buffer, rom_size - bytes, rom_base + bytes); if (got == -1) { err = errno; @@ -138,7 +138,7 @@ pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) close(fd); } - + /* Disable the device's ROM. */ if (PCI_ROM && ((rom_base_tmp & 0x000000001) == 0)) { diff --git a/lib/libpciaccess/src/linux_devmem.h b/lib/libpciaccess/src/linux_devmem.h index 2337f30b8..e69557fec 100644 --- a/lib/libpciaccess/src/linux_devmem.h +++ b/lib/libpciaccess/src/linux_devmem.h @@ -26,7 +26,7 @@ * \file linux_devmem.h * Functions and datastructures that are private to the /dev/mem based * back-end for pciaccess. - * + * * \author Ian Romanick <idr@us.ibm.com> */ diff --git a/lib/libpciaccess/src/linux_sysfs.c b/lib/libpciaccess/src/linux_sysfs.c index 1832ee7ed..9566d408f 100644 --- a/lib/libpciaccess/src/linux_sysfs.c +++ b/lib/libpciaccess/src/linux_sysfs.c @@ -1,6 +1,7 @@ /* * (C) Copyright IBM Corporation 2006 * All Rights Reserved. + * Copyright 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -44,6 +45,18 @@ #include <dirent.h> #include <errno.h> +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) +#include <sys/io.h> +#else +#define inb(x) -1 +#define inw(x) -1 +#define inl(x) -1 +#define outb(x) do {} while (0) +#define outw(x) do {} while (0) +#define outl(x) do {} while (0) +#define iopl(x) -1 +#endif + #include "config.h" #ifdef HAVE_MTRR @@ -79,7 +92,7 @@ pci_system_linux_sysfs_create( void ) /* If the directory "/sys/bus/pci/devices" exists, then the PCI subsystem * can be accessed using this interface. */ - + if ( stat( SYS_BUS_PCI, & st ) == 0 ) { pci_sys = calloc( 1, sizeof( struct pci_system ) ); if ( pci_sys != NULL ) { @@ -114,7 +127,7 @@ pci_system_linux_sysfs_create( void ) static int scan_sys_pci_filter( const struct dirent * d ) { - return !((strcmp( d->d_name, "." ) == 0) + return !((strcmp( d->d_name, "." ) == 0) || (strcmp( d->d_name, ".." ) == 0)); } @@ -122,7 +135,7 @@ scan_sys_pci_filter( const struct dirent * d ) int populate_entries( struct pci_system * p ) { - struct dirent ** devices; + struct dirent ** devices = NULL; int n; int i; int err = 0; @@ -219,7 +232,7 @@ pci_device_linux_sysfs_probe( struct pci_device * dev ) * parsing issues and non-root users can write to PCI config * registers, we use a different file in the device's sysfs * directory called "resource". - * + * * The resource file contains all of the needed information in * a format that is consistent across all platforms. Each BAR * and the expansion ROM have a single line of data containing @@ -251,9 +264,9 @@ pci_device_linux_sysfs_probe( struct pci_device * dev ) dev->regions[i].base_addr = strtoull( next, & next, 16 ); high_addr = strtoull( next, & next, 16 ); flags = strtoull( next, & next, 16 ); - + if ( dev->regions[i].base_addr != 0 ) { - dev->regions[i].size = (high_addr + dev->regions[i].size = (high_addr - dev->regions[i].base_addr) + 1; dev->regions[i].is_IO = (flags & 0x01); @@ -293,7 +306,7 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) dev->bus, dev->dev, dev->func ); - + fd = open( name, O_RDWR ); if ( fd == -1 ) { #ifdef LINUX_ROM @@ -338,7 +351,7 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) total_bytes += bytes; } - + lseek( fd, 0, SEEK_SET ); write( fd, "0", 1 ); @@ -387,7 +400,9 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data, /* If zero bytes were read, then we assume it's the end of the * config file. */ - if ( bytes <= 0 ) { + if (bytes == 0) + break; + if ( bytes < 0 ) { err = errno; break; } @@ -396,7 +411,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data, offset += bytes; data_bytes += bytes; } - + if ( bytes_read != NULL ) { *bytes_read = size - temp_size; } @@ -445,7 +460,9 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, /* If zero bytes were written, then we assume it's the end of the * config file. */ - if ( bytes <= 0 ) { + if ( bytes == 0 ) + break; + if ( bytes < 0 ) { err = errno; break; } @@ -454,7 +471,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, offset += bytes; data_bytes += bytes; } - + if ( bytes_written != NULL ) { *bytes_written = size - temp_size; } @@ -469,9 +486,9 @@ pci_device_linux_sysfs_map_range_wc(struct pci_device *dev, { char name[256]; int fd; - const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? (PROT_READ | PROT_WRITE) : PROT_READ; - const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? O_RDWR : O_RDONLY; const off_t offset = map->base - dev->regions[map->region].base_addr; @@ -500,10 +517,10 @@ pci_device_linux_sysfs_map_range_wc(struct pci_device *dev, /** * Map a memory region for a device using the Linux sysfs interface. - * + * * \param dev Device whose memory region is to be mapped. * \param map Parameters of the mapping that is to be created. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -521,9 +538,9 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, char name[256]; int fd; int err = 0; - const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? (PROT_READ | PROT_WRITE) : PROT_READ; - const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? O_RDWR : O_RDONLY; const off_t offset = map->base - dev->regions[map->region].base_addr; #ifdef HAVE_MTRR @@ -604,10 +621,10 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, /** * Unmap a memory region for a device using the Linux sysfs interface. - * + * * \param dev Device whose memory region is to be unmapped. * \param map Parameters of the mapping that is to be destroyed. - * + * * \return * Zero on success or an \c errno value on failure. * @@ -634,7 +651,7 @@ pci_device_linux_sysfs_unmap_range(struct pci_device *dev, err = pci_device_generic_unmap_range (dev, map); if (err) return err; - + #ifdef HAVE_MTRR if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { sentry.type = MTRR_TYPE_WRBACK; @@ -669,7 +686,7 @@ static void pci_device_linux_sysfs_enable(struct pci_device *dev) dev->bus, dev->dev, dev->func ); - + fd = open( name, O_RDWR ); if (fd == -1) return; @@ -691,7 +708,7 @@ static int pci_device_linux_sysfs_boot_vga(struct pci_device *dev) dev->bus, dev->dev, dev->func ); - + fd = open( name, O_RDONLY ); if (fd == -1) return 0; @@ -718,7 +735,7 @@ static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev) dev->bus, dev->dev, dev->func ); - + ret = stat(name, &dummy); if (ret < 0) return 0; @@ -765,12 +782,17 @@ pci_device_linux_sysfs_open_legacy_io(struct pci_io_handle *ret, dev = pci_device_get_parent_bridge(dev); } - /* If not, /dev/port is the best we can do */ - if (!dev) - ret->fd = open("/dev/port", O_RDWR); + /* + * You would think you'd want to use /dev/port here. Don't make that + * mistake, /dev/port only does byte-wide i/o cycles which means it + * doesn't work. If you think this is stupid, well, you're right. + */ - if (ret->fd < 0) - return NULL; + /* If we've no other choice, iopl */ + if (ret->fd < 0) { + if (iopl(3)) + return NULL; + } ret->base = base; ret->size = size; @@ -782,7 +804,8 @@ static void pci_device_linux_sysfs_close_io(struct pci_device *dev, struct pci_io_handle *handle) { - close(handle->fd); + if (handle->fd > -1) + close(handle->fd); } static uint32_t @@ -790,8 +813,11 @@ pci_device_linux_sysfs_read32(struct pci_io_handle *handle, uint32_t port) { uint32_t ret; - pread(handle->fd, &ret, 4, port + handle->base); - + if (handle->fd > -1) + pread(handle->fd, &ret, 4, port + handle->base); + else + ret = inl(port + handle->base); + return ret; } @@ -800,7 +826,10 @@ pci_device_linux_sysfs_read16(struct pci_io_handle *handle, uint32_t port) { uint16_t ret; - pread(handle->fd, &ret, 2, port + handle->base); + if (handle->fd > -1) + pread(handle->fd, &ret, 2, port + handle->base); + else + ret = inw(port + handle->base); return ret; } @@ -810,7 +839,10 @@ pci_device_linux_sysfs_read8(struct pci_io_handle *handle, uint32_t port) { uint8_t ret; - pread(handle->fd, &ret, 1, port + handle->base); + if (handle->fd > -1) + pread(handle->fd, &ret, 1, port + handle->base); + else + ret = inb(port + handle->base); return ret; } @@ -819,25 +851,93 @@ static void pci_device_linux_sysfs_write32(struct pci_io_handle *handle, uint32_t port, uint32_t data) { - pwrite(handle->fd, &data, 4, port + handle->base); + if (handle->fd > -1) + pwrite(handle->fd, &data, 4, port + handle->base); + else + outl(data, port + handle->base); } static void pci_device_linux_sysfs_write16(struct pci_io_handle *handle, uint32_t port, uint16_t data) { - pwrite(handle->fd, &data, 2, port + handle->base); + if (handle->fd > -1) + pwrite(handle->fd, &data, 2, port + handle->base); + else + outw(data, port + handle->base); } static void pci_device_linux_sysfs_write8(struct pci_io_handle *handle, uint32_t port, uint8_t data) { - pwrite(handle->fd, &data, 1, port + handle->base); + if (handle->fd > -1) + pwrite(handle->fd, &data, 1, port + handle->base); + else + outb(data, port + handle->base); +} + +static int +pci_device_linux_sysfs_map_legacy(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, unsigned map_flags, void **addr) +{ + char name[PATH_MAX]; + int flags = O_RDONLY; + int prot = PROT_READ; + int fd; + int ret=0; + + if (map_flags & PCI_DEV_MAP_FLAG_WRITABLE) { + flags = O_RDWR; /* O_RDWR != O_WRONLY | O_RDONLY */; + prot |= PROT_WRITE; + } + + /* First check if there's a legacy memory method for the device */ + while (dev) { + snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_mem", + dev->domain, dev->bus); + + fd = open(name, flags); + if (fd >= 0) + break; + + dev = pci_device_get_parent_bridge(dev); + } + + /* If not, /dev/mem is the best we can do */ + if (!dev) + fd = open("/dev/mem", flags); + + if (fd < 0) + return errno; + + *addr = mmap(NULL, size, prot, MAP_SHARED, fd, base); + if (*addr == MAP_FAILED) { + ret = errno; + } + + close(fd); + return ret; +} + +static int +pci_device_linux_sysfs_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size) +{ + return munmap(addr, size); +} + + +static void +pci_system_linux_destroy(void) +{ +#ifdef HAVE_MTRR + if (pci_sys->mtrr_fd != -1) + close(pci_sys->mtrr_fd); +#endif } static const struct pci_system_methods linux_sysfs_methods = { - .destroy = NULL, + .destroy = pci_system_linux_destroy, .destroy_device = NULL, .read_rom = pci_device_linux_sysfs_read_rom, .probe = pci_device_linux_sysfs_probe, @@ -861,4 +961,7 @@ static const struct pci_system_methods linux_sysfs_methods = { .write32 = pci_device_linux_sysfs_write32, .write16 = pci_device_linux_sysfs_write16, .write8 = pci_device_linux_sysfs_write8, + + .map_legacy = pci_device_linux_sysfs_map_legacy, + .unmap_legacy = pci_device_linux_sysfs_unmap_legacy, }; diff --git a/lib/libpciaccess/src/netbsd_pci.c b/lib/libpciaccess/src/netbsd_pci.c index f33b3ebfb..d351e8f56 100644 --- a/lib/libpciaccess/src/netbsd_pci.c +++ b/lib/libpciaccess/src/netbsd_pci.c @@ -210,7 +210,7 @@ pci_device_netbsd_write(struct pci_device *dev, const void *data, io.cfgreg.reg = offset; memcpy(&io.cfgreg.val, data, 4); - if (ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io) == -1) + if (ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io) == -1) return errno; offset += 4; diff --git a/lib/libpciaccess/src/openbsd_pci.c b/lib/libpciaccess/src/openbsd_pci.c index ed2f1663d..b21df2a0f 100644 --- a/lib/libpciaccess/src/openbsd_pci.c +++ b/lib/libpciaccess/src/openbsd_pci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Mark Kettenis + * Copyright (c) 2008, 2011 Mark Kettenis * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -192,7 +192,8 @@ pci_device_openbsd_map_range(struct pci_device *dev, mo.mo_arg[0] = MEMRANGE_SET_UPDATE; if (ioctl(aperturefd, MEMRANGE_SET, &mo)) - (void)fprintf(stderr, "mtrr set failed: %s\n", + (void)fprintf(stderr, "mtrr set %lx %lx failed: %s\n", + (intptr_t)map->base, (intptr_t)map->size, strerror(errno)); } #endif @@ -394,6 +395,141 @@ pci_device_openbsd_probe(struct pci_device *device) return 0; } +#if defined(__i386__) || defined(__amd64__) +#include <machine/sysarch.h> +#include <machine/pio.h> +#endif + +static struct pci_io_handle * +pci_device_openbsd_open_legacy_io(struct pci_io_handle *ret, + struct pci_device *dev, pciaddr_t base, pciaddr_t size) +{ +#if defined(__i386__) + struct i386_iopl_args ia; + + ia.iopl = 1; + if (sysarch(I386_IOPL, &ia)) + return NULL; + + ret->base = base; + ret->size = size; + return ret; +#elif defined(__amd64__) + struct amd64_iopl_args ia; + + ia.iopl = 1; + if (sysarch(AMD64_IOPL, &ia)) + return NULL; + + ret->base = base; + ret->size = size; + return ret; +#elif defined(PCI_MAGIC_IO_RANGE) + ret->memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + aperturefd, PCI_MAGIC_IO_RANGE + base); + if (ret->memory == MAP_FAILED) + return NULL; + + ret->base = base; + ret->size = size; + return ret; +#else + return NULL; +#endif +} + +static uint32_t +pci_device_openbsd_read32(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inl(handle->base + reg); +#else + return *(uint32_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static uint16_t +pci_device_openbsd_read16(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inw(handle->base + reg); +#else + return *(uint16_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static uint8_t +pci_device_openbsd_read8(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inb(handle->base + reg); +#else + return *(uint8_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static void +pci_device_openbsd_write32(struct pci_io_handle *handle, uint32_t reg, + uint32_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outl(handle->base + reg, data); +#else + *(uint16_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static void +pci_device_openbsd_write16(struct pci_io_handle *handle, uint32_t reg, + uint16_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outw(handle->base + reg, data); +#else + *(uint8_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static void +pci_device_openbsd_write8(struct pci_io_handle *handle, uint32_t reg, + uint8_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outb(handle->base + reg, data); +#else + *(uint32_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static int +pci_device_openbsd_map_legacy(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, unsigned map_flags, void **addr) +{ + struct pci_device_mapping map; + int err; + + map.base = base; + map.size = size; + map.flags = map_flags; + map.memory = NULL; + err = pci_device_openbsd_map_range(dev, &map); + *addr = map.memory; + + return err; +} + +static int +pci_device_openbsd_unmap_legacy(struct pci_device *dev, void *addr, + pciaddr_t size) +{ + struct pci_device_mapping map; + + map.memory = addr; + map.size = size; + map.flags = 0; + return pci_device_openbsd_unmap_range(dev, &map); +} + static const struct pci_system_methods openbsd_pci_methods = { pci_system_openbsd_destroy, NULL, @@ -403,7 +539,21 @@ static const struct pci_system_methods openbsd_pci_methods = { pci_device_openbsd_unmap_range, pci_device_openbsd_read, pci_device_openbsd_write, - pci_fill_capabilities_generic + pci_fill_capabilities_generic, + NULL, + NULL, + NULL, + NULL, + pci_device_openbsd_open_legacy_io, + NULL, + pci_device_openbsd_read32, + pci_device_openbsd_read16, + pci_device_openbsd_read8, + pci_device_openbsd_write32, + pci_device_openbsd_write16, + pci_device_openbsd_write8, + pci_device_openbsd_map_legacy, + pci_device_openbsd_unmap_legacy }; int @@ -584,7 +734,6 @@ int pci_device_vgaarb_set_target(struct pci_device *dev) { pci_sys->vga_target = dev; - return 0; } int diff --git a/lib/libpciaccess/src/pciaccess_private.h b/lib/libpciaccess/src/pciaccess_private.h index 1111ef07f..32f8a7552 100644 --- a/lib/libpciaccess/src/pciaccess_private.h +++ b/lib/libpciaccess/src/pciaccess_private.h @@ -25,7 +25,7 @@ /** * \file pciaccess_private.h * Functions and datastructures that are private to the pciaccess library. - * + * * \author Ian Romanick <idr@us.ibm.com> */ @@ -46,12 +46,12 @@ int pci_device_generic_unmap_range(struct pci_device *dev, struct pci_system_methods { void (*destroy)( void ); void (*destroy_device)( struct pci_device * dev ); - int (*read_rom)( struct pci_device * dev, void * buffer ); + int (*read_rom)( struct pci_device * dev, void * buffer ); int (*probe)( struct pci_device * dev ); int (*map_range)(struct pci_device *dev, struct pci_device_mapping *map); int (*unmap_range)(struct pci_device * dev, struct pci_device_mapping *map); - + int (*read)(struct pci_device * dev, void * data, pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read ); @@ -77,6 +77,10 @@ struct pci_system_methods { void (*write16)( struct pci_io_handle *handle, uint32_t reg, uint16_t data ); void (*write8)( struct pci_io_handle *handle, uint32_t reg, uint8_t data ); + + int (*map_legacy)(struct pci_device *dev, pciaddr_t base, pciaddr_t size, + unsigned map_flags, void **addr); + int (*unmap_legacy)(struct pci_device *dev, void *addr, pciaddr_t size); }; struct pci_device_mapping { @@ -90,13 +94,14 @@ struct pci_device_mapping { struct pci_io_handle { pciaddr_t base; pciaddr_t size; + void *memory; int fd; }; struct pci_device_private { struct pci_device base; const char * device_string; - + uint8_t header_type; /** @@ -105,7 +110,7 @@ struct pci_device_private { /*@{*/ const struct pci_agp_info * agp; /**< AGP capability information. */ /*@}*/ - + /** * Base address of the device's expansion ROM. */ diff --git a/lib/libpciaccess/src/solx_devfs.c b/lib/libpciaccess/src/solx_devfs.c index 24bb1b930..5e91a1404 100644 --- a/lib/libpciaccess/src/solx_devfs.c +++ b/lib/libpciaccess/src/solx_devfs.c @@ -1,6 +1,6 @@ /* * (C) Copyright IBM Corporation 2006 - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. + * 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 @@ -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,12 +62,31 @@ 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; +#ifdef __sparc + struct pci_device **devlist; + volatile size_t num_allocated_elems; + volatile size_t num_devices; +#endif } 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; +#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 @@ -83,6 +102,10 @@ static int xsvc_fd = -1; # 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. @@ -103,61 +126,36 @@ static int xsvc_fd = -1; # define U45_SB_CLASS_RID 0x06040000 #endif -static int pci_device_solx_devfs_map_range(struct pci_device *dev, - struct pci_device_mapping *map); - -static int pci_device_solx_devfs_read_rom( struct pci_device * dev, - void * buffer ); - -static int pci_device_solx_devfs_probe( struct pci_device * dev ); - -static int pci_device_solx_devfs_read( struct pci_device * dev, void * data, - pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read ); - -static int pci_device_solx_devfs_write( struct pci_device * dev, - 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 do_probe(nexus_t *nexus, struct pci_system *pci_sys); - -static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg); - -static void pci_system_solx_devfs_destroy( void ); - -static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, - uint8_t func_no, pci_conf_hdr_t *config_hdr_p); - -int pci_system_solx_devfs_create( void ); - -static const struct pci_system_methods solx_devfs_methods = { - .destroy = pci_system_solx_devfs_destroy, - .destroy_device = NULL, - .read_rom = pci_device_solx_devfs_read_rom, - .probe = pci_device_solx_devfs_probe, - .map_range = pci_device_solx_devfs_map_range, - .unmap_range = pci_device_generic_unmap_range, - - .read = pci_device_solx_devfs_read, - .write = pci_device_solx_devfs_write, - - .fill_capabilities = pci_fill_capabilities_generic -}; +#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 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; } } return NULL; } +#endif #define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset]) #define GET_CONFIG_VAL_16(offset) \ @@ -186,69 +184,33 @@ pci_system_solx_devfs_destroy( void ) next = nexus->next; 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; } -} - -/* - * Attempt to access PCI subsystem using Solaris's devfs interface. - * Solaris version - */ -_pci_hidden int -pci_system_solx_devfs_create( void ) -{ - int err = 0; - di_node_t di_node; - - - 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 { - err = errno; - } - - if (err != 0) { - if (pci_sys != NULL) { - free(pci_sys->devices); - free(pci_sys); - pci_sys = NULL; - } - } - - return (err); +#endif } /* @@ -289,7 +251,7 @@ get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_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; @@ -367,6 +329,10 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) 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; } @@ -412,12 +378,9 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) * 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; @@ -436,8 +399,9 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) 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); - 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 @@ -446,14 +410,45 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) 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, + "Error allocating memory for PCI devices:" + " %s\n discarding additional devices\n", + strerror(errno)); + 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; } +#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 @@ -470,14 +465,72 @@ probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys) return (rval); } + +/* + * Solaris version + * Probe a given nexus config space for devices. + * + * fd is the file descriptor of the nexus. + * input_args contains commandline options as specified by the user. + */ +static int +do_probe(nexus_t *nexus, probe_info_t *pinfo) +{ + pcitool_reg_t prg; + uint32_t bus; + uint8_t dev; + uint32_t last_bus = nexus->last_bus; + uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT; + uint8_t first_bus = nexus->first_bus; + uint8_t first_dev = 0; + int rval = 0; + + prg.barnum = 0; /* Config space. */ + + /* Must read in 4-byte quantities. */ + prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; + + prg.data = 0; + + /* + * Loop through all valid bus / dev / func combinations to check for + * all devices, with the following exceptions: + * + * When nothing is found at function 0 of a bus / dev combination, skip + * the other functions of that bus / dev combination. + * + * When a found device's function 0 is probed and it is determined that + * it is not a multifunction device, skip probing of that device's + * other functions. + */ + for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) { + prg.bus_no = (uint8_t)bus; + + for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) { + prg.dev_no = dev; + rval = probe_dev(nexus, &prg, pinfo); + } + + /* + * Ultra-45 southbridge workaround: + * ECANCELED tells to skip to the next bus. + */ + if (rval == ECANCELED) { + rval = 0; + } + } + + return (rval); +} + /* * This function is called from di_walk_minor() when any PROBE is processed */ 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]; @@ -488,6 +541,13 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) int numval; 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); @@ -505,11 +565,17 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 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 */ @@ -520,14 +586,43 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 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) { + numval = di_prop_ints(prop, &ints); + if (numval == 1) { + domain = ints[0]; } } } -#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)); @@ -538,6 +633,19 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) } nexus->first_bus = first_bus; 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) { @@ -558,11 +666,15 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 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; @@ -577,64 +689,6 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) return DI_WALK_CONTINUE; } - -/* - * Solaris version - * Probe a given nexus config space for devices. - * - * fd is the file descriptor of the nexus. - * input_args contains commandline options as specified by the user. - */ -static int -do_probe(nexus_t *nexus, struct pci_system *pci_sys) -{ - pcitool_reg_t prg; - uint32_t bus; - uint8_t dev; - uint32_t last_bus = nexus->last_bus; - uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT; - uint8_t first_bus = nexus->first_bus; - uint8_t first_dev = 0; - int rval = 0; - - prg.barnum = 0; /* Config space. */ - - /* Must read in 4-byte quantities. */ - prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; - - prg.data = 0; - - /* - * Loop through all valid bus / dev / func combinations to check for - * all devices, with the following exceptions: - * - * When nothing is found at function 0 of a bus / dev combination, skip - * the other functions of that bus / dev combination. - * - * When a found device's function 0 is probed and it is determined that - * it is not a multifunction device, skip probing of that device's - * other functions. - */ - for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) { - prg.bus_no = (uint8_t)bus; - - for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) { - prg.dev_no = dev; - rval = probe_dev(nexus, &prg, pci_sys); - } - - /* - * Ultra-45 southbridge workaround: - * ECANCELED tells to skip to the next bus. - */ - if (rval == ECANCELED) { - rval = 0; - } - } - - return (rval); -} - static int find_target_node(di_node_t node, void *arg) { @@ -667,6 +721,11 @@ find_target_node(di_node_t node, void *arg) 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); @@ -696,55 +755,50 @@ find_target_node(di_node_t node, void *arg) 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; pci_regspec_t *reg; int i; - pciaddr_t bytes; int len = 0; uint ent = 0; + nexus_t *nexus; - err = pci_device_solx_devfs_read( dev, config, 0, 256, & bytes ); +#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; - if ( bytes >= 64 ) { - struct pci_device_private *priv = - (struct pci_device_private *) dev; + /* + * 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); + } - 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); + if (args.node != DI_NODE_NIL) { +#ifdef __sparc + di_minor_t minor; +#endif - /* - * 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]; +#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 - priv->header_type = config[14]; - /* - * starting to find if it is MEM/MEM64/IO - * using libdevinfo - */ - if ((rnode = di_init("/", 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) { /* * It will succeed for sure, because it was * successfully called in find_target_node @@ -753,6 +807,12 @@ pci_device_solx_devfs_probe( struct pci_device * dev ) "assigned-addresses", ®buf); +#ifdef __sparc + if ((len <= 0) && di_phdl) { + len = di_prom_prop_lookup_ints(di_phdl, args.node, + "assigned-addresses", ®buf); + } +#endif } if (len <= 0) @@ -845,6 +905,70 @@ pci_device_solx_devfs_probe( struct pci_device * dev ) return (err); } +/** + * Map a memory region for a device using /dev/xsvc. + * + * \param dev Device whose memory region is to be mapped. + * \param map Parameters of the mapping that is to be created. + * + * \return + * Zero on success or an \c errno value on failure. + */ +static int +pci_device_solx_devfs_map_range(struct pci_device *dev, + struct pci_device_mapping *map) +{ + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + ? (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 + */ + if (xsvc_fd < 0) { + if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) { + err = errno; + (void) fprintf(stderr, "can not open /dev/xsvc: %s\n", + strerror(errno)); + return err; + } + } + + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base); +#endif + + if (map->memory == MAP_FAILED) { + err = errno; + + (void) fprintf(stderr, "map rom region =%llx failed: %s\n", + map->base, strerror(errno)); + } + +#ifdef __sparc + close (map_fd); +#endif + + return err; +} + /* * Solaris version: read the VGA ROM data */ @@ -880,7 +1004,13 @@ 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_bus(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; @@ -932,7 +1062,13 @@ 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_bus(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; @@ -946,15 +1082,19 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data, switch (size) { case 1: cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN; + cfg_prg.data = *((const uint8_t *)data); break; case 2: cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN; + cfg_prg.data = *((const uint16_t *)data); break; case 4: cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; + cfg_prg.data = *((const uint32_t *)data); break; case 8: cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN; + cfg_prg.data = *((const uint64_t *)data); break; default: return EINVAL; @@ -964,7 +1104,6 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data, 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. @@ -984,42 +1123,72 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data, } -/** - * Map a memory region for a device using /dev/xsvc. - * - * \param dev Device whose memory region is to be mapped. - * \param map Parameters of the mapping that is to be created. - * - * \return - * Zero on success or an \c errno value on failure. + +static const struct pci_system_methods solx_devfs_methods = { + .destroy = pci_system_solx_devfs_destroy, + .destroy_device = NULL, + .read_rom = pci_device_solx_devfs_read_rom, + .probe = pci_device_solx_devfs_probe, + .map_range = pci_device_solx_devfs_map_range, + .unmap_range = pci_device_generic_unmap_range, + + .read = pci_device_solx_devfs_read, + .write = pci_device_solx_devfs_write, + + .fill_capabilities = pci_fill_capabilities_generic +}; + +/* + * Attempt to access PCI subsystem using Solaris's devfs interface. + * Solaris version */ -static int -pci_device_solx_devfs_map_range(struct pci_device *dev, - struct pci_device_mapping *map) +_pci_hidden int +pci_system_solx_devfs_create( void ) { - const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) - ? (PROT_READ | PROT_WRITE) : PROT_READ; int err = 0; + di_node_t di_node; + probe_info_t pinfo; + struct pci_device_private *devices; - /* - * Still used xsvc to do the user space mapping - */ - if (xsvc_fd < 0) { - if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) { - err = errno; - (void) fprintf(stderr, "can not open /dev/xsvc: %s\n", - strerror(errno)); - return err; - } + if (nexus_list != NULL) { + return 0; } - map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base); - if (map->memory == MAP_FAILED) { + if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { err = errno; + (void) fprintf(stderr, "di_init() failed: %s\n", + strerror(errno)); + return (err); + } - (void) fprintf(stderr, "map rom region =%llx failed: %s\n", - map->base, strerror(errno)); + if ((devices = calloc(INITIAL_NUM_DEVICES, + sizeof (struct pci_device_private))) == NULL) { + err = errno; + di_fini(di_node); + return (err); } - 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; + (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); } |