[rtems commit] Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space

Joel Sherrill joel at rtems.org
Thu Mar 10 16:45:12 UTC 2016


Module:    rtems
Branch:    master
Commit:    f770fcb3688f4db8aabb13964dfcbe28ef6fbd02
Changeset: http://git.rtems.org/rtems/commit/?id=f770fcb3688f4db8aabb13964dfcbe28ef6fbd02

Author:    Joel Sherrill <joel at rtems.org>
Date:      Thu Mar  3 10:36:24 2016 -0600

Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space

This patch fundamentally results from enhancements to the pc386 BSP
to support systems which do **NOT** have the legacy PCI BIOS. The
patch adds support for detecting when legacy PCI BIOS is not
present and then using IO space to access to PCI Configuration Space.
This resulted in dynamically selected between two implementations
of PCI and refactoring out the shared methods.

This patch adds shared implementations of pci_bus_count() and
pci_find_device(). Subsequent patches will remove implementations
of these methods in other BSPs where possible.

---

 c/src/lib/libbsp/Makefile.am                   |   3 +
 c/src/lib/libbsp/i386/Makefile.am              |   1 +
 c/src/lib/libbsp/i386/pc386/Makefile.am        |   3 +
 c/src/lib/libbsp/i386/pc386/include/bsp.h      |   7 +
 c/src/lib/libbsp/i386/pc386/startup/bspstart.c |  29 ++-
 c/src/lib/libbsp/i386/shared/pci/pci_io.c      | 198 ++++++++++++++++++
 c/src/lib/libbsp/i386/shared/pci/pcibios.c     | 149 ++------------
 c/src/lib/libbsp/shared/pci/pci_bus_count.c    |  67 ++++++
 c/src/lib/libbsp/shared/pci/pci_find_device.c  | 274 +++++++++++++++++++++++++
 9 files changed, 596 insertions(+), 135 deletions(-)

diff --git a/c/src/lib/libbsp/Makefile.am b/c/src/lib/libbsp/Makefile.am
index 16c276f..c54fdcb 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 f10b764..3b6df65 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 a9c645b..fc73afd 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 3d29e3e..5778c75 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 ac871f0..f74300e 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 0000000..5947c04
--- /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 7dc53a1..e746494 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 0000000..d0c7c80
--- /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 0000000..1feddcc
--- /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 at 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;
+}




More information about the vc mailing list