From 98afe3169509bceb7d81ad056fc16d16b71b006a Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 4 Nov 2005 03:34:08 +0000 Subject: 2005-11-03 Till Straumann * 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. --- .../lib/libbsp/powerpc/shared/motorola/motorola.c | 76 ++++- .../powerpc/shared/pci/detect_raven_bridge.c | 63 +++- c/src/lib/libbsp/powerpc/shared/pci/pci.c | 364 +++++++++++---------- c/src/lib/libbsp/powerpc/shared/pci/pci.h | 38 +++ .../lib/libbsp/powerpc/shared/pci/pcifinddevice.c | 150 +++++++-- 5 files changed, 489 insertions(+), 202 deletions(-) (limited to 'c') 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 +#include + #include #include #include @@ -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 +#include 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 #include +#include + +/* 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 0 ? PCI_MAX_FUNCTIONS : 1; - for (fun=0; fun 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; } -- cgit v1.2.3