summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/Makefile.am3
-rw-r--r--c/src/lib/libbsp/i386/Makefile.am1
-rw-r--r--c/src/lib/libbsp/i386/pc386/Makefile.am3
-rw-r--r--c/src/lib/libbsp/i386/pc386/include/bsp.h7
-rw-r--r--c/src/lib/libbsp/i386/pc386/startup/bspstart.c29
-rw-r--r--c/src/lib/libbsp/i386/shared/pci/pci_io.c198
-rw-r--r--c/src/lib/libbsp/i386/shared/pci/pcibios.c149
-rw-r--r--c/src/lib/libbsp/shared/pci/pci_bus_count.c67
-rw-r--r--c/src/lib/libbsp/shared/pci/pci_find_device.c274
9 files changed, 596 insertions, 135 deletions
diff --git a/c/src/lib/libbsp/Makefile.am b/c/src/lib/libbsp/Makefile.am
index 16c276f7b0..c54fdcb7d6 100644
--- a/c/src/lib/libbsp/Makefile.am
+++ b/c/src/lib/libbsp/Makefile.am
@@ -29,6 +29,9 @@ EXTRA_DIST += shared/include/coverhd.h
EXTRA_DIST += shared/gdbstub/rtems-stub-glue.c
EXTRA_DIST += shared/include/bootcard.h
+EXTRA_DIST += shared/pci/pci_bus_count.c
+EXTRA_DIST += shared/pci/pci_find_device.c
+
include_bspdir = $(includedir)/bsp
include_bsp_HEADERS =
diff --git a/c/src/lib/libbsp/i386/Makefile.am b/c/src/lib/libbsp/i386/Makefile.am
index f10b764067..3b6df65b1d 100644
--- a/c/src/lib/libbsp/i386/Makefile.am
+++ b/c/src/lib/libbsp/i386/Makefile.am
@@ -22,6 +22,7 @@ EXTRA_DIST += shared/irq/irq_init.c
# shared/pci
EXTRA_DIST += shared/pci/pcibios.c
+EXTRA_DIST += shared/pci/pci_io.c
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.am b/c/src/lib/libbsp/i386/pc386/Makefile.am
index a9c645bb67..fc73afdbe9 100644
--- a/c/src/lib/libbsp/i386/pc386/Makefile.am
+++ b/c/src/lib/libbsp/i386/pc386/Makefile.am
@@ -141,6 +141,9 @@ libbsp_a_SOURCES += ../../shared/gnatinstallhandler.c
# pci
libbsp_a_SOURCES += ../../i386/shared/pci/pcibios.c
+libbsp_a_SOURCES += ../../i386/shared/pci/pci_io.c
+libbsp_a_SOURCES += ../../shared/pci/pci_bus_count.c
+libbsp_a_SOURCES += ../../shared/pci/pci_find_device.c
include_HEADERS += ../../i386/shared/comm/uart.h
# startup
diff --git a/c/src/lib/libbsp/i386/pc386/include/bsp.h b/c/src/lib/libbsp/i386/pc386/include/bsp.h
index 3d29e3ec18..5778c75696 100644
--- a/c/src/lib/libbsp/i386/pc386/include/bsp.h
+++ b/c/src/lib/libbsp/i386/pc386/include/bsp.h
@@ -59,6 +59,7 @@
#include <rtems/clockdrv.h>
#include <rtems/score/cpu.h>
#include <rtems/bspIo.h>
+#include <rtems/pci.h>
#ifdef __cplusplus
extern "C" {
@@ -275,6 +276,12 @@ uint32_t BSP_irq_count_dump(FILE *f);
void raw_idt_notify(void);
void C_dispatch_isr(int vector);
+/*
+ * PCI Support Methods
+ */
+const pci_config_access_functions *pci_bios_initialize(void);
+const pci_config_access_functions *pci_io_initialize(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/i386/pc386/startup/bspstart.c b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
index ac871f0565..f74300e971 100644
--- a/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
+++ b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
@@ -34,17 +34,37 @@
#include <libcpu/cpuModel.h>
/*
+ * PCI Bus Configuration
+ */
+rtems_pci_config_t BSP_pci_configuration = {
+ (volatile unsigned char*)0,
+ (volatile unsigned char*)0,
+ NULL
+};
+
+/*
* Helper to initialize the PCI Bus
*/
static void bsp_pci_initialize_helper(void)
{
#if (BSP_IS_EDISON == 0)
- int pci_init_retval;
+ const pci_config_access_functions *pci_accessors;
- pci_init_retval = pci_initialize();
- if (pci_init_retval != PCIB_ERR_SUCCESS) {
- printk("PCI bus: could not initialize PCI BIOS interface\n");
+ pci_accessors = pci_bios_initialize();
+ if (pci_accessors != NULL) {
+ printk("PCI bus: using PCI BIOS interface\n");
+ BSP_pci_configuration.pci_functions = pci_accessors;
+ return;
}
+
+ pci_accessors = pci_io_initialize();
+ if (pci_accessors != NULL) {
+ printk("PCI bus: using PCI I/O interface\n");
+ BSP_pci_configuration.pci_functions = pci_accessors;
+ return;
+ }
+
+ printk("PCI bus: could not initialize PCI BIOS interface\n");
#endif
}
@@ -65,7 +85,6 @@ static void bsp_start_default( void )
*edison_wd = 0x11f8;
#endif
-
/*
* Calibrate variable for 1ms-loop (see timer.c)
*/
diff --git a/c/src/lib/libbsp/i386/shared/pci/pci_io.c b/c/src/lib/libbsp/i386/shared/pci/pci_io.c
new file mode 100644
index 0000000000..5947c04388
--- /dev/null
+++ b/c/src/lib/libbsp/i386/shared/pci/pci_io.c
@@ -0,0 +1,198 @@
+#include <rtems.h>
+#include <rtems/pci.h>
+#include <bsp.h>
+
+static int pci_io_initialized = 0;
+
+/*
+ * Forward reference. Initialized at bottom.
+ */
+static const pci_config_access_functions pci_io_indirect_functions;
+
+/*
+ * Detects presense of PCI Configuration is in I/O space. If so, return
+ * pointer to accessor methods.
+ *
+ * NOTE: TBD to determine if (a) PCI Bus exists and (b) this is the
+ * access method.
+ */
+const pci_config_access_functions *pci_io_initialize(void)
+{
+ pci_io_initialized = 1;
+
+ printk( "PCI I/O Support Initialized\n" );
+
+ return &pci_io_indirect_functions;
+}
+
+/*
+ * Build PCI Address
+ */
+static inline uint32_t pci_io_build_address(
+ uint16_t bus,
+ uint16_t slot,
+ uint16_t function,
+ uint16_t offset
+)
+{
+ uint32_t bus_u32 = (uint32_t)bus;
+ uint32_t slot_u32 = (uint32_t)slot;
+ uint32_t function_u32 = (uint32_t)function;
+ uint32_t address;
+
+ /*
+ * create configuration address as per figure at
+ * http://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
+ */
+ address = (uint32_t) 0x80000000; /* Bit 31 - Enable Bit */
+ /* Bits 30-24 - Reserved */
+ address |= bus_u32 << 16; /* Bits 23-16 - Bus Number */
+ address |= slot_u32 << 11; /* Bits 15-11 - Device/Slot Number */
+ address |= function_u32 << 8; /* Bits 10-8 - Function Number */
+ address |= offset & 0xfc; /* Bits 7-2 - Offset/Register Number */
+ /* Bits 1-0 - Reserved 0 */
+ return address;
+}
+
+static int BSP_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 3) * 8) = 0 will choose the first byte of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 3) * 8)) & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 2) * 8)) & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ *value = tmp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_byte(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_word(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_long(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static const pci_config_access_functions pci_io_indirect_functions = {
+ BSP_pci_read_config_byte,
+ BSP_pci_read_config_word,
+ BSP_pci_read_config_dword,
+ BSP_pci_write_config_byte,
+ BSP_pci_write_config_word,
+ BSP_pci_write_config_dword
+};
diff --git a/c/src/lib/libbsp/i386/shared/pci/pcibios.c b/c/src/lib/libbsp/i386/shared/pci/pcibios.c
index 7dc53a125e..e74649413b 100644
--- a/c/src/lib/libbsp/i386/shared/pci/pcibios.c
+++ b/c/src/lib/libbsp/i386/shared/pci/pcibios.c
@@ -40,16 +40,23 @@ static int pcib_convert_err(int err);
#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+
/*
- * Detects presense of PCI BIOS, returns
- * error code
+ * Forward reference. Initialized at bottom.
*/
-int
-pci_initialize(void)
+static const pci_config_access_functions pci_bios_indirect_functions;
+
+/* prototype before defining */
+const pci_config_access_functions *pci_bios_initialize(void);
+
+/*
+ * Detects presense of PCI BIOS, returns pointer to accessor methods.
+ */
+const pci_config_access_functions *pci_bios_initialize(void)
{
unsigned char *ucp;
- unsigned char sum;
- int i;
+ unsigned char sum;
+ int i;
pcibInitialized = 0;
@@ -80,7 +87,7 @@ pci_initialize(void)
if (ucp >= (unsigned char *)0xFFFFF) {
/* BIOS-32 not found */
- return PCIB_ERR_NOTPRESENT;
+ return NULL;
}
/* BIOS-32 found, let us find PCI BIOS */
@@ -102,7 +109,7 @@ pci_initialize(void)
if ((pcibExchg[0] & 0xff) != 0) {
/* Not found */
- return PCIB_ERR_NOTPRESENT;
+ return NULL;
}
/* Found PCI entry point */
@@ -125,130 +132,18 @@ pci_initialize(void)
if ((pcibExchg[0] & 0xff00) != 0) {
/* Not found */
- return PCIB_ERR_NOTPRESENT;
+ return NULL;
}
if (pcibExchg[3] != 0x20494350) {
/* Signature does not match */
- return PCIB_ERR_NOTPRESENT;
+ return NULL;
}
/* Success */
-
pcibInitialized = 1;
- return PCIB_ERR_SUCCESS;
-}
-
-/*
- * Find specified device and return its signature: combination
- * of bus number, device number and function number
- */
-static int
-pcib_find_by_devid(int vendorId, int devId, int idx, int *sig)
-{
- if (!pcibInitialized) {
- return PCIB_ERR_UNINITIALIZED;
- }
-
- pcibExchg[0] = pcibEntry;
- pcibExchg[1] = vendorId;
- pcibExchg[2] = devId;
- pcibExchg[3] = idx;
-
- __asm__ (" pusha");
- __asm__ (" movl pcibExchg, %edi");
- __asm__ (" movb $0xb1, %ah");
- __asm__ (" movb $0x02, %al");
- __asm__ (" movl pcibExchg+4, %edx");
- __asm__ (" movl pcibExchg+8, %ecx");
- __asm__ (" movl pcibExchg+12, %esi");
- __asm__ (" pushl %cs");
- __asm__ (" call *%edi");
- __asm__ (" movl %eax, pcibExchg");
- __asm__ (" movl %ebx, pcibExchg+4");
- __asm__ (" popa");
-
- *sig = pcibExchg[1] & 0xffff;
- return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
-}
-
-int
-pci_find_device(
- unsigned short vendorid,
- unsigned short deviceid,
- int instance,
- int *pbus,
- int *pdev,
- int *pfun
-)
-{
- int status;
- int sig = 0;
-
- status = pcib_find_by_devid( vendorid, deviceid, instance, &sig );
-
- *pbus = PCIB_DEVSIG_BUS(sig);
- *pdev = PCIB_DEVSIG_DEV(sig);
- *pfun = PCIB_DEVSIG_FUNC(sig);
- return status ? -1 : 0;
-}
-
-static uint8_t ucBusCount = 0xff;
-
-unsigned char
-pci_bus_count(void)
-{
- if ( ucBusCount == 0xff ) {
- unsigned char bus;
- unsigned char dev;
- unsigned char fun;
- unsigned char nfn;
- unsigned char hd = 0;
- uint32_t d = 0;
-
- ucBusCount = 0;
-
- for (bus=0; bus< 0xff; bus++) {
- for (dev=0; dev<PCI_MAX_DEVICES; dev++) {
- pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &d);
-
- if ( -1 == d ) {
- continue;
- }
-
- pci_read_config_byte(bus, dev, fun, PCI_HEADER_TYPE, &hd);
- nfn = (hd & 0x80) ? PCI_MAX_FUNCTIONS : 1;
-
- for ( fun=0; fun<nfn; fun++ ) {
-
- pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &d);
- if ( -1 == d )
- continue;
-
- pci_read_config_dword(bus, dev, fun, PCI_CLASS_REVISION, &d);
-
- if ( (d >> 16) == PCI_CLASS_BRIDGE_PCI ) {
- pci_read_config_byte(bus, dev, fun, PCI_SUBORDINATE_BUS, &hd);
-
- if ( hd > ucBusCount )
- ucBusCount = hd;
- }
-
- }
- }
- }
-
- if ( ucBusCount == 0 ) {
- printk("pci_bus_count() found 0 busses, assuming 1\n");
- ucBusCount = 1;
- } else if ( ucBusCount == 0xff ) {
- printk("pci_bus_count() found 0xff busses, assuming 1\n");
- ucBusCount = 1;
- }
- }
-
- return ucBusCount;
+ return &pci_bios_indirect_functions;
}
/*
@@ -568,7 +463,7 @@ BSP_pci_write_config_dword(
return PCIBIOS_SUCCESSFUL;
}
-const pci_config_access_functions pci_indirect_functions = {
+static const pci_config_access_functions pci_bios_indirect_functions = {
BSP_pci_read_config_byte,
BSP_pci_read_config_word,
BSP_pci_read_config_dword,
@@ -576,9 +471,3 @@ const pci_config_access_functions pci_indirect_functions = {
BSP_pci_write_config_word,
BSP_pci_write_config_dword
};
-
-rtems_pci_config_t BSP_pci_configuration = {
- (volatile unsigned char*)0,
- (volatile unsigned char*)0,
- &pci_indirect_functions
-};
diff --git a/c/src/lib/libbsp/shared/pci/pci_bus_count.c b/c/src/lib/libbsp/shared/pci/pci_bus_count.c
new file mode 100644
index 0000000000..d0c7c80f54
--- /dev/null
+++ b/c/src/lib/libbsp/shared/pci/pci_bus_count.c
@@ -0,0 +1,67 @@
+/*
+ * This software is Copyright (C) 1998 by T.sqware - all rights limited
+ * It is provided in to the public domain "as is", can be freely modified
+ * as far as this copyight notice is kept unchanged, but does not imply
+ * an endorsement by T.sqware of the product in which it is included.
+ */
+
+#include <rtems.h>
+#include <rtems/pci.h>
+
+static uint8_t pci_number_of_buses = 0xff;
+
+unsigned char pci_bus_count(void)
+{
+ if ( pci_number_of_buses != 0xff ) {
+ return pci_number_of_buses;
+ }
+
+ uint8_t bus;
+ uint8_t device;
+ uint8_t function;
+ uint8_t number_of_functions;
+ uint8_t header = 0;
+ uint8_t buses = 0;
+ uint32_t vendor = 0;
+ uint32_t class_rev = 0;
+
+ pci_number_of_buses = 0;
+
+ for (bus=0; bus < 0xff; bus++) {
+ for (device=0; device < PCI_MAX_DEVICES; device++) {
+
+ pci_read_config_dword(bus, device, 0, PCI_VENDOR_ID, &vendor);
+ if ( vendor == -1 ) {
+ continue;
+ }
+
+ pci_read_config_byte(bus, device, 0, PCI_HEADER_TYPE, &header);
+ number_of_functions = (header & 0x80) ? PCI_MAX_FUNCTIONS : 1;
+
+ for ( function=0; function < number_of_functions; function++ ) {
+ pci_read_config_dword(bus, device, function, PCI_VENDOR_ID, &vendor);
+ if ( vendor == -1 ) {
+ continue;
+ }
+
+ pci_read_config_dword(bus, device, function, PCI_CLASS_REVISION, &class_rev);
+ if ( (class_rev >> 16) == PCI_CLASS_BRIDGE_PCI ) {
+ pci_read_config_byte(bus, device, function, PCI_SUBORDINATE_BUS, &buses);
+ if ( buses > pci_number_of_buses ) {
+ pci_number_of_buses = buses;
+ }
+ }
+ }
+ }
+ }
+
+ if ( pci_number_of_buses == 0 ) {
+ printk("pci_bus_count() found 0 busses, assuming 1\n");
+ pci_number_of_buses = 1;
+ } else if ( pci_number_of_buses == 0xff ) {
+ printk("pci_bus_count() found 0xff busses, assuming 1\n");
+ pci_number_of_buses = 1;
+ }
+
+ return pci_number_of_buses;
+}
diff --git a/c/src/lib/libbsp/shared/pci/pci_find_device.c b/c/src/lib/libbsp/shared/pci/pci_find_device.c
new file mode 100644
index 0000000000..1feddcc574
--- /dev/null
+++ b/c/src/lib/libbsp/shared/pci/pci_find_device.c
@@ -0,0 +1,274 @@
+/**
+ * @file
+ *
+ * This file implements a BSP independent version of pci_find_device().
+ */
+
+/*
+ * The software in this file was based upon the pci_find_device()
+ * implementation provided by Till Straumann under the following terms.
+ * That implementation had been copied to multiple BSPs. This implementation
+ * is BSP independent and follows RTEMS Project coding guidelines.
+ *
+ * COPYRIGHT (c) 2016.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2001,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+
+#include <rtems/pci.h>
+#include <rtems/bspIo.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+/*
+ * Public methods from this file
+ */
+void pci_dump(FILE *f);
+
+/*
+ * These are used to construct the handle returned by pci_find_device()
+ * but the caller does not need to know how to decode them.
+ */
+#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
+#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
+#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
+
+/*
+ * Function pointer to helper function called during bus iteration.
+ */
+typedef int (*pci_scan_helper_t)(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+);
+
+/*
+ *
+ */
+static uint32_t pci_scan(
+ uint32_t handle,
+ pci_scan_helper_t helper,
+ void *uarg
+);
+
+typedef struct {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ int instance;
+ uint8_t bus;
+ uint8_t device;
+ uint8_t function;
+} pci_scan_arg_t;
+
+static int find_dev_helper(
+ int bus,
+ int device,
+ int function,
+ void *uarg
+)
+{
+ pci_scan_arg_t *scan = uarg;
+ uint16_t vendor_tmp;
+ uint16_t device_tmp;
+
+ pci_read_config_word(bus, device, function, PCI_VENDOR_ID, &vendor_tmp);
+ if (scan->vendor_id == vendor_tmp) {
+ pci_read_config_word(bus, device, function, PCI_DEVICE_ID, &device_tmp);
+ if (scan->device_id == device_tmp && scan->instance-- == 0) {
+ scan->bus = bus;
+ scan->device = device;
+ scan->function = function;
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int pci_find_device(
+ uint16_t vendorid,
+ uint16_t deviceid,
+ int instance,
+ int *bus,
+ int *device,
+ int *function
+)
+{
+ pci_scan_arg_t scan;
+
+ scan.instance = instance;
+ scan.vendor_id = vendorid;
+ scan.device_id = deviceid;
+
+ if ( pci_scan(0, find_dev_helper, (void*)&scan) != 0 ) {
+ *bus = scan.bus;
+ *device = scan.device;
+ *function = scan.function;
+ return 0;
+ }
+ return -1;
+}
+
+static int dump_dev_helper(
+ int bus,
+ int device,
+ int function,
+ void *arg
+)
+{
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t cmd;
+ uint16_t status;
+ uint32_t base0;
+ uint32_t base1;
+ uint8_t irq_pin;
+ uint8_t int_line;
+ FILE *fp = arg;
+
+ pci_read_config_word (bus, device, function, PCI_VENDOR_ID, &vendor_id);
+ pci_read_config_word (bus, device, function, PCI_DEVICE_ID, &device_id);
+ pci_read_config_word (bus, device, function, PCI_COMMAND, &cmd);
+ pci_read_config_word (bus, device, function, PCI_STATUS, &status);
+ pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_0, &base0);
+ pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_1, &base1);
+ pci_read_config_byte (bus, device, function, PCI_INTERRUPT_PIN, &irq_pin);
+ pci_read_config_byte (bus, device, function, PCI_INTERRUPT_LINE, &int_line);
+
+ fprintf(
+ fp,
+ "%3d:0x%02x:%d 0x%04x:0x%04x 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 " %d %3d(0x%02x)\n",
+ bus,
+ device,
+ function,
+ vendor_id,
+ device_id,
+ cmd,
+ status,
+ base0,
+ base1,
+ irq_pin,
+ int_line,
+ int_line
+ );
+ return 0;
+}
+
+void pci_dump(
+ FILE *fp
+)
+{
+ if ( !fp )
+ fp = stdout;
+ fprintf(
+ fp,
+ "BUS:SLOT:FUN VENDOR:DEV_ID CMD STAT BASE_ADDR0 BASE_ADDR1 INTn IRQ_LINE\n"
+ );
+ pci_scan(0, dump_dev_helper, fp);
+}
+
+static uint32_t pci_scan(
+ uint32_t handle,
+ pci_scan_helper_t helper,
+ void *arg
+)
+{
+ uint32_t vendor;
+ uint8_t bus;
+ uint8_t dev;
+ uint8_t fun;
+ uint8_t hd;
+
+ bus = PCIB_DEVSIG_BUS( (unsigned long)handle );
+ dev = PCIB_DEVSIG_DEV( (unsigned long)handle );
+ fun = PCIB_DEVSIG_FUNC( (unsigned long)handle );
+
+ hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1;
+
+ for (; bus<pci_bus_count(); bus++, dev=0) {
+ for (; dev<PCI_MAX_DEVICES; dev++, fun=0) {
+ for (; fun<hd; fun++) {
+ /*
+ * The last devfn id/slot is special; must skip it
+ */
+ if ((PCI_MAX_DEVICES-1 == dev) && (PCI_MAX_FUNCTIONS-1 == fun) )
+ break;
+
+ (void)pci_read_config_dword(bus, dev, 0, PCI_VENDOR_ID, &vendor);
+ if (PCI_INVALID_VENDORDEVICEID == vendor)
+ continue;
+
+ if ( fun == 0 ) {
+ pci_read_config_byte(bus,dev, 0, PCI_HEADER_TYPE, &hd);
+ hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
+ }
+
+ (void)pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &vendor);
+ if (PCI_INVALID_VENDORDEVICEID == vendor)
+ continue;
+ #ifdef PCI_DEBUG
+ fprintf(
+ stderr,
+ "pci_scan: found 0x%08" PRIx32 " at %d/x%02x/%d\n", vendor, bus, dev, fun
+ );
+ #endif
+ if ( (*helper)(bus, dev, fun, arg) > 0 ) {
+ if ( ++fun >= hd ) {
+ fun = 0;
+ if ( ++dev >= PCI_MAX_DEVICES ) {
+ dev = 0;
+ bus++;
+ }
+ }
+ return PCIB_DEVSIG_MAKE(bus,dev,fun);
+ }
+ }
+ }
+ }
+ return 0;
+}