diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-05-24 14:14:01 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-05-24 14:14:01 +0000 |
commit | 0f1aba46fc25a15bcbc53898548b85ff8b5f8455 (patch) | |
tree | 05b115425a1a111e8076e7bcd284d1284d1be2a6 /lib/libpciaccess/src | |
parent | f091cb11ce9394593383465493467b328134bc42 (diff) |
Merge libpciaccess 0.10.2, including kettenis@ OpenBSD port.
Diffstat (limited to 'lib/libpciaccess/src')
-rw-r--r-- | lib/libpciaccess/src/Makefile.am | 7 | ||||
-rw-r--r-- | lib/libpciaccess/src/Makefile.in | 24 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_capability.c | 2 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_device_name.c | 5 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_init.c | 13 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_interface.c | 255 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_iterator.c | 3 | ||||
-rw-r--r-- | lib/libpciaccess/src/common_map.c | 55 | ||||
-rw-r--r-- | lib/libpciaccess/src/freebsd_pci.c | 184 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_devmem.c | 156 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_devmem.h | 34 | ||||
-rw-r--r-- | lib/libpciaccess/src/linux_sysfs.c | 208 | ||||
-rw-r--r-- | lib/libpciaccess/src/openbsd_pci.c | 444 | ||||
-rw-r--r-- | lib/libpciaccess/src/pciaccess_private.h | 46 | ||||
-rw-r--r-- | lib/libpciaccess/src/scanpci.c | 15 | ||||
-rw-r--r-- | lib/libpciaccess/src/solx_devfs.c | 79 |
16 files changed, 1195 insertions, 335 deletions
diff --git a/lib/libpciaccess/src/Makefile.am b/lib/libpciaccess/src/Makefile.am index 2920ed275..8c53de5ed 100644 --- a/lib/libpciaccess/src/Makefile.am +++ b/lib/libpciaccess/src/Makefile.am @@ -26,7 +26,7 @@ AM_CFLAGS = @PCIACCESS_CFLAGS@ lib_LTLIBRARIES = libpciaccess.la if LINUX -OS_SUPPORT = linux_sysfs.c +OS_SUPPORT = linux_sysfs.c linux_devmem.c linux_devmem.h endif if FREEBSD @@ -38,7 +38,7 @@ OS_SUPPORT = openbsd_pci.c endif if SOLARIS -OS_SUPPORT = solx_devfs.c +OS_SUPPORT = solx_devfs.c pci_tools.h endif libpciaccess_la_SOURCES = common_bridge.c \ @@ -47,6 +47,7 @@ libpciaccess_la_SOURCES = common_bridge.c \ common_interface.c \ common_capability.c \ common_device_name.c \ + common_map.c \ pciaccess_private.h \ $(OS_SUPPORT) @@ -54,7 +55,7 @@ INCLUDES = -I$(top_srcdir)/include libpciaccess_la_LIBADD = @PCIACCESS_LIBS@ -libpciaccess_la_LDFLAGS = -version-number 0:8:0 -no-undefined +libpciaccess_la_LDFLAGS = -version-number 0:10:2 -no-undefined libpciaccessincludedir = $(includedir) libpciaccessinclude_HEADERS = \ diff --git a/lib/libpciaccess/src/Makefile.in b/lib/libpciaccess/src/Makefile.in index ef5720c34..ed916bf14 100644 --- a/lib/libpciaccess/src/Makefile.in +++ b/lib/libpciaccess/src/Makefile.in @@ -85,16 +85,18 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libpciaccess_la_DEPENDENCIES = am__libpciaccess_la_SOURCES_DIST = common_bridge.c common_iterator.c \ common_init.c common_interface.c common_capability.c \ - common_device_name.c pciaccess_private.h freebsd_pci.c \ - linux_sysfs.c openbsd_pci.c solx_devfs.c + common_device_name.c common_map.c pciaccess_private.h \ + freebsd_pci.c linux_sysfs.c linux_devmem.c linux_devmem.h \ + openbsd_pci.c solx_devfs.c pci_tools.h @FREEBSD_FALSE@@LINUX_FALSE@@OPENBSD_FALSE@@SOLARIS_TRUE@am__objects_1 = solx_devfs.lo @FREEBSD_FALSE@@LINUX_FALSE@@OPENBSD_TRUE@am__objects_1 = \ @FREEBSD_FALSE@@LINUX_FALSE@@OPENBSD_TRUE@ openbsd_pci.lo -@FREEBSD_FALSE@@LINUX_TRUE@am__objects_1 = linux_sysfs.lo +@FREEBSD_FALSE@@LINUX_TRUE@am__objects_1 = linux_sysfs.lo \ +@FREEBSD_FALSE@@LINUX_TRUE@ linux_devmem.lo @FREEBSD_TRUE@am__objects_1 = freebsd_pci.lo am_libpciaccess_la_OBJECTS = common_bridge.lo common_iterator.lo \ common_init.lo common_interface.lo common_capability.lo \ - common_device_name.lo $(am__objects_1) + common_device_name.lo common_map.lo $(am__objects_1) libpciaccess_la_OBJECTS = $(am_libpciaccess_la_OBJECTS) PROGRAMS = $(noinst_PROGRAMS) am_scanpci_OBJECTS = scanpci.$(OBJEXT) @@ -140,6 +142,7 @@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ @@ -166,6 +169,7 @@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +NMEDIT = @NMEDIT@ OBJEXT = @OBJEXT@ OPENBSD_FALSE = @OPENBSD_FALSE@ OPENBSD_TRUE = @OPENBSD_TRUE@ @@ -180,6 +184,7 @@ PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ PCIACCESS_LIBS = @PCIACCESS_LIBS@ PCIIDS_PATH = @PCIIDS_PATH@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS_FALSE = @SOLARIS_FALSE@ @@ -189,7 +194,9 @@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DSYMUTIL = @ac_ct_DSYMUTIL@ ac_ct_F77 = @ac_ct_F77@ +ac_ct_NMEDIT = @ac_ct_NMEDIT@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ @@ -232,21 +239,22 @@ target_alias = @target_alias@ AM_CFLAGS = @PCIACCESS_CFLAGS@ lib_LTLIBRARIES = libpciaccess.la @FREEBSD_TRUE@OS_SUPPORT = freebsd_pci.c -@LINUX_TRUE@OS_SUPPORT = linux_sysfs.c +@LINUX_TRUE@OS_SUPPORT = linux_sysfs.c linux_devmem.c linux_devmem.h @OPENBSD_TRUE@OS_SUPPORT = openbsd_pci.c -@SOLARIS_TRUE@OS_SUPPORT = solx_devfs.c +@SOLARIS_TRUE@OS_SUPPORT = solx_devfs.c pci_tools.h libpciaccess_la_SOURCES = common_bridge.c \ common_iterator.c \ common_init.c \ common_interface.c \ common_capability.c \ common_device_name.c \ + common_map.c \ pciaccess_private.h \ $(OS_SUPPORT) INCLUDES = -I$(top_srcdir)/include libpciaccess_la_LIBADD = @PCIACCESS_LIBS@ -libpciaccess_la_LDFLAGS = -version-number 0:8:0 -no-undefined +libpciaccess_la_LDFLAGS = -version-number 0:10:2 -no-undefined libpciaccessincludedir = $(includedir) libpciaccessinclude_HEADERS = \ $(top_srcdir)/include/pciaccess.h @@ -339,7 +347,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_init.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_iterator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_pci.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux_devmem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux_sysfs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openbsd_pci.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanpci.Po@am__quote@ diff --git a/lib/libpciaccess/src/common_capability.c b/lib/libpciaccess/src/common_capability.c index 48f6ed4b0..31d59eb0d 100644 --- a/lib/libpciaccess/src/common_capability.c +++ b/lib/libpciaccess/src/common_capability.c @@ -59,7 +59,7 @@ * later to try again for the second capability. This could lead to memory * leaks or other quirky behavior. */ -int +_pci_hidden int pci_fill_capabilities_generic( struct pci_device * dev ) { struct pci_device_private * const dev_priv = diff --git a/lib/libpciaccess/src/common_device_name.c b/lib/libpciaccess/src/common_device_name.c index 12f88f5f9..b10518714 100644 --- a/lib/libpciaccess/src/common_device_name.c +++ b/lib/libpciaccess/src/common_device_name.c @@ -46,6 +46,7 @@ #endif #include "pciaccess.h" +#include "pciaccess_private.h" #define DO_MATCH(a,b) (((a) == PCI_MATCH_ANY) || ((a) == (b))) @@ -92,7 +93,7 @@ struct pci_device_leaf { /** * Root of the PCI vendor ID search tree. */ -struct pci_id_node * tree = NULL; +_pci_hidden struct pci_id_node * tree = NULL; /** * Name of the file containing the PCI ID information. @@ -227,7 +228,7 @@ populate_vendor( struct pci_id_leaf * vend, int fill_device_data ) /* vendor_name may already be set from a previous invocation * of this function with fill_device_data = 0. */ - if (vend->vendor_name != NULL) { + if (vend->vendor_name == NULL) { vend->vendor_name = strdup( & buf[ num_tabs + 6 ] ); } diff --git a/lib/libpciaccess/src/common_init.c b/lib/libpciaccess/src/common_init.c index c16f98ada..ff241838b 100644 --- a/lib/libpciaccess/src/common_init.c +++ b/lib/libpciaccess/src/common_init.c @@ -35,7 +35,7 @@ #include "pciaccess.h" #include "pciaccess_private.h" -struct pci_system * pci_sys; +_pci_hidden struct pci_system * pci_sys; /** * Initialize the PCI subsystem for access. @@ -54,17 +54,24 @@ pci_system_init( void ) #ifdef linux err = pci_system_linux_sysfs_create(); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__DragonFly__) err = pci_system_freebsd_create(); #elif defined(__OpenBSD__) err = pci_system_openbsd_create(); #elif defined(__sun) - err = pci_system_solx_devfs_create(); + err = pci_system_solx_devfs_create(); #endif return err; } +void +pci_system_init_dev_mem(int fd) +{ +#ifdef __OpenBSD__ + pci_system_openbsd_init_dev_mem(fd); +#endif +} /** * Shutdown all access to the PCI subsystem. diff --git a/lib/libpciaccess/src/common_interface.c b/lib/libpciaccess/src/common_interface.c index 908e91589..663ab44ef 100644 --- a/lib/libpciaccess/src/common_interface.c +++ b/lib/libpciaccess/src/common_interface.c @@ -30,12 +30,13 @@ */ #include <stdlib.h> +#include <string.h> #include <errno.h> #include "pciaccess.h" #include "pciaccess_private.h" -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) #include <byteswap.h> #if __BYTE_ORDER == __BIG_ENDIAN @@ -56,23 +57,20 @@ #define LETOH_32(x) (x) #define HTOLE_32(x) (x) -#elif defined(__OpenBSD__) +#else -#include <sys/types.h> +#include <sys/endian.h> -#define LETOH_16(x) letoh16(x) #define HTOLE_16(x) htole16(x) -#define LETOH_32(x) letoh32(x) #define HTOLE_32(x) htole32(x) -#else - -#include <sys/endian.h> - +#if defined(__FreeBSD__) || defined(__DragonFly__) #define LETOH_16(x) le16toh(x) -#define HTOLE_16(x) htole16(x) #define LETOH_32(x) le32toh(x) -#define HTOLE_32(x) htole32(x) +#else +#define LETOH_16(x) letoh16(x) +#define LETOH_32(x) letoh32(x) +#endif #endif /* others */ @@ -140,25 +138,27 @@ pci_device_probe( struct pci_device * dev ) * \return * Zero on success or an \c errno value on failure. * - * \sa pci_device_unmap_region + * \sa pci_device_map_range, pci_device_unmap_range + * \deprecated */ int -pci_device_map_region( struct pci_device * dev, unsigned region, - int write_enable ) +pci_device_map_region(struct pci_device * dev, unsigned region, + int write_enable) { - if ( dev == NULL ) { - return EFAULT; - } + const unsigned map_flags = + (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0; - if ( (region > 5) || (dev->regions[ region ].size == 0) ) { - return ENOENT; + if ((region > 5) || (dev->regions[region].size == 0)) { + return ENOENT; } - if ( dev->regions[ region ].memory != NULL ) { - return 0; + if (dev->regions[region].memory != NULL) { + return 0; } - return (pci_sys->methods->map)( dev, region, write_enable ); + return pci_device_map_range(dev, dev->regions[region].base_addr, + dev->regions[region].size, map_flags, + &dev->regions[region].memory); } @@ -178,52 +178,112 @@ pci_device_map_region( struct pci_device * dev, unsigned region, * \return * Zero on success or an \c errno value on failure. * - * \sa pci_device_unmap_memory_range, pci_device_map_region + * \sa pci_device_map_range + */ +int pci_device_map_memory_range(struct pci_device *dev, + pciaddr_t base, pciaddr_t size, + int write_enable, void **addr) +{ + return pci_device_map_range(dev, base, size, + (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0, + addr); +} + + +/** + * Map the specified memory range so that it can be accessed by the CPU. + * + * Maps the specified memory range for access by the processor. The pointer + * to the mapped region is stored in \c addr. In addtion, the + * \c pci_mem_region::memory pointer for the BAR will be updated. + * + * \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. + * + * \return + * Zero on success or an \c errno value on failure. + * + * \sa pci_device_unmap_range */ int -pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base, - pciaddr_t size, int write_enable, - void **addr) +pci_device_map_range(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, unsigned map_flags, + void **addr) { + struct pci_device_private *const devp = + (struct pci_device_private *) dev; + struct pci_device_mapping *mappings; unsigned region; + unsigned i; int err = 0; *addr = NULL; if (dev == NULL) { - return EFAULT; + return EFAULT; } for (region = 0; region < 6; region++) { - const struct pci_mem_region const* r = &dev->regions[region]; + const struct pci_mem_region const* r = &dev->regions[region]; - if (r->size != 0) { - if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) { - if ((base + size) > (r->base_addr + r->size)) { - return E2BIG; - } + if (r->size != 0) { + if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) { + if ((base + size) > (r->base_addr + r->size)) { + return E2BIG; + } - break; - } - } + break; + } + } } if (region > 5) { - return ENOENT; + return ENOENT; } + /* Make sure that there isn't already a mapping with the same base and + * size. + */ + for (i = 0; i < devp->num_mappings; i++) { + if ((devp->mappings[i].base == base) + && (devp->mappings[i].size == size)) { + return EINVAL; + } + } + + + mappings = realloc(devp->mappings, + (sizeof(devp->mappings[0]) * (devp->num_mappings + 1))); + if (mappings == NULL) { + return ENOMEM; + } + + mappings[devp->num_mappings].base = base; + mappings[devp->num_mappings].size = size; + mappings[devp->num_mappings].region = region; + mappings[devp->num_mappings].flags = map_flags; + mappings[devp->num_mappings].memory = NULL; + if (dev->regions[region].memory == NULL) { - err = (*pci_sys->methods->map)(dev, region, write_enable); + err = (*pci_sys->methods->map_range)(dev, + &mappings[devp->num_mappings]); } - - if (err == 0) { - const pciaddr_t offset = base - dev->regions[region].base_addr; - *addr = ((uint8_t *)dev->regions[region].memory) + offset; + if (err == 0) { + *addr = mappings[devp->num_mappings].memory; + devp->num_mappings++; + } else { + mappings = realloc(devp->mappings, + (sizeof(devp->mappings[0]) * devp->num_mappings)); } + devp->mappings = mappings; + return err; } @@ -240,24 +300,29 @@ pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base, * \return * Zero on success or an \c errno value on failure. * - * \sa pci_device_map_region + * \sa pci_device_map_range, pci_device_unmap_range + * \deprecated */ int pci_device_unmap_region( struct pci_device * dev, unsigned region ) { - if ( dev == NULL ) { - return EFAULT; + int err; + + if (dev == NULL) { + return EFAULT; } - if ( (region > 5) || (dev->regions[ region ].size == 0) ) { - return ENOENT; + if ((region > 5) || (dev->regions[region].size == 0)) { + return ENOENT; } - if ( dev->regions[ region ].memory == NULL ) { - return 0; + err = pci_device_unmap_range(dev, dev->regions[region].memory, + dev->regions[region].size); + if (!err) { + dev->regions[region].memory = NULL; } - - return (pci_sys->methods->unmap)( dev, region ); + + return err; } @@ -274,41 +339,74 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region ) * \return * Zero on success or an \c errno value on failure. * - * \sa pci_device_map_memory_range, pci_device_unmap_region + * \sa pci_device_map_range, pci_device_unmap_range + * \deprecated */ int pci_device_unmap_memory_range(struct pci_device *dev, void *memory, - pciaddr_t size) + pciaddr_t size) { - unsigned region; + return pci_device_unmap_range(dev, memory, size); +} + + +/** + * Unmap the specified memory range so that it can no longer be accessed by the CPU. + * + * Unmaps the specified memory range that was previously mapped via + * \c pci_device_map_memory_range. + * + * \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. + * + * \sa pci_device_map_range + */ +int +pci_device_unmap_range(struct pci_device *dev, void *memory, + pciaddr_t size) +{ + struct pci_device_private *const devp = + (struct pci_device_private *) dev; + unsigned i; + int err; if (dev == NULL) { - return EFAULT; + return EFAULT; } - for (region = 0; region < 6; region++) { - const struct pci_mem_region const* r = &dev->regions[region]; - const uint8_t *const mem = r->memory; - - if (r->size != 0) { - if ((mem <= memory) && ((mem + r->size) > memory)) { - if ((memory + size) > (mem + r->size)) { - return E2BIG; - } - - break; - } - } + for (i = 0; i < devp->num_mappings; i++) { + if ((devp->mappings[i].memory == memory) + && (devp->mappings[i].size == size)) { + break; + } } - if (region > 5) { - return ENOENT; + if (i == devp->num_mappings) { + 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)); } - return (dev->regions[region].memory != NULL) - ? (*pci_sys->methods->unmap)(dev, region) - : 0; + return err; } @@ -506,3 +604,14 @@ pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, return err; } + +void +pci_device_enable(struct pci_device *dev) +{ + if (dev == NULL) { + return; + } + + if (pci_sys->methods->enable) + pci_sys->methods->enable(dev); +} diff --git a/lib/libpciaccess/src/common_iterator.c b/lib/libpciaccess/src/common_iterator.c index 73d275574..83cade326 100644 --- a/lib/libpciaccess/src/common_iterator.c +++ b/lib/libpciaccess/src/common_iterator.c @@ -158,6 +158,9 @@ pci_device_next( struct pci_device_iterator * iter ) { struct pci_device_private * d = NULL; + if (!iter) + return NULL; + switch( iter->mode ) { case match_any: if ( iter->next_index < pci_sys->num_devices ) { diff --git a/lib/libpciaccess/src/common_map.c b/lib/libpciaccess/src/common_map.c new file mode 100644 index 000000000..8757151cc --- /dev/null +++ b/lib/libpciaccess/src/common_map.c @@ -0,0 +1,55 @@ +/* + * (C) Copyright IBM Corporation 2007 + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> + +#include "pciaccess.h" +#include "pciaccess_private.h" + +/** + * \file common_map.c + * Platform independent memory map routines. + * + * \author Ian Romanick <idr@us.ibm.com> + */ + +/** + * Unmap the specified region using the munmap. + * + * \param dev Device whose memory region is to be mapped. + * \param map Memory mapping that is to be undone. + * + * \return + * Zero on success or an \c errno value on failure. + * + * \sa pci_device_unmap_range + */ +_pci_hidden int +pci_device_generic_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map) +{ + return (munmap(map->memory, map->size) == -1) ? errno : 0; +} diff --git a/lib/libpciaccess/src/freebsd_pci.c b/lib/libpciaccess/src/freebsd_pci.c index 751298d90..67ca9e312 100644 --- a/lib/libpciaccess/src/freebsd_pci.c +++ b/lib/libpciaccess/src/freebsd_pci.c @@ -38,12 +38,26 @@ #include <fcntl.h> #include <errno.h> #include <sys/types.h> +#include <sys/param.h> #include <sys/pciio.h> #include <sys/mman.h> +#include <sys/memrange.h> + +#if __FreeBSD_version >= 700053 +#define DOMAIN_SUPPORT 1 +#else +#define DOMAIN_SUPPORT 0 +#endif #include "pciaccess.h" #include "pciaccess_private.h" +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 +#define PCIS_DISPLAY_XGA 0x01 +#define PCIS_DISPLAY_3D 0x02 +#define PCIS_DISPLAY_OTHER 0x80 + /** * FreeBSD private pci_system structure that extends the base pci_system * structure. @@ -61,62 +75,89 @@ 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 region Region, on the range [0, 5], that is to be mapped. - * \param write_enable Map for writing (non-zero). - * + * + * \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_freebsd_map( struct pci_device *dev, unsigned region, - int write_enable ) +pci_device_freebsd_map_range(struct pci_device *dev, + struct pci_device_mapping *map) { - int fd, err = 0, prot; + 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; + + int fd, err = 0; - fd = open( "/dev/mem", write_enable ? O_RDWR : O_RDONLY ); - if ( fd == -1 ) + fd = open("/dev/mem", O_RDWR); + if (fd == -1) return errno; - prot = write_enable ? (PROT_READ | PROT_WRITE) : PROT_READ; - dev->regions[ region ].memory = mmap( NULL, dev->regions[ region ].size, - prot, MAP_SHARED, fd, - dev->regions[ region ].base_addr); + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, map->base); - if ( dev->regions[ region ].memory == MAP_FAILED ) { - close( fd ); - dev->regions[ region ].memory = NULL; + if (map->memory == MAP_FAILED) { err = errno; } - close( fd ); + mrd.mr_base = map->base; + mrd.mr_len = map->size; + strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner)); + if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE) + mrd.mr_flags = MDF_WRITEBACK; + else if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) + mrd.mr_flags = MDF_WRITECOMBINE; + else + mrd.mr_flags = MDF_UNCACHEABLE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + + /* No need to set an MTRR if it's the default mode. */ + if (mrd.mr_flags != MDF_UNCACHEABLE) { + if (ioctl(fd, MEMRANGE_SET, &mro)) { + fprintf(stderr, "failed to set mtrr: %s\n", strerror(errno)); + } + } + + close(fd); return err; } -/** - * Unmap the specified region. - * - * \param dev Device whose memory region is to be unmapped. - * \param region Region, on the range [0, 5], that is to be unmapped. - * - * \return - * Zero on success or an \c errno value on failure. - */ static int -pci_device_freebsd_unmap( struct pci_device * dev, unsigned region ) +pci_device_freebsd_unmap_range( struct pci_device *dev, + struct pci_device_mapping *map ) { - int err = 0; - - if ( munmap( dev->regions[ region ].memory, - dev->regions[ region ].size ) == -1) { - err = errno; + struct mem_range_desc mrd; + struct mem_range_op mro; + int fd; + + if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || + (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) + { + fd = open("/dev/mem", O_RDWR); + if (fd != -1) { + mrd.mr_base = map->base; + mrd.mr_len = map->size; + strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner)); + mrd.mr_flags = MDF_UNCACHEABLE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + + if (ioctl(fd, MEMRANGE_SET, &mro)) { + fprintf(stderr, "failed to unset mtrr: %s\n", strerror(errno)); + } + + close(fd); + } else { + fprintf(stderr, "Failed to open /dev/mem\n"); + } } - dev->regions[ region ].memory = NULL; - - return err; + return pci_device_generic_unmap_range(dev, map); } static int @@ -126,6 +167,9 @@ pci_device_freebsd_read( struct pci_device * dev, void * data, { struct pci_io io; +#if DOMAIN_SUPPORT + io.pi_sel.pc_domain = dev->domain; +#endif io.pi_sel.pc_bus = dev->bus; io.pi_sel.pc_dev = dev->dev; io.pi_sel.pc_func = dev->func; @@ -163,6 +207,9 @@ pci_device_freebsd_write( struct pci_device * dev, const void * data, { struct pci_io io; +#if DOMAIN_SUPPORT + io.pi_sel.pc_domain = dev->domain; +#endif io.pi_sel.pc_bus = dev->bus; io.pi_sel.pc_dev = dev->dev; io.pi_sel.pc_func = dev->func; @@ -187,6 +234,42 @@ pci_device_freebsd_write( struct pci_device * dev, const void * data, return 0; } +/** + * Read a VGA rom using the 0xc0000 mapping. + * + * This function should be extended to handle access through PCI resources, + * which should be more reliable when available. + */ +static int +pci_device_freebsd_read_rom( struct pci_device * dev, void * buffer ) +{ + void *bios; + int memfd; + + if ( ( dev->device_class & 0x00ffff00 ) != + ( ( PCIC_DISPLAY << 16 ) | ( PCIS_DISPLAY_VGA << 8 ) ) ) + { + return ENOSYS; + } + + memfd = open( "/dev/mem", O_RDONLY ); + if ( memfd == -1 ) + return errno; + + bios = mmap( NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000 ); + if ( bios == MAP_FAILED ) { + close( memfd ); + return errno; + } + + memcpy( buffer, bios, dev->rom_size ); + + munmap( bios, dev->rom_size ); + close( memfd ); + + return 0; +} + /** Returns the number of regions (base address registers) the device has */ static int @@ -314,12 +397,22 @@ pci_device_freebsd_probe( struct pci_device * dev ) bar = 0x10; for (i = 0; i < pci_device_freebsd_get_num_regions( dev ); i++) { pci_device_freebsd_get_region_info( dev, i, bar ); - if (dev->regions[i].is_64) + if (dev->regions[i].is_64) { bar += 0x08; - else + i++; + } else bar += 0x04; } + /* If it's a VGA device, set up the rom size for read_rom using the + * 0xc0000 mapping. + */ + if ((dev->device_class & 0x00ffff00) == + ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8))) + { + dev->rom_size = 64 * 1024; + } + return 0; } @@ -334,10 +427,10 @@ pci_system_freebsd_destroy(void) static const struct pci_system_methods freebsd_pci_methods = { .destroy = pci_system_freebsd_destroy, .destroy_device = NULL, /* nothing to do for this */ - .read_rom = NULL, /* XXX: Fill me in */ + .read_rom = pci_device_freebsd_read_rom, .probe = pci_device_freebsd_probe, - .map = pci_device_freebsd_map, - .unmap = pci_device_freebsd_unmap, + .map_range = pci_device_freebsd_map_range, + .unmap_range = pci_device_freebsd_unmap_range, .read = pci_device_freebsd_read, .write = pci_device_freebsd_write, .fill_capabilities = pci_fill_capabilities_generic, @@ -346,7 +439,7 @@ static const struct pci_system_methods freebsd_pci_methods = { /** * Attempt to access the FreeBSD PCI interface. */ -int +_pci_hidden int pci_system_freebsd_create( void ) { struct pci_conf_io pciconfio; @@ -394,13 +487,18 @@ pci_system_freebsd_create( void ) for ( i = 0; i < pciconfio.num_matches; i++ ) { struct pci_conf *p = &pciconf[ i ]; - pci_sys->devices[ i ].base.domain = 0; /* XXX */ +#if DOMAIN_SUPPORT + pci_sys->devices[ i ].base.domain = p->pc_sel.pc_domain; +#else + pci_sys->devices[ i ].base.domain = 0; +#endif pci_sys->devices[ i ].base.bus = p->pc_sel.pc_bus; pci_sys->devices[ i ].base.dev = p->pc_sel.pc_dev; pci_sys->devices[ i ].base.func = p->pc_sel.pc_func; pci_sys->devices[ i ].base.vendor_id = p->pc_vendor; pci_sys->devices[ i ].base.device_id = p->pc_device; pci_sys->devices[ i ].base.subvendor_id = p->pc_subvendor; + pci_sys->devices[ i ].base.subdevice_id = p->pc_subdevice; pci_sys->devices[ i ].base.device_class = (uint32_t)p->pc_class << 16 | (uint32_t)p->pc_subclass << 8 | (uint32_t)p->pc_progif; } diff --git a/lib/libpciaccess/src/linux_devmem.c b/lib/libpciaccess/src/linux_devmem.c new file mode 100644 index 000000000..21b45efdd --- /dev/null +++ b/lib/libpciaccess/src/linux_devmem.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright IBM Corporation 2007 + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \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. + * + * \author Ian Romanick <idr@us.ibm.com> + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#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 "pciaccess.h" +#include "pciaccess_private.h" +#include "linux_devmem.h" + +/** + * 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? + */ +_pci_hidden int +pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) +{ + struct pci_device_private *priv = (struct pci_device_private *) dev; + int fd; + int err = 0; + uint32_t rom_base_tmp; + pciaddr_t rom_base; + pciaddr_t rom_size; + int PCI_ROM; + + + /* Handle some special cases of legacy devices. + */ + if (priv->base.rom_size == 0) { + /* VGA ROMs are supposed to be at 0xC0000. + */ + if ((priv->base.device_class & 0x00ffff00) == 0x000030000) { + rom_base = 0x000C0000; + rom_size = 0x00010000; + PCI_ROM = 0; + } + else { + /* "Function not implemented." + */ + return ENOSYS; + } + } + else { + rom_base = priv->rom_base; + rom_size = priv->base.rom_size; + PCI_ROM = 1; + } + + + + /* Enable the device's ROM. + */ + if (PCI_ROM) { + err = pci_device_cfg_read_u32(& priv->base, & rom_base_tmp, 48); + if (err) { + return err; + } + + if ((rom_base_tmp & 0x000000001) == 0) { + 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); + if (fd < 0) { + err = errno; + } + else { + size_t bytes; + + for (bytes = 0; bytes < rom_size; /* empty */) { + const ssize_t got = pread(fd, buffer, rom_size - bytes, + rom_base + bytes); + if (got == -1) { + err = errno; + break; + } + + bytes += got; + } + + close(fd); + } + + + /* Disable the device's ROM. + */ + if (PCI_ROM && ((rom_base_tmp & 0x000000001) == 0)) { + const int tmp_err = pci_device_cfg_write_u32(& priv->base, + rom_base_tmp, 48); + + /* Prefer to return the first error that occured. + */ + if (err == 0) { + err = tmp_err; + } + } + + return err; +} diff --git a/lib/libpciaccess/src/linux_devmem.h b/lib/libpciaccess/src/linux_devmem.h new file mode 100644 index 000000000..2337f30b8 --- /dev/null +++ b/lib/libpciaccess/src/linux_devmem.h @@ -0,0 +1,34 @@ +/* + * (C) Copyright IBM Corporation 2007 + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \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> + */ + +extern int pci_device_linux_devmem_read_rom(struct pci_device *dev, + void *buffer); diff --git a/lib/libpciaccess/src/linux_sysfs.c b/lib/libpciaccess/src/linux_sysfs.c index 8a4bd0fd2..9e53fac21 100644 --- a/lib/libpciaccess/src/linux_sysfs.c +++ b/lib/libpciaccess/src/linux_sysfs.c @@ -44,19 +44,29 @@ #include <dirent.h> #include <errno.h> +#include "config.h" + +#ifdef HAVE_MTRR +#include <asm/mtrr.h> +#include <sys/ioctl.h> +#endif + #include "pciaccess.h" #include "pciaccess_private.h" +#include "linux_devmem.h" + +static void pci_device_linux_sysfs_enable(struct pci_device *dev); static int pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ); static int pci_device_linux_sysfs_probe( struct pci_device * dev ); -static int pci_device_linux_sysfs_map_region( struct pci_device * dev, - unsigned region, int write_enable ); +static int pci_device_linux_sysfs_map_range(struct pci_device *dev, + struct pci_device_mapping *map); -static int pci_device_linux_sysfs_unmap_region( struct pci_device * dev, - unsigned region ); +static int pci_device_linux_sysfs_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map); static int pci_device_linux_sysfs_read( struct pci_device * dev, void * data, pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read ); @@ -70,13 +80,14 @@ static const struct pci_system_methods linux_sysfs_methods = { .destroy_device = NULL, .read_rom = pci_device_linux_sysfs_read_rom, .probe = pci_device_linux_sysfs_probe, - .map = pci_device_linux_sysfs_map_region, - .unmap = pci_device_linux_sysfs_unmap_region, + .map_range = pci_device_linux_sysfs_map_range, + .unmap_range = pci_device_linux_sysfs_unmap_range, .read = pci_device_linux_sysfs_read, .write = pci_device_linux_sysfs_write, - .fill_capabilities = pci_fill_capabilities_generic + .fill_capabilities = pci_fill_capabilities_generic, + .enable = pci_device_linux_sysfs_enable, }; #define SYS_BUS_PCI "/sys/bus/pci/devices" @@ -88,7 +99,7 @@ static int populate_entries(struct pci_system * pci_sys); /** * Attempt to access PCI subsystem using Linux's sysfs interface. */ -int +_pci_hidden int pci_system_linux_sysfs_create( void ) { int err = 0; @@ -103,6 +114,9 @@ pci_system_linux_sysfs_create( void ) pci_sys = calloc( 1, sizeof( struct pci_system ) ); if ( pci_sys != NULL ) { pci_sys->methods = & linux_sysfs_methods; +#ifdef HAVE_MTRR + pci_sys->mtrr_fd = open("/proc/mtrr", O_WRONLY); +#endif err = populate_entries(pci_sys); } else { @@ -141,7 +155,7 @@ populate_entries( struct pci_system * p ) struct dirent ** devices; int n; int i; - int err; + int err = 0; n = scandir( SYS_BUS_PCI, & devices, scan_sys_pci_filter, alphasort ); @@ -278,6 +292,7 @@ pci_device_linux_sysfs_probe( struct pci_device * dev ) high_addr = strtoull( next, & next, 16 ); flags = strtoull( next, & next, 16 ); if ( low_addr != 0 ) { + priv->rom_base = low_addr; dev->rom_size = (high_addr - low_addr) + 1; } } @@ -294,6 +309,7 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) int fd; struct stat st; int err = 0; + size_t rom_size; size_t total_bytes; @@ -306,7 +322,10 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) fd = open( name, O_RDWR ); if ( fd == -1 ) { - return errno; + /* If reading the ROM using sysfs fails, fall back to the old + * /dev/mem based interface. + */ + return pci_device_linux_devmem_read_rom(dev, buffer); } @@ -315,6 +334,9 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) return errno; } + rom_size = st.st_size; + if ( rom_size == 0 ) + rom_size = 0x10000; /* This is a quirky thing on Linux. Even though the ROM and the file * for the ROM in sysfs are read-only, the string "1" must be written to @@ -324,9 +346,9 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) write( fd, "1", 1 ); lseek( fd, 0, SEEK_SET ); - for ( total_bytes = 0 ; total_bytes < st.st_size ; /* empty */ ) { + for ( total_bytes = 0 ; total_bytes < rom_size ; /* empty */ ) { const int bytes = read( fd, (char *) buffer + total_bytes, - st.st_size - total_bytes ); + rom_size - total_bytes ); if ( bytes == -1 ) { err = errno; break; @@ -356,7 +378,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data, pciaddr_t temp_size = size; int err = 0; int fd; - + char *data_bytes = data; if ( bytes_read != NULL ) { *bytes_read = 0; @@ -381,7 +403,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data, while ( temp_size > 0 ) { - const ssize_t bytes = pread64( fd, data, temp_size, offset ); + const ssize_t bytes = pread64( fd, data_bytes, temp_size, offset ); /* If zero bytes were read, then we assume it's the end of the * config file. @@ -393,7 +415,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data, temp_size -= bytes; offset += bytes; - data += bytes; + data_bytes += bytes; } if ( bytes_read != NULL ) { @@ -414,7 +436,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, pciaddr_t temp_size = size; int err = 0; int fd; - + const char *data_bytes = data; if ( bytes_written != NULL ) { *bytes_written = 0; @@ -439,7 +461,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, while ( temp_size > 0 ) { - const ssize_t bytes = pwrite64( fd, data, temp_size, offset ); + const ssize_t bytes = pwrite64( fd, data_bytes, temp_size, offset ); /* If zero bytes were written, then we assume it's the end of the * config file. @@ -451,7 +473,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, temp_size -= bytes; offset += bytes; - data += bytes; + data_bytes += bytes; } if ( bytes_written != NULL ) { @@ -466,14 +488,13 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, /** * Map a memory region for a device using the Linux sysfs interface. * - * \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). + * \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. * - * \sa pci_device_map_region, pci_device_linux_sysfs_unmap_region + * \sa pci_device_map_rrange, pci_device_linux_sysfs_unmap_range * * \todo * Some older 2.6.x kernels don't implement the resourceN files. On those @@ -481,51 +502,83 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, * \c mmap64 may need to be used. */ static int -pci_device_linux_sysfs_map_region( struct pci_device * dev, unsigned region, - int write_enable ) +pci_device_linux_sysfs_map_range(struct pci_device *dev, + struct pci_device_mapping *map) { char name[256]; int fd; int err = 0; - const int prot = (write_enable) ? (PROT_READ | PROT_WRITE) : PROT_READ; - + 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) + ? O_RDWR : O_RDONLY; + const off_t offset = map->base - dev->regions[map->region].base_addr; +#ifdef HAVE_MTRR + struct mtrr_sentry sentry = { + .base = map->base, + .size = map->size, + .type = MTRR_TYPE_UNCACHABLE + }; +#endif + + snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func, + map->region); + + fd = open(name, open_flags); + if (fd == -1) { + return errno; + } - snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource%u", - SYS_BUS_PCI, - dev->domain, - dev->bus, - dev->dev, - dev->func, - region ); - fd = open( name, (write_enable) ? O_RDWR : O_RDONLY ); - if ( fd == -1 ) { - return errno; + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); + if (map->memory == MAP_FAILED) { + err = errno; + map->memory = NULL; } + close(fd); - dev->regions[ region ].memory = mmap( NULL, dev->regions[ region ].size, - prot, MAP_SHARED, fd, 0 ); - if ( dev->regions[ region ].memory == MAP_FAILED ) { - err = errno; - dev->regions[ region ].memory = NULL; +#ifdef HAVE_MTRR + if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { + sentry.type = MTRR_TYPE_WRBACK; + } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { + sentry.type = MTRR_TYPE_WRCOMB; } - close( fd ); + if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { + if (ioctl(pci_sys->mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) < 0) { + /* FIXME: Should we report an error in this case? + */ + fprintf(stderr, "error setting MTRR " + "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", + sentry.base, sentry.size, sentry.type, + strerror(errno), errno); +/* err = errno;*/ + } + /* KLUDGE ALERT -- rewrite the PTEs to turn off the CD and WT bits */ + mprotect (map->memory, map->size, PROT_NONE); + mprotect (map->memory, map->size, PROT_READ|PROT_WRITE); + } +#endif + return err; } - /** - * Unmap the specified region using the Linux sysfs interface. - * - * \param dev Device whose memory region is to be mapped. - * \param region Region, on the range [0, 5], that is to be mapped. - * + * 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. * - * \sa pci_device_unmap_region, pci_device_linux_sysfs_map_region + * \sa pci_device_map_rrange, pci_device_linux_sysfs_map_range * * \todo * Some older 2.6.x kernels don't implement the resourceN files. On those @@ -533,16 +586,61 @@ pci_device_linux_sysfs_map_region( struct pci_device * dev, unsigned region, * \c mmap64 may need to be used. */ static int -pci_device_linux_sysfs_unmap_region( struct pci_device * dev, unsigned region ) +pci_device_linux_sysfs_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map) { int err = 0; - - if ( munmap( dev->regions[ region ].memory, dev->regions[ region ].size ) - == -1 ) { - err = errno; +#ifdef HAVE_MTRR + struct mtrr_sentry sentry = { + .base = map->base, + .size = map->size, + .type = MTRR_TYPE_UNCACHABLE + }; +#endif + + 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; + } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { + sentry.type = MTRR_TYPE_WRCOMB; } - dev->regions[ region ].memory = NULL; + if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { + if (ioctl(pci_sys->mtrr_fd, MTRRIOC_DEL_ENTRY, &sentry) < 0) { + /* FIXME: Should we report an error in this case? + */ + fprintf(stderr, "error setting MTRR " + "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", + sentry.base, sentry.size, sentry.type, + strerror(errno), errno); +/* err = errno;*/ + } + } +#endif return err; } + +static void pci_device_linux_sysfs_enable(struct pci_device *dev) +{ + char name[256]; + int fd; + + snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/enable", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func ); + + fd = open( name, O_RDWR ); + if (fd == -1) + return; + + write( fd, "1", 1 ); + close(fd); +} diff --git a/lib/libpciaccess/src/openbsd_pci.c b/lib/libpciaccess/src/openbsd_pci.c index 80ac26adb..5c06b4743 100644 --- a/lib/libpciaccess/src/openbsd_pci.c +++ b/lib/libpciaccess/src/openbsd_pci.c @@ -1,144 +1,406 @@ -/* $OpenBSD: openbsd_pci.c,v 1.1 2007/06/06 21:01:25 matthieu Exp $ */ /* - * (C) Copyright Eric Anholt 2006 - * (C) Copyright IBM Corporation 2006 - * All Rights Reserved. + * Copyright (c) 2008 Mark Kettenis * - * 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 - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. */ -/** - * \file openbsd_pci.c - * - * Access the kernel PCI support using /dev/pci's ioctl and mmap interface. - * - * \author Eric Anholt <eric@anholt.net> - */ -#include <stdlib.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/memrange.h> +#include <sys/mman.h> +#include <sys/pciio.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <errno.h> +#include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/pciio.h> -#include <sys/mman.h> #include "pciaccess.h" #include "pciaccess_private.h" -/** - * OpenBSD private pci_system structure that extends the base pci_system - * structure. - * - * It is initialized once and used as a global, just as pci_system is used. - */ -struct openbsd_pci_system { - struct pci_system pci_sys; /* must come first */ - int pcidev; /**< fd for /dev/pci */ -} *openbsd_pci_sys; +static int pcifd; +static int aperturefd = -1; -/** - * Map a memory region for a device using /dev/mem. - * - * \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. - */ static int -pci_device_openbsd_map(struct pci_device *dev, unsigned int region, - int write_enable) +pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val) { + struct pci_io io; + int err; + + bzero(&io, sizeof(io)); + io.pi_sel.pc_bus = bus; + io.pi_sel.pc_dev = dev; + io.pi_sel.pc_func = func; + io.pi_reg = reg; + io.pi_width = 4; + + err = ioctl(pcifd, PCIOCREAD, &io); + if (err) + return (err); + + *val = io.pi_data; + + return (0); } -/** - * Unmap the specified region. - * - * \param dev Device whose memory region is to be unmapped. - * \param region Region, on the range [0, 5], that is to be unmapped. - * - * \return - * Zero on success or an \c errno value on failure. - */ static int -pci_device_openbsd_unmap(struct pci_device *dev, unsigned int region) +pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val) { + struct pci_io io; + + bzero(&io, sizeof(io)); + io.pi_sel.pc_bus = bus; + io.pi_sel.pc_dev = dev; + io.pi_sel.pc_func = func; + io.pi_reg = reg; + io.pi_width = 4; + io.pi_data = val; + + return ioctl(pcifd, PCIOCWRITE, &io); } static int -pci_device_openbsd_read(struct pci_device *dev, void *data, - pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) +pci_nfuncs(int bus, int dev) { + uint32_t hdr; + + if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0) + return -1; + + return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1); } static int -pci_device_openbsd_write(struct pci_device *dev, const void *data, - pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) +pci_device_openbsd_map_range(struct pci_device *dev, + struct pci_device_mapping *map) { -} + struct mem_range_desc mr; + struct mem_range_op mo; + int prot = PROT_READ; + + if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE) + prot |= PROT_WRITE; + + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd, + map->base); + if (map->memory == MAP_FAILED) + return errno; + + /* No need to set an MTRR if it's the default mode. */ + if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || + (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { + mr.mr_base = map->base; + mr.mr_len = map->size; + mr.mr_flags = 0; + if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE) + mr.mr_flags |= MDF_WRITEBACK; + if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) + mr.mr_flags |= MDF_WRITECOMBINE; + strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner)); + + mo.mo_desc = &mr; + mo.mo_arg[0] = MEMRANGE_SET_UPDATE; + if (ioctl(aperturefd, MEMRANGE_SET, &mo)) + return errno; + } + + return 0; +} static int -pci_device_openbsd_probe(struct pci_device *dev) +pci_device_openbsd_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map) { + struct mem_range_desc mr; + struct mem_range_op mo; + + if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || + (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { + mr.mr_base = map->base; + mr.mr_len = map->size; + mr.mr_flags = MDF_UNCACHEABLE; + strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner)); + + mo.mo_desc = &mr; + mo.mo_arg[0] = MEMRANGE_SET_REMOVE; + + (void)ioctl(aperturefd, MEMRANGE_SET, &mo); + } + + return pci_device_generic_unmap_range(dev, map); } static int -pci_device_openbsd_read_rom(struct pci_device *dev, void *buffer) +pci_device_openbsd_read(struct pci_device *dev, void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) { + struct pci_io io; + + io.pi_sel.pc_bus = dev->bus; + io.pi_sel.pc_dev = dev->dev; + io.pi_sel.pc_func = dev->func; + + *bytes_read = 0; + while (size > 0) { + int toread = MIN(size, 4 - (offset & 0x3)); + + io.pi_reg = (offset & ~0x3); + io.pi_width = 4; + + if (ioctl(pcifd, PCIOCREAD, &io) == -1) + return errno; + + io.pi_data = htole32(io.pi_data); + io.pi_data >>= ((offset & 0x3) * 8); + + memcpy(data, &io.pi_data, toread); + + offset += toread; + data = (char *)data + toread; + size -= toread; + *bytes_read += toread; + } + + return 0; } +static int +pci_device_openbsd_write(struct pci_device *dev, const void *data, + pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) +{ + struct pci_io io; + + if ((offset % 4) == 0 || (size % 4) == 0) + return EINVAL; + + io.pi_sel.pc_bus = dev->bus; + io.pi_sel.pc_dev = dev->dev; + io.pi_sel.pc_func = dev->func; + + *bytes_written = 0; + while (size > 0) { + io.pi_reg = offset; + io.pi_width = 4; + memcpy(&io.pi_data, data, 4); + + if (ioctl(pcifd, PCIOCWRITE, &io) == -1) + return errno; + + offset += 4; + data = (char *)data + 4; + size -= 4; + *bytes_written += 4; + } + + return 0; +} static void pci_system_openbsd_destroy(void) { - free(openbsd_pci_sys->pci_sys.devices); - openbsd_pci_sys = NULL; + close(aperturefd); + close(pcifd); + free(pci_sys); + pci_sys = NULL; +} + +static int +pci_device_openbsd_probe(struct pci_device *device) +{ + struct pci_device_private *priv = (struct pci_device_private *)device; + struct pci_mem_region *region; + uint64_t reg64, size64; + uint32_t bar, reg, size; + int bus, dev, func, err; + + bus = device->bus; + dev = device->dev; + func = device->func; + + err = pci_read(bus, dev, func, PCI_BHLC_REG, ®); + if (err) + return err; + + priv->header_type = PCI_HDRTYPE_TYPE(reg); + if (priv->header_type != 0) + return 0; + + region = device->regions; + for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; + bar += sizeof(uint32_t), region++) { + err = pci_read(bus, dev, func, bar, ®); + if (err) + return err; + + /* Probe the size of the region. */ + err = pci_write(bus, dev, func, bar, ~0); + if (err) + return err; + pci_read(bus, dev, func, bar, &size); + pci_write(bus, dev, func, bar, reg); + + if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { + region->is_IO = 1; + region->base_addr = PCI_MAPREG_IO_ADDR(reg); + region->size = PCI_MAPREG_IO_SIZE(size); + } else { + if (PCI_MAPREG_MEM_PREFETCHABLE(reg)) + region->is_prefetchable = 1; + switch(PCI_MAPREG_MEM_TYPE(reg)) { + case PCI_MAPREG_MEM_TYPE_32BIT: + case PCI_MAPREG_MEM_TYPE_32BIT_1M: + region->base_addr = PCI_MAPREG_MEM_ADDR(reg); + region->size = PCI_MAPREG_MEM_SIZE(size); + break; + case PCI_MAPREG_MEM_TYPE_64BIT: + region->is_64 = 1; + + reg64 = reg; + size64 = size; + + bar += sizeof(uint32_t); + + err = pci_read(bus, dev, func, bar, ®); + if (err) + return err; + reg64 |= (uint64_t)reg << 32; + + err = pci_write(bus, dev, func, bar, ~0); + if (err) + return err; + pci_read(bus, dev, func, bar, &size); + pci_write(bus, dev, func, bar, reg64 >> 32); + size64 |= (uint64_t)size << 32; + + region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64); + region->size = PCI_MAPREG_MEM64_SIZE(size64); + region++; + break; + } + } + } + + return 0; } static const struct pci_system_methods openbsd_pci_methods = { - .destroy = pci_system_openbsd_destroy, - .destroy_device = NULL, - .read_rom = pci_device_openbsd_read_rom, - .probe = pci_device_openbsd_probe, - .map = pci_device_openbsd_map, - .unmap = pci_device_openbsd_unmap, - .read = pci_device_openbsd_read, - .write = pci_device_openbsd_write, - .fill_capabilities = pci_fill_capabilities_generic, + pci_system_openbsd_destroy, + NULL, + NULL, + pci_device_openbsd_probe, + pci_device_openbsd_map_range, + pci_device_openbsd_unmap_range, + pci_device_openbsd_read, + pci_device_openbsd_write, + pci_fill_capabilities_generic }; -/** - * Attempt to acces the OpenBSD PCI interface. - */ int pci_system_openbsd_create(void) { - openbsd_pci_sys = calloc(1, sizeof(struct openbsd_pci_system)); - if (openbsd_pci_sys = NULL) + struct pci_device_private *device; + int bus, dev, func, ndevs, nfuncs; + uint32_t reg; + + pcifd = open("/dev/pci", O_RDWR); + if (pcifd == -1) + return ENXIO; + + pci_sys = calloc(1, sizeof(struct pci_system)); + if (pci_sys == NULL) { + close(aperturefd); + close(pcifd); return ENOMEM; - pci_sys = &openbsd_pci_sys->pci_sys; + } + pci_sys->methods = &openbsd_pci_methods; - + + ndevs = 0; + for (bus = 0; bus < 256; bus++) { + for (dev = 0; dev < 32; dev++) { + nfuncs = pci_nfuncs(bus, dev); + for (func = 0; func < nfuncs; func++) { + if (pci_read(bus, dev, func, PCI_ID_REG, + ®) != 0) + continue; + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || + PCI_VENDOR(reg) == 0) + continue; + + ndevs++; + } + } + } + + pci_sys->num_devices = ndevs; + pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); + if (pci_sys->devices == NULL) { + free(pci_sys); + close(pcifd); + return ENOMEM; + } + + device = pci_sys->devices; + for (bus = 0; bus < 256; bus++) { + for (dev = 0; dev < 32; dev++) { + nfuncs = pci_nfuncs(bus, dev); + for (func = 0; func < nfuncs; func++) { + if (pci_read(bus, dev, func, PCI_ID_REG, + ®) != 0) + continue; + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || + PCI_VENDOR(reg) == 0) + continue; + + device->base.domain = 0; + device->base.bus = bus; + device->base.dev = dev; + device->base.func = func; + device->base.vendor_id = PCI_VENDOR(reg); + device->base.device_id = PCI_PRODUCT(reg); + + if (pci_read(bus, dev, func, PCI_CLASS_REG, + ®) != 0) + continue; + + device->base.device_class = + PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 | + PCI_SUBCLASS(reg) << 8; + device->base.revision = PCI_REVISION(reg); + + if (pci_read(bus, dev, func, PCI_SUBVEND_0, + ®) != 0) + continue; + + device->base.subvendor_id = PCI_VENDOR(reg); + device->base.subdevice_id = PCI_PRODUCT(reg); + + device++; + } + } + } + return 0; } + +void +pci_system_openbsd_init_dev_mem(int fd) +{ + aperturefd = fd; +} diff --git a/lib/libpciaccess/src/pciaccess_private.h b/lib/libpciaccess/src/pciaccess_private.h index b23e58953..6048af1fa 100644 --- a/lib/libpciaccess/src/pciaccess_private.h +++ b/lib/libpciaccess/src/pciaccess_private.h @@ -29,16 +29,28 @@ * \author Ian Romanick <idr@us.ibm.com> */ +#if defined(__GNUC__) && (__GNUC__ >= 4) +# define _pci_hidden __attribute__((visibility("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +# define _pci_hidden __hidden +#else /* not gcc >= 4 and not Sun Studio >= 8 */ +# define _pci_hidden +#endif /* GNUC >= 4 */ + +struct pci_device_mapping; int pci_fill_capabilities_generic( struct pci_device * dev ); +int pci_device_generic_unmap_range(struct pci_device *dev, + struct pci_device_mapping *map); struct pci_system_methods { void (*destroy)( void ); void (*destroy_device)( struct pci_device * dev ); int (*read_rom)( struct pci_device * dev, void * buffer ); int (*probe)( struct pci_device * dev ); - int (*map)( struct pci_device * dev, unsigned region, int write_enable ); - int (*unmap)( struct pci_device * dev, unsigned region ); + 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 ); @@ -47,6 +59,15 @@ struct pci_system_methods { pciaddr_t size, pciaddr_t * bytes_written ); int (*fill_capabilities)( struct pci_device * dev ); + void (*enable)( struct pci_device *dev ); +}; + +struct pci_device_mapping { + pciaddr_t base; + pciaddr_t size; + unsigned region; + unsigned flags; + void *memory; }; struct pci_device_private { @@ -63,6 +84,11 @@ struct pci_device_private { /*@}*/ /** + * Base address of the device's expansion ROM. + */ + pciaddr_t rom_base; + + /** * \name Bridge information. */ /*@{*/ @@ -71,7 +97,14 @@ struct pci_device_private { struct pci_pcmcia_bridge_info * pcmcia; } bridge; /*@}*/ - + + /** + * \name Mappings active on this device. + */ + /*@{*/ + struct pci_device_mapping *mappings; + unsigned num_mappings; + /*@}*/ }; @@ -93,9 +126,16 @@ struct pci_system { * Array of known devices. */ struct pci_device_private * devices; + +#ifdef HAVE_MTRR + int mtrr_fd; +#endif }; extern struct pci_system * pci_sys; extern int pci_system_linux_sysfs_create( void ); extern int pci_system_freebsd_create( void ); +extern int pci_system_openbsd_create( void ); +extern void pci_system_openbsd_init_dev_mem( int ); +extern int pci_system_solx_devfs_create( void ); diff --git a/lib/libpciaccess/src/scanpci.c b/lib/libpciaccess/src/scanpci.c index a3ec5c50e..c8a6adf81 100644 --- a/lib/libpciaccess/src/scanpci.c +++ b/lib/libpciaccess/src/scanpci.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <stdio.h> +#include <err.h> #include "pciaccess.h" @@ -60,7 +61,10 @@ print_pci_device( struct pci_device * dev, int verbose ) dev_name = "Device unknown"; } - printf("\npci bus 0x%04x cardnum 0x%02x function 0x%02x:" + printf("\npci "); + if (dev->domain != 0) + printf("domain 0x%04x ", dev->domain); + printf("bus 0x%04x cardnum 0x%02x function 0x%02x:" " vendor 0x%04x device 0x%04x\n", dev->bus, dev->dev, @@ -127,10 +131,10 @@ print_pci_device( struct pci_device * dev, int verbose ) pci_device_probe( dev ); for ( i = 0 ; i < 6 ; i++ ) { if ( dev->regions[i].base_addr != 0 ) { - printf( " BASE%u 0x%08x addr 0x%08x %s", + printf( " BASE%u 0x%08x SIZE %d %s", i, - 0, (intptr_t) dev->regions[i].base_addr, + (size_t) dev->regions[i].size, (dev->regions[i].is_IO) ? "I/O" : "MEM" ); if ( ! dev->regions[i].is_IO ) { @@ -176,8 +180,11 @@ int main( int argc, char ** argv ) { struct pci_device_iterator * iter; struct pci_device * dev; + int ret; - pci_system_init(); + ret = pci_system_init(); + if (ret != 0) + err(1, "Couldn't initialize PCI system"); iter = pci_slot_match_iterator_create( NULL ); diff --git a/lib/libpciaccess/src/solx_devfs.c b/lib/libpciaccess/src/solx_devfs.c index 058b604c5..a2daec164 100644 --- a/lib/libpciaccess/src/solx_devfs.c +++ b/lib/libpciaccess/src/solx_devfs.c @@ -100,19 +100,14 @@ static int xsvc_fd = -1; #define DEBUGON 0 - +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_map_region( struct pci_device * dev, - unsigned region, int write_enable ); - -static int pci_device_solx_devfs_unmap_region( struct pci_device * dev, - unsigned region ); - static int pci_device_solx_devfs_read( struct pci_device * dev, void * data, pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read ); @@ -144,8 +139,8 @@ static const struct pci_system_methods solx_devfs_methods = { .destroy_device = NULL, .read_rom = pci_device_solx_devfs_read_rom, .probe = pci_device_solx_devfs_probe, - .map = pci_device_solx_devfs_map_region, - .unmap = pci_device_solx_devfs_unmap_region, + .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, @@ -599,7 +594,7 @@ pci_device_solx_devfs_probe( struct pci_device * dev ) * using libdevinfo */ if ((rnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { - (void) fprintf(stderr, "di_init failed: $s\n", + (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno)); err = errno; } else { @@ -758,7 +753,7 @@ pci_device_solx_devfs_read( struct pci_device * dev, void * data, cfg_prg.offset = offset + i; if ((err = ioctl(root_fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) { - fprintf(stderr, "read bdf<%x,%x,%x,%x> config space failure\n", + fprintf(stderr, "read bdf<%x,%x,%x,%llx> config space failure\n", cfg_prg.bus_no, cfg_prg.dev_no, cfg_prg.func_no, @@ -836,55 +831,39 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data, } -/* - * Solaris Version +/** + * 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_region( struct pci_device * dev, unsigned region, - int write_enable ) +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; + if (xsvc_fd < 0) { if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) { - (void) fprintf(stderr, "can not open xsvc driver\n"); - - return (-1); + (void) fprintf(stderr, "can not open xsvc driver\n"); + return errno; } } - dev->regions[region].memory = mmap(NULL, dev->regions[region].size, - (write_enable) ? (PROT_READ | PROT_WRITE) : PROT_READ, MAP_SHARED, - xsvc_fd, dev->regions[region].base_addr); + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, + map->base); + if (map->memory == MAP_FAILED) { + err = errno; - if (dev->regions[region].memory == MAP_FAILED) { - dev->regions[region].memory = 0; - - (void) fprintf(stderr, "map rom region =%x failed", - dev->regions[region].base_addr); - return (-1); + (void) fprintf(stderr, "map rom region =%llx failed", + map->base); } - - /* - * Still used xsvc to do the user space mapping - */ - return (0); -} - -/* - * Solaris version - */ -static int -pci_device_solx_devfs_unmap_region( struct pci_device * dev, unsigned region ) -{ - int err = 0; - - if ( munmap( dev->regions[ region ].memory, dev->regions[ region ].size ) - == -1 ) { - err = errno; - } - - dev->regions[ region ].memory = NULL; - - return (err); + return err; } |