summaryrefslogtreecommitdiff
path: root/lib/libpciaccess/src
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2008-05-24 14:14:01 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2008-05-24 14:14:01 +0000
commit0f1aba46fc25a15bcbc53898548b85ff8b5f8455 (patch)
tree05b115425a1a111e8076e7bcd284d1284d1be2a6 /lib/libpciaccess/src
parentf091cb11ce9394593383465493467b328134bc42 (diff)
Merge libpciaccess 0.10.2, including kettenis@ OpenBSD port.
Diffstat (limited to 'lib/libpciaccess/src')
-rw-r--r--lib/libpciaccess/src/Makefile.am7
-rw-r--r--lib/libpciaccess/src/Makefile.in24
-rw-r--r--lib/libpciaccess/src/common_capability.c2
-rw-r--r--lib/libpciaccess/src/common_device_name.c5
-rw-r--r--lib/libpciaccess/src/common_init.c13
-rw-r--r--lib/libpciaccess/src/common_interface.c255
-rw-r--r--lib/libpciaccess/src/common_iterator.c3
-rw-r--r--lib/libpciaccess/src/common_map.c55
-rw-r--r--lib/libpciaccess/src/freebsd_pci.c184
-rw-r--r--lib/libpciaccess/src/linux_devmem.c156
-rw-r--r--lib/libpciaccess/src/linux_devmem.h34
-rw-r--r--lib/libpciaccess/src/linux_sysfs.c208
-rw-r--r--lib/libpciaccess/src/openbsd_pci.c444
-rw-r--r--lib/libpciaccess/src/pciaccess_private.h46
-rw-r--r--lib/libpciaccess/src/scanpci.c15
-rw-r--r--lib/libpciaccess/src/solx_devfs.c79
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, &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, &reg);
+ 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, &reg);
+ 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,
+ &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,
+ &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,
+ &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,
+ &reg) != 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;
}