summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386
diff options
context:
space:
mode:
authorJoel Sherrill <joel@rtems.org>2016-03-03 10:36:24 -0600
committerJoel Sherrill <joel@rtems.org>2016-03-10 10:30:25 -0600
commitf770fcb3688f4db8aabb13964dfcbe28ef6fbd02 (patch)
tree298c432cb62516bb77f9a022e28837ba953e440a /c/src/lib/libbsp/i386
parentpc386/configure.ac: Delete incorrect and unused AM_CONDITIONAL (diff)
downloadrtems-f770fcb3688f4db8aabb13964dfcbe28ef6fbd02.tar.bz2
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.
Diffstat (limited to 'c/src/lib/libbsp/i386')
-rw-r--r--c/src/lib/libbsp/i386/Makefile.am1
-rw-r--r--c/src/lib/libbsp/i386/pc386/Makefile.am3
-rw-r--r--c/src/lib/libbsp/i386/pc386/include/bsp.h7
-rw-r--r--c/src/lib/libbsp/i386/pc386/startup/bspstart.c29
-rw-r--r--c/src/lib/libbsp/i386/shared/pci/pci_io.c198
-rw-r--r--c/src/lib/libbsp/i386/shared/pci/pcibios.c149
6 files changed, 252 insertions, 135 deletions
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
-};