diff options
Diffstat (limited to 'bsps/powerpc/shared')
-rw-r--r-- | bsps/powerpc/shared/pci/detect_raven_bridge.c | 197 | ||||
-rw-r--r-- | bsps/powerpc/shared/pci/generic_clear_hberrs.c | 63 | ||||
-rw-r--r-- | bsps/powerpc/shared/pci/pci.c | 640 | ||||
-rw-r--r-- | bsps/powerpc/shared/pci/pcifinddevice.c | 212 |
4 files changed, 1112 insertions, 0 deletions
diff --git a/bsps/powerpc/shared/pci/detect_raven_bridge.c b/bsps/powerpc/shared/pci/detect_raven_bridge.c new file mode 100644 index 0000000000..0a1c04a2e2 --- /dev/null +++ b/bsps/powerpc/shared/pci/detect_raven_bridge.c @@ -0,0 +1,197 @@ +#include <libcpu/io.h> +#include <libcpu/spr.h> +#include <inttypes.h> + +#include <bsp.h> +#include <bsp/pci.h> +#include <bsp/consoleIo.h> +#include <bsp/residual.h> +#include <bsp/openpic.h> +#include <bsp/irq.h> + +#include <rtems/bspIo.h> +#include <libcpu/cpuIdent.h> + +#define SHOW_RAVEN_SETTINGS + +#define RAVEN_MPIC_IOSPACE_ENABLE 0x0001 +#define RAVEN_MPIC_MEMSPACE_ENABLE 0x0002 +#define RAVEN_MASTER_ENABLE 0x0004 +#define RAVEN_PARITY_CHECK_ENABLE 0x0040 +#define RAVEN_SYSTEM_ERROR_ENABLE 0x0100 +#define RAVEN_CLEAR_EVENTS_MASK 0xf9000000 + +#define RAVEN_MPIC_MEREN ((volatile unsigned *)0xfeff0020) +#define RAVEN_MPIC_MERST ((volatile unsigned *)0xfeff0024) +#define MEREN_VAL 0x2f00 + +#define pci BSP_pci_configuration + +extern const pci_config_access_functions pci_direct_functions; +extern const pci_config_access_functions pci_indirect_functions; + +#if defined(mvme2100) +/* 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(void) +{ + /* + * 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 + * Address Map B (CHRP) although the Programmer's Reference Guide says + * it defaults to Map A. + */ + /* We have an EPIC Interrupt Controller */ + OpenPIC = (volatile struct OpenPIC *) (EUMBBAR + BSP_OPEN_PIC_BASE_OFFSET); + 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 [generic_clear_hberrs.c]). + */ +/* + * 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(void) +{ + PPC_DEVICE *hostbridge; + uint32_t id0; + uint32_t tmp; + + /* + * This code assumes that the host bridge is located at + * bus 0, dev 0, func 0 AND that the old pre PCI 2.1 + * standard devices detection mechanism that was used on PC + * (still used in BSD source code) works. + */ + hostbridge=residual_find_device(&residualCopy, PROCESSORDEVICE, NULL, + BridgeController, + PCIBridge, -1, 0); + if (hostbridge) { + if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) { + pci.pci_functions=&pci_indirect_functions; + /* Should be extracted from residual data, + * indeed MPC106 in CHRP mode is different, + * but we should not use residual data in + * this case anyway. + */ + pci.pci_config_addr = ((volatile unsigned char *) + (ptr_mem_map->io_base+0xcf8)); + pci.pci_config_data = ptr_mem_map->io_base+0xcfc; + } else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) { + pci.pci_functions=&pci_direct_functions; + pci.pci_config_data=(unsigned char *) 0x80800000; + } else { + } + } else { + /* Let us try by experimentation at our own risk! */ + pci.pci_functions = &pci_direct_functions; + /* On all direct bridges I know the host bridge itself + * appears as device 0 function 0. + */ + pci_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &id0); + if (id0==~0U) { + pci.pci_functions = &pci_indirect_functions; + pci.pci_config_addr = ((volatile unsigned char*) + (ptr_mem_map->io_base+0xcf8)); + pci.pci_config_data = ((volatile unsigned char*)ptr_mem_map->io_base+0xcfc); + } + /* Here we should check that the host bridge is actually + * present, but if it not, we are in such a desperate + * situation, that we probably can't even tell it. + */ + } + pci_read_config_dword(0, 0, 0, 0, &id0); +#ifdef SHOW_RAVEN_SETTINGS + printk("idreg 0 = 0x%" PRIu32 "\n",id0); +#endif + if((id0 == PCI_VENDOR_ID_MOTOROLA + + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) || + (id0 == PCI_VENDOR_ID_MOTOROLA + + (PCI_DEVICE_ID_MOTOROLA_HAWK<<16))) { + /* + * We have a Raven bridge. We will get information about its settings + */ + pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0); +#ifdef SHOW_RAVEN_SETTING + printk("RAVEN PCI command register = %x\n",id0); +#endif + id0 |= RAVEN_CLEAR_EVENTS_MASK; + pci_write_config_dword(0, 0, 0, PCI_COMMAND, id0); + pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0); +#ifdef SHOW_RAVEN_SETTING + printk("After error clearing RAVEN PCI command register = %x\n",id0); +#endif + + if (id0 & RAVEN_MPIC_IOSPACE_ENABLE) { + pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_0, &tmp); +#ifdef SHOW_RAVEN_SETTING + printk("Raven MPIC is accessed via IO Space Access at address : %x\n",(tmp & ~0x1)); +#endif + } + if (id0 & RAVEN_MPIC_MEMSPACE_ENABLE) { + pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_1, &tmp); +#ifdef SHOW_RAVEN_SETTING + printk("Raven MPIC is accessed via memory Space Access at address : %x\n", tmp); +#endif + OpenPIC=(volatile struct OpenPIC *) (tmp + PREP_ISA_MEM_BASE); + printk("OpenPIC found at %p.\n", OpenPIC); + } + } + +#if BSP_PCI_IRQ_NUMBER > 0 + if (OpenPIC == (volatile struct OpenPIC *)0) { + rtems_panic("OpenPic Not found\n"); + } +#endif + +} + +#endif diff --git a/bsps/powerpc/shared/pci/generic_clear_hberrs.c b/bsps/powerpc/shared/pci/generic_clear_hberrs.c new file mode 100644 index 0000000000..1bc4009b15 --- /dev/null +++ b/bsps/powerpc/shared/pci/generic_clear_hberrs.c @@ -0,0 +1,63 @@ +#include <libcpu/io.h> +#include <libcpu/spr.h> + +#include <bsp.h> +#include <bsp/pci.h> + +#include <rtems/bspIo.h> + +#define PCI_ERR_BITS 0xf900 +#define PCI_STATUS_OK(x) (!((x)&PCI_ERR_BITS)) + +/* For now, just clear errors in the PCI status reg. + * + * Returns: (for diagnostic purposes) + * original settings (i.e. before applying the clearing + * sequence) or the error bits or 0 if there were no errors. + * + */ + +unsigned short +(*_BSP_clear_vmebridge_errors)(int) = 0; + +unsigned long +_BSP_clear_hostbridge_errors(int enableMCP, int quiet) +{ +unsigned long rval; +unsigned short pcistat; +int count; + + if (enableMCP) + return -1; /* exceptions not supported / MCP not wired */ + + /* read error status for info return */ + pci_read_config_word(0,0,0,PCI_STATUS,&pcistat); + rval = pcistat; + + count=10; + do { + /* clear error reporting registers */ + + /* clear PCI status register */ + pci_write_config_word(0,0,0,PCI_STATUS, PCI_ERR_BITS); + + /* read new status */ + pci_read_config_word(0,0,0,PCI_STATUS, &pcistat); + + } while ( ! PCI_STATUS_OK(pcistat) && count-- ); + + if ( !PCI_STATUS_OK(rval) && !quiet) { + printk("Cleared PCI errors: pci_stat was 0x%04lx\n", rval); + } + if ( !PCI_STATUS_OK(pcistat) ) { + printk("Unable to clear PCI errors: still 0x%04x after 10 attempts\n", pcistat); + } + + rval &= PCI_ERR_BITS; + + /* Some VME bridges (Tsi148) don't propagate VME bus errors to PCI status reg. */ + if ( _BSP_clear_vmebridge_errors ) + rval |= _BSP_clear_vmebridge_errors(quiet)<<16; + + return rval; +} diff --git a/bsps/powerpc/shared/pci/pci.c b/bsps/powerpc/shared/pci/pci.c new file mode 100644 index 0000000000..f75151ad46 --- /dev/null +++ b/bsps/powerpc/shared/pci/pci.c @@ -0,0 +1,640 @@ +/* + * pci.c : this file contains basic PCI Io functions. + * + * Copyright (C) 1999 valette@crf.canon.fr + * + * This code is heavily inspired by the public specification of STREAM V2 + * that can be found at : + * + * <http://www.chorus.com/Documentation/index.html> by following + * the STREAM API Specification Document link. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * Till Straumann, <strauman@slac.stanford.edu>, 1/2002 + * - 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> + +#undef SHOW_PCI_SETTING + +/* allow for overriding these definitions */ +#ifndef PCI_CONFIG_ADDR +#define PCI_CONFIG_ADDR 0xcf8 +#endif +#ifndef PCI_CONFIG_DATA +#define PCI_CONFIG_DATA 0xcfc +#endif + +/* define a shortcut */ +#define pci BSP_pci_configuration + +#ifndef PCI_CONFIG_ADDR_VAL +#define PCI_CONFIG_ADDR_VAL(bus, slot, funcion, offset) \ + (0x80<<24|((bus)<<16)|(PCI_DEVFN((slot),(function))<<8)|(((offset)&~3))) +#endif + +#ifndef PCI_CONFIG_WR_ADDR +#define PCI_CONFIG_WR_ADDR( addr, val ) out_le32((volatile uint32_t*)(addr), (val)) +#endif + +#define PCI_CONFIG_SET_ADDR(addr, bus, slot,function,offset) \ + PCI_CONFIG_WR_ADDR((addr), PCI_CONFIG_ADDR_VAL((bus), (slot), (function), (offset))) + + +extern void detect_host_bridge(void); + +/* + * Bit encode for PCI_CONFIG_HEADER_TYPE register + */ +unsigned char ucMaxPCIBus; + +static int +indirect_pci_read_config_byte( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint8_t *val +) { + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + *val = in_8(pci.pci_config_data + (offset&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_pci_read_config_word( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint16_t *val +) { + *val = 0xffff; + if (offset&1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + *val = in_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3))); + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_pci_read_config_dword( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint32_t *val +) { + *val = 0xffffffff; + if (offset&3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + *val = in_le32((volatile uint32_t *)pci.pci_config_data); + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_pci_write_config_byte( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint8_t val +) { + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + out_8(pci.pci_config_data + (offset&3), val); + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_pci_write_config_word( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint16_t val +) { + if (offset&1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + out_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)), val); + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_pci_write_config_dword( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint32_t val +) { + if (offset&3) + return PCIBIOS_BAD_REGISTER_NUMBER; + PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset); + out_le32((volatile uint32_t *)pci.pci_config_data, val); + return PCIBIOS_SUCCESSFUL; +} + +const pci_config_access_functions pci_indirect_functions = { + indirect_pci_read_config_byte, + indirect_pci_read_config_word, + indirect_pci_read_config_dword, + indirect_pci_write_config_byte, + indirect_pci_write_config_word, + indirect_pci_write_config_dword +}; + +rtems_pci_config_t BSP_pci_configuration = { + (volatile unsigned char*)PCI_CONFIG_ADDR, + (volatile unsigned char*)PCI_CONFIG_DATA, + &pci_indirect_functions +}; + +static int +direct_pci_read_config_byte( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint8_t *val +) { + if (bus != 0 || (1<<slot & 0xff8007fe)) { + *val=0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + *val=in_8(pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset); + return PCIBIOS_SUCCESSFUL; +} + +static int +direct_pci_read_config_word( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint16_t *val +) { + *val = 0xffff; + if (offset&1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0 || (1<<slot & 0xff8007fe)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *val=in_le16((volatile uint16_t *) + (pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset)); + return PCIBIOS_SUCCESSFUL; +} + +static int +direct_pci_read_config_dword( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint32_t *val +) { + *val = 0xffffffff; + if (offset&3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0 || (1<<slot & 0xff8007fe)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *val=in_le32((volatile uint32_t *) + (pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset)); + return PCIBIOS_SUCCESSFUL; +} + +static int +direct_pci_write_config_byte( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint8_t val +) { + if (bus != 0 || (1<<slot & 0xff8007fe)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_8(pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset, + val); + return PCIBIOS_SUCCESSFUL; +} + +static int +direct_pci_write_config_word( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint16_t val +) { + if (offset&1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0 || (1<<slot & 0xff8007fe)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_le16((volatile uint16_t *) + (pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset), + val); + return PCIBIOS_SUCCESSFUL; +} + +static int +direct_pci_write_config_dword( + unsigned char bus, + unsigned char slot, + unsigned char function, + unsigned char offset, + uint32_t val +) { + if (offset&3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0 || (1<<slot & 0xff8007fe)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_le32((volatile uint32_t *) + (pci.pci_config_data + ((1<<slot)&~1) + + (function<<8) + offset), + val); + return PCIBIOS_SUCCESSFUL; +} + +const pci_config_access_functions pci_direct_functions = { + direct_pci_read_config_byte, + direct_pci_read_config_word, + direct_pci_read_config_dword, + direct_pci_write_config_byte, + direct_pci_write_config_word, + direct_pci_write_config_dword +}; + +#define PRINT_MSG() \ + 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 +** the names defined in the routing record. +*/ +static int test_intname( + const struct _int_map *row, + int pbus, + int pslot, + int pfun, + int int_pin, + int int_name +) { + int j, k; + int _nopin= -1, _noname= -1; + + for (j=0; row->pin_route[j].pin > -1; j++) { + if ( row->pin_route[j].pin == int_pin ) { + _nopin = 0; + + for (k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ ) { + if ( row->pin_route[j].int_name[k] == int_name ) { + _noname=0; break; + } + } + break; + } + } + + 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 +{ + int bus; + int slot; +}; + +static int FindPCIbridge( int mybus, struct pcibridge *pb ) +{ + int pbus, pslot; + uint8_t bussec, buspri; + uint16_t devid, vendorid, dclass; + + 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; + + pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid); + if ( vendorid == 0xffff ) continue; + + pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass); + + if ( dclass == PCI_CLASS_BRIDGE_PCI ) { + pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS, &buspri); + pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec); + +#ifdef SHOW_PCI_SETTING + printk("pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ", + pbus, pslot, mybus, buspri, bussec ); +#endif + if ( bussec == mybus ) { +#ifdef SHOW_PCI_SETTING + printk("match\n"); +#endif + /* found our nearest bridge going towards the root */ + pb->bus = pbus; + pb->slot = pslot; + + return 0; + } +#ifdef SHOW_PCI_SETTING + printk("no match\n"); +#endif + } + + } + } + return -1; +} + +void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) ) +{ + unsigned char cvalue; + uint16_t devid; + 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 + * INTERRUPT_NAME if one isn't already in place. Then, drivers can + * trivially use INTERRUPT_NAME to hook up with devices. + */ + + 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; + + /* got a device */ + pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue); + nfuns = cvalue & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1; + + 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, pfun, PCI_INTERRUPT_PIN, &cvalue); + int_pin = cvalue; + + pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue); + int_name = cvalue; + + /* printk("pci : device %d:0x%02x:%i devid %04x, intpin %d, intline %d\n", + pbus, pslot, pfun, devid, int_pin, int_name ); */ + +#ifdef SHOW_PCI_SETTING + { + unsigned short cmd,stat; + unsigned char lat, seclat, csize; + + 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 ); + + + 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 ); + } + } + } + } + } +} + +/* + * This routine determines the maximum bus number in the system + */ +int pci_initialize(void) +{ + unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs; + unsigned char ucHeader; + unsigned char ucMaxSubordinate; + uint32_t ulClass; + uint32_t ulDeviceID; + + detect_host_bridge(); + + /* + * Scan PCI bus 0 looking for PCI-PCI bridges + */ + for (ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) { + pci_read_config_dword(0, ucSlotNumber, 0, PCI_VENDOR_ID, &ulDeviceID); + if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) { + /* This slot is empty */ + continue; + } + pci_read_config_byte(0, ucSlotNumber, 0, PCI_HEADER_TYPE, &ucHeader); + if (ucHeader&PCI_HEADER_TYPE_MULTI_FUNCTION) { + ucNumFuncs=PCI_MAX_FUNCTIONS; + } else { + ucNumFuncs=1; + } + for (ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) { + pci_read_config_dword(0, ucSlotNumber, ucFnNumber, + PCI_VENDOR_ID, &ulDeviceID); + if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) { + /* This slot/function is empty */ + continue; + } + + /* This slot/function has a device fitted. */ + pci_read_config_dword(0, ucSlotNumber, ucFnNumber, + PCI_CLASS_REVISION, &ulClass); + ulClass >>= 16; + if (ulClass == PCI_CLASS_BRIDGE_PCI) { + /* We have found a PCI-PCI bridge */ + pci_read_config_byte(0, ucSlotNumber, ucFnNumber, + PCI_SUBORDINATE_BUS, &ucMaxSubordinate); + if (ucMaxSubordinate>ucMaxPCIBus) { + ucMaxPCIBus=ucMaxSubordinate; + } + } + } + } + return PCIB_ERR_SUCCESS; +} + +/* + * Return the number of PCI busses in the system + */ +unsigned char pci_bus_count(void) +{ + return (ucMaxPCIBus+1); +} diff --git a/bsps/powerpc/shared/pci/pcifinddevice.c b/bsps/powerpc/shared/pci/pcifinddevice.c new file mode 100644 index 0000000000..8aad50547a --- /dev/null +++ b/bsps/powerpc/shared/pci/pcifinddevice.c @@ -0,0 +1,212 @@ +/* find a particular PCI device + * (we assume, the firmware configured the PCI bus[es] for us) + */ + +/* + * 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 <inttypes.h> +#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( + unsigned short vendorid, + unsigned short deviceid, + int instance, + int *pbus, + 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 +) +{ + uint16_t vi,di; + uint16_t cd,st; + uint32_t b1,b2; + uint8_t 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", */ + fprintf(f,"%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 " %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 +) { + + uint32_t d; + unsigned char bus,dev,fun,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,&d); + if (PCI_INVALID_VENDORDEVICEID == d) + continue; + + if ( 0 == fun ) { + 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,&d); + if (PCI_INVALID_VENDORDEVICEID == d) + continue; +#ifdef PCI_DEBUG + printk("BSP_pciScan: found 0x%08x at %d/x%02x/%d\n",d,bus,dev,fun); +#endif + 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 0; +} |