From afd4c7bbff2487a3d40121e4c22e53db6fcddeb4 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 13 Dec 2006 20:04:05 +0000 Subject: * vmeUniverse/vme_am_defs.h: Added address modifiers for 2eVME. Added flags for 2eSST and DBW16. * vmeUniverse/vmeUniverse.h: Removed AM definitions and include vme_am_defs.h instead. Declare new routine vmeUniverseMapCRG(). Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to vmeUniverseInstallIrqMgrAlt() to 'flags' since now more options are available. Added new flag to install 'posted-write' workaround. * vmeUniverse/vmeUniverse.c: Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Data width of outbound port can now be restricted to 16-bit (if new DBW16 flag set in address modifier). Added vmeUniverseMapCRG() for mapping local registers onto VME. Interrupt manager now implements a workaround (enabled at installation time) which flushes the write-fifo after user ISR returns. This requires the universe's registers to be accessible from VME (either CSR space or CRG mapped to A16/A24/A32), though. * vmeUniverse/vmeTsi148.h: vmeTsi148ClearVMEBusErrors() now returns the fault address as a 32-bit address (not ulonglong anymore). The driver only supports 32-bit addresses. Declare new routine vmeTsi148MapCRG(). Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to vmeTsi148InstallIrqMgrAlt() to 'flags' to allow more options to be supported. Added comments explaining the 'posted-write' workaround implemented by the interrupt manager. * vmeUniverse/vmeTsi148.c: Clear 'SYSFAIL' during initialization. Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Added support for 2eSST when configuring windows (untested - I have no 2eSST). Added vmeTsi148MapCRG() for mapping local registers onto VME. Implemented 'posted-write' workaround for interrupt manager (consult source for details). --- c/src/lib/libbsp/shared/ChangeLog | 34 ++ c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c | 448 +++++++++++++++++++--- c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.h | 102 +++-- c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c | 265 ++++++++++++- c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h | 271 +++++++------ c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h | 34 +- 6 files changed, 922 insertions(+), 232 deletions(-) (limited to 'c') diff --git a/c/src/lib/libbsp/shared/ChangeLog b/c/src/lib/libbsp/shared/ChangeLog index 2d3fe3e93e..5882b10ce6 100644 --- a/c/src/lib/libbsp/shared/ChangeLog +++ b/c/src/lib/libbsp/shared/ChangeLog @@ -1,3 +1,37 @@ +2006-12-13 Till Straumann + * vmeUniverse/vme_am_defs.h: Added address modifiers for 2eVME. Added + flags for 2eSST and DBW16. + + * vmeUniverse/vmeUniverse.h: Removed AM definitions and include vme_am_defs.h + instead. Declare new routine vmeUniverseMapCRG(). Export 'irq manager' API + only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to + vmeUniverseInstallIrqMgrAlt() to 'flags' since now more options are available. + Added new flag to install 'posted-write' workaround. + + * vmeUniverse/vmeUniverse.c: Allow BSP to override BSP_PCI2LOCAL_ADDR() + macro. Data width of outbound port can now be restricted to 16-bit + (if new DBW16 flag set in address modifier). Added vmeUniverseMapCRG() + for mapping local registers onto VME. Interrupt manager now implements + a workaround (enabled at installation time) which flushes the write-fifo + after user ISR returns. This requires the universe's registers to be + accessible from VME (either CSR space or CRG mapped to A16/A24/A32), + though. + + * vmeUniverse/vmeTsi148.h: vmeTsi148ClearVMEBusErrors() now returns + the fault address as a 32-bit address (not ulonglong anymore). The + driver only supports 32-bit addresses. Declare new routine vmeTsi148MapCRG(). + Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined. + Renamed 'shared' argument to vmeTsi148InstallIrqMgrAlt() to 'flags' + to allow more options to be supported. Added comments explaining the + 'posted-write' workaround implemented by the interrupt manager. + + * vmeUniverse/vmeTsi148.c: Clear 'SYSFAIL' during initialization. + Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Added support for + 2eSST when configuring windows (untested - I have no 2eSST). + Added vmeTsi148MapCRG() for mapping local registers onto VME. + Implemented 'posted-write' workaround for interrupt manager + (consult source for details). + 2006-12-13 Joel Sherrill PR 1190/bsps diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c index c2bc9b1f1a..71c4f37b26 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c @@ -16,6 +16,8 @@ #include #include +#define __INSIDE_RTEMS_BSP__ + #include "vmeTsi148.h" #define STATIC static @@ -54,7 +56,16 @@ # define TSI_OTAT_MRPFD (1<<18) # define TSI_OTAT_PFS(x) (((x)&3)<<16) # define TSI_OTAT_2eSSTM(x) (((x)&7)<<11) +# define TSI_OTAT_2eSSTM_160 TSI_OTAT_2eSSTM(0) +# define TSI_OTAT_2eSSTM_267 TSI_OTAT_2eSSTM(1) +# define TSI_OTAT_2eSSTM_320 TSI_OTAT_2eSSTM(2) # define TSI_OTAT_TM(x) (((x)&7)<<8) +# define TSI_TM_SCT_IDX 0 +# define TSI_TM_BLT_IDX 1 +# define TSI_TM_MBLT_IDX 2 +# define TSI_TM_2eVME_IDX 3 +# define TSI_TM_2eSST_IDX 4 +# define TSI_TM_2eSSTB_IDX 5 # define TSI_OTAT_DBW(x) (((x)&3)<<6) # define TSI_OTAT_SUP (1<<5) # define TSI_OTAT_PGM (1<<4) @@ -71,6 +82,17 @@ #define TSI_VIACK_1_REG 0x204 +#define TSI_VSTAT_REG 0x23c +# define TSI_VSTAT_CPURST (1<<15) /* clear power-up reset bit */ +# define TSI_VSTAT_BDFAIL (1<<14) +# define TSI_VSTAT_PURSTS (1<<12) +# define TSI_VSTAT_BDFAILS (1<<11) +# define TSI_VSTAT_SYSFLS (1<<10) +# define TSI_VSTAT_ACFAILS (1<< 9) +# define TSI_VSTAT_SCONS (1<< 8) +# define TSI_VSTAT_GAP (1<< 5) +# define TSI_VSTAT_GA_MSK (0x1f) + #define TSI_VEAU_REG 0x260 #define TSI_VEAL_REG 0x264 #define TSI_VEAT_REG 0x268 @@ -96,6 +118,9 @@ # define TSI_ITAT_TH (1<<18) # define TSI_ITAT_VFS(x) (((x)&3)<<16) # define TSI_ITAT_2eSSTM(x) (((x)&7)<<12) +# define TSI_ITAT_2eSSTM_160 TSI_ITAT_2eSSTM(0) +# define TSI_ITAT_2eSSTM_267 TSI_ITAT_2eSSTM(1) +# define TSI_ITAT_2eSSTM_320 TSI_ITAT_2eSSTM(2) # define TSI_ITAT_2eSSTB (1<<11) # define TSI_ITAT_2eSST (1<<10) # define TSI_ITAT_2eVME (1<<9) @@ -111,6 +136,20 @@ # define TSI_ITAT_PGM (1<<1) # define TSI_ITAT_DATA (1<<0) +#define TSI_CBAU_REG 0x40c +#define TSI_CBAL_REG 0x410 +#define TSI_CRGAT_REG 0x414 +# define TSI_CRGAT_EN (1<<7) +# define TSI_CRGAT_AS_MSK (7<<4) +# define TSI_CRGAT_A16 (0<<4) +# define TSI_CRGAT_A24 (1<<4) +# define TSI_CRGAT_A32 (2<<4) +# define TSI_CRGAT_A64 (4<<4) +# define TSI_CRGAT_SUP (1<<3) +# define TSI_CRGAT_USR (1<<2) +# define TSI_CRGAT_PGM (1<<1) +# define TSI_CRGAT_DATA (1<<0) + #define TSI_VICR_REG 0x440 # define TSI_VICR_CNTS(v) (((v)&3)<<30) # define TSI_VICR_CNTS_DIS (0<<30) @@ -183,10 +222,18 @@ #define TSI_INTM1_REG 0x458 #define TSI_INTM2_REG 0x45c +#define TSI_CBAR_REG 0xffc + +#define TSI_CSR_OFFSET 0x7f000 + +#define TSI_CRG_SIZE (1<<12) /* 4k */ + #define TSI_RD(base, reg) in_be32((volatile unsigned *)((base) + (reg)/sizeof(*base))) #define TSI_RD16(base, reg) in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short)) -#define TSI_RD8(base, reg) *((volatile unsigned char *)(base) + (reg)) +#define TSI_LE_RD16(base, reg) in_le16((volatile unsigned short *)(base) + (reg)/sizeof(short)) +#define TSI_LE_RD32(base, reg) in_le32((volatile unsigned *)(base) + (reg)/sizeof(*base)) +#define TSI_RD8(base, reg) in_8((volatile unsigned char *)(base) + (reg)) #define TSI_WR(base, reg, val) out_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)), val) #define UNIV_SCTL_AM_MASK (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER) @@ -214,7 +261,12 @@ typedef unsigned int pci_ulong; /* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses. * Should be defined by the BSP. */ -#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE) +#ifndef BSP_PCI2LOCAL_ADDR +#ifndef PCI_MEM_BASE +#define PCI_MEM_BASE 0 +#endif +#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE) +#endif typedef struct { BERegister *base; @@ -224,6 +276,10 @@ typedef struct { static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}}; +/* forward decl */ +extern int vmeTsi148RegPort; +extern int vmeTsi148RegCSR; + /* registers should be mapped to guarded, non-cached memory; hence * subsequent stores are ordered. eieio is only needed to enforce * ordering of loads with respect to stores. @@ -280,7 +336,7 @@ unsigned short wrd; return -1; /* Assume upper BAR is zero */ - *pbase=(BERegister*)(PCI_TO_LOCAL_ADDR(busaddr) & ~0xff); + *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff); if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline)) return -1; @@ -339,6 +395,9 @@ int port; TSI_WR(base, TSI_INTM2_REG, 0); TSI_WR(base, TSI_VICR_REG, 0); TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL); + /* Clear BDFAIL / (--> SYSFAIL) */ +# define TSI_VSTAT_BDFAIL (1<<14) + TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL); } void @@ -351,28 +410,31 @@ vmeTsi148Reset() * Tsi148 control mode word */ +static unsigned long ck2esst(unsigned long am) +{ + if ( VME_AM_IS_2eSST(am) ) { + /* make sure 2eVME is selected */ + am &= ~VME_AM_MASK; + am |= VME_AM_2eVME_6U; + } + return am; +} + STATIC int am2omode(unsigned long address_space, unsigned long *pmode) { -unsigned long mode=0; -unsigned long tm, mask; +unsigned long mode = 0; +unsigned long tm = TSI_TM_SCT_IDX; - if ( ! (VME_MODE_DBW32_DISABLE & address_space ) ) + if ( ! (VME_MODE_DBW16 & address_space ) ) mode |= TSI_OTAT_DBW(1); if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) ) mode |= TSI_OTAT_MRPFD; else { - mode |= TSI_OTAT_PFS(address_space>>12); + mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ); } - mode |= TSI_OTAT_2eSSTM(address_space>>16); - for ( tm = 1, mask = VME_MODE_BLT; ! (mask & address_space); tm++, mask<<=1 ) { - if ( VME_MODE_2eSST_BCST == mask ) { - tm = 0; /* select default: BLT enabled */ - break; - } - } - mode |= TSI_OTAT_TM(tm); + address_space = ck2esst(address_space); switch (address_space & VME_AM_MASK) { case VME_AM_STD_SUP_PGM: @@ -381,6 +443,17 @@ unsigned long tm, mask; mode |= TSI_OTAT_PGM; /* fall thru */ + case VME_AM_STD_SUP_BLT: + case VME_AM_STD_SUP_MBLT: + + case VME_AM_STD_USR_BLT: + case VME_AM_STD_USR_MBLT: + switch ( address_space & 3 ) { + case 0: tm = TSI_TM_MBLT_IDX; break; + case 3: tm = TSI_TM_BLT_IDX; break; + default: break; + } + case VME_AM_STD_SUP_DATA: case VME_AM_STD_USR_DATA: @@ -392,8 +465,20 @@ unsigned long tm, mask; mode |= TSI_OTAT_PGM; /* fall thru */ + case VME_AM_EXT_SUP_BLT: + case VME_AM_EXT_SUP_MBLT: + + case VME_AM_EXT_USR_BLT: + case VME_AM_EXT_USR_MBLT: + switch ( address_space & 3 ) { + case 0: tm = TSI_TM_MBLT_IDX; break; + case 3: tm = TSI_TM_BLT_IDX; break; + default: break; + } + case VME_AM_EXT_SUP_DATA: case VME_AM_EXT_USR_DATA: + mode |= TSI_OTAT_ADMODE_A32; break; @@ -406,12 +491,32 @@ unsigned long tm, mask; mode |= TSI_OTAT_ADMODE_CSR; break; + case VME_AM_2eVME_6U: + case VME_AM_2eVME_3U: + mode |= TSI_OTAT_ADMODE_A32; + if ( VME_AM_IS_2eSST(address_space) ) { + tm = ( VME_AM_2eSST_BCST & address_space ) ? + TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX; + switch ( VME_AM_IS_2eSST(address_space) ) { + default: + case VME_AM_2eSST_LO: mode |= TSI_OTAT_2eSSTM_160; break; + case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break; + case VME_AM_2eSST_HI: mode |= TSI_OTAT_2eSSTM_320; break; + } + } else { + tm = TSI_TM_2eVME_IDX; + } + break; + case 0: /* disable the port alltogether */ break; default: return -1; } + + mode |= TSI_OTAT_TM(tm); + if ( VME_AM_IS_SUP(address_space) ) mode |= TSI_OTAT_SUP; *pmode = mode; @@ -422,30 +527,40 @@ STATIC int am2imode(unsigned long address_space, unsigned long *pmode) { unsigned long mode=0; -unsigned long tm, mask; - - mode |= TSI_ITAT_VFS(address_space>>12); - mode |= TSI_ITAT_2eSSTM(address_space>>16); +unsigned long pgm = 0; + + mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ); + + if ( VME_AM_IS_2eSST(address_space) ) { + mode |= TSI_ITAT_2eSST; + if ( VME_AM_2eSST_BCST & address_space ) + mode |= TSI_ITAT_2eSSTB; + switch ( VME_AM_IS_2eSST(address_space) ) { + default: + case VME_AM_2eSST_LO: mode |= TSI_ITAT_2eSSTM_160; break; + case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break; + case VME_AM_2eSST_HI: mode |= TSI_ITAT_2eSSTM_320; break; + } + address_space = ck2esst(address_space); + } mode |= TSI_ITAT_BLT; + mode |= TSI_ITAT_MBLT; - mask = VME_MODE_BLT; - tm = TSI_ITAT_BLT; - do { - mask<<=1; tm<<=1; - if ( address_space & mask ) - mode |= tm; - } while ( TSI_ITAT_2eSSTB != tm ); - - tm = 0; + mode |= TSI_ITAT_PGM; /* always allow PGM access */ + mode |= TSI_ITAT_USR; /* always allow USR access */ switch (address_space & VME_AM_MASK) { case VME_AM_STD_SUP_PGM: case VME_AM_STD_USR_PGM: - tm = 1; + pgm = 1; /* fall thru */ + case VME_AM_STD_SUP_BLT: + case VME_AM_STD_SUP_MBLT: + case VME_AM_STD_USR_BLT: + case VME_AM_STD_USR_MBLT: case VME_AM_STD_SUP_DATA: case VME_AM_STD_USR_DATA: @@ -454,9 +569,15 @@ unsigned long tm, mask; case VME_AM_EXT_SUP_PGM: case VME_AM_EXT_USR_PGM: - tm = 1; + pgm = 1; /* fall thru */ + case VME_AM_2eVME_6U: + case VME_AM_2eVME_3U: + case VME_AM_EXT_SUP_BLT: + case VME_AM_EXT_SUP_MBLT: + case VME_AM_EXT_USR_BLT: + case VME_AM_EXT_USR_MBLT: case VME_AM_EXT_SUP_DATA: case VME_AM_EXT_USR_DATA: mode |= TSI_ITAT_ADMODE_A32; @@ -477,12 +598,8 @@ unsigned long tm, mask; if ( VME_AM_IS_SUP(address_space) ) mode |= TSI_ITAT_SUP; - else - mode |= TSI_ITAT_USR; - if ( tm ) - mode |= TSI_ITAT_PGM; - else + if ( !pgm ) mode |= TSI_ITAT_DATA; *pmode = mode; @@ -531,6 +648,7 @@ configTsiPort( unsigned long long start, limit, offst; unsigned long mode, mask, tat_reg, tsau_reg; char *name = (isout ? "Outbound" : "Inbound"); +int i,s,l; CHECK_BASE(base,0,-1); @@ -541,6 +659,11 @@ char *name = (isout ? "Outbound" : "Inbound"); return -1; } + if ( base == devs[0].base && isout && vmeTsi148RegPort == port ) { + uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name); + return -1; + } + if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) { uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name); return -1; @@ -554,6 +677,21 @@ char *name = (isout ? "Outbound" : "Inbound"); tat_reg = TSI_OTAT_REG(port); tsau_reg = TSI_OTSAU_REG(port); mode |= TSI_OTAT_EN; + + /* check for overlap */ + for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) { + /* ignore 'this' port */ + if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) ) + continue; + + /* check requested PCI range against current port 'i' config */ + s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */ + l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */ + if ( ! ( start + length <= s || start > s + l ) ) { + uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l); + return -1; + } + } } else { start = vme_address; offst = (unsigned long long)pci_address - start; @@ -561,6 +699,31 @@ char *name = (isout ? "Outbound" : "Inbound"); tat_reg = TSI_ITAT_REG(port); tsau_reg = TSI_ITSAU_REG(port); mode |= TSI_ITAT_EN; + + /* check for overlap */ + for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) { + /* ignore 'this' port */ + if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) ) + continue; + + if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) { + /* different address space */ + continue; + } + + if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) { + /* orthogonal privileges */ + continue; + } + + /* check requested VME range against current port 'i' config */ + s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */ + l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */ + if ( ! ( start + length <= s || start > s + l ) ) { + uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l); + return -1; + } + } } /* If they pass 'length==0' just disable */ @@ -661,8 +824,8 @@ vmeTsi148OutboundPortCfg( } -int -vmeTsi148XlateAddrXX( +static int +xlateFindPort( BERegister *base, /* TSI 148 base address */ int outbound, /* look in the outbound windows */ int reverse, /* reverse mapping; for outbound ports: map local to VME */ @@ -680,16 +843,27 @@ unsigned long tsau_reg, tat_reg, gran, skip; mode = 0; /* silence warning */ - if ( VME_MODE_EXACT_MATCH & as ) { - mode_msk = ~0; - } else { - if ( outbound ) - mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN; - else - mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN; + switch ( as & VME_MODE_MATCH_MASK ) { + case VME_MODE_EXACT_MATCH: + mode_msk = ~0; + break; + + case VME_MODE_AS_MATCH: + if ( outbound ) + mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN; + else + mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN; + break; + + default: + if ( outbound ) + mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN; + else + mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN; + break; } - as &= ~VME_MODE_EXACT_MATCH; + as &= ~VME_MODE_MATCH_MASK; if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) { uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument"); @@ -727,7 +901,7 @@ unsigned long tsau_reg, tat_reg, gran, skip; if ( aIn >= start && aIn <= limit ) { /* found it */ *paOut = (unsigned long)(a + offst); - return 0; + return port; } } } @@ -736,6 +910,20 @@ unsigned long tsau_reg, tat_reg, gran, skip; return -1; } +int +vmeTsi148XlateAddrXX( + BERegister *base, /* TSI 148 base address */ + int outbound, /* look in the outbound windows */ + int reverse, /* reverse mapping; for outbound ports: map local to VME */ + unsigned long as, /* address space */ + unsigned long aIn, /* address to look up */ + unsigned long *paOut/* where to put result */ + ) +{ +int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut ); + return port < 0 ? -1 : 0; +} + int vmeTsi148XlateAddr( int outbound, /* look in the outbound windows */ @@ -922,6 +1110,48 @@ vmeTsi148DisableAllOutboundPorts(void) } +/* Map internal register block to VME */ + +int +vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as ) +{ +uint32_t mode; + + CHECK_BASE( b, 0, -1 ); + + if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) { + uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n"); + return -1; + } + + /* enable all, SUP/USR/PGM/DATA accesses */ + mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM | TSI_CRGAT_DATA; + + if ( VME_AM_IS_SHORT(as) ) { + mode |= TSI_CRGAT_A16; + } else + if ( VME_AM_IS_STD(as) ) { + mode |= TSI_CRGAT_A24; + } else + if ( VME_AM_IS_EXT(as) ) { + mode |= TSI_CRGAT_A32; + } else { + return -2; + } + + /* map CRG to VME bus */ + TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1))); + TSI_WR( b, TSI_CRGAT_REG, mode ); + + return 0; +} + +int +vmeTsi148MapCRG(uint32_t vme_base, uint32_t as ) +{ + return vmeTsi148MapCRGXX( devs[0].base, vme_base, as ); +} + /* Interrupt Subsystem */ typedef struct @@ -932,7 +1162,10 @@ IRQEntryRec_ { static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0}; -int vmeTsi148IrqMgrInstalled=0; +int vmeTsi148IrqMgrInstalled = 0; +int vmeTsi148RegPort = -1; +int vmeTsi148RegCSR = 0; +BERegister *vmeTsi148RegBase = 0; static volatile unsigned long wire_mask[TSI_NUM_WIRES] = {0}; /* wires are offset by 1 so we can initialize the wire table to all zeros */ @@ -1094,7 +1327,16 @@ unsigned long msk,lintstat,vector, vecarg; int lvl; /* only handle interrupts routed to this pin */ - while ( (lintstat = (TSI_RD(b, TSI_INTS_REG) & wire_mask[pin])) ) { + + /* NOTE: we read the status register over VME, thus flushing the FIFO + * where the user ISR possibly left write commands to clear + * the interrupt condition at the device. + * This is very important - otherwise, the IRQ level may still be + * asserted and we would detect an interrupt here but the subsequent + * IACK would fail since the write operation was flushed to the + * device in the mean time. + */ + while ( (lintstat = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) { /* bit 0 is never set since it is never set in wire_mask */ @@ -1154,11 +1396,16 @@ int lvl; if ( !(ip=irqHdlTbl[vector])) { /* TODO: log error message - RTEMS has no logger :-( */ vmeTsi148IntDisable(lvl); - printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABING level %i\n", + printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABLING level %i\n", lvl, vector, lvl); } else { /* dispatch handler, it must clear the IRQ at the device */ ip->isr(ip->usrData, vecarg); + /* convenience for disobedient users who don't use in_xxx/out_xxx; make + * sure we order the subsequent read from the status register after + * their business. + */ + iobarrier_rw(); } } while ( (lintstat &= ~msk) ); /* check if a new irq is pending already */ @@ -1213,10 +1460,54 @@ va_list ap; return rval; } +#ifndef BSP_EARLY_PROBE_VME +#define BSP_EARLY_PROBE_VME(addr) \ + ( \ + vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ), \ + ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 ) \ + && 0 == vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ) ) \ + ) +#endif + +/* Check if there is a vme address/as is mapped in any of the outbound windows + * and look for the PCI vendordevice ID there. + * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7) + * on success. Address translated into CPU address is returned in *pcpu_addr. + */ +static int +mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr) +{ +int j; +char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG"; + + /* try to find mapping */ + if ( 0 > (j = xlateFindPort( + devs[0].base, + 1, 0, + as | VME_MODE_AS_MATCH, + vme_addr, + pcpu_addr ) ) ) { + uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr); + uprintf(stderr," in outbound windows.\n"); + } + else { + /* found a slot number; probe it */ + *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr ); + if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) { + uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype); + return j; + } else { + uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype); + } + } + return -1; +} + int vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap) { int i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES]; +unsigned long cpu_base, vme_reg_base; if (vmeTsi148IrqMgrInstalled) return -4; @@ -1248,6 +1539,57 @@ int i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES]; } } + i = -1; + + /* first try VME CSR space; do we have a base address set ? */ + + uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n"); + + if ( ( i = ((TSI_RD( devs[0].base, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) { + uprintf(stderr,"Trying to find CSR on VME...\n"); + vme_reg_base = i*0x80000 + TSI_CSR_OFFSET; + i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base); + if ( i >= 0 ) + vmeTsi148RegCSR = 1; + } else { + i = -1; + } + + if ( -1 == i ) { + + uprintf(stderr,"Trying to find CRG on VME...\n"); + + /* Next we see if the CRG block is mapped to VME */ + + if ( (TSI_CRGAT_EN & (j = TSI_RD( devs[0].base, TSI_CRGAT_REG ))) ) { + switch ( j & TSI_CRGAT_AS_MSK ) { + case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break; + case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break; + case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break; + default: + break; + } + vme_reg_base = TSI_RD( devs[0].base, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1); + } + + if ( -1 == i ) { + } else { + i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base ); + } + } + + if ( i < 0 ) { + uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n"); + uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n"); + uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n"); + uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n"); + cpu_base = (unsigned long)devs[0].base; + i = -1; + } + + vmeTsi148RegBase = (BERegister*)cpu_base; + vmeTsi148RegPort = i; + /* give them a chance to override buggy PCI info */ if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) { uprintf(stderr,"Overriding main IRQ line PCI info with %d\n", @@ -1591,7 +1933,7 @@ bail: } unsigned long -vmeTsi148ClearVMEBusErrorsXX(BERegister *base, unsigned long long *paddr) +vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr) { unsigned long rval; @@ -1600,8 +1942,12 @@ unsigned long rval; rval = TSI_RD(base, TSI_VEAT_REG); if ( rval & TSI_VEAT_VES ) { if ( paddr ) { +#if 0 /* no 64-bit support yet */ *paddr = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32; *paddr |= TSI_RD(base, TSI_VEAL_REG); +#else + *paddr = TSI_RD(base, TSI_VEAL_REG); +#endif } /* clear errors */ TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL); @@ -1612,7 +1958,7 @@ unsigned long rval; } unsigned long -vmeTsi148ClearVMEBusErrors(unsigned long long *paddr) +vmeTsi148ClearVMEBusErrors(uint32_t *paddr) { return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, paddr); } diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.h b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.h index 575e23daec..1db70db647 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.h +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.h @@ -7,33 +7,27 @@ * Sept. 2005. */ +#include #include + /* NOTE: A64 currently not implemented */ /* These can be ored with the AM */ -#define VME_MODE_PREFETCH_ENABLE VME_AM_IS_MEMORY -#define VME_MODE_PREFETCH_SIZE(x) (((x)&3)<<12) -#define VME_MODE_2eSSTM(x) (((x)&7)<<16) +/* NOTE: unlike the universe, the tsi148 doesn't allow for disabling posted writes ! */ -#define VME_MODE_DBW32_DISABLE (8<<12) +#define VME_MODE_PREFETCH_ENABLE VME_AM_IS_MEMORY +#define _LD_VME_MODE_PREFETCHSZ 24 +#define VME_MODE_PREFETCH_SIZE(x) (((x)&3)<<_LD_VME_MODE_PREFETCHSZ) -/* Transfer modes: - * - * On a outbound window, only the least significant - * bit that is set is considered. - * On a inbound window, the bitwise OR of modes - * is accepted. +/* These bits can be or'ed with the address-modifier when calling + * the 'XlateAddr' routine below to further qualify the + * search criteria. */ -#define VME_MODE_BLT (1<<20) -#define VME_MODE_MBLT (1<<21) -#define VME_MODE_2eVME (1<<22) -#define VME_MODE_2eSST (1<<23) -#define VME_MODE_2eSST_BCST (1<<24) -#define VME_MODE_MASK (31<<20) - -#define VME_MODE_EXACT_MATCH (1<<31) +#define VME_MODE_MATCH_MASK (3<<30) +#define VME_MODE_EXACT_MATCH (2<<30) /* all bits must match */ +#define VME_MODE_AS_MATCH (1<<30) /* only A16/24/32 must match */ #ifdef __cplusplus extern "C" { @@ -260,17 +254,43 @@ vmeTsi148DisableAllOutboundPorts(void); * 0 if no error has occurred since this routine was last called. * Contents of the 'VEAT' register (bit definitions as above) * otherwise. - * If a non-NULL 'paddr' argument is provided then the 64-bit error - * address is stored in *paddr (only if return value is non-zero). + * If a non-NULL 'paddr' argument is provided then the lower 32-bit + * of the error address is stored in *paddr (only if return value is + * non-zero). * * SIDE EFFECTS: this routine clears the error attribute register, allowing * for future errors to be latched. */ unsigned long -vmeTsi148ClearVMEBusErrorsXX(BERegister *base, unsigned long long *paddr); +vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr); unsigned long -vmeTsi148ClearVMEBusErrors(unsigned long long *paddr); +vmeTsi148ClearVMEBusErrors(uint32_t *paddr); + +/* Map internal register block to VME. + * + * This routine is intended for BSP implementors. The registers must be + * accessible from VME so that the interrupt handler can flush the + * bridge FIFO (see below). + * + * vme_base: VME address where the TSI registers (4k) can be mapped. + * This VME address must fall into a range covered by + * any pre-configured outbound window. + * address_space: The desired VME address space. + * (all of SUP/USR/PGM/DATA are always accepted). + * + * See NOTES [vmeTsi148InstallIrqMgrAlt()] below for further information. + * + * RETURNS: 0 on success, nonzero on error. It is not possible (and results + * in a non-zero return code) to change the CRG VME address after + * initializing the interrupt manager as it uses the CRG. + */ +int +vmeTsi148MapCRGXX(BERegister *base, uint32_t vme_base, uint32_t address_space); + +int +vmeTsi148MapCRG(uint32_t vme_base, uint32_t address_space); + /* VME Interrupt Handler functionality */ @@ -486,6 +506,10 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector); #define TSI_NUM_INT_VECS 275 +#ifdef __INSIDE_RTEMS_BSP__ + +#include + /* the tsi148 interrupt handler is capable of routing all sorts of * (VME) interrupts to 4 different lines (some of) which may be hooked up * in a (board specific) way to a PIC. @@ -513,15 +537,18 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector); * from PCI config space is wrong for some boards! * * PARAMETERS: - * shared: use the BSP_install_rtems_shared_irq_handler() instead + * flags: VMETSI148_IRQ_MGR_FLAG_SHARED: + * use the BSP_install_rtems_shared_irq_handler() instead * of BSP_install_rtems_irq_handler(). Use this if the PIC * line is used by other devices, too. * CAVEAT: shared interrupts need RTEMS workspace, i.e., the * VME interrupt manager can only be installed * *after workspace is initialized* if 'shared' is nonzero * (i.e., *not* from bspstart()). + * * tsi_pin_0: to which output pin (of the tsi148) should the 7 * VME irq levels be routed. + * * pic_pin_0: specifies to which PIC input the 'main' output is * wired on your board. If passed a value < 0, the driver * reads this information from PCI config space ("IRQ line"). @@ -530,13 +557,40 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector); * In any case must the varargs list be terminated by '-1'. * * RETURNS: 0 on success, -1 on failure. - * + * + * NOTES: The Tsi148 always does 'posted' writes through a FIFO buffer. + * This effectively makes VME write operations asynchronous + * which can have undesired side-effects. + * In particular, consider the case of an ISR clearing the + * interrupt condition by writing to a CSR. The write operation + * doesn't really do anything but goes into the FIFO and + * the user ISR returns. At this point, the interrupt manager + * may find the IRQ still pending, trying another IACK + * cycle. Because it is probable that at this time the FIFO + * has been flushed and the CSR-write operation been effective, + * the IACK then times out. + * Note that this phenomenon becomes more obvious as CPUs + * become faster. + * + * To avoid this race condition and many VME drivers having + * to be re-written, a VME read (having the desired side-effect + * of flushing the write FIFO) must be issued between the + * user ISR returning and the interrupt manager checking for + * more pending interrupts. + * + * Therefore, the BSP needs to map the Tsi148 register + * block to VME so that a read over VME can be effectuated. + * (In addition to being mapped to VME, the mapped address + * range must be accessible through an outbound window.) */ + +#define VMETSI148_IRQ_MGR_FLAG_SHARED 1 int vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...); int vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap); +#endif #ifdef __cplusplus } diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c index 87f17d91e8..f14ab1156e 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c @@ -6,7 +6,11 @@ */ #include -#include + +#if defined(__rtems__) +#define __INSIDE_RTEMS_BSP__ +#endif + #include "vmeUniverse.h" #define UNIV_NUM_MPORTS 8 /* number of master ports */ @@ -33,6 +37,7 @@ #define UNIV_MCTL_PGM (0x00004000) #define UNIV_MCTL_VCT (0x00000100) #define UNIV_MCTL_SUPER (0x00001000) +#define UNIV_MCTL_VDW16 (0x00400000) #define UNIV_MCTL_VDW32 (0x00800000) #define UNIV_MCTL_VDW64 (0x00c00000) @@ -77,12 +82,18 @@ * Should be defined by the BSP. */ typedef unsigned int pci_ulong; -#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE) + +#ifndef BSP_PCI2LOCAL_ADDR +#ifndef PCI_MEM_BASE +#define PCI_MEM_BASE 0 +#endif +#define BSP_PCI2LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE) +#endif #elif defined(__vxworks) typedef unsigned long pci_ulong; -#define PCI_TO_LOCAL_ADDR(memaddr) (memaddr) +#define BSP_PCI2LOCAL_ADDR(memaddr) (memaddr) #define BSP_PCI_FIND_DEVICE pciFindDevice #define BSP_PCI_CONFIG_IN_LONG pciConfigInLong #define BSP_PCI_CONFIG_IN_BYTE pciConfigInByte @@ -97,6 +108,11 @@ typedef unsigned long pci_ulong; volatile LERegister *vmeUniverse0BaseAddr=0; int vmeUniverse0PciIrqLine=-1; +#ifdef __rtems__ +int vmeUniverseRegPort = -1; +int vmeUniverseRegCSR = 0; +#endif + #define DFLT_BASE volatile LERegister *base = vmeUniverse0BaseAddr #define CHECK_DFLT_BASE(base) \ @@ -271,7 +287,7 @@ unsigned char irqline; || ((unsigned long)(busaddr) & 1)) return -1; } - *pbase=(volatile LERegister*)PCI_TO_LOCAL_ADDR(busaddr); + *pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr); if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline)) return -1; @@ -301,6 +317,8 @@ unsigned long mode=0; * ???????? */ + address_space &= ~VME_MODE_MATCH_MASK; + if (!ismaster) { mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM; mode |= UNIV_SCTL_USER; @@ -308,7 +326,11 @@ unsigned long mode=0; mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN; mode |= UNIV_SCTL_EN; } else { - mode |= UNIV_MCTL_VDW64 | UNIV_MCTL_VCT /* enable block transfers */; + if ( VME_MODE_DBW16 & address_space ) + mode |= UNIV_MCTL_VDW16; + else + mode |= UNIV_MCTL_VDW64; + mode |= UNIV_MCTL_VCT /* enable block transfers */; if ( VME_AM_IS_MEMORY & address_space ) mode |= UNIV_MCTL_PWEN; mode |= UNIV_MCTL_EN; @@ -316,7 +338,7 @@ unsigned long mode=0; address_space &= ~VME_AM_IS_MEMORY; - switch (address_space) { + switch (address_space & VME_AM_MASK) { case VME_AM_STD_SUP_PGM: case VME_AM_STD_USR_PGM: if (ismaster) @@ -592,7 +614,7 @@ typedef struct XlatRec_ { * * RETURNS: -1: invalid space * 0: invalid address (not found in range) - * 1: success + * port+1: success */ static int @@ -614,11 +636,24 @@ unsigned long cntrl, start, bound, offst, mask, x; return -1; } - if ( ! (VME_MODE_EXACT_MATCH & l->aspace) ) { - cntrl &= (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK); - offst &= (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK); + + switch (VME_MODE_MATCH_MASK & l->aspace) { + case VME_MODE_EXACT_MATCH: + mask = -1 & ~VME_MODE_MATCH_MASK; + break; + + case VME_MODE_AS_MATCH: + mask = UNIV_CTL_VAS; + break; + + default: + mask = (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK); + break; } + cntrl &= mask; + offst &= mask; + if ( cntrl != offst ) return 0; /* mode doesn't match requested AM */ @@ -639,7 +674,7 @@ unsigned long cntrl, start, bound, offst, mask, x; */ if (l->address >= start && l->address < bound) { l->address+=offst; - return 1; + return 1 + port; } } else { x = l->address - offst; @@ -647,12 +682,24 @@ unsigned long cntrl, start, bound, offst, mask, x; if (x >= start && x < bound) { /* valid address found */ l->address = x; - return 1; + return 1 + port; } } return 0; } +/* check if there is any active window with write posting enabled */ +static int +hasPWENWindow( + int ismaster, + int portno, + volatile LERegister *preg, + void *parm) +{ +unsigned long cntrl = READ_LE0(preg); +unsigned long mask = ismaster ? (UNIV_MCTL_EN|UNIV_MCTL_PWEN) : (UNIV_SCTL_EN|UNIV_SCTL_PWEN); + return (cntrl & mask) == mask ? -1 : 0; +} static int mapOverAll(volatile LERegister *base, int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg) @@ -696,8 +743,8 @@ showUniversePorts(volatile LERegister *base, int ismaster, FILE *f) mapOverAll(base,ismaster,showUniversePort,f); } -int -vmeUniverseXlateAddrXX( +static int +xlateFindPort( volatile LERegister *base, /* Universe base address */ int master, /* look in the master windows */ int reverse, /* reverse mapping; for masters: map local to VME */ @@ -717,6 +764,19 @@ XlatRec l; return rval; } +int +vmeUniverseXlateAddrXX( + volatile LERegister *base, /* Universe base address */ + int master, /* look in the master windows */ + int reverse, /* reverse mapping; for masters: map local to VME */ + unsigned long as, /* address space */ + unsigned long aIn, /* address to look up */ + unsigned long *paOut/* where to put result */ + ) +{ + return xlateFindPort(base, master, reverse, as, aIn, paOut) >= 0 ? 0 : -1; +} + int vmeUniverseXlateAddr( int master, /* look in the master windows */ @@ -757,8 +817,10 @@ vmeUniverseReset(void) /* disable universe register access from VME bus */ vmeUniverseWriteReg(0, UNIV_REGOFF_VRAI_CTL); +#if 0 /* leave CSR bus image alone; IRQ manager can use it */ /* disable VME bus image of VME CSR */ vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL); +#endif /* I had problems with a Joerger vtr10012_8 card who would @@ -1082,9 +1144,56 @@ vmeUniverseIntRaise(int level, unsigned vector) } +/* Map internal register block to VME */ +#define UNIV_CRG_SIZE (1<<12) + +int +vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long as ) +{ +uint32_t mode; + + CHECK_DFLT_BASE(base); + +#ifdef __rtems__ + if ( vmeUniverseRegPort > -1 && ! vmeUniverseRegCSR ) { + uprintf(stderr,"vmeUniverse: CRG already mapped and in use by interrupt manager\n"); + return -1; + } +#endif + + /* enable all, SUP/USR/PGM/DATA accesses */ + mode = UNIV_VRAI_CTL_EN | UNIV_VRAI_CTL_PGM | UNIV_VRAI_CTL_DATA | UNIV_VRAI_CTL_SUPER | UNIV_VRAI_CTL_USER; + + if ( VME_AM_IS_SHORT(as) ) { + mode |= UNIV_VRAI_CTL_VAS_A16; + } else + if ( VME_AM_IS_STD(as) ) { + mode |= UNIV_VRAI_CTL_VAS_A24; + } else + if ( VME_AM_IS_EXT(as) ) { + mode |= UNIV_VRAI_CTL_VAS_A32; + } else { + return -2; + } + + /* map CRG to VME bus */ + WRITE_LE( (vme_base & ~(UNIV_CRG_SIZE-1)), base, UNIV_REGOFF_VRAI_BS ); + WRITE_LE( mode, base, UNIV_REGOFF_VRAI_CTL ); + + return 0; +} + +int +vmeUniverseMapCRG(unsigned long vme_base, unsigned long as ) +{ + return vmeUniverseMapCRGXX( vmeUniverse0BaseAddr, vme_base, as ); +} + + /* RTEMS interrupt subsystem */ #ifdef __rtems__ + #include typedef struct @@ -1095,7 +1204,9 @@ UniverseIRQEntryRec_ { static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0}; -int vmeUniverseIrqMgrInstalled=0; +int vmeUniverseIrqMgrInstalled = 0; + +volatile LERegister *vmeUniverseRegBase = 0; /* We support 4 wires between universe + PIC */ @@ -1350,6 +1461,17 @@ unsigned long linten; } else { /* dispatch handler, it must clear the IRQ at the device */ ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK); + + /* insert a VME read operation to flush fifo, making sure all user write-ops complete */ +#ifdef __PPC__ + /* courtesy to disobedient users who don't use I/O ops */ + asm volatile("eieio"); +#endif + READ_LE0(vmeUniverseRegBase); +#ifdef __PPC__ + /* make sure this is ordered before re-enabling */ + asm volatile("eieio"); +#endif } /* clear this interrupt level; allow the universe to handler further interrupts */ @@ -1412,21 +1534,63 @@ rtems_irq_connect_data aarrggh; } } +#ifndef BSP_EARLY_PROBE_VME +#define BSP_EARLY_PROBE_VME(addr) \ + ( \ + ((PCI_DEVICE_UNIVERSEII << 16) | PCI_VENDOR_TUNDRA ) == READ_LE( ((volatile LERegister*)(addr)), 0 ) \ + ) +#endif + +/* Check if there is a vme address/as is mapped in any of the outbound windows + * and look for the PCI vendordevice ID there. + * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7) + * on success. Address translated into CPU address is returned in *pcpu_addr. + */ +static int +mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr) +{ +int j; +char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG"; + + /* try to find mapping */ + if ( 0 > (j = xlateFindPort( + vmeUniverse0BaseAddr, + 1, 0, + as | VME_MODE_AS_MATCH, + vme_addr, + pcpu_addr ) ) ) { + uprintf(stderr,"vmeUniverse - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr); + uprintf(stderr," in outbound windows.\n"); + } else { + /* found a slot number; probe it */ + *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr ); + if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) { + uprintf(stderr,"vmeUniverse - IRQ manager using VME %s to flush FIFO\n", regtype); + return j; + } else { + uprintf(stderr,"vmeUniverse - Found slot info but detection of universe in VME %s space failed\n", regtype); + } + } + return -1; +} + + int -vmeUniverseInstallIrqMgrAlt(int shared, int uni_pin0, int pic_pin0, ...) +vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...) { int rval; va_list ap; va_start(ap, pic_pin0); - rval = vmeUniverseInstallIrqMgrVa(shared, uni_pin0, pic_pin0, ap); + rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap); va_end(ap); return rval; } int -vmeUniverseInstallIrqMgrVa(int shared, int uni_pin0, int pic_pin0, va_list ap) +vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap) { int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES]; +unsigned long cpu_base, vme_reg_base; if (vmeUniverseIrqMgrInstalled) return -4; @@ -1462,6 +1626,69 @@ int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES]; } } + if ( flags & VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND ) { + + /* Find registers on VME so the ISR can issue a read to flush the FIFO */ + uprintf(stderr,"vmeUniverse IRQ manager: looking for registers on VME...\n"); + + /* NOTE: The universe [unlike the Tsi148] doesn't know about geographical + * addressing but the MotLoad firmware [mvme5500] is kind enough to + * program VCSR_BS based on the board's geographical address for us :-) + */ + if ( ( i = ((READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VCSR_BS ) >> 27) & 0x1f ) ) > 0 ) { + uprintf(stderr,"Trying to find CSR on VME...\n"); + vme_reg_base = i*0x80000 + UNIV_CSR_OFFSET; + i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base); + if ( i >= 0 ) + vmeUniverseRegCSR = 1; + } else { + i = -1; + } + + if ( -1 == i ) { + + uprintf(stderr,"Trying to find CRG on VME...\n"); + + /* Next we see if the CRG block is mapped to VME */ + + if ( UNIV_VRAI_CTL_EN & (j = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_CTL )) ) { + switch ( j & UNIV_VRAI_CTL_VAS_MSK ) { + case UNIV_VRAI_CTL_VAS_A16 : i = VME_AM_SUP_SHORT_IO; break; + case UNIV_VRAI_CTL_VAS_A24 : i = VME_AM_STD_SUP_DATA; break; + case UNIV_VRAI_CTL_VAS_A32 : i = VME_AM_EXT_SUP_DATA; break; + default: + break; + } + vme_reg_base = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_BS ) & ~(UNIV_CRG_SIZE - 1); + } + + if ( -1 == i ) { + } else { + i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base ); + } + } + + if ( i < 0 ) { + if ( mapOverAll( vmeUniverse0BaseAddr, 1, hasPWENWindow, 0 ) ) { + uprintf(stderr,"vmeUniverse IRQ manager - BSP configuration error: registers not found on VME\n"); + uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeUniverseMapCRG()])\n"); + uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n"); + uprintf(stderr,"back from user ISR to flush universe FIFO as a work-around or\n"); + uprintf(stderr,"make sure ISR accesses device using a window with posted-writes disabled\n"); + } else { + uprintf(stderr,"vmeUniverse IRQ manager - registers not found on VME; falling back to PCI\n"); + } + vmeUniverseRegBase = vmeUniverse0BaseAddr; + vmeUniverseRegPort = -1; + } else { + vmeUniverseRegBase = (volatile LERegister*)cpu_base; + vmeUniverseRegPort = i; + } + } else { + vmeUniverseRegBase = vmeUniverse0BaseAddr; + vmeUniverseRegPort = -1; + } + /* give them a chance to override buggy PCI info */ if ( pic_pin[0] >= 0 && vmeUniverse0PciIrqLine != pic_pin[0] ) { uprintf(stderr,"Overriding main IRQ line PCI info with %d\n", @@ -1472,7 +1699,7 @@ int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES]; for ( i = 0; uni_pin[i] >= 0; i++ ) { /* offset wire # by one so we can initialize to 0 == invalid */ universe_wire[i] = uni_pin[i] + 1; - connectIsr(shared, universeVMEISR, pic_pin[i], i); + connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i); } specialPin = uni_pin[1] >= 0 ? 1 : 0; diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h index 5e40135e3a..7cea3df059 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h @@ -14,82 +14,18 @@ #include #else -/* vxworks compatible addressing modes */ +#include -#ifndef VME_AM_STD_SUP_ASCENDING -#define VME_AM_STD_SUP_ASCENDING 0x3f -#endif -#ifndef VME_AM_STD_SUP_PGM -#define VME_AM_STD_SUP_PGM 0x3e -#endif -#ifndef VME_AM_STD_USR_ASCENDING -#define VME_AM_STD_USR_ASCENDING 0x3b -#endif -#ifndef VME_AM_STD_USR_PGM -#define VME_AM_STD_USR_PGM 0x3a -#endif -#ifndef VME_AM_STD_SUP_DATA -#define VME_AM_STD_SUP_DATA 0x3d -#endif -#ifndef VME_AM_STD_USR_DATA -#define VME_AM_STD_USR_DATA 0x39 -#endif -#ifndef VME_AM_EXT_SUP_ASCENDING -#define VME_AM_EXT_SUP_ASCENDING 0x0f -#endif -#ifndef VME_AM_EXT_SUP_PGM -#define VME_AM_EXT_SUP_PGM 0x0e -#endif -#ifndef VME_AM_EXT_USR_ASCENDING -#define VME_AM_EXT_USR_ASCENDING 0x0b -#endif -#ifndef VME_AM_EXT_USR_PGM -#define VME_AM_EXT_USR_PGM 0x0a -#endif -#ifndef VME_AM_EXT_SUP_DATA -#define VME_AM_EXT_SUP_DATA 0x0d -#endif -#ifndef VME_AM_EXT_USR_DATA -#define VME_AM_EXT_USR_DATA 0x09 -#endif -#ifndef VME_AM_CSR -#define VME_AM_CSR 0x2f -#endif -#ifndef VME_AM_SUP_SHORT_IO -#define VME_AM_SUP_SHORT_IO 0x2d -#endif -#ifndef VME_AM_USR_SHORT_IO -#define VME_AM_USR_SHORT_IO 0x29 -#endif -#ifndef VME_AM_IS_SHORT -#define VME_AM_IS_SHORT(a) (((a) & 0xf0) == 0x20) -#endif -#ifndef VME_AM_IS_STD -#define VME_AM_IS_STD(a) (((a) & 0xf0) == 0x30) -#endif -#ifndef VME_AM_IS_EXT -#define VME_AM_IS_EXT(a) (((a) & 0xf0) == 0x00) -#endif -#ifndef VME_AM_IS_SUP -#define VME_AM_IS_SUP(a) ((a) & 4) -#endif -#ifndef VME_AM_MASK -#define VME_AM_MASK 0xff -#endif - -/* Enables posted writes (and on a VME slave: prefetched reads, too) */ -#ifndef VME_AM_IS_MEMORY -#define VME_AM_IS_MEMORY (1<<8) #endif -#endif - - - -/* When looking for an address translation, ask for a match of VME_MODE_PWEN etc., too */ -#define VME_MODE_EXACT_MATCH (1<<31) +/* These bits can be or'ed with the address-modifier when calling + * the 'XlateAddr' routine below to further qualify the + * search criteria. + */ +#define VME_MODE_MATCH_MASK (3<<30) +#define VME_MODE_EXACT_MATCH (2<<30) /* all bits must match */ +#define VME_MODE_AS_MATCH (1<<30) /* only A16/24/32 must match */ -#include typedef unsigned long LERegister; /* emphasize contents are little endian */ @@ -450,8 +386,9 @@ typedef struct VmeUniverseDMAPacketRec_ { # define UNIV_VRAI_CTL_SUPER (1<<21) /* supervisor AM */ # define UNIV_VRAI_CTL_USER (1<<20) /* user AM */ # define UNIV_VRAI_CTL_VAS_A16 (0<<16) /* A16 */ -# define UNIV_VRAI_CTL_VAS_A24 (1<<16) /* A16 */ -# define UNIV_VRAI_CTL_VAS_A32 (2<<16) /* A16 */ +# define UNIV_VRAI_CTL_VAS_A24 (1<<16) /* A14 */ +# define UNIV_VRAI_CTL_VAS_A32 (2<<16) /* A32 */ +# define UNIV_VRAI_CTL_VAS_MSK (3<<16) /* VMEbus register acces image base address register */ #define UNIV_REGOFF_VRAI_BS 0xf74 @@ -490,7 +427,10 @@ typedef struct VmeUniverseDMAPacketRec_ { /* VMEbus CSR base address register */ #define UNIV_REGOFF_VCSR_BS 0xffc -#define UNIV_VCSR_BS_MASK (0xfff80000) +#define UNIV_VCSR_BS_MASK (0xf8000000) + +/* offset of universe registers in VME-CSR slot */ +#define UNIV_CSR_OFFSET 0x7f000 #ifdef __cplusplus extern "C" { @@ -760,7 +700,36 @@ vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector); int vmeUniverseIntRaise(int level, unsigned vector); +/* Map internal register block to VME. + * + * This routine is intended for BSP implementors. The registers can be + * made accessible from VME so that the interrupt handler can flush the + * bridge FIFO (see below). The preferred method is by accessing VME CSR, + * though, if these are mapped [and the BSP provides an outbound window]. + * On the universe we can also disable posted writes in the 'ordinary' + * outbound windows. + * + * vme_base: VME address where the universe registers (4k) can be mapped. + * This VME address must fall into a range covered by + * any pre-configured outbound window. + * address_space: The desired VME address space. + * (all of SUP/USR/PGM/DATA are always accepted). + * + * See NOTES [vmeUniverseInstallIrqMgrAlt()] below for further information. + * + * RETURNS: 0 on success, nonzero on error. It is not possible (and results + * in a non-zero return code) to change the CRG VME address after + * initializing the interrupt manager as it uses the CRG. + */ +int +vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long address_space); + +int +vmeUniverseMapCRG(unsigned long vme_base, unsigned long address_space); + + #ifdef __rtems__ + /* VME Interrupt Handler functionality */ /* we dont use the current RTEMS/BSP interrupt API for the @@ -783,6 +752,41 @@ vmeUniverseIntRaise(int level, unsigned vector); typedef void (*VmeUniverseISR) (void *usrArg, unsigned long vector); +/* use these special vectors to connect a handler to the + * universe specific interrupts (such as "DMA done", + * VOWN, error irqs etc.) + * NOTE: The wrapper clears all status LINT bits (except + * for regular VME irqs). Also note that it is the user's + * responsibility to enable the necessary interrupts in + * LINT_EN + * + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * DO NOT CHANGE THE ORDER OF THESE VECTORS - THE DRIVER + * DEPENDS ON IT + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + */ +#define UNIV_VOWN_INT_VEC 256 +#define UNIV_DMA_INT_VEC 257 +#define UNIV_LERR_INT_VEC 258 +#define UNIV_VERR_INT_VEC 259 +/* 260 is reserved */ +#define UNIV_VME_SW_IACK_INT_VEC 261 +#define UNIV_PCI_SW_INT_VEC 262 +#define UNIV_SYSFAIL_INT_VEC 263 +#define UNIV_ACFAIL_INT_VEC 264 +#define UNIV_MBOX0_INT_VEC 265 +#define UNIV_MBOX1_INT_VEC 266 +#define UNIV_MBOX2_INT_VEC 267 +#define UNIV_MBOX3_INT_VEC 268 +#define UNIV_LM0_INT_VEC 269 +#define UNIV_LM1_INT_VEC 270 +#define UNIV_LM2_INT_VEC 271 +#define UNIV_LM3_INT_VEC 272 + +#define UNIV_NUM_INT_VECS 273 + + /* install a handler for a VME vector * RETURNS 0 on success, nonzero on failure. */ @@ -864,39 +868,34 @@ vmeUniverseIntIsEnabled(unsigned int level); int vmeUniverseIntRoute(unsigned int level, unsigned int pin); -/* use these special vectors to connect a handler to the - * universe specific interrupts (such as "DMA done", - * VOWN, error irqs etc.) - * NOTE: The wrapper clears all status LINT bits (except - * for regular VME irqs). Also note that it is the user's - * responsibility to enable the necessary interrupts in - * LINT_EN +/* Loopback test of the VME interrupt subsystem. + * - installs ISRs on 'vector' and on UNIV_VME_SW_IACK_INT_VEC + * - asserts VME interrupt 'level' + * - waits for both interrupts: 'ordinary' VME interrupt of 'level' and + * IACK completion interrupt ('special' vector UNIV_VME_SW_IACK_INT_VEC). * - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * DO NOT CHANGE THE ORDER OF THESE VECTORS - THE DRIVER - * DEPENDS ON IT - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * + * NOTES: + * - make sure no other handler responds to 'level'. + * - make sure no ISR is installed on both vectors yet. + * - ISRs installed by this routine are removed after completion. + * - no concurrent access protection of all involved resources + * (levels, vectors and registers [see vmeUniverseIntRaise()]) + * is implemented. + * - this routine is intended for TESTING (when implementing new BSPs etc.). + * - one RTEMS message queue is temporarily used (created/deleted). + * - the universe 1 always yields a zero vector (VIRQx_STATID) in response + * to a self-generated VME interrupt. As a workaround, the routine + * only accepts a zero vector when running on a universe 1. + * + * RETURNS: + * 0: Success. + * -1: Invalid arguments. + * 1: Test failed (outstanding interrupts). + * rtems_status_code: Failed RTEMS directive. */ -#define UNIV_VOWN_INT_VEC 256 -#define UNIV_DMA_INT_VEC 257 -#define UNIV_LERR_INT_VEC 258 -#define UNIV_VERR_INT_VEC 259 -/* 260 is reserved */ -#define UNIV_VME_SW_IACK_INT_VEC 261 -#define UNIV_PCI_SW_INT_VEC 262 -#define UNIV_SYSFAIL_INT_VEC 263 -#define UNIV_ACFAIL_INT_VEC 264 -#define UNIV_MBOX0_INT_VEC 265 -#define UNIV_MBOX1_INT_VEC 266 -#define UNIV_MBOX2_INT_VEC 267 -#define UNIV_MBOX3_INT_VEC 268 -#define UNIV_LM0_INT_VEC 269 -#define UNIV_LM1_INT_VEC 270 -#define UNIV_LM2_INT_VEC 271 -#define UNIV_LM3_INT_VEC 272 +int +vmeUniverseIntLoopbackTst(int level, unsigned vector); -#define UNIV_NUM_INT_VECS 273 /* the universe interrupt handler is capable of routing all sorts of * (VME) interrupts to 8 different lines (some of) which may be hooked up @@ -939,12 +938,18 @@ vmeUniverseIntRoute(unsigned int level, unsigned int pin); * RETURNS: 0 on success, -1 on failure. * */ + +/* This routine is outside of the __INSIDE_RTEMS_BSP__ test for bwrds compatibility ONLY */ int vmeUniverseInstallIrqMgr(int vmeIrqUnivOut, int vmeIrqPicLine, int specialIrqUnivOut, int specialIrqPicLine); + +#if defined(__INSIDE_RTEMS_BSP__) +#include + /* up to 4 universe outputs are now supported by this alternate * entry point. * Terminate the vararg list (uni_pin/pic_pin pairs) with a @@ -952,46 +957,40 @@ vmeUniverseInstallIrqMgr(int vmeIrqUnivOut, * E.g., the old interface is now just a wrapper to * vmeUniverseInstallIrqMgrAlt(0, vmeUnivOut, vmePicLint, specUnivOut, specPicLine, -1); * - * The 'shared' argument uses the BSP_install_rtems_shared_irq_handler() + * The 'IRQ_MGR_SHARED' flag uses the BSP_install_rtems_shared_irq_handler() * API. CAVEAT: shared interrupts need RTEMS workspace, i.e., the * VME interrupt manager can only be installed *after workspace is initialized* * if 'shared' is nonzero (i.e., *not* from bspstart()). + * + * If 'PW_WORKAROUND' flag is set then the interrupt manager will try to + * find a way to access the control registers from VME so that the universe's + * posted write FIFO can be flushed after the user ISR returns: + * + * The installation routine looks first for CSR registers in CSR space (this + * requires: + * - a VME64 crate with autoid or geographical addressing + * - the firmware or BSP to figure out the slot number and program the CSR base + * in the universe. + * - the BSP to open an outbound window to CSR space. + * + * If CSR registers cannot be found then the installation routine looks for CRG registers: + * - BSP must map CRG on VME + * - CRG must be visible in outbound window + * CAVEAT: multiple boards with same BSP on single backplane must not map their CRG + * to the same address! */ -int -vmeUniverseInstallIrqMgrAlt(int shared, int uni_pin0, int pic_pin0, ...); + +#define VMEUNIVERSE_IRQ_MGR_FLAG_SHARED 1 /* use shared interrupts */ +#define VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND 2 /* use shared interrupts */ int -vmeUniverseInstallIrqMgrVa(int shared, int uni_pin0, int pic_pin0, va_list ap); +vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...); -/* Loopback test of the VME interrupt subsystem. - * - installs ISRs on 'vector' and on UNIV_VME_SW_IACK_INT_VEC - * - asserts VME interrupt 'level' - * - waits for both interrupts: 'ordinary' VME interrupt of 'level' and - * IACK completion interrupt ('special' vector UNIV_VME_SW_IACK_INT_VEC). - * - * NOTES: - * - make sure no other handler responds to 'level'. - * - make sure no ISR is installed on both vectors yet. - * - ISRs installed by this routine are removed after completion. - * - no concurrent access protection of all involved resources - * (levels, vectors and registers [see vmeUniverseIntRaise()]) - * is implemented. - * - this routine is intended for TESTING (when implementing new BSPs etc.). - * - one RTEMS message queue is temporarily used (created/deleted). - * - the universe 1 always yields a zero vector (VIRQx_STATID) in response - * to a self-generated VME interrupt. As a workaround, the routine - * only accepts a zero vector when running on a universe 1. - * - * RETURNS: - * 0: Success. - * -1: Invalid arguments. - * 1: Test failed (outstanding interrupts). - * rtems_status_code: Failed RTEMS directive. - */ int -vmeUniverseIntLoopbackTst(int level, unsigned vector); +vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap); -#endif +#endif /* __INSIDE_RTEMS_BSP__ */ +#endif /* __rtems__ */ #ifdef __cplusplus } diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h b/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h index c822ae086f..7a45327f62 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h +++ b/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h @@ -3,6 +3,8 @@ /* vxworks compatible addressing modes */ +/* NOTE: 64-bit *addresses* are not supported [data are]. */ + #ifndef VME_AM_STD_SUP_BLT #define VME_AM_STD_SUP_BLT 0x3f #endif @@ -63,6 +65,12 @@ #ifndef VME_AM_EXT_USR_MBLT #define VME_AM_EXT_USR_MBLT 0x08 #endif +#ifndef VME_AM_2eVME_6U +#define VME_AM_2eVME_6U 0x20 +#endif +#ifndef VME_AM_2eVME_3U +#define VME_AM_2eVME_3U 0x21 +#endif #ifndef VME_AM_CSR #define VME_AM_CSR 0x2f #endif @@ -99,8 +107,30 @@ #define VME_AM_IS_MEMORY (1<<8) #endif -/* Flags 1<<11 .. 1<<8 are reserved - * Flags 1<<12 .. 1<<31 are for driver specific options +/* I don't know AMs for 2eSST so we use some extra bits; + * HOWEVER: these are just qualifiers to the VME_AM_2eVME_xx modes + * i.e., if you want 2eSST you must also select 2eVME... + */ + +/* 2eSST broadcast; you still need to set one of the speed bits */ +#define VME_AM_2eSST_BCST (1<<9) +/* Low speed (driver specific) */ +#define VME_AM_2eSST_LO (1<<10) +/* Mid speed (driver specific) */ +#define VME_AM_2eSST_MID (2<<10) +/* High speed (driver specific) */ +#define VME_AM_2eSST_HI (3<<10) + +#define VME_AM_IS_2eSST(am) ((am) & (3<<10)) + +/* Use 16-bit transfers for coupled- or BLT cycles + * (MBLT, 2exxx are probably always 64-bit) + */ +#define VME_MODE_DBW16 (1<<12) + +/* Unused Flags 1<<12 .. 1<<23 are reserved + * Flags 1<<24 .. 1<<31 are for driver specific options */ + #endif -- cgit v1.2.3