[PATCH 05/17] Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space

Joel Sherrill joel at rtems.org
Thu Mar 10 16:31:02 UTC 2016


On Wed, Mar 9, 2016 at 8:21 PM, Gedare Bloom <gedare at rtems.org> wrote:

> On Wed, Mar 9, 2016 at 5:24 PM, Joel Sherrill <joel at rtems.org> wrote:
> > 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/startup/bspstart.c |  31 ++-
> >  c/src/lib/libbsp/i386/shared/pci/pci_io.c      | 200 ++++++++++++++++++
> >  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
> +++++++++++++++++++++++++
> >  8 files changed, 594 insertions(+), 134 deletions(-)
> >  create mode 100644 c/src/lib/libbsp/i386/shared/pci/pci_io.c
> >  create mode 100644 c/src/lib/libbsp/shared/pci/pci_bus_count.c
> >  create mode 100644 c/src/lib/libbsp/shared/pci/pci_find_device.c
> >
> > 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/startup/bspstart.c
> b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
> > index ac871f0..a0bbf66 100644
> > --- a/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
> > +++ b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
> > @@ -34,17 +34,40 @@
> >  #include <libcpu/cpuModel.h>
> >
> >  /*
> > + * PCI Bus Configuration
> > + */
> > +rtems_pci_config_t BSP_pci_configuration = {
> > +  (volatile unsigned char*)0,
> > +  (volatile unsigned char*)0,
> > +  NULL
> > +};
> > +
> > +const pci_config_access_functions *pci_bios_initialize(void);
> > +const pci_config_access_functions *pci_io_initialize(void);
> > +
> > +/*
> >   * 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
> >  }
> >
> > 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..9103b5c
> > --- /dev/null
> > +++ b/c/src/lib/libbsp/i386/shared/pci/pci_io.c
> > @@ -0,0 +1,200 @@
> > +#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;
> > +
> > +/* prototype before defining */
> > +const pci_config_access_functions *pci_io_initialize(void);
> > +
> Why isn't this coming from a header?
>
>
Just avoiding adding things to the bsp.h but that's another issue. I moved
this
prototype and the additional ones in bspstart.c to include/bsp.h.

Eventually we have to address public/private in bsp.h but that's not this
pass.

Thanks. I was torn on what to do.



> > +/*
> > + * 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;
> > +}
> > --
> > 1.8.3.1
> >
> > _______________________________________________
> > devel mailing list
> > devel at rtems.org
> > http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20160310/43e108ef/attachment-0002.html>


More information about the devel mailing list