summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2005-11-04 03:34:08 +0000
committerTill Straumann <strauman@slac.stanford.edu>2005-11-04 03:34:08 +0000
commit98afe3169509bceb7d81ad056fc16d16b71b006a (patch)
treeb69c3f20cb82fd70e1612ec4a72f4a169fc62cf8 /c
parent2005-11-03 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-98afe3169509bceb7d81ad056fc16d16b71b006a.tar.bz2
2005-11-03 Till Straumann <strauman@slac.stanford.edu>
* shared/motorola/motorola.c, shared/pci/detect_raven_bridge.c, shared/pci/pci.c, shared/pci/pci.h, shared/pci/pcifinddevice.c: Several PCI enhancements and fixes: all BSP flavors now use the generic clear_hostbridge_errors() routine (this means that only polling memory probing is possible [see detect_raven_bridge.c for details]). Interrupt fixup routine now supports multi-function devices. Interrupt fixup routine now honours a flag/option so that wrong firmware values can be overridden. Fixed irq routing table for mvme2100 [PMC]. Added irq routing table for mvme2300. Added a BSP_pciScan() routine that executes a user callback on each non-empty slot/fun. Added BSP_pciConfigDump() to display basic config headers.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/powerpc/shared/motorola/motorola.c76
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/detect_raven_bridge.c63
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pci.c364
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pci.h38
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c150
5 files changed, 489 insertions, 202 deletions
diff --git a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
index d928028f4c..7040a9860b 100644
--- a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
+++ b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
@@ -110,17 +110,79 @@ static struct _int_map mtx603_intmap[] = {
NULL_INTMAP };
+static struct _int_map mvme23xx_intmap[] = {
+/* Raven Hostbridge; has int_pin == 0
+ {0, 0, 0, {{0, {-1,-1,-1,-1}},
+ NULL_PINMAP}},
+*/
+
+/* Winbond PCI/ISA 83c553; has int_pin == 0
+ {0, 11, 0, {{0, {-1,-1,-1,-1}},
+ NULL_PINMAP}},
+*/
+
+#if 0 /* Leave as ISA interrupts for now */
+ {0, 13, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {11,21,-1,-1,-1}}, /* Universe ISA/PCI */
+ /* strictly speaking, a non-multi function device
+ * must only use pin A
+ */
+ {2, {22,-1,-1,-1,-1}}, /* Universe */
+ {3, {23,-1,-1,-1,-1}}, /* Universe */
+ {4, {24,-1,-1,-1,-1}}, /* Universe */
+ NULL_PINMAP}},
+
+ {0, 14, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {10,18,-1,-1}}, /* DEC Tulip enet (ISA/PCI) */
+ NULL_PINMAP}},
+#endif
+
+ {0, 16, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {25,-1,-1,-1}}, /* pci/pmc slot 1 */
+ {2, {26,-1,-1,-1}},
+ {3, {27,-1,-1,-1}},
+ {4, {28,-1,-1,-1}},
+ NULL_PINMAP}},
+
+ {0, 17, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {28,-1,-1,-1}}, /* pci/pmc slot 2 */ /* orig: 0xf */
+ {2, {25,-1,-1,-1}},
+ {3, {26,-1,-1,-1}},
+ {4, {27,-1,-1,-1}},
+ NULL_PINMAP}},
+
+ NULL_INTMAP };
+
static struct _int_map mvme2100_intmap[] = {
- {0, 0, 0, {{1, {16,-1,-1,-1}}, /* something shows up in slot 0 and OpenPIC */
- /* 0 is unused. This hushes the init code. */
+ {0, 0, 0, {{1, {16,-1,-1,-1}}, /* something shows up in slot 0 and OpenPIC */
+ /* 0 is unused. This hushes the init code. */
NULL_PINMAP}},
- {0, 13, 0, {{1, {23,24,25,26}}, /* PCI INT[A-D]/Universe Lint[0-3] */
+ {0, 13, 0, {{1, {23,-1,-1,-1}}, /* Universe Lint[0-3]; not quite legal */
+ {2, {24,-1,-1,-1}}, /* since the universe is a single-function */
+ {3, {25,-1,-1,-1}}, /* device. We leave it for info purposes */
+ {4, {26,-1,-1,-1}},
NULL_PINMAP}},
{0, 14, 0, {{1, {17,-1,-1,-1}}, /* onboard ethernet */
NULL_PINMAP}},
+ {0, 16, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {18,-1,-1,-1}}, /* PMC slot; all pins are routed to 18 */
+ {2, {18,-1,-1,-1}}, /* I give the OVERRIDE option since I had */
+ {3, {18,-1,-1,-1}}, /* problems with devices behind a bridge */
+ {4, {18,-1,-1,-1}}, /* on a PMC card reading irq line 0... */
+ NULL_PINMAP}},
+
+ /* FIXME: I don't know how MIP works or what it is; these probably won't work */
+
+ {0, -1, PCI_FIXUP_OPT_OVERRIDE_NAME,
+ {{1, {23,-1,-1,-1}}, /* PCI INT[A-D] expansion */
+ {2, {24,-1,-1,-1}},
+ {3, {25,-1,-1,-1}},
+ {4, {26,-1,-1,-1}},
+ NULL_PINMAP}},
+
NULL_INTMAP };
/*
@@ -169,8 +231,8 @@ static const mot_info_t mot_boards[] = {
{0x1E0, 0xF6, "MTX Plus", NULL, NULL},
{0x1E0, 0xF7, "MTX w/o Parallel Port", mtx603_intmap, prep_pci_swizzle},
{0x1E0, 0xF8, "MTX w/ Parallel Port", mtx603_intmap, prep_pci_swizzle},
- {0x1E0, 0xF9, "MVME 2300", NULL, NULL},
- {0x1E0, 0xFA, "MVME 2300SC/2600", NULL, NULL},
+ {0x1E0, 0xF9, "MVME 2300", mvme23xx_intmap, prep_pci_swizzle},
+ {0x1E0, 0xFA, "MVME 2300SC/2600", mvme23xx_intmap, prep_pci_swizzle},
{0x1E0, 0xFB, "MVME 2600 with MVME712M", NULL, NULL},
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761", NULL, NULL},
{0x1E0, 0xFD, "MVME 3600 with MVME712M", NULL, NULL},
@@ -188,9 +250,9 @@ prep_t checkPrepBoardType(RESIDUAL *res)
prep_t PREP_type;
/* figure out what kind of prep workstation we are */
if ( res->ResidualLength != 0 ) {
- if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+ if ( !strncmp((char*)res->VitalProductData.PrintableModel,"IBM",3) )
PREP_type = PREP_IBM;
- else if (!strncmp(res->VitalProductData.PrintableModel,
+ else if (!strncmp((char*)res->VitalProductData.PrintableModel,
"Radstone",8)){
PREP_type = PREP_Radstone;
}
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/detect_raven_bridge.c b/c/src/lib/libbsp/powerpc/shared/pci/detect_raven_bridge.c
index 1f02d4d2f6..2decf4e33a 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/detect_raven_bridge.c
+++ b/c/src/lib/libbsp/powerpc/shared/pci/detect_raven_bridge.c
@@ -23,15 +23,14 @@
#define RAVEN_MPIC_MEREN ((volatile unsigned *)0xfeff0020)
#define RAVEN_MPIC_MERST ((volatile unsigned *)0xfeff0024)
-/* enable machine check on all conditions */
#define MEREN_VAL 0x2f00
#define pci BSP_pci_configuration
-extern unsigned int EUMBBAR;
extern const pci_config_access_functions pci_direct_functions;
extern const pci_config_access_functions pci_indirect_functions;
+
#define PCI_ERR_BITS 0xf900
#define PCI_STATUS_OK(x) (!((x)&PCI_ERR_BITS))
@@ -78,9 +77,15 @@ int count;
return rval & PCI_ERR_BITS;
}
+#if (defined(mpc8240) || defined(mpc8245))
+/* FIXME - this should really be in a separate file - the 2100 doesn't
+ * have a raven chip so there is no point having 2100 code here
+ */
+
+extern unsigned int EUMBBAR;
+
void detect_host_bridge()
{
-#if (defined(mpc8240) || defined(mpc8245))
/*
* If the processor is an 8240 or an 8245 then the PIC is built
* in instead of being on the PCI bus. The MVME2100 is using Processor
@@ -92,8 +97,57 @@ void detect_host_bridge()
pci.pci_functions = &pci_indirect_functions;
pci.pci_config_addr = (volatile unsigned char *) 0xfec00000;
pci.pci_config_data = (volatile unsigned char *) 0xfee00000;
+}
#else
+
+#if 0
+/* Unfortunately, PCI config space access to empty slots generates
+ * a 'signalled master abort' condition --> we can't really use
+ * the machine check interrupt for memory probing unless
+ * we use probing for PCI scanning also (which would make
+ * all that code either BSP dependent or requiring yet another
+ * API, sigh...).
+ * So for the moment, we just don't use MCP on all mvme2xxx
+ * boards (using the generic, hostbridge-independent 'clear'
+ * implementation above).
+ */
+/*
+ * enableMCP: whether to enable MCP checkstop / machine check interrupts
+ * on the hostbridge and in HID0.
+ *
+ * NOTE: HID0 and MEREN are left alone if this flag is 0
+ *
+ * quiet : be silent
+ *
+ * RETURNS : raven MERST register contents (lowermost 16 bits), 0 if
+ * there were no errors
+ */
+unsigned long
+_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
+{
+unsigned merst;
+
+ merst = in_be32(RAVEN_MPIC_MERST);
+ /* write back value to clear status */
+ out_be32(RAVEN_MPIC_MERST, merst);
+
+ if (enableMCP) {
+ if (!quiet)
+ printk("Enabling MCP generation on hostbridge errors\n");
+ out_be32(RAVEN_MPIC_MEREN, MEREN_VAL);
+ } else {
+ out_be32(RAVEN_MPIC_MEREN, 0);
+ if ( !quiet && enableMCP ) {
+ printk("leaving MCP interrupt disabled\n");
+ }
+ }
+ return (merst & 0xffff);
+}
+#endif
+
+void detect_host_bridge()
+{
PPC_DEVICE *hostbridge;
unsigned int id0;
unsigned int tmp;
@@ -173,9 +227,10 @@ void detect_host_bridge()
printk("OpenPIC found at %x.\n", OpenPIC);
}
}
-#endif
if (OpenPIC == (volatile struct OpenPIC *)0) {
BSP_panic("OpenPic Not found\n");
}
}
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pci.c b/c/src/lib/libbsp/powerpc/shared/pci/pci.c
index 67268ea1cb..399558e5a7 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pci.c
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pci.c
@@ -19,6 +19,9 @@
* - separated bridge detection code out of this file
*/
+#include <rtems.h>
+#include <bsp.h>
+
#include <libcpu/io.h>
#include <bsp/pci.h>
#include <rtems/bspIo.h>
@@ -278,8 +281,8 @@ const pci_config_access_functions pci_direct_functions = {
};
#define PRINT_MSG() \
- printk("pci : Device %d:%02x routed to interrupt_line %d\n", \
- pbus, pslot, int_name )
+ printk("pci : Device %d:0x%02x:%d routed to interrupt_line %d\n", \
+ pbus, pslot, pfun, int_name )
/*
** Validate a test interrupt name and print a warning if its not one of
@@ -289,6 +292,7 @@ static int test_intname(
const struct _int_map *row,
int pbus,
int pslot,
+ int pfun,
int int_pin,
int int_name
) {
@@ -308,16 +312,25 @@ static int test_intname(
}
}
- if ( _nopin ) {
- printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n",
- pbus, pslot, int_pin );
- return -1;
- } else {
- if ( _noname )
- printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d,"
- " using it anyway\n", pbus, pslot, int_name );
- }
- return 0;
+ if( _nopin )
+ {
+ printk("pci : Device %d:0x%02x:%d supplied a bogus interrupt_pin %d\n", pbus, pslot, pfun, int_pin );
+ return -1;
+ }
+ else
+ {
+ if( _noname ) {
+ unsigned char v = row->pin_route[j].int_name[0];
+ printk("pci : Device %d:0x%02x:%d supplied a suspicious interrupt_line %d, ", pbus, pslot, pfun, int_name );
+ if ( (row->opts & PCI_FIXUP_OPT_OVERRIDE_NAME) && 255 != (v = row->pin_route[j].int_name[0]) ) {
+ printk("OVERRIDING with %d from fixup table\n", v);
+ pci_write_config_byte(pbus,pslot,pfun,PCI_INTERRUPT_LINE,v);
+ } else {
+ printk("using it anyway\n");
+ }
+ }
+ }
+ return 0;
}
struct pcibridge
@@ -347,7 +360,7 @@ static int FindPCIbridge( int mybus, struct pcibridge *pb )
pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec);
#if 0
- printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d ",
+ printk("pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ",
pbus, pslot, mybus, buspri, bussec );
#endif
if ( bussec == mybus ) {
@@ -374,7 +387,7 @@ void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
{
unsigned char cvalue;
uint16_t devid;
- int ismatch, i, j, pbus, pslot, int_pin, int_name;
+ int ismatch, i, j, pbus, pslot, pfun, int_pin, int_name, nfuns;
/*
* If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
@@ -383,173 +396,180 @@ void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
*/
for (pbus=0; pbus< pci_bus_count(); pbus++) {
- for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
- pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
- if ( devid == 0xffff ) continue;
+ for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
+ if ( devid == 0xffff ) continue;
+
+ /* got a device */
+ pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue);
+ nfuns = cvalue & PCI_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1;
- /* got a device */
+ for (pfun=0; pfun< nfuns; pfun++) {
+ pci_read_config_word(pbus, pslot, pfun, PCI_DEVICE_ID, &devid);
+ if( devid == 0xffff ) continue;
- pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
- int_pin = cvalue;
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_PIN, &cvalue);
+ int_pin = cvalue;
- pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
- int_name = cvalue;
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue);
+ int_name = cvalue;
- /* printk("pci : device %d:%02x devid %04x, intpin %d, intline %d\n",
- pbus, pslot, devid, int_pin, int_name ); */
+ /* printk("pci : device %d:0x%02x:%i devid %04x, intpin %d, intline %d\n",
+ pbus, pslot, pfun, devid, int_pin, int_name ); */
#if 0
- {
- unsigned short cmd,stat;
- unsigned char lat, seclat, csize;
-
- pci_read_config_word(pbus,pslot,0,PCI_COMMAND, &cmd );
- pci_read_config_word(pbus,pslot,0,PCI_STATUS, &stat );
- pci_read_config_byte(pbus,pslot,0,PCI_LATENCY_TIMER, &lat );
- pci_read_config_byte(pbus,pslot,0,PCI_SEC_LATENCY_TIMER, &seclat );
- pci_read_config_byte(pbus,pslot,0,PCI_CACHE_LINE_SIZE, &csize );
-
-
- printk("pci : device %d:%02x cmd %04X, stat %04X, latency %d, "
- " sec_latency %d, clsize %d\n", pbus, pslot, cmd, stat,
- lat, seclat, csize);
- }
-#endif
+ {
+ unsigned short cmd,stat;
+ unsigned char lat, seclat, csize;
- if ( int_pin > 0 ) {
- ismatch = 0;
-
- /*
- * first run thru the bspmap table and see if we have an
- * explicit configuration
- */
- for (i=0; bspmap[i].bus > -1; i++) {
- if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) {
- ismatch = -1;
- /* we have a record in the table that gives specific
- * pins and interrupts for devices in this slot */
- if ( int_name == 255 ) {
- /* find the vector associated with whatever pin the
- * device gives us
- */
- for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ) {
- if ( bspmap[i].pin_route[j].pin == int_pin ) {
- int_name = bspmap[i].pin_route[j].int_name[0];
- break;
- }
- }
- if ( int_name == -1 ) {
- printk("pci : Unable to resolve device %d:%d w/ swizzled int "
- "pin %i to an interrupt_line.\n", pbus, pslot, int_pin );
- } else {
- PRINT_MSG();
- pci_write_config_byte( pbus,pslot,0,
- PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
- }
- } else {
- test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
- }
- break;
- }
- }
+ pci_read_config_word(pbus,pslot,pfun,PCI_COMMAND, &cmd );
+ pci_read_config_word(pbus,pslot,pfun,PCI_STATUS, &stat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_LATENCY_TIMER, &lat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_SEC_LATENCY_TIMER, &seclat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_CACHE_LINE_SIZE, &csize );
- if ( !ismatch ) {
- /*
- * no match, which means we're on a bus someplace. Work
- * backwards from it to one of our defined busses,
- * swizzling thru each bridge on the way.
- */
-
- /* keep pbus, pslot pointed to the device being
- * configured while we track down the bridges using
- * tbus,tslot. We keep searching the routing table because
- * we may end up finding our bridge in it
- */
-
- int tbus= pbus, tslot= pslot;
-
- for (;;) {
- for (i=0; bspmap[i].bus > -1; i++) {
- if ( bspmap[i].bus == tbus &&
- (bspmap[i].slot == tslot || bspmap[i].slot == -1) ) {
- ismatch = -1;
- /* found a record for this bus, so swizzle the
- * int_pin which we then use to find the
- * interrupt_name.
- */
-
- if ( int_name == 255 ) {
- /*
- * FIXME. I can't believe this little hack
- * is right. It does not yield an error in
- * convienently simple situations.
- */
- if ( tbus ) int_pin = (*swizzler)(tslot,int_pin);
-
- /*
- * int_pin points to the interrupt channel
- * this card ends up delivering interrupts
- * on. Find the int_name servicing it.
- */
- for (int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++){
- if ( bspmap[i].pin_route[j].pin == int_pin ) {
- int_name = bspmap[i].pin_route[j].int_name[0];
- break;
- }
- }
-
- if ( int_name == -1 ) {
- printk("pci : Unable to resolve device %d:%d w/ swizzled "
- "int pin %i to an interrupt_line.\n",
- pbus, pslot, int_pin );
- } else {
- PRINT_MSG();
- pci_write_config_byte(pbus,pslot,0,
- PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue));
- }
- } else {
- test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
- }
- goto donesearch;
- }
- }
-
- if ( !ismatch ) {
- struct pcibridge pb;
-
- /*
- * Haven't found our bus in the int map, so work
- * upwards thru the bridges till we find it.
- */
-
- if ( FindPCIbridge( tbus, &pb )== 0 ) {
- int_pin = (*swizzler)(tslot,int_pin);
-
- /* our next bridge up is on pb.bus, pb.slot- now
- * instead of pointing to the device we're
- * trying to configure, we move from bridge to
- * bridge.
- */
-
- tbus = pb.bus;
- tslot = pb.slot;
- } else {
- printk("pci : No bridge from bus %i towards root found\n",
- tbus );
- goto donesearch;
- }
- }
- }
- }
- donesearch:
- if ( !ismatch && int_pin != 0 && int_name == 255 ) {
- printk("pci : Unable to match device %d:%d with an int "
- "routing table entry\n", pbus, pslot );
- }
- }
- }
- }
+ printk("pci : device %d:0x%02x:%d cmd %04X, stat %04X, latency %d, "
+ " sec_latency %d, clsize %d\n", pbus, pslot, pfun, cmd, stat,
+ lat, seclat, csize);
+ }
+#endif
+
+ if ( int_pin > 0 ) {
+ ismatch = 0;
+
+ /*
+ * first run thru the bspmap table and see if we have an
+ * explicit configuration
+ */
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) {
+ ismatch = -1;
+ /* we have a record in the table that gives specific
+ * pins and interrupts for devices in this slot */
+ if ( int_name == 255 ) {
+ /* find the vector associated with whatever pin the
+ * device gives us
+ */
+ for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ) {
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+ if ( int_name == -1 ) {
+ printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled int "
+ "pin %i to an interrupt_line.\n", pbus, pslot, pfun, int_pin );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte( pbus,pslot,pfun,
+ PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
+ }
+ } else {
+ test_intname( &bspmap[i],pbus,pslot,pfun,int_pin,int_name);
+ }
+ break;
+ }
+ }
+
+ if ( !ismatch ) {
+ /*
+ * no match, which means we're on a bus someplace. Work
+ * backwards from it to one of our defined busses,
+ * swizzling thru each bridge on the way.
+ */
+
+ /* keep pbus, pslot pointed to the device being
+ * configured while we track down the bridges using
+ * tbus,tslot. We keep searching the routing table because
+ * we may end up finding our bridge in it
+ */
+
+ int tbus= pbus, tslot= pslot;
+
+ for (;;) {
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == tbus &&
+ (bspmap[i].slot == tslot || bspmap[i].slot == -1) ) {
+ ismatch = -1;
+ /* found a record for this bus, so swizzle the
+ * int_pin which we then use to find the
+ * interrupt_name.
+ */
+
+ if ( int_name == 255 ) {
+ /*
+ * FIXME. I can't believe this little hack
+ * is right. It does not yield an error in
+ * convienently simple situations.
+ */
+ if ( tbus ) int_pin = (*swizzler)(tslot,int_pin);
+
+ /*
+ * int_pin points to the interrupt channel
+ * this card ends up delivering interrupts
+ * on. Find the int_name servicing it.
+ */
+ for (int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++){
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+
+ if ( int_name == -1 ) {
+ printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled "
+ "int pin %i to an interrupt_line.\n",
+ pbus, pslot, pfun, int_pin );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte(pbus,pslot,pfun,
+ PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue));
+ }
+ } else {
+ test_intname(&bspmap[i],pbus,pslot,pfun,int_pin,int_name);
+ }
+ goto donesearch;
+ }
+ }
+
+ if ( !ismatch ) {
+ struct pcibridge pb;
+
+ /*
+ * Haven't found our bus in the int map, so work
+ * upwards thru the bridges till we find it.
+ */
+
+ if ( FindPCIbridge( tbus, &pb )== 0 ) {
+ int_pin = (*swizzler)(tslot,int_pin);
+
+ /* our next bridge up is on pb.bus, pb.slot- now
+ * instead of pointing to the device we're
+ * trying to configure, we move from bridge to
+ * bridge.
+ */
+
+ tbus = pb.bus;
+ tslot = pb.slot;
+ } else {
+ printk("pci : No bridge from bus %i towards root found\n",
+ tbus );
+ goto donesearch;
+ }
+ }
+ }
+ }
+donesearch:
+
+ if ( !ismatch && int_pin != 0 && int_name == 255 ) {
+ printk("pci : Unable to match device %d:0x%02x:%d with an int "
+ "routing table entry\n", pbus, pslot, pfun );
+ }
+ }
+ }
+ }
+ }
}
/*
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pci.h b/c/src/lib/libbsp/powerpc/shared/pci/pci.h
index f81d84c32b..95ab36ee22 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pci.h
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pci.h
@@ -19,6 +19,7 @@
#define BSP_POWERPC_PCI_H
#include <rtems/pci.h>
+#include <stdio.h>
struct _pin_routes
{
@@ -30,9 +31,46 @@ struct _int_map
struct _pin_routes pin_route[5];
};
+/* If there's a conflict between a name in the routing table and
+ * what's already set on the device, reprogram the device setting
+ * to reflect int_name[0] for the routing table entry
+ */
+#define PCI_FIXUP_OPT_OVERRIDE_NAME (1<<0)
+
void FixupPCI( const struct _int_map *, int (*swizzler)(int,int) );
/* FIXME: This probably belongs into rtems/pci.h */
extern unsigned char pci_bus_count();
+/* FIXME: This also is generic and could go into rtems/pci.h */
+
+/* Scan pci config space and run a user callback on each
+ * device present; the user callback may return 0 to
+ * continue the scan or a value > 0 to abort the scan.
+ * Return values < 0 are reserved and must not be used.
+ *
+ * RETURNS: a (opaque) handle pointing to the bus/slot/fn-triple
+ * just after where the scan was aborted by a callback
+ * returning 1 (see above) or NULL if all devices were
+ * scanned.
+ * The handle may be passed to this routine to resume the
+ * scan continuing with the device after the one causing the
+ * abort.
+ * Pass a NULL 'handle' argument to start scanning from
+ * the beginning (bus/slot/fn = 0/0/0).
+ */
+typedef void *BSP_PciScanHandle;
+typedef int (*BSP_PciScannerCb)(int bus, int slot, int fun, void *uarg);
+
+BSP_PciScanHandle
+BSP_pciScan(BSP_PciScanHandle handle, BSP_PciScannerCb cb, void *uarg);
+
+/* Dump basic config. space info to a file. The argument may
+ * be NULL in which case 'stdout' is used.
+ * NOTE: the C-library must be functional before you can use
+ * this routine.
+ */
+void
+BSP_pciConfigDump(FILE *fp);
+
#endif /* BSP_POWERPC_PCI_H */
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c b/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
index 2c2c011dca..c660877680 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
@@ -12,6 +12,48 @@
#include <bsp/pci.h>
#include <rtems/bspIo.h>
+#include <stdio.h>
+
+/* Stolen from i386... */
+
+/*
+ * Make device signature from bus number, device number and function
+ * number
+ */
+#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
+
+/*
+ * Extract various parts from device signature
+ */
+#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
+#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
+#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+
+typedef struct {
+ unsigned short vid,did;
+ int inst;
+} fd_arg;
+
+static int
+find_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+) {
+fd_arg *a = uarg;
+unsigned short s;
+
+ pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
+ if (a->vid == s) {
+ pci_read_config_word(bus,dev,fun,PCI_DEVICE_ID,&s);
+ if (a->did == s && 0 == a->inst-- ) {
+ a->inst = PCIB_DEVSIG_MAKE( bus, dev, fun );
+ return 1;
+ }
+ }
+ return 0;
+}
int
pci_find_device(
@@ -22,39 +64,109 @@ pci_find_device(
int *pdev,
int *pfun
) {
+fd_arg a;
+void *h;
+ a.vid = vendorid;
+ a.did = deviceid;
+ a.inst = instance;
+
+ if ( (h = BSP_pciScan(0, find_dev_cb, (void*)&a)) ) {
+ *pbus = PCIB_DEVSIG_BUS( a.inst );
+ *pdev = PCIB_DEVSIG_DEV( a.inst );
+ *pfun = PCIB_DEVSIG_FUNC( a.inst );
+ return 0;
+ }
+ return -1;
+}
+
+static int
+dump_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+) {
+unsigned short vi,di;
+unsigned short cd,st;
+unsigned int b1,b2;
+unsigned char il,ip;
+FILE *f = uarg;
+
+ pci_read_config_word (bus, dev, fun, PCI_VENDOR_ID, &vi);
+ pci_read_config_word (bus, dev, fun, PCI_DEVICE_ID, &di);
+ pci_read_config_word (bus, dev, fun, PCI_COMMAND, &cd);
+ pci_read_config_word (bus, dev, fun, PCI_STATUS, &st);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_0, &b1);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_1, &b2);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_LINE, &il);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_PIN, &ip);
+
+ fprintf(f,"%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08x 0x%08x %d -> %3d (=0x%02x)\n",
+ bus, dev, fun, vi, di, cd, st, b1, b2, ip, il, il);
+ return 0;
+}
+
+void
+BSP_pciConfigDump(FILE *f)
+{
+ if ( !f )
+ f = stdout;
+ fprintf(f,"BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE\n");
+ BSP_pciScan(0, dump_dev_cb, f);
+}
+
+BSP_PciScanHandle
+BSP_pciScan(
+ BSP_PciScanHandle handle,
+ BSP_PciScannerCb cb,
+ void *uarg
+) {
+
unsigned int d;
- unsigned short s;
unsigned char bus,dev,fun,hd;
- for (bus=0; bus<pci_bus_count(); bus++) {
- for (dev=0; dev<PCI_MAX_DEVICES; dev++) {
+ bus = PCIB_DEVSIG_BUS( (unsigned long)handle );
+ dev = PCIB_DEVSIG_DEV( (unsigned long)handle );
+ fun = PCIB_DEVSIG_FUNC( (unsigned long)handle );
- pci_read_config_byte(bus,dev,0, PCI_HEADER_TYPE, &hd);
- hd = (hd & PCI_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
+ hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1;
- for (fun=0; fun<hd; fun++) {
+ 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;
+ if (PCI_MAX_DEVICES-1==dev && PCI_MAX_FUNCTIONS-1 == fun)
+ break;
+
+ (void)pci_read_config_dword(bus,dev,0,PCI_VENDOR_ID,&d);
+ if (PCI_INVALID_VENDORDEVICEID == d)
+ continue;
+
+ if ( 0 == fun ) {
+ pci_read_config_byte(bus,dev,0, PCI_HEADER_TYPE, &hd);
+ hd = (hd & PCI_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
+ }
+
(void)pci_read_config_dword(bus,dev,fun,PCI_VENDOR_ID,&d);
if (PCI_INVALID_VENDORDEVICEID == d)
continue;
#ifdef PCI_DEBUG
- printk("pci_find_by_devid: found 0x%08x at %d/%d/%d\n",d,bus,dev,fun);
+ printk("BSP_pciScan: found 0x%08x at %d/x%02x/%d\n",d,bus,dev,fun);
#endif
- (void) pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
- if (vendorid != s)
- continue;
- (void) pci_read_config_word(bus,dev,fun,PCI_DEVICE_ID,&s);
- if (deviceid == s) {
- if (instance--) continue;
- *pbus=bus; *pdev=dev; *pfun=fun;
- return 0;
- }
+ if ( cb(bus,dev,fun,uarg) > 0 ) {
+ if ( ++fun >= hd ) {
+ fun = 0;
+ if ( ++dev >= PCI_MAX_DEVICES ) {
+ dev = 0;
+ bus++;
+ }
+ }
+ return (void*) PCIB_DEVSIG_MAKE(bus,dev,fun);
+ }
}
}
}
- return -1;
+ return 0;
}