diff options
-rw-r--r-- | c/src/lib/libbsp/Makefile.am | 3 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/Makefile.am | 1 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/Makefile.am | 3 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/include/bsp.h | 7 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/startup/bspstart.c | 29 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/shared/pci/pci_io.c | 198 | ||||
-rw-r--r-- | c/src/lib/libbsp/i386/shared/pci/pcibios.c | 149 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/pci/pci_bus_count.c | 67 | ||||
-rw-r--r-- | 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 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; +} |