[PATCH 05/17] Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space
Gedare Bloom
gedare at rtems.org
Thu Mar 10 02:21:37 UTC 2016
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?
> +/*
> + * 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
More information about the devel
mailing list