Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:59

0001 /* Driver for the Tundra Universe II pci-vme bridge */
0002 
0003 /*
0004  * Authorship
0005  * ----------
0006  * This software was created by
0007  *     Till Straumann <strauman@slac.stanford.edu>, 2000-2007,
0008  *     Stanford Linear Accelerator Center, Stanford University.
0009  *
0010  * Acknowledgement of sponsorship
0011  * ------------------------------
0012  * This software was produced by
0013  *     the Stanford Linear Accelerator Center, Stanford University,
0014  *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
0015  *
0016  * Government disclaimer of liability
0017  * ----------------------------------
0018  * Neither the United States nor the United States Department of Energy,
0019  * nor any of their employees, makes any warranty, express or implied, or
0020  * assumes any legal liability or responsibility for the accuracy,
0021  * completeness, or usefulness of any data, apparatus, product, or process
0022  * disclosed, or represents that its use would not infringe privately owned
0023  * rights.
0024  *
0025  * Stanford disclaimer of liability
0026  * --------------------------------
0027  * Stanford University makes no representations or warranties, express or
0028  * implied, nor assumes any liability for the use of this software.
0029  *
0030  * Stanford disclaimer of copyright
0031  * --------------------------------
0032  * Stanford University, owner of the copyright, hereby disclaims its
0033  * copyright and all other rights in this software.  Hence, anyone may
0034  * freely use it for any purpose without restriction.
0035  *
0036  * Maintenance of notices
0037  * ----------------------
0038  * In the interest of clarity regarding the origin and status of this
0039  * SLAC software, this and all the preceding Stanford University notices
0040  * are to remain affixed to any copy or derivative of this software made
0041  * or distributed by the recipient and are to be affixed to any copy of
0042  * software made or distributed by the recipient that contains a copy or
0043  * derivative of this software.
0044  *
0045  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0046  */
0047 
0048 #include <stdio.h>
0049 #include <inttypes.h>
0050 
0051 #if defined(__rtems__)
0052 #ifndef __INSIDE_RTEMS_BSP__
0053 #define __INSIDE_RTEMS_BSP__
0054 #endif
0055 #endif
0056 
0057 #include <bsp/vmeUniverse.h>
0058 #include <bsp/vmeUniverseDMA.h>
0059 
0060 #define UNIV_NUM_MPORTS     8 /* number of master ports */
0061 #define UNIV_NUM_SPORTS     8 /* number of slave ports */
0062 
0063 #define PCI_VENDOR_TUNDRA   0x10e3
0064 #define PCI_DEVICE_UNIVERSEII   0
0065 #define PCI_UNIVERSE_BASE0  0x10
0066 #define PCI_UNIVERSE_BASE1  0x14
0067 
0068 #define UNIV_REGOFF_PCITGT0_CTRL 0x100
0069 #define UNIV_REGOFF_PCITGT4_CTRL 0x1a0
0070 #define UNIV_REGOFF_VMESLV0_CTRL 0xf00
0071 #define UNIV_REGOFF_VMESLV4_CTRL 0xf90
0072 
0073 #define UNIV_CTL_VAS16      (0x00000000)
0074 #define UNIV_CTL_VAS24      (0x00010000)
0075 #define UNIV_CTL_VAS32      (0x00020000)
0076 #define UNIV_MCTL_VASCSR    (0x00050000)
0077 #define UNIV_CTL_VAS        (0x00070000)
0078 
0079 #define UNIV_MCTL_EN        (0x80000000)
0080 #define UNIV_MCTL_PWEN      (0x40000000)
0081 #define UNIV_MCTL_PGM       (0x00004000)
0082 #define UNIV_MCTL_VCT       (0x00000100)
0083 #define UNIV_MCTL_SUPER     (0x00001000)
0084 #define UNIV_MCTL_VDW16     (0x00400000)
0085 #define UNIV_MCTL_VDW32     (0x00800000)
0086 #define UNIV_MCTL_VDW64     (0x00c00000)
0087 
0088 #define UNIV_MCTL_AM_MASK   (UNIV_CTL_VAS | UNIV_MCTL_PGM | UNIV_MCTL_SUPER)
0089 
0090 #define UNIV_SCTL_EN        (0x80000000)
0091 #define UNIV_SCTL_PWEN      (0x40000000)
0092 #define UNIV_SCTL_PREN      (0x20000000)
0093 #define UNIV_SCTL_PGM       (0x00800000)
0094 #define UNIV_SCTL_DAT       (0x00400000)
0095 #define UNIV_SCTL_SUPER     (0x00200000)
0096 #define UNIV_SCTL_USER      (0x00100000)
0097 
0098 #define UNIV_SCTL_AM_MASK   (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
0099 
0100 #ifdef __rtems__
0101 
0102 #include <stdlib.h>
0103 #include <rtems/bspIo.h>    /* printk */
0104 #include <rtems/error.h>
0105 #include <rtems/pci.h>
0106 #include <rtems/score/sysstate.h>
0107 #include <bsp.h>
0108 #include <libcpu/byteorder.h>
0109 
0110 /* allow the BSP to override the default routines */
0111 #ifndef BSP_PCI_FIND_DEVICE
0112 #define BSP_PCI_FIND_DEVICE         pci_find_device
0113 #endif
0114 #ifndef BSP_PCI_CONFIG_IN_LONG
0115 #define BSP_PCI_CONFIG_IN_LONG      pci_read_config_dword
0116 #endif
0117 #ifndef BSP_PCI_CONFIG_IN_BYTE
0118 #define BSP_PCI_CONFIG_IN_BYTE      pci_read_config_byte
0119 #endif
0120 #ifndef BSP_PCI_CONFIG_IN_SHORT
0121 #define BSP_PCI_CONFIG_IN_SHORT     pci_read_config_word
0122 #endif
0123 #ifndef BSP_PCI_CONFIG_OUT_SHORT
0124 #define BSP_PCI_CONFIG_OUT_SHORT    pci_write_config_word
0125 #endif
0126 
0127 /* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
0128  * Should be defined by the BSP.
0129  */
0130 typedef uint32_t pci_ulong;
0131 
0132 #ifndef BSP_PCI2LOCAL_ADDR
0133 #ifndef PCI_MEM_BASE
0134 #define PCI_MEM_BASE 0
0135 #endif
0136 #define BSP_PCI2LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
0137 #endif
0138 
0139 #ifndef BSP_LOCAL2PCI_ADDR
0140 #ifndef PCI_DRAM_OFFSET
0141 #define PCI_DRAM_OFFSET 0
0142 #endif
0143 #define BSP_LOCAL2PCI_ADDR(pciaddr) ((uint32_t)(pciaddr) + PCI_DRAM_OFFSET)
0144 #endif
0145 
0146 
0147 #elif defined(__vxworks)
0148 typedef unsigned long pci_ulong;
0149 #define BSP_PCI2LOCAL_ADDR(memaddr) (memaddr)
0150 #define BSP_PCI_FIND_DEVICE     pciFindDevice
0151 #define BSP_PCI_CONFIG_IN_LONG  pciConfigInLong
0152 #define BSP_PCI_CONFIG_IN_BYTE  pciConfigInByte
0153 #else
0154 #error "vmeUniverse not ported to this architecture yet"
0155 #endif
0156 
0157 #ifndef PCI_INTERRUPT_LINE
0158 #define PCI_INTERRUPT_LINE      0x3c
0159 #endif
0160 
0161 volatile LERegister *vmeUniverse0BaseAddr=0;
0162 int vmeUniverse0PciIrqLine=-1;
0163 
0164 #ifdef __rtems__
0165 int vmeUniverseRegPort = -1;
0166 int vmeUniverseRegCSR  = 0;
0167 #endif
0168 
0169 #define DFLT_BASE   volatile LERegister *base = vmeUniverse0BaseAddr
0170 
0171 #define CHECK_DFLT_BASE(base) \
0172     do { \
0173         /* get the universe base address */ \
0174         if (!base) { \
0175             if (vmeUniverseInit()) { \
0176                 uprintf(stderr,"unable to find the universe in pci config space\n"); \
0177                 return -1; \
0178             } else { \
0179                 base = vmeUniverse0BaseAddr; \
0180             } \
0181         } \
0182     } while (0)
0183 
0184 #if 0
0185 /* public access functions */
0186 volatile LERegister *
0187 vmeUniverseBaseAddr(void)
0188 {
0189     if (!vmeUniverse0BaseAddr) vmeUniverseInit();
0190     return vmeUniverse0BaseAddr;
0191 }
0192 
0193 int
0194 vmeUniversePciIrqLine(void)
0195 {
0196     if (vmeUniverse0PciIrqLine<0) vmeUniverseInit();
0197     return vmeUniverse0PciIrqLine;
0198 }
0199 #endif
0200 
0201 static inline void
0202 WRITE_LE(
0203     unsigned long val,
0204     volatile LERegister    *adrs,
0205     unsigned long off)
0206 {
0207 #if (__LITTLE_ENDIAN__ == 1)
0208     *(volatile unsigned long*)(((unsigned long)adrs)+off)=val;
0209 #elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
0210     /* offset is in bytes and MUST not end up in r0 */
0211     __asm__ __volatile__("stwbrx %1, %0, %2" :: "b"(off),"r"(val),"r"(adrs));
0212 #elif defined(__rtems__)
0213     st_le32((volatile uint32_t *)(((uint32_t)adrs)+off), val);
0214 #else
0215 #error "little endian register writing not implemented"
0216 #endif
0217 }
0218 
0219 #if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)
0220 #define SYNC __asm__ __volatile__("sync")
0221 #else
0222 #define SYNC
0223 #warning "SYNC instruction unknown for this architecture"
0224 #endif
0225 
0226 /* registers should be mapped to guarded, non-cached memory; hence
0227  * subsequent stores are ordered. eieio is only needed to enforce
0228  * ordering of loads with respect to stores.
0229  */
0230 #define EIEIO_REG
0231 
0232 static inline unsigned long
0233 READ_LE0(volatile LERegister *adrs)
0234 {
0235 #if (__LITTLE_ENDIAN__ == 1)
0236     return *(volatile unsigned long *)adrs;
0237 #elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
0238 register unsigned long rval;
0239 __asm__ __volatile__("lwbrx %0, 0, %1":"=r"(rval):"r"(adrs));
0240     return rval;
0241 #elif defined(__rtems__)
0242     return ld_le32((volatile uint32_t*)adrs);
0243 #else
0244 #error "little endian register reading not implemented"
0245 #endif
0246 }
0247 
0248 static inline unsigned long
0249 READ_LE(volatile LERegister *adrs, unsigned long off)
0250 {
0251 #if (__LITTLE_ENDIAN__ == 1)
0252     return  *((volatile LERegister *)(((unsigned long)adrs)+off));
0253 #elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
0254 register unsigned long rval;
0255     /* offset is in bytes and MUST not end up in r0 */
0256 __asm__ __volatile__("lwbrx %0, %2, %1"
0257                 : "=r"(rval)
0258                 : "r"(adrs), "b"(off));
0259 #if 0
0260 __asm__ __volatile__("eieio");
0261 #endif
0262 return rval;
0263 #else
0264 return READ_LE0((volatile LERegister *)(((unsigned long)adrs)+off));
0265 #endif
0266 }
0267 
0268 #define PORT_UNALIGNED(addr,port) \
0269     ( (port)%4 ? ((addr) & 0xffff) : ((addr) & 4095) )
0270 
0271 
0272 #define UNIV_REV(base) (READ_LE(base,2*sizeof(LERegister)) & 0xff)
0273 
0274 #if defined(__rtems__) && 0
0275 static int
0276 uprintk(char *fmt, va_list ap)
0277 {
0278 int     rval;
0279 extern int k_vsprintf(char *, char *, va_list);
0280 /* during bsp init, there is no malloc and no stdio,
0281  * hence we assemble the message on the stack and revert
0282  * to printk
0283  */
0284 char    buf[200];
0285     rval = k_vsprintf(buf,fmt,ap);
0286     if (rval > sizeof(buf))
0287             rtems_panic("vmeUniverse/uprintk: buffer overrun");
0288     printk(buf);
0289     return rval;
0290 }
0291 #endif
0292 
0293 
0294 /* private printing wrapper */
0295 static void
0296 uprintf(FILE *f, char *fmt, ...)
0297 {
0298 va_list ap;
0299     va_start(ap, fmt);
0300 #ifdef __rtems__
0301     if (!f || !_System_state_Is_up(_System_state_Get())) {
0302         /* Might be called at an early stage when
0303          * stdio is not yet initialized.
0304          * There is no vprintk, hence we must assemble
0305          * to a buffer.
0306          */
0307         vprintk(fmt,ap);
0308     } else
0309 #endif
0310     {
0311         vfprintf(f,fmt,ap);
0312     }
0313     va_end(ap);
0314 }
0315 
0316 static int
0317 vmeUniverseFindPciBase(
0318     int instance,
0319     volatile LERegister **pbase
0320     )
0321 {
0322 int bus,dev,fun;
0323 unsigned short wrd;
0324 pci_ulong busaddr;
0325 unsigned char irqline;
0326 
0327     if (BSP_PCI_FIND_DEVICE(
0328             PCI_VENDOR_TUNDRA,
0329             PCI_DEVICE_UNIVERSEII,
0330             instance,
0331             &bus,
0332             &dev,
0333             &fun))
0334         return -1;
0335     if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr))
0336         return -1;
0337     if ((unsigned long)(busaddr) & 1) {
0338         /* it's IO space, try BASE1 */
0339         if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr)
0340            || ((unsigned long)(busaddr) & 1))
0341             return -1;
0342     }
0343     *pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr);
0344 
0345     if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
0346         return -1;
0347 
0348     /* Enable PCI master and memory access */
0349     BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
0350     BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
0351 
0352     return irqline;
0353 }
0354 
0355 /* convert an address space selector to a corresponding
0356  * universe control mode word
0357  */
0358 
0359 static int
0360 am2mode(int ismaster, unsigned long address_space, unsigned long *pmode)
0361 {
0362 unsigned long mode=0;
0363 unsigned long vdw =0;
0364 
0365     /* NOTE: reading the CY961 (Echotek ECDR814) with VDW32
0366      *       generated bus errors when reading 32-bit words
0367      *       - very weird, because the registers are 16-bit
0368      *         AFAIK.
0369      *       - 32-bit accesses worked fine on vxWorks which
0370      *         has the port set to 64-bit.
0371      *       ????????
0372      */
0373 
0374     address_space &= ~VME_MODE_MATCH_MASK;
0375 
0376     if (!ismaster) {
0377         mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM;
0378         mode |= UNIV_SCTL_USER;
0379         if ( VME_AM_IS_MEMORY & address_space )
0380             mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN;
0381         mode |= UNIV_SCTL_EN;
0382     } else {
0383         switch ( VME_MODE_DBW_MSK & address_space ) {
0384             default:
0385                 vdw = UNIV_MCTL_VDW64;
0386             break;
0387 
0388             case VME_MODE_DBW8:
0389                 break;
0390 
0391             case VME_MODE_DBW16:
0392                 vdw = UNIV_MCTL_VDW16;
0393                 break;
0394 
0395             case VME_MODE_DBW32:
0396                 vdw = UNIV_MCTL_VDW32;
0397                 break;
0398         }
0399         if ( VME_AM_IS_MEMORY & address_space )
0400             mode |= UNIV_MCTL_PWEN;
0401         mode |= UNIV_MCTL_EN;
0402     }
0403 
0404     address_space &= ~VME_AM_IS_MEMORY;
0405 
0406     switch (address_space & VME_AM_MASK) {
0407         case VME_AM_STD_SUP_PGM:
0408         case VME_AM_STD_USR_PGM:
0409             if (ismaster)
0410                 mode |= UNIV_MCTL_PGM ;
0411             else {
0412                 mode &= ~UNIV_SCTL_DAT;
0413             }
0414 
0415             /* fall thru */
0416 
0417         case VME_AM_STD_SUP_DATA:
0418         case VME_AM_STD_USR_DATA:
0419         case VME_AM_STD_SUP_BLT:
0420         case VME_AM_STD_SUP_MBLT:
0421         case VME_AM_STD_USR_BLT:
0422         case VME_AM_STD_USR_MBLT:
0423 
0424             if ( ismaster ) {
0425                 switch ( address_space & 3 ) {
0426                     case 0: /* mblt */
0427                         if ( UNIV_MCTL_VDW64 != vdw )
0428                             return -1;
0429                         break;
0430 
0431                     case 3: /* blt  */
0432                         mode |= UNIV_MCTL_VCT;
0433                         /* universe may do mblt anyways so go back to
0434                          * 32-bit width
0435                          */
0436                         vdw   = UNIV_MCTL_VDW32;
0437                 }
0438             }
0439 
0440             mode |= UNIV_CTL_VAS24;
0441             break;
0442 
0443 
0444         case VME_AM_EXT_SUP_PGM:
0445         case VME_AM_EXT_USR_PGM:
0446             if (ismaster)
0447                 mode |= UNIV_MCTL_PGM ;
0448             else {
0449                 mode &= ~UNIV_SCTL_DAT;
0450             }
0451             /* fall thru */
0452 
0453         case VME_AM_EXT_SUP_DATA:
0454         case VME_AM_EXT_USR_DATA:
0455         case VME_AM_EXT_SUP_BLT:
0456         case VME_AM_EXT_SUP_MBLT:
0457         case VME_AM_EXT_USR_BLT:
0458         case VME_AM_EXT_USR_MBLT:
0459 
0460             if ( ismaster ) {
0461                 switch ( address_space & 3 ) {
0462                     case 0: /* mblt */
0463                         if ( UNIV_MCTL_VDW64 != vdw )
0464                             return -1;
0465                         break;
0466 
0467                     case 3: /* blt  */
0468                         mode |= UNIV_MCTL_VCT;
0469                         /* universe may do mblt anyways so go back to
0470                          * 32-bit width
0471                          */
0472                         vdw   = UNIV_MCTL_VDW32;
0473                 }
0474             }
0475 
0476             mode |= UNIV_CTL_VAS32;
0477 
0478             break;
0479 
0480         case VME_AM_SUP_SHORT_IO:
0481         case VME_AM_USR_SHORT_IO:
0482             mode |= UNIV_CTL_VAS16;
0483             break;
0484 
0485         case VME_AM_CSR:
0486             if ( !ismaster )
0487                 return -1;
0488             mode |= UNIV_MCTL_VASCSR;
0489             break;
0490 
0491         case 0: /* disable the port alltogether */
0492             break;
0493 
0494         default:
0495             return -1;
0496     }
0497     if ( VME_AM_IS_SUP(address_space) )
0498         mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER);
0499 
0500     mode |= vdw; /* vdw still 0 in slave mode */
0501     *pmode = mode;
0502     return 0;
0503 }
0504 
0505 static int
0506 disableUniversePort(int ismaster, int portno, volatile unsigned long *preg, void *param)
0507 {
0508 unsigned long cntrl;
0509     cntrl=READ_LE0(preg);
0510     cntrl &= ~(ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN);
0511     WRITE_LE(cntrl,preg,0);
0512     SYNC; /* make sure this command completed */
0513     return 0;
0514 }
0515 
0516 static int
0517 cfgUniversePort(
0518     volatile LERegister *base,
0519     unsigned long   ismaster,
0520     unsigned long   port,
0521     unsigned long   address_space,
0522     unsigned long   vme_address,
0523     unsigned long   local_address,
0524     unsigned long   length)
0525 {
0526 volatile LERegister *preg;
0527 unsigned long   p=port;
0528 unsigned long   mode=0;
0529 
0530     CHECK_DFLT_BASE(base);
0531 
0532     /* check parameters */
0533     if (port >= (ismaster ? UNIV_NUM_MPORTS : UNIV_NUM_SPORTS)) {
0534         uprintf(stderr,"invalid port\n");
0535         return -1;
0536     }
0537     /* port start, bound addresses and offset must lie on 64k boundary
0538      * (4k for port 0 and 4)
0539      */
0540     if ( PORT_UNALIGNED(local_address,port) ) {
0541         uprintf(stderr,"local address misaligned\n");
0542         return -1;
0543     }
0544     if ( PORT_UNALIGNED(vme_address,port) ) {
0545         uprintf(stderr,"vme address misaligned\n");
0546         return -1;
0547     }
0548     if ( PORT_UNALIGNED(length,port) ) {
0549         uprintf(stderr,"length misaligned\n");
0550         return -1;
0551     }
0552 
0553     /* check address space validity */
0554     if (am2mode(ismaster,address_space,&mode)) {
0555         uprintf(stderr,"invalid address space\n");
0556         return -1;
0557     }
0558 
0559     /* get the universe base address */
0560     if (!base && vmeUniverseInit()) {
0561         return -1;
0562     }
0563 
0564     preg=base;
0565 
0566     /* find out if we have a rev. II chip */
0567     if ( UNIV_REV(base) < 2 ) {
0568         if (port>3) {
0569             uprintf(stderr,"Universe rev. < 2 has only 4 ports\n");
0570             return -1;
0571         }
0572     }
0573 
0574     /* finally, configure the port */
0575 
0576     /* find the register set for our port */
0577     if (port<4) {
0578         preg += (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister);
0579     } else {
0580         preg += (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister);
0581         p-=4;
0582     }
0583     preg += 5 * p;
0584 
0585     /* temporarily disable the port */
0586     disableUniversePort(ismaster,port,preg,0);
0587 
0588     /* address_space == 0 means disable */
0589     if (address_space != 0) {
0590         unsigned long start,offst;
0591         /* set the port starting address;
0592          * this is the local address for the master
0593          * and the VME address for the slave
0594          */
0595         if (ismaster) {
0596             start=local_address;
0597             /* let it overflow / wrap around 0 */
0598             offst=vme_address-local_address;
0599         } else {
0600             start=vme_address;
0601             /* let it overflow / wrap around 0 */
0602             offst=local_address-vme_address;
0603         }
0604 #undef TSILL
0605 #ifdef TSILL
0606         uprintf(stderr,"writing 0x%08x to 0x%08x + 4\n",start,preg);
0607 #else
0608         WRITE_LE(start,preg,4);
0609 #endif
0610         /* set bound address */
0611         length+=start;
0612 #ifdef TSILL
0613         uprintf(stderr,"writing 0x%08x to 0x%08x + 8\n",length,preg);
0614 #else
0615         WRITE_LE(length,preg,8);
0616 #endif
0617         /* set offset */
0618 #ifdef TSILL
0619         uprintf(stderr,"writing 0x%08x to 0x%08x + 12\n",offst,preg);
0620 #else
0621         WRITE_LE(offst,preg,12);
0622 #endif
0623 
0624 #ifdef TSILL
0625         uprintf(stderr,"writing 0x%08x to 0x%08x + 0\n",mode,preg);
0626 #else
0627         EIEIO_REG;  /* make sure mode is written last */
0628         WRITE_LE(mode,preg,0);
0629         SYNC;       /* enforce completion */
0630 #endif
0631 
0632 #ifdef TSILL
0633         uprintf(stderr,
0634             "universe %s port %lu successfully configured\n",
0635                 ismaster ? "master" : "slave",
0636                 port);
0637 #endif
0638 
0639 #ifdef __vxworks
0640         if (ismaster)
0641             uprintf(stderr,
0642             "WARNING: on the synergy, sysMasterPortsShow() may show incorrect settings (it uses cached values)\n");
0643 #endif
0644     }
0645     return 0;
0646 }
0647 
0648 static int
0649 showUniversePort(
0650         int     ismaster,
0651         int     portno,
0652         volatile LERegister *preg,
0653         void        *parm)
0654 {
0655     FILE *f=parm ? (FILE *)parm : stdout;
0656     unsigned long cntrl, start, bound, offst, mask;
0657 
0658     cntrl = READ_LE0(preg++);
0659 #undef TSILL
0660 #ifdef TSILL
0661     uprintf(stderr,"showUniversePort: *(0x%08x): 0x%08x\n",preg-1,cntrl);
0662 #endif
0663 #undef TSILL
0664 
0665     /* skip this port if disabled */
0666     if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))
0667         return 0;
0668 
0669     /* for the master `start' is the PCI address,
0670      * for the slave  `start' is the VME address
0671      */
0672     mask = ~PORT_UNALIGNED(0xffffffff,portno);
0673 
0674     start = READ_LE0(preg++)&mask;
0675     bound = READ_LE0(preg++)&mask;
0676     offst = READ_LE0(preg++)&mask;
0677 
0678     offst+=start; /* calc start on the other bus */
0679 
0680     if (ismaster) {
0681         uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",
0682             portno,offst,bound-start,start);
0683     } else {
0684         uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",
0685             portno,start,bound-start,offst);
0686     }
0687 
0688     switch (cntrl & UNIV_CTL_VAS) {
0689         case UNIV_CTL_VAS16:   uprintf(f,"A16, "); break;
0690         case UNIV_CTL_VAS24:   uprintf(f,"A24, "); break;
0691         case UNIV_CTL_VAS32:   uprintf(f,"A32, "); break;
0692         case UNIV_MCTL_VASCSR: if ( ismaster ) { uprintf(f,"CSR, "); break; }
0693                                /* else fallthru */
0694         default: uprintf(f,"A??, "); break;
0695     }
0696 
0697     if (ismaster) {
0698         unsigned vdw;
0699         switch ( cntrl & UNIV_MCTL_VDW64 ) {
0700             case UNIV_MCTL_VDW64:
0701                 vdw = 64;
0702             break;
0703 
0704             case UNIV_MCTL_VDW32:
0705                 vdw = 32;
0706             break;
0707 
0708             case UNIV_MCTL_VDW16:
0709                 vdw = 16;
0710             break;
0711 
0712             default:
0713                 vdw = 8;
0714             break;
0715         }
0716 
0717         if ( 64 == vdw ) {
0718             switch ( UNIV_CTL_VAS & cntrl ) {
0719                 case UNIV_CTL_VAS24:
0720                 case UNIV_CTL_VAS32:
0721                     uprintf(f,"D64 [MBLT], ");
0722                     break;
0723 
0724                 default:
0725                     uprintf(f,"D64, ");
0726                     break;
0727             }
0728         } else {
0729             uprintf(f, "D%u%s, ", vdw, (cntrl & UNIV_MCTL_VCT) ? " [BLT]" : "");
0730         }
0731 
0732         uprintf(f,"%s, %s",
0733             cntrl&UNIV_MCTL_PGM ?   "Pgm" : "Dat",
0734             cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr");
0735         if ( cntrl & UNIV_MCTL_PWEN )
0736             uprintf(f,", PWEN");
0737     } else {
0738         uprintf(f,"%s %s %s %s",
0739             cntrl&UNIV_SCTL_PGM ?   "Pgm," : "    ",
0740             cntrl&UNIV_SCTL_DAT ?   "Dat," : "    ",
0741             cntrl&UNIV_SCTL_SUPER ? "Sup," : "    ",
0742             cntrl&UNIV_SCTL_USER  ? "Usr" :  "");
0743         if ( cntrl & UNIV_SCTL_PWEN )
0744             uprintf(f,", PWEN");
0745         if ( cntrl & UNIV_SCTL_PREN )
0746             uprintf(f,", PREN");
0747     }
0748     uprintf(f,"\n");
0749     return 0;
0750 }
0751 
0752 typedef struct XlatRec_ {
0753     unsigned long   address;
0754     unsigned long   aspace;
0755     unsigned        reverse; /* find reverse mapping of this port */
0756 } XlatRec, *Xlat;
0757 
0758 /* try to translate an address through the bridge
0759  *
0760  * IN:  l->address, l->aspace
0761  * OUT: l->address (translated address)
0762  *
0763  * RETURNS: -1: invalid space
0764  *           0: invalid address (not found in range)
0765  *      port+1: success
0766  */
0767 
0768 static int
0769 xlatePort(int ismaster, int port, volatile LERegister *preg, void *parm)
0770 {
0771 Xlat    l=(Xlat)parm;
0772 unsigned long cntrl, start, bound, offst, mask, x;
0773 
0774     cntrl = READ_LE0(preg++);
0775 
0776     /* skip this port if disabled */
0777     if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))
0778         return 0;
0779 
0780     /* check for correct address space */
0781     if ( am2mode(ismaster,l->aspace,&offst) ) {
0782         uprintf(stderr,"vmeUniverse WARNING: invalid adressing mode 0x%x\n",
0783                        l->aspace);
0784         return -1;
0785     }
0786 
0787 
0788     switch (VME_MODE_MATCH_MASK & l->aspace) {
0789         case VME_MODE_EXACT_MATCH:
0790             mask = -1 & ~VME_MODE_MATCH_MASK;
0791             break;
0792 
0793         case VME_MODE_AS_MATCH:
0794             mask = UNIV_CTL_VAS;
0795             break;
0796 
0797         default:
0798             mask = (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK);
0799             break;
0800     }
0801 
0802     cntrl &= mask;
0803     offst &= mask;
0804 
0805     if ( cntrl != offst )
0806         return 0; /* mode doesn't match requested AM */
0807 
0808     /* OK, we found a matching mode, now we must check the address range */
0809     mask = ~PORT_UNALIGNED(0xffffffff,port);
0810 
0811     /* for the master `start' is the PCI address,
0812      * for the slave  `start' is the VME address
0813      */
0814     start = READ_LE0(preg++) & mask;
0815     bound = READ_LE0(preg++) & mask;
0816     offst = READ_LE0(preg++) & mask;
0817 
0818     /* translate address to the other bus */
0819     if (l->reverse) {
0820         /* reverse mapping, i.e. for master ports we map from
0821          * VME to PCI, for slave ports we map from VME to PCI
0822          */
0823         if (l->address >= start && l->address < bound) {
0824                 l->address+=offst;
0825                 return 1 + port;
0826         }
0827     } else {
0828         x = l->address - offst;
0829 
0830         if (x >= start && x < bound) {
0831             /* valid address found */
0832             l->address = x;
0833             return 1 + port;
0834         }
0835     }
0836     return 0;
0837 }
0838 
0839 /* check if there is any active window with write posting enabled */
0840 static int
0841 hasPWENWindow(
0842         int     ismaster,
0843         int     portno,
0844         volatile LERegister *preg,
0845         void        *parm)
0846 {
0847 unsigned long cntrl = READ_LE0(preg);
0848 unsigned long mask  = ismaster ? (UNIV_MCTL_EN|UNIV_MCTL_PWEN) : (UNIV_SCTL_EN|UNIV_SCTL_PWEN);
0849     return (cntrl & mask) == mask ? -1 : 0;
0850 }
0851 
0852 static int
0853 mapOverAll(volatile LERegister *base, int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg)
0854 {
0855 volatile LERegister *rptr;
0856 unsigned long   port;
0857 int rval;
0858 
0859     CHECK_DFLT_BASE(base);
0860 
0861     rptr = (base +
0862         (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister));
0863 #undef TSILL
0864 #ifdef TSILL
0865     uprintf(stderr,"mapoverall: base is 0x%08x, rptr 0x%08x\n",base,rptr);
0866 #endif
0867 #undef TSILL
0868     for (port=0; port<4; port++) {
0869         if ((rval=func(ismaster,port,rptr,arg))) return rval;
0870         rptr+=5; /* register block spacing */
0871     }
0872 
0873     /* only rev. 2 has 8 ports */
0874     if (UNIV_REV(base)<2) return -1;
0875 
0876     rptr = (base +
0877         (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister));
0878     for (port=4; port<UNIV_NUM_MPORTS; port++) {
0879         if ((rval=func(ismaster,port,rptr,arg))) return rval;
0880         rptr+=5; /* register block spacing */
0881     }
0882     return 0;
0883 }
0884 
0885 static void
0886 showUniversePorts(volatile LERegister *base, int ismaster, FILE *f)
0887 {
0888     if (!f) f=stdout;
0889     uprintf(f,"Universe %s Ports:\n",ismaster ? "Master" : "Slave");
0890     uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
0891     mapOverAll(base,ismaster,showUniversePort,f);
0892 }
0893 
0894 static int
0895 xlateFindPort(
0896     volatile LERegister *base,  /* Universe base address */
0897     int master,         /* look in the master windows */
0898     int reverse,        /* reverse mapping; for masters: map local to VME */
0899     unsigned long as,   /* address space */
0900     unsigned long aIn,  /* address to look up */
0901     unsigned long *paOut/* where to put result */
0902     )
0903 {
0904 int rval;
0905 XlatRec l;
0906     l.aspace  = as;
0907     l.address = aIn;
0908     l.reverse = reverse;
0909     /* map result -1/0/1 to -2/-1/0 with 0 on success */
0910     rval = mapOverAll(base,master,xlatePort,(void*)&l) - 1;
0911     *paOut = l.address;
0912     return rval;
0913 }
0914 
0915 int
0916 vmeUniverseXlateAddrXX(
0917     volatile LERegister *base,  /* Universe base address */
0918     int master,         /* look in the master windows */
0919     int reverse,        /* reverse mapping; for masters: map local to VME */
0920     unsigned long as,   /* address space */
0921     unsigned long aIn,  /* address to look up */
0922     unsigned long *paOut/* where to put result */
0923     )
0924 {
0925     return xlateFindPort(base, master, reverse, as, aIn, paOut) >= 0 ? 0 : -1;
0926 }
0927 
0928 int
0929 vmeUniverseXlateAddr(
0930     int master,         /* look in the master windows */
0931     int reverse,        /* reverse mapping; for masters: map local to VME */
0932     unsigned long as,   /* address space */
0933     unsigned long aIn,  /* address to look up */
0934     unsigned long *paOut/* where to put result */
0935     )
0936 {
0937     DFLT_BASE;
0938     return vmeUniverseXlateAddrXX(base, master, reverse, as, aIn, paOut);
0939 }
0940 
0941 
0942 void
0943 vmeUniverseReset(void)
0944 {
0945     /* disable/reset special cycles (ADOH, RMW) */
0946     vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_CTL);
0947     vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_ADDR);
0948     vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_EN);
0949 
0950     /* set coupled window timeout to 0 (release VME after each transaction)
0951      * CRT (coupled request timeout) is unused by Universe II
0952      */
0953     vmeUniverseWriteReg(UNIV_LMISC_CRT_128_US, UNIV_REGOFF_LMISC);
0954 
0955     /* disable/reset DMA engine */
0956     vmeUniverseWriteReg(0, UNIV_REGOFF_DCTL);
0957     vmeUniverseWriteReg(0, UNIV_REGOFF_DTBC);
0958     vmeUniverseWriteReg(0, UNIV_REGOFF_DLA);
0959     vmeUniverseWriteReg(0, UNIV_REGOFF_DVA);
0960     vmeUniverseWriteReg(0, UNIV_REGOFF_DCPP);
0961 
0962     /* disable location monitor */
0963     vmeUniverseWriteReg(0, UNIV_REGOFF_LM_CTL);
0964 
0965     /* disable universe register access from VME bus */
0966     vmeUniverseWriteReg(0, UNIV_REGOFF_VRAI_CTL);
0967 
0968 #if 0   /* leave CSR bus image alone; IRQ manager can use it */
0969     /* disable VME bus image of VME CSR */
0970     vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL);
0971 #endif
0972 
0973 
0974     /* I had problems with a Joerger vtr10012_8 card who would
0975      * only be accessible after tweaking the U2SPEC register
0976      * (the t27 parameter helped).
0977      * I use the same settings here that are used by the
0978      * Synergy VGM-powerpc BSP for vxWorks.
0979      */
0980     if (2==UNIV_REV(vmeUniverse0BaseAddr))
0981         vmeUniverseWriteReg(UNIV_U2SPEC_DTKFLTR |
0982                         UNIV_U2SPEC_MASt11   |
0983                         UNIV_U2SPEC_READt27_NODELAY |
0984                         UNIV_U2SPEC_POSt28_FAST |
0985                         UNIV_U2SPEC_PREt28_FAST,
0986                         UNIV_REGOFF_U2SPEC);
0987 
0988     /* disable interrupts, reset routing */
0989     vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_EN);
0990     vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP0);
0991     vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP1);
0992 
0993     vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_EN);
0994     vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP0);
0995     vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP1);
0996 
0997     vmeUniverseDisableAllSlaves();
0998 
0999     vmeUniverseDisableAllMasters();
1000 
1001     vmeUniverseWriteReg(UNIV_VCSR_CLR_SYSFAIL, UNIV_REGOFF_VCSR_CLR);
1002 
1003     /* clear interrupt status bits */
1004     vmeUniverseWriteReg(UNIV_LINT_STAT_CLR, UNIV_REGOFF_LINT_STAT);
1005     vmeUniverseWriteReg(UNIV_VINT_STAT_CLR, UNIV_REGOFF_VINT_STAT);
1006 
1007     vmeUniverseWriteReg(UNIV_V_AMERR_V_STAT, UNIV_REGOFF_V_AMERR);
1008 
1009     vmeUniverseWriteReg(
1010         vmeUniverseReadReg(UNIV_REGOFF_PCI_CSR) |
1011         UNIV_PCI_CSR_D_PE | UNIV_PCI_CSR_S_SERR | UNIV_PCI_CSR_R_MA |
1012         UNIV_PCI_CSR_R_TA | UNIV_PCI_CSR_S_TA,
1013         UNIV_REGOFF_PCI_CSR);
1014 
1015     vmeUniverseWriteReg(UNIV_L_CMDERR_L_STAT, UNIV_REGOFF_L_CMDERR);
1016 
1017     vmeUniverseWriteReg(
1018         UNIV_DGCS_STOP | UNIV_DGCS_HALT | UNIV_DGCS_DONE |
1019         UNIV_DGCS_LERR | UNIV_DGCS_VERR | UNIV_DGCS_P_ERR,
1020         UNIV_REGOFF_DGCS);
1021 }
1022 
1023 int
1024 vmeUniverseInit(void)
1025 {
1026 int rval;
1027     if ( (rval=vmeUniverseFindPciBase(0,&vmeUniverse0BaseAddr)) < 0 ) {
1028         uprintf(stderr,"unable to find the universe in pci config space\n");
1029     } else {
1030         vmeUniverse0PciIrqLine = rval;
1031         rval                   = 0;
1032         uprintf(stderr,"Universe II PCI-VME bridge detected at 0x%08x, IRQ %d\n",
1033                 (unsigned int)vmeUniverse0BaseAddr, vmeUniverse0PciIrqLine);
1034     }
1035     return rval;
1036 }
1037 
1038 void
1039 vmeUniverseMasterPortsShowXX(volatile LERegister *base, FILE *f)
1040 {
1041     showUniversePorts(base,1,f);
1042 }
1043 
1044 void
1045 vmeUniverseMasterPortsShow(FILE *f)
1046 {
1047     DFLT_BASE;
1048     showUniversePorts(base,1,f);
1049 }
1050 
1051 void
1052 vmeUniverseSlavePortsShowXX(volatile LERegister *base, FILE *f)
1053 {
1054     showUniversePorts(base,0,f);
1055 }
1056 
1057 void
1058 vmeUniverseSlavePortsShow(FILE *f)
1059 {
1060     DFLT_BASE;
1061     showUniversePorts(base,0,f);
1062 }
1063 
1064 int
1065 vmeUniverseMasterPortCfgXX(
1066     volatile LERegister *base,
1067     unsigned long   port,
1068     unsigned long   address_space,
1069     unsigned long   vme_address,
1070     unsigned long   local_address,
1071     unsigned long   length)
1072 {
1073     return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
1074 }
1075 
1076 int
1077 vmeUniverseMasterPortCfg(
1078     unsigned long   port,
1079     unsigned long   address_space,
1080     unsigned long   vme_address,
1081     unsigned long   local_address,
1082     unsigned long   length)
1083 {
1084     DFLT_BASE;
1085     return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
1086 }
1087 
1088 int
1089 vmeUniverseSlavePortCfgXX(
1090     volatile LERegister *base,
1091     unsigned long   port,
1092     unsigned long   address_space,
1093     unsigned long   vme_address,
1094     unsigned long   local_address,
1095     unsigned long   length)
1096 {
1097     return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
1098 }
1099 
1100 int
1101 vmeUniverseSlavePortCfg(
1102     unsigned long   port,
1103     unsigned long   address_space,
1104     unsigned long   vme_address,
1105     unsigned long   local_address,
1106     unsigned long   length)
1107 {
1108     DFLT_BASE;
1109     return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
1110 }
1111 
1112 
1113 void
1114 vmeUniverseDisableAllSlavesXX(volatile LERegister *base)
1115 {
1116     mapOverAll(base,0,disableUniversePort,0);
1117 }
1118 
1119 void
1120 vmeUniverseDisableAllSlaves(void)
1121 {
1122     DFLT_BASE;
1123     mapOverAll(base,0,disableUniversePort,0);
1124 }
1125 
1126 void
1127 vmeUniverseDisableAllMastersXX(volatile LERegister *base)
1128 {
1129     mapOverAll(base,1,disableUniversePort,0);
1130 }
1131 
1132 void
1133 vmeUniverseDisableAllMasters(void)
1134 {
1135     DFLT_BASE;
1136     mapOverAll(base,1,disableUniversePort,0);
1137 }
1138 
1139 unsigned long
1140 vmeUniverseReadRegXX(volatile LERegister *base, unsigned long offset)
1141 {
1142 unsigned long rval;
1143     rval = READ_LE(base,offset);
1144     return rval;
1145 }
1146 
1147 
1148 unsigned long
1149 vmeUniverseReadReg(unsigned long offset)
1150 {
1151 unsigned long rval;
1152     rval = READ_LE(vmeUniverse0BaseAddr,offset);
1153     return rval;
1154 }
1155 
1156 void
1157 vmeUniverseWriteRegXX(volatile LERegister *base, unsigned long value, unsigned long offset)
1158 {
1159     WRITE_LE(value, base, offset);
1160 }
1161 
1162 void
1163 vmeUniverseWriteReg(unsigned long value, unsigned long offset)
1164 {
1165     WRITE_LE(value, vmeUniverse0BaseAddr, offset);
1166 }
1167 
1168 void
1169 vmeUniverseResetBus(void)
1170 {
1171     vmeUniverseWriteReg(
1172         vmeUniverseReadReg(UNIV_REGOFF_MISC_CTL) | UNIV_MISC_CTL_SW_SYSRST,
1173         UNIV_REGOFF_MISC_CTL);
1174 }
1175 
1176 void
1177 vmeUniverseCvtToLE(unsigned long *ptr, unsigned long num)
1178 {
1179 #if !defined(__LITTLE_ENDIAN__) || (__LITTLE_ENDIAN__ != 1)
1180 register unsigned long *p=ptr+num;
1181     while (p > ptr) {
1182 #if (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
1183         __asm__ __volatile__(
1184             "lwzu 0, -4(%0)\n"
1185             "stwbrx 0, 0, %0\n"
1186             : "=r"(p) : "0"(p) : "r0"
1187             );
1188 #elif defined(__rtems__)
1189         p--; st_le32(p, *p);
1190 #else
1191 #error  "vmeUniverse: endian conversion not implemented for this architecture"
1192 #endif
1193     }
1194 #endif
1195 }
1196 
1197 int
1198 vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector)
1199 {
1200 unsigned long v;
1201 unsigned long b;
1202 
1203     CHECK_DFLT_BASE(base);
1204 
1205     if ( level < 1 || level > 7 || vector > 255 )
1206         return -1;  /* invalid argument */
1207 
1208     if ( vector & 1 ) /* SW interrupts always ACK an even vector (pp 2-67) */
1209         return -1;
1210 
1211 
1212     /* Check if already asserted */
1213     if ( vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_STAT ) & UNIV_VINT_STAT_SWINT(level) ) {
1214         return -2;  /* already asserted */
1215     }
1216 
1217     /* Write Vector */
1218     vmeUniverseWriteRegXX(base, UNIV_VINT_STATID(vector), UNIV_REGOFF_VINT_STATID );
1219 
1220     if ( UNIV_REV(base) >= 2 ) {
1221         /* universe II has individual bits for individual levels */
1222         b = UNIV_VINT_STAT_SWINT(level);
1223     } else {
1224         /* version that is compatible with universe I */
1225         v  = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_MAP1);
1226         v &= ~UNIV_VINT_MAP1_SWINT(0x7);
1227         v |=  UNIV_VINT_MAP1_SWINT(level);
1228         vmeUniverseWriteRegXX(base, v, UNIV_REGOFF_VINT_MAP1);
1229         b  = UNIV_VINT_EN_SWINT;
1230     }
1231     v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_EN);
1232     /* make sure it is clear, then assert */
1233     vmeUniverseWriteRegXX(base, v & ~b, UNIV_REGOFF_VINT_EN );
1234     vmeUniverseWriteRegXX(base, v |  b, UNIV_REGOFF_VINT_EN );
1235 
1236     return 0;
1237 
1238 }
1239 
1240 int
1241 vmeUniverseIntRaise(int level, unsigned vector)
1242 {
1243     return vmeUniverseIntRaiseXX(vmeUniverse0BaseAddr, level, vector);
1244 }
1245 
1246 
1247 /* Map internal register block to VME */
1248 #define UNIV_CRG_SIZE (1<<12)
1249 
1250 int
1251 vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long as )
1252 {
1253 uint32_t mode;
1254 
1255     CHECK_DFLT_BASE(base);
1256 
1257 #ifdef __rtems__
1258     if ( vmeUniverseRegPort > -1 && ! vmeUniverseRegCSR ) {
1259         uprintf(stderr,"vmeUniverse: CRG already mapped and in use by interrupt manager\n");
1260         return -1;
1261     }
1262 #endif
1263 
1264     /* enable all, SUP/USR/PGM/DATA accesses */
1265     mode = UNIV_VRAI_CTL_EN | UNIV_VRAI_CTL_PGM | UNIV_VRAI_CTL_DATA | UNIV_VRAI_CTL_SUPER | UNIV_VRAI_CTL_USER;
1266 
1267     if ( VME_AM_IS_SHORT(as) ) {
1268         mode |= UNIV_VRAI_CTL_VAS_A16;
1269     } else
1270     if ( VME_AM_IS_STD(as) ) {
1271         mode |= UNIV_VRAI_CTL_VAS_A24;
1272     } else
1273     if ( VME_AM_IS_EXT(as) ) {
1274         mode |= UNIV_VRAI_CTL_VAS_A32;
1275     } else {
1276         return -2;
1277     }
1278 
1279     /* map CRG to VME bus */
1280     WRITE_LE( (vme_base & ~(UNIV_CRG_SIZE-1)), base, UNIV_REGOFF_VRAI_BS );
1281     WRITE_LE( mode, base, UNIV_REGOFF_VRAI_CTL );
1282 
1283     return 0;
1284 }
1285 
1286 int
1287 vmeUniverseMapCRG(unsigned long vme_base, unsigned long as )
1288 {
1289     return vmeUniverseMapCRGXX( vmeUniverse0BaseAddr, vme_base, as );
1290 }
1291 
1292 #ifdef __rtems__
1293 /* DMA Support -- including linked-list implementation */
1294 #include "bspVmeDmaListP.h"
1295 #include <bsp/vmeUniverseDMA.h>
1296 
1297 /* Filter valid bits of DCTL */
1298 #define DCTL_MODE_MASK \
1299     ( UNIV_DCTL_VDW_MSK | UNIV_DCTL_VAS_MSK | UNIV_DCTL_PGM | UNIV_DCTL_SUPER | UNIV_DCTL_VCT )
1300 
1301 static uint32_t
1302 xfer_mode2dctl(uint32_t xfer_mode)
1303 {
1304 uint32_t dctl;
1305 unsigned long ul;
1306 
1307     /* Check requested bus mode */
1308 
1309     /* Universe does not support 'non-incrementing' DMA */
1310 
1311     /* NOTE: Universe IIb/d *does* support NOINC_VME but states
1312      *       that the VME address needs to be reprogrammed
1313      *       when re-issuing a transfer
1314      */
1315     if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_PCI )
1316         return BSP_VMEDMA_STATUS_UNSUP;
1317 
1318     /* ignore memory hint */
1319     xfer_mode &= ~VME_AM_IS_MEMORY;
1320 
1321     if ( VME_AM_IS_2eSST(xfer_mode) )
1322         return BSP_VMEDMA_STATUS_UNSUP;
1323 
1324     if ( ! VME_AM_IS_SHORT(xfer_mode) && ! VME_AM_IS_STD(xfer_mode) && ! VME_AM_IS_EXT(xfer_mode) )
1325         return BSP_VMEDMA_STATUS_UNSUP;
1326 
1327     /* Luckily DCTL bits match MCTL bits so we can use am2mode */
1328     if ( am2mode( 1, xfer_mode, &ul ) )
1329         return BSP_VMEDMA_STATUS_UNSUP;
1330     dctl = (uint32_t) ul;
1331 
1332     /* However, the book says that for DMA VAS==5 [which would
1333      * be a CSR access] is reserved. Tests indicate that
1334      * CSR access works on the IIb/d but not really (odd 32-bit
1335      * addresses read 0) on the II.
1336      * Nevertheless, we disallow DMA CSR access at this point
1337      * in order to play it safe...
1338      */
1339     switch ( UNIV_DCTL_VAS_MSK & dctl ) {
1340         case UNIV_DCTL_VAS_A24:
1341         case UNIV_DCTL_VAS_A32:
1342             /* fixup the data width; universe may always use MBLT
1343              * if data width is 64-bit so we go back to 32-bit
1344              * if they didn't explicitely ask for MBLT cycles
1345              */
1346             if (   (xfer_mode & 0xb) != 8 /* MBLT */
1347                 && ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) ) {
1348                 dctl &= ~UNIV_DCTL_VDW_MSK;
1349                 dctl |= UNIV_DCTL_VDW_32;
1350             }
1351             break;
1352 
1353         case UNIV_DCTL_VAS_A16:
1354             break;
1355 
1356         default:
1357             return BSP_VMEDMA_STATUS_UNSUP;
1358     }
1359 
1360     /* Make sure other MCTL bits are masked */
1361     dctl &= DCTL_MODE_MASK;
1362 
1363     if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) {
1364         /* If they want NOINC_VME then we have to do some
1365          * fixup :-( ('errata' [in this case: feature addition] doc. pp. 11+)
1366          */
1367         dctl &= ~UNIV_DCTL_VCT; /* clear block xfer flag */
1368         dctl |= UNIV_DCTL_NO_VINC;
1369         /* cannot do 64 bit transfers; go back to 32 */
1370         if ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) {
1371             dctl &= ~UNIV_DCTL_VDW_MSK;
1372             dctl |= UNIV_DCTL_VDW_32;
1373         }
1374     }
1375 
1376     /* Set direction flag */
1377 
1378     if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode )
1379         dctl |= UNIV_DCTL_L2V;
1380 
1381     return dctl;
1382 }
1383 
1384 /* Convert canonical xfer_mode into Universe setup bits; return -1 if request
1385  * cannot be satisfied (unsupported features)
1386  */
1387 int
1388 vmeUniverseDmaSetupXX(volatile LERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
1389 {
1390 uint32_t dctl, dgcs;
1391 
1392     if ( channel != 0 )
1393         return BSP_VMEDMA_STATUS_UNSUP;
1394 
1395     dctl = xfer_mode2dctl(xfer_mode);
1396 
1397     if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl )
1398         return BSP_VMEDMA_STATUS_UNSUP;
1399 
1400     /* Enable all interrupts at the controller */
1401     dgcs = UNIV_DGCS_INT_MSK;
1402 
1403     switch ( mode ) {
1404         case BSP_VMEDMA_OPT_THROUGHPUT:
1405             dgcs |= UNIV_DGCS_VON_1024 | UNIV_DGCS_VOFF_0_US;
1406             /* VON counts are different in NO_VINC mode :-( */
1407             dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
1408                     UNIV_DGCS_VON_2048 : UNIV_DGCS_VON_1024;
1409         break;
1410 
1411         case BSP_VMEDMA_OPT_LOWLATENCY:
1412             dgcs |= UNIV_DGCS_VOFF_0_US;
1413             /* VON counts are different in NO_VINC mode :-( */
1414             dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
1415                     UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256;
1416         break;
1417 
1418         case BSP_VMEDMA_OPT_SHAREDBUS:
1419             dgcs |= UNIV_DGCS_VOFF_512_US;
1420             /* VON counts are different in NO_VINC mode :-( */
1421             dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
1422                     UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256;
1423         break;
1424 
1425         case BSP_VMEDMA_OPT_CUSTOM:
1426             dctl = ((uint32_t*)custom)[0];
1427             dgcs = ((uint32_t*)custom)[1];
1428         break;
1429 
1430         default:
1431         case BSP_VMEDMA_OPT_DEFAULT:
1432         break;
1433     }
1434 
1435     /* clear status bits */
1436     dgcs |= UNIV_DGCS_STATUS_CLEAR;
1437 
1438     vmeUniverseWriteRegXX(base, dctl, UNIV_REGOFF_DCTL);
1439     vmeUniverseWriteRegXX(base, dgcs, UNIV_REGOFF_DGCS);
1440 
1441     return BSP_VMEDMA_STATUS_OK;
1442 }
1443 
1444 int
1445 vmeUniverseDmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
1446 {
1447 DFLT_BASE;
1448     return vmeUniverseDmaSetupXX(base, channel, mode, xfer_mode, custom);
1449 }
1450 
1451 int
1452 vmeUniverseDmaStartXX(volatile LERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
1453 {
1454     if ( channel != 0 )
1455         return BSP_VMEDMA_STATUS_UNSUP;
1456 
1457     if ((pci_addr & 7) != (vme_addr & 7)) {
1458         uprintf(stderr,"vmeUniverseDmaStartXX: misaligned addresses\n");
1459         return -1;
1460     }
1461 
1462     {
1463     /* help the compiler allocate registers */
1464     register volatile LERegister *b=base;
1465     register unsigned long dgcsoff=UNIV_REGOFF_DGCS,dgcs;
1466 
1467     dgcs=READ_LE(b, dgcsoff);
1468 
1469     /* clear status and make sure CHAIN is clear */
1470     dgcs &= ~UNIV_DGCS_CHAIN;
1471     WRITE_LE(dgcs,
1472               b, dgcsoff);
1473     WRITE_LE(pci_addr,
1474               b, UNIV_REGOFF_DLA);
1475     WRITE_LE(vme_addr,
1476               b, UNIV_REGOFF_DVA);
1477     WRITE_LE(n_bytes,
1478               b, UNIV_REGOFF_DTBC);
1479     dgcs |= UNIV_DGCS_GO;
1480     EIEIO_REG; /* make sure GO is written after everything else */
1481     WRITE_LE(dgcs,
1482               b, dgcsoff);
1483     }
1484     SYNC; /* enforce command completion */
1485     return 0;
1486 }
1487 
1488 /* This entry point is deprecated */
1489 int
1490 vmeUniverseStartDMAXX(
1491     volatile LERegister *base,
1492     unsigned long local_addr,
1493     unsigned long vme_addr,
1494     unsigned long count)
1495 {
1496     return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count);
1497 }
1498 
1499 int
1500 vmeUniverseDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
1501 {
1502     DFLT_BASE; /* vmeUniverseDmaStartXX doesn't check for a valid base address for efficiency reasons */
1503     return vmeUniverseDmaStartXX(base, channel, pci_addr, vme_addr, n_bytes);
1504 }
1505 
1506 /* This entry point is deprecated */
1507 int
1508 vmeUniverseStartDMA(
1509     unsigned long local_addr,
1510     unsigned long vme_addr,
1511     unsigned long count)
1512 {
1513     DFLT_BASE; /* vmeUniverseStartDMAXX doesn't check for a valid base address for efficiency reasons */
1514     return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count);
1515 }
1516 
1517 uint32_t
1518 vmeUniverseDmaStatusXX(volatile LERegister *base, int channel)
1519 {
1520 uint32_t dgcs;
1521     if ( channel != 0 )
1522         return BSP_VMEDMA_STATUS_UNSUP;
1523 
1524     dgcs = vmeUniverseReadRegXX(base, UNIV_REGOFF_DGCS);
1525 
1526     dgcs &= UNIV_DGCS_STATUS_CLEAR;
1527 
1528     if ( 0 == dgcs || UNIV_DGCS_DONE == dgcs )
1529         return BSP_VMEDMA_STATUS_OK;
1530 
1531     if ( UNIV_DGCS_ACT & dgcs )
1532         return BSP_VMEDMA_STATUS_BUSY;
1533 
1534     if ( UNIV_DGCS_LERR & dgcs )
1535         return BSP_VMEDMA_STATUS_BERR_PCI;
1536 
1537     if ( UNIV_DGCS_VERR & dgcs )
1538         return BSP_VMEDMA_STATUS_BERR_VME;
1539 
1540     return BSP_VMEDMA_STATUS_OERR;
1541 }
1542 
1543 uint32_t
1544 vmeUniverseDmaStatus(int channel)
1545 {
1546 DFLT_BASE;
1547     return vmeUniverseDmaStatusXX(base, channel);
1548 }
1549 
1550 /* bspVmeDmaList driver interface implementation */
1551 
1552 /* Cannot use VmeUniverseDMAPacketRec because st_le32 expects unsigned *
1553  * and we get 'alias' warnings when we submit uint32_t *
1554  */
1555 
1556 typedef volatile uint32_t LERegister1;
1557 
1558 typedef struct VmeUniverseDmaListDescRec_ {
1559     LERegister1 dctl;
1560     LERegister1 dtbc;
1561     LERegister1 dla;
1562     LERegister1 dummy1;
1563     LERegister1 dva;
1564     LERegister1 dummy2;
1565     LERegister1 dcpp;
1566     LERegister1 dummy3;
1567 } __attribute__((aligned(32), __may_alias__))
1568 VmeUniverseDmaListDescRec;
1569 
1570 typedef VmeUniverseDmaListDescRec *VmeUniverseDmaListDesc;
1571 
1572 static void     uni_desc_init  (DmaDescriptor);
1573 static int      uni_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
1574 static void     uni_desc_setnxt(DmaDescriptor, DmaDescriptor);
1575 static void     uni_desc_dump  (DmaDescriptor);
1576 static int      uni_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p);
1577 
1578 VMEDmaListClassRec  vmeUniverseDmaListClass = {
1579     desc_size:  sizeof(VmeUniverseDMAPacketRec),
1580     desc_align: 32,
1581     freeList:   0,
1582     desc_alloc: 0,
1583     desc_free:  0,
1584     desc_init:  uni_desc_init,
1585     desc_setnxt:uni_desc_setnxt,
1586     desc_setup: uni_desc_setup,
1587     desc_start: uni_desc_start,
1588     desc_refr:  0,
1589     desc_dump:  uni_desc_dump,
1590 };
1591 
1592 static void     uni_desc_init  (DmaDescriptor p)
1593 {
1594 VmeUniverseDmaListDesc d = p;
1595     st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL );
1596 }
1597 
1598 static void     uni_desc_setnxt(DmaDescriptor p, DmaDescriptor n)
1599 {
1600 VmeUniverseDmaListDesc d = p;
1601     if ( 0 == n ) {
1602         st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL );
1603     } else {
1604         st_le32( &d->dcpp, BSP_LOCAL2PCI_ADDR( (uint32_t)n));
1605     }
1606 }
1607 
1608 static int
1609 uni_desc_setup (
1610     DmaDescriptor p,
1611     uint32_t    attr_mask,
1612     uint32_t    xfer_mode,
1613     uint32_t    pci_addr,
1614     uint32_t    vme_addr,
1615     uint32_t    n_bytes)
1616 {
1617 VmeUniverseDmaListDesc d = p;
1618 LERegister1            dctl;
1619 
1620     if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
1621         dctl = xfer_mode2dctl(xfer_mode);
1622 
1623         if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl )
1624             return -1;
1625 
1626         st_le32( &d->dctl, dctl );
1627     }
1628 
1629     /* Last 3 bits of src & destination addresses must be the same.
1630      * For sake of simplicity we enforce (stricter) 8-byte alignment
1631      */
1632 
1633     if ( BSP_VMEDMA_MSK_PCIA & attr_mask ) {
1634         if ( pci_addr & 0x7 )
1635             return -1;
1636 
1637         st_le32( &d->dla, pci_addr );
1638     }
1639 
1640     if ( BSP_VMEDMA_MSK_VMEA & attr_mask ) {
1641         if ( vme_addr & 0x7 )
1642             return -1;
1643 
1644         st_le32( &d->dva, vme_addr );
1645     }
1646 
1647     if ( BSP_VMEDMA_MSK_BCNT & attr_mask ) {
1648         st_le32( &d->dtbc, n_bytes );
1649     }
1650 
1651     return 0;
1652 }
1653 
1654 static int      uni_desc_start
1655 (volatile void *controller_addr, int channel, DmaDescriptor p)
1656 {
1657 volatile LERegister *base = controller_addr;
1658 uint32_t            dgcs;
1659 
1660     if ( !base )
1661         base = vmeUniverse0BaseAddr;
1662 
1663     dgcs  = vmeUniverseReadRegXX( base, UNIV_REGOFF_DGCS );
1664 
1665     if ( UNIV_DGCS_ACT & dgcs )
1666         return BSP_VMEDMA_STATUS_BUSY;
1667 
1668     if ( !p ) {
1669         /* Chain bit is cleared by non-linked-list start command
1670          * but do this anyways...
1671          */
1672         dgcs &= ~UNIV_DGCS_CHAIN;
1673         vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs);
1674         return 0;
1675     }
1676 
1677     /* clear status and set CHAIN bit */
1678     dgcs |= UNIV_DGCS_CHAIN;
1679 
1680     vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs);
1681 
1682     /* make sure count is 0 for linked list DMA */
1683     vmeUniverseWriteRegXX( base, 0x0, UNIV_REGOFF_DTBC);
1684 
1685     /* set the address of the descriptor chain */
1686     vmeUniverseWriteRegXX( base, BSP_LOCAL2PCI_ADDR((uint32_t)p), UNIV_REGOFF_DCPP);
1687 
1688     /* and GO */
1689     dgcs |= UNIV_DGCS_GO;
1690     vmeUniverseWriteReg(dgcs, UNIV_REGOFF_DGCS);
1691 
1692     return 0;
1693 }
1694 
1695 static void
1696 uni_desc_dump(DmaDescriptor p)
1697 {
1698 VmeUniverseDmaListDesc d = p;
1699 LERegister1            dcpp = ld_le32(&d->dcpp);
1700 
1701     printf("   DLA: 0x%08x\n", ld_le32(&d->dla));
1702     printf("   DVA: 0x%08x\n", ld_le32(&d->dva));
1703     printf("  DCPP: 0x%08"PRIx32"%s\n", dcpp, (dcpp & UNIV_DCPP_IMG_NULL) ? " (LAST)" : "");
1704     printf("   CTL: 0x%08x\n", ld_le32(&d->dctl));
1705     printf("   TBC: 0x%08x\n", ld_le32(&d->dtbc));
1706 }
1707 
1708 /* RTEMS interrupt subsystem */
1709 
1710 #include <bsp/irq.h>
1711 #include <rtems/irq.h>
1712 
1713 typedef struct
1714 UniverseIRQEntryRec_ {
1715         VmeUniverseISR  isr;
1716         void            *usrData;
1717 } UniverseIRQEntryRec, *UniverseIRQEntry;
1718 
1719 static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0};
1720 
1721 int          vmeUniverseIrqMgrInstalled = 0;
1722 
1723 volatile LERegister *vmeUniverseRegBase = 0;
1724 
1725 /* We support 4 wires between universe + PIC */
1726 
1727 #define UNIV_NUM_WIRES 4
1728 
1729 static volatile unsigned long   wire_mask[UNIV_NUM_WIRES]     = {0};
1730 /* wires are offset by 1 so we can initialize the wire table to all zeros */
1731 static int                      universe_wire[UNIV_NUM_WIRES] = {0};
1732 
1733 static int
1734 lvl2bit(unsigned int level)
1735 {
1736 int shift = -1;
1737     if ( level >= UNIV_DMA_INT_VEC && level <= UNIV_LM3_INT_VEC ) {
1738         shift = 8 + (level-UNIV_DMA_INT_VEC);
1739     } else if ( UNIV_VOWN_INT_VEC == level ) {
1740         shift = 0;
1741     } else if ( 1 <= level && level <=7 ) {
1742         shift = level;
1743     } else {
1744         /* invalid level */
1745     }
1746     return shift;
1747 }
1748 
1749 RTEMS_INTERRUPT_LOCK_DEFINE( static, vmeUniverse_lock, "vmeUniverse_lock" )
1750 
1751 int
1752 vmeUniverseIntRoute(unsigned int level, unsigned int pin)
1753 {
1754 int             i, shift;
1755 unsigned long   mask, mapreg, wire;
1756 rtems_interrupt_lock_context lock_context;
1757 
1758     if ( pin >= UNIV_NUM_WIRES || ! universe_wire[pin] || !vmeUniverseIrqMgrInstalled )
1759         return -1;
1760 
1761     if ( (shift = lvl2bit(level)) < 0 ) {
1762         return -1; /* invalid level */
1763     }
1764 
1765     mask = 1<<shift;
1766 
1767     /* calculate the mapping register and contents */
1768     if ( shift < 8 ) {
1769         mapreg = UNIV_REGOFF_LINT_MAP0;
1770     } else if ( shift < 16 ) {
1771         shift -= 8;
1772         mapreg = UNIV_REGOFF_LINT_MAP1;
1773     } else if ( shift < 24 ) {
1774         shift -= 16;
1775         mapreg = UNIV_REGOFF_LINT_MAP2;
1776     } else {
1777         return -1;
1778     }
1779 
1780     shift <<=2;
1781 
1782     /* wires are offset by 1 so we can initialize the wire table to all zeros */
1783     wire = (universe_wire[pin]-1) << shift;
1784 
1785     rtems_interrupt_lock_acquire( &vmeUniverse_lock, &lock_context );
1786 
1787     for ( i = 0; i<UNIV_NUM_WIRES; i++ ) {
1788         wire_mask[i] &= ~mask;
1789     }
1790     wire_mask[pin] |= mask;
1791 
1792     mask = vmeUniverseReadReg(mapreg) & ~ (0xf<<shift);
1793     mask |= wire;
1794     vmeUniverseWriteReg( mask, mapreg );
1795 
1796     rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
1797     return 0;
1798 }
1799 
1800 VmeUniverseISR
1801 vmeUniverseISRGet(unsigned long vector, void **parg)
1802 {
1803 VmeUniverseISR            rval = 0;
1804 volatile UniverseIRQEntry *pe  = universeHdlTbl + vector;
1805 rtems_interrupt_lock_context lock_context;
1806 
1807     if ( vector>=UNIV_NUM_INT_VECS || ! *pe )
1808         return 0;
1809 
1810     rtems_interrupt_lock_acquire( &vmeUniverse_lock, &lock_context );
1811         if ( *pe ) {
1812             if (parg)
1813                 *parg=(*pe)->usrData;
1814             rval = (*pe)->isr;
1815         }
1816     rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
1817     return rval;
1818 }
1819 
1820 #define SPECIAL_IRQ_MSK  ( ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1) )
1821 
1822 static void
1823 universeSpecialISR(unsigned long status)
1824 {
1825 register UniverseIRQEntry   ip;
1826 register unsigned           vec;
1827 register unsigned long      s;
1828 
1829     /* handle all LINT bits except for the 'normal' VME interrupts */
1830 
1831     /* clear all detected special interrupts */
1832     vmeUniverseWriteReg( (status & SPECIAL_IRQ_MSK), UNIV_REGOFF_LINT_STAT );
1833 
1834     /* do VOWN first */
1835     vec=UNIV_VOWN_INT_VEC;
1836     if ( (status & UNIV_LINT_STAT_VOWN) && (ip=universeHdlTbl[vec]))
1837         ip->isr(ip->usrData,vec);
1838 
1839     /* now continue with DMA and scan through all bits;
1840      * we assume the vectors are in the right order!
1841      *
1842      * The initial right shift brings the DMA bit into position 0;
1843      * the loop is left early if there are no more bits set.
1844      */
1845     for ( s = status>>8; s; s >>= 1) {
1846         vec++;
1847         if ( (s&1) && (ip=universeHdlTbl[vec]) )
1848             ip->isr(ip->usrData,vec);
1849     }
1850 
1851 /*
1852  *  clear our line in the VINT_STAT register
1853  *  seems to be not neccessary...
1854     vmeUniverseWriteReg(
1855                     UNIV_VINT_STAT_LINT(specialIrqUnivOut),
1856                     UNIV_REGOFF_VINT_STAT);
1857  */
1858 }
1859 
1860 /*
1861  * interrupts from VME to PCI seem to be processed more or less
1862  * like this:
1863  *
1864  *
1865  *   VME IRQ ------
1866  *                  & ----- LINT_STAT ----
1867  *                  |                       &  ---------- PCI LINE
1868  *                  |                       |
1869  *                  |                       |
1870  *       LINT_EN ---------------------------
1871  *
1872  *  I.e.
1873  *   - if LINT_EN is disabled, a VME IRQ will not set LINT_STAT.
1874  *   - while LINT_STAT is set, it will pull the PCI line unless
1875  *     masked by LINT_EN.
1876  *   - VINT_STAT(lint_bit) seems to have no effect beyond giving
1877  *     status info.
1878  *
1879  *  Hence, it is possible to
1880  *    - arm (set LINT_EN, routing etc.)
1881  *    - receive an irq (sets. LINT_STAT)
1882  *    - the ISR then:
1883  *            * clears LINT_EN, results in masking LINT_STAT (which
1884  *              is still set to prevent another VME irq at the same
1885  *              level to be ACKEd by the universe.
1886  *            * do PCI_EOI to allow nesting of higher VME irqs.
1887  *              (previous step also cleared LINT_EN of lower levels)
1888  *            * when the handler returns, clear LINT_STAT
1889  *            * re-enable setting LINT_EN.
1890  */
1891 
1892 static void
1893 universeVMEISR(rtems_irq_hdl_param arg)
1894 {
1895 int                 pin = (int)arg;
1896 UniverseIRQEntry    ip;
1897 unsigned long       msk,lintstat,status;
1898 int                 lvl;
1899 #if defined(BSP_PIC_DO_EOI)
1900 unsigned long       linten;
1901 #endif
1902 
1903         /* determine the highest priority IRQ source */
1904         lintstat  = vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT);
1905 
1906         /* only handle interrupts routed to this pin */
1907         lintstat &= wire_mask[pin];
1908 
1909 #ifdef __PPC__
1910         asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat & ~SPECIAL_IRQ_MSK));
1911         lvl = 31-lvl;
1912         msk = 1<<lvl;
1913 #else
1914         for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7;
1915              lvl>0;
1916              lvl--, msk>>=1) {
1917             if (lintstat & msk) break;
1918         }
1919 #endif
1920 
1921 #ifndef BSP_PIC_DO_EOI  /* Software priorities not supported */
1922 
1923         if ( (status = (lintstat & SPECIAL_IRQ_MSK)) )
1924             universeSpecialISR( status );
1925 
1926         if ( lvl <= 0)
1927             return;
1928 
1929 #else
1930         if ( lvl <= 0 ) {
1931                 /* try the special handler */
1932                 universeSpecialISR( lintstat & SPECIAL_IRQ_MSK );
1933 
1934                 /*
1935                  * let the pic end this cycle
1936                  */
1937                 if ( 0 == pin )
1938                     BSP_PIC_DO_EOI;
1939 
1940                 return;
1941         }
1942         linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);
1943 
1944         /* mask this and all lower levels that are routed to the same pin */
1945         vmeUniverseWriteReg(
1946                         linten & ~( ((msk<<1)-UNIV_LINT_STAT_VIRQ1) & wire_mask[pin]),
1947                         UNIV_REGOFF_LINT_EN
1948                         );
1949 
1950         /* end this interrupt
1951          * cycle on the PCI bus, so higher level interrupts can be
1952          * caught from now on...
1953          */
1954         if ( 0 == pin )
1955             BSP_PIC_DO_EOI;
1956 #endif
1957 
1958         /* get vector and dispatch handler */
1959         status = vmeUniverseReadReg(UNIV_REGOFF_VIRQ1_STATID - 4 + (lvl<<2));
1960         /* determine the highest priority IRQ source */
1961 
1962         if (status & UNIV_VIRQ_ERR) {
1963                 /* TODO: log error message - RTEMS has no logger :-( */
1964 #ifdef BSP_PIC_DO_EOI
1965             linten &= ~msk;
1966 #else
1967             vmeUniverseIntDisable(lvl);
1968 #endif
1969             printk("vmeUniverse ISR: error read from STATID register; (level: %i) STATID: 0x%08lx -- DISABLING\n", lvl, status);
1970         } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) {
1971 #ifdef BSP_PIC_DO_EOI
1972             linten &= ~msk;
1973 #else
1974             vmeUniverseIntDisable(lvl);
1975 #endif
1976                 /* TODO: log error message - RTEMS has no logger :-( */
1977             printk("vmeUniverse ISR: no handler installed for this vector; (level: %i) STATID: 0x%08lx -- DISABLING\n", lvl, status);
1978         } else {
1979                 /* dispatch handler, it must clear the IRQ at the device */
1980                 ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK);
1981 
1982                 /* insert a VME read operation to flush fifo, making sure all user write-ops complete */
1983 #ifdef __PPC__
1984                 /* courtesy to disobedient users who don't use I/O ops */
1985                 asm volatile("eieio");
1986 #endif
1987                 READ_LE0(vmeUniverseRegBase);
1988 #ifdef __PPC__
1989                 /* make sure this is ordered before re-enabling */
1990                 asm volatile("eieio");
1991 #endif
1992         }
1993 
1994         /* clear this interrupt level; allow the universe to handler further interrupts */
1995         vmeUniverseWriteReg(msk, UNIV_REGOFF_LINT_STAT);
1996 
1997 /*
1998  *  this seems not to be necessary; we just leave the
1999  *  bit set to save a couple of instructions...
2000         vmeUniverseWriteReg(
2001                     UNIV_VINT_STAT_LINT(vmeIrqUnivOut),
2002                     UNIV_REGOFF_VINT_STAT);
2003 */
2004 
2005 #ifdef BSP_PIC_DO_EOI
2006 
2007         /* re-enable the previous level */
2008         vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN);
2009 #endif
2010 }
2011 
2012 
2013 /* STUPID API */
2014 static void
2015 my_no_op(const rtems_irq_connect_data * arg)
2016 {}
2017 
2018 static int
2019 my_isOn(const rtems_irq_connect_data *arg)
2020 {
2021         return (int)vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);
2022 }
2023 
2024 typedef struct {
2025     int uni_pin, pic_pin;
2026 } IntRoute;
2027 
2028 static void
2029 connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int pic_pin)
2030 {
2031 rtems_irq_connect_data  aarrggh;
2032     aarrggh.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
2033     aarrggh.off    = my_no_op;
2034     aarrggh.isOn   = my_isOn;
2035     aarrggh.hdl    = isr;
2036     aarrggh.handle = (rtems_irq_hdl_param)pic_pin;
2037     aarrggh.name   = pic_line;
2038 
2039     if ( shared ) {
2040 #if BSP_SHARED_HANDLER_SUPPORT > 0
2041         if (!BSP_install_rtems_shared_irq_handler(&aarrggh))
2042             rtems_panic("unable to install vmeUniverse shared irq handler");
2043 #else
2044         uprintf(stderr,"vmeUniverse: WARNING: your BSP doesn't support sharing interrupts\n");
2045         if (!BSP_install_rtems_irq_handler(&aarrggh))
2046             rtems_panic("unable to install vmeUniverse irq handler");
2047 #endif
2048     } else {
2049         if (!BSP_install_rtems_irq_handler(&aarrggh))
2050             rtems_panic("unable to install vmeUniverse irq handler");
2051     }
2052 }
2053 
2054 #ifndef BSP_EARLY_PROBE_VME
2055 #define BSP_EARLY_PROBE_VME(addr)   \
2056     (                                                                                                           \
2057         ((PCI_DEVICE_UNIVERSEII << 16) | PCI_VENDOR_TUNDRA ) == READ_LE( ((volatile LERegister*)(addr)), 0 )    \
2058     )
2059 #endif
2060 
2061 /* Check if there is a vme address/as is mapped in any of the outbound windows
2062  * and look for the PCI vendordevice ID there.
2063  * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
2064  *          on success. Address translated into CPU address is returned in *pcpu_addr.
2065  */
2066 static int
2067 mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
2068 {
2069 int j;
2070 char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
2071 
2072     /* try to find mapping */
2073     if ( 0 > (j = xlateFindPort(
2074                 vmeUniverse0BaseAddr,
2075                 1, 0,
2076                 as | VME_MODE_AS_MATCH,
2077                 vme_addr,
2078                 pcpu_addr ) ) ) {
2079             uprintf(stderr,"vmeUniverse - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
2080             uprintf(stderr,"              in outbound windows.\n");
2081     } else {
2082             /* found a slot number; probe it */
2083             *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
2084             if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
2085                 uprintf(stderr,"vmeUniverse - IRQ manager using VME %s to flush FIFO\n", regtype);
2086                 return j;
2087             } else {
2088                 uprintf(stderr,"vmeUniverse - Found slot info but detection of universe in VME %s space failed\n", regtype);
2089             }
2090     }
2091     return -1;
2092 }
2093 
2094 
2095 int
2096 vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...)
2097 {
2098 int     rval;
2099 va_list ap;
2100     va_start(ap, pic_pin0);
2101     rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap);
2102     va_end(ap);
2103     return rval;
2104 }
2105 
2106 int
2107 vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap)
2108 {
2109 int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES];
2110 unsigned long cpu_base, vme_reg_base;
2111 
2112     if (vmeUniverseIrqMgrInstalled)                return -4;
2113 
2114     /* check parameters */
2115 
2116     if ( uni_pin0 < 0 || uni_pin0 > 7 )            return -1;
2117 
2118     uni_pin[0] = uni_pin0;
2119     pic_pin[0] = pic_pin0 < 0 ? vmeUniverse0PciIrqLine : pic_pin0;
2120     i = 1;
2121     while ( (uni_pin[i] = va_arg(ap, int)) >= 0 ) {
2122 
2123         if ( i >= UNIV_NUM_WIRES ) {
2124                                                    return -5;
2125         }
2126 
2127         pic_pin[i] = va_arg(ap,int);
2128 
2129         if ( uni_pin[i] > 7 ) {
2130                                                    return -2;
2131         }
2132         if ( pic_pin[i] < 0 ) {
2133                                                    return -3;
2134         }
2135         i++;
2136     }
2137 
2138     /* all routings must be different */
2139     for ( i=0; uni_pin[i] >= 0; i++ ) {
2140         for ( j=i+1; uni_pin[j] >= 0; j++ ) {
2141             if ( uni_pin[j] == uni_pin[i] )        return -6;
2142             if ( pic_pin[j] == pic_pin[i] )        return -7;
2143         }
2144     }
2145 
2146     if ( flags & VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND ) {
2147 
2148         /* Find registers on VME so the ISR can issue a read to flush the FIFO */
2149         uprintf(stderr,"vmeUniverse IRQ manager: looking for registers on VME...\n");
2150 
2151         /* NOTE: The universe [unlike the Tsi148] doesn't know about geographical
2152          *       addressing but the MotLoad firmware [mvme5500] is kind enough to
2153          *       program VCSR_BS based on the board's geographical address for us :-)
2154          */
2155         if ( ( i = ((READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VCSR_BS ) >> 27) & 0x1f ) ) > 0 ) {
2156             uprintf(stderr,"Trying to find CSR on VME...\n");
2157             vme_reg_base = i*0x80000 + UNIV_CSR_OFFSET;
2158             i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
2159             if ( i >= 0 )
2160                 vmeUniverseRegCSR = 1;
2161         } else {
2162             i = -1;
2163         }
2164 
2165         if ( -1 == i ) {
2166 
2167             uprintf(stderr,"Trying to find CRG on VME...\n");
2168 
2169             /* Next we see if the CRG block is mapped to VME */
2170 
2171             if ( UNIV_VRAI_CTL_EN & (j = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_CTL )) ) {
2172                 switch ( j & UNIV_VRAI_CTL_VAS_MSK ) {
2173                     case UNIV_VRAI_CTL_VAS_A16 : i = VME_AM_SUP_SHORT_IO; break;
2174                     case UNIV_VRAI_CTL_VAS_A24 : i = VME_AM_STD_SUP_DATA; break;
2175                     case UNIV_VRAI_CTL_VAS_A32 : i = VME_AM_EXT_SUP_DATA; break;
2176                     default:
2177                                                  break;
2178                 }
2179                 vme_reg_base = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_BS ) & ~(UNIV_CRG_SIZE - 1);
2180             }
2181 
2182             if ( -1 == i ) {
2183             } else {
2184                 i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
2185             }
2186         }
2187 
2188         if ( i < 0 ) {
2189             if ( mapOverAll( vmeUniverse0BaseAddr, 1, hasPWENWindow, 0 ) ) {
2190                 uprintf(stderr,"vmeUniverse IRQ manager - BSP configuration error: registers not found on VME\n");
2191                 uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeUniverseMapCRG()])\n");
2192                 uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
2193                 uprintf(stderr,"back from user ISR to flush universe FIFO as a work-around or\n");
2194                 uprintf(stderr,"make sure ISR accesses device using a window with posted-writes disabled\n");
2195             } else {
2196                 uprintf(stderr,"vmeUniverse IRQ manager - registers not found on VME; falling back to PCI\n");
2197             }
2198             vmeUniverseRegBase = vmeUniverse0BaseAddr;
2199             vmeUniverseRegPort = -1;
2200         } else {
2201             vmeUniverseRegBase = (volatile LERegister*)cpu_base;
2202             vmeUniverseRegPort = i;
2203         }
2204     } else {
2205         vmeUniverseRegBase = vmeUniverse0BaseAddr;
2206         vmeUniverseRegPort = -1;
2207     }
2208 
2209     /* give them a chance to override buggy PCI info */
2210     if ( pic_pin[0] >= 0 && vmeUniverse0PciIrqLine != pic_pin[0] ) {
2211         uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
2212                 pic_pin[0]);
2213         vmeUniverse0PciIrqLine=pic_pin[0];
2214     }
2215 
2216     for ( i = 0; uni_pin[i] >= 0; i++ ) {
2217         /* offset wire # by one so we can initialize to 0 == invalid */
2218         universe_wire[i] = uni_pin[i] + 1;
2219         connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i);
2220     }
2221 
2222     specialPin = uni_pin[1] >= 0 ? 1 : 0;
2223 
2224     /* setup routing */
2225 
2226     /* IntRoute checks for mgr being installed */
2227     vmeUniverseIrqMgrInstalled=1;
2228 
2229     /* route 7 VME irqs to first / 'normal' pin */
2230     for ( i=1; i<8; i++ )
2231         vmeUniverseIntRoute( i, 0 );
2232     for ( i=UNIV_VOWN_INT_VEC; i<=UNIV_LM3_INT_VEC; i++ ) {
2233         if ( vmeUniverseIntRoute( i, specialPin ) )
2234             printk("Routing lvl %i -> wire # %i failed\n", i, specialPin);
2235     }
2236 
2237     return 0;
2238 }
2239 
2240 int
2241 vmeUniverseInstallIrqMgr(int vmeIrqUnivOut,
2242                          int vmeIrqPicLine,
2243                          int specialIrqUnivOut,
2244                          int specialIrqPicLine)
2245 {
2246     return vmeUniverseInstallIrqMgrAlt(
2247                 0,  /* bwds compat. */
2248                 vmeIrqUnivOut, vmeIrqPicLine,
2249                 specialIrqUnivOut, specialIrqPicLine,
2250                 -1);
2251 }
2252 
2253 int
2254 vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
2255 {
2256 UniverseIRQEntry          ip;
2257 volatile UniverseIRQEntry *pe;
2258 rtems_interrupt_lock_context lock_context;
2259 
2260         if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
2261                 return -1;
2262 
2263         pe = universeHdlTbl + vector;
2264 
2265         if (*pe || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec))))
2266                 return -1;
2267 
2268         ip->isr=hdl;
2269         ip->usrData=arg;
2270 
2271         rtems_interrupt_lock_acquire( &vmeUniverse_lock, &lock_context );
2272         if ( *pe ) {
2273             /* oops; someone intervened */
2274             rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
2275             free(ip);
2276             return -1;
2277         }
2278         *pe = ip;
2279         rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
2280         return 0;
2281 }
2282 
2283 int
2284 vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
2285 {
2286 UniverseIRQEntry          ip;
2287 volatile UniverseIRQEntry *pe;
2288 rtems_interrupt_lock_context lock_context;
2289 
2290         if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
2291                 return -1;
2292 
2293         pe = universeHdlTbl + vector;
2294 
2295         rtems_interrupt_lock_acquire( &vmeUniverse_lock, &lock_context );
2296         ip = *pe;
2297         if (!ip || ip->isr!=hdl || ip->usrData!=arg) {
2298             rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
2299             return -1;
2300         }
2301         *pe = 0;
2302         rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
2303         free(ip);
2304         return 0;
2305 }
2306 
2307 static int
2308 intDoEnDis(unsigned int level, int dis)
2309 {
2310 unsigned long       v;
2311 int             shift;
2312 rtems_interrupt_lock_context lock_context;
2313 
2314     if (  ! vmeUniverseIrqMgrInstalled || (shift = lvl2bit(level)) < 0 )
2315         return -1;
2316 
2317     v = 1<<shift;
2318 
2319     if ( !dis )
2320         return vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & v ? 1 : 0;
2321 
2322     rtems_interrupt_lock_acquire( &vmeUniverse_lock, &lock_context );
2323     if ( dis<0 )
2324         vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & ~v, UNIV_REGOFF_LINT_EN );
2325     else {
2326         vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) |  v, UNIV_REGOFF_LINT_EN  );
2327     }
2328     rtems_interrupt_lock_release( &vmeUniverse_lock, &lock_context );
2329     return 0;
2330 }
2331 
2332 int
2333 vmeUniverseIntEnable(unsigned int level)
2334 {
2335     return intDoEnDis(level, 1);
2336 }
2337 
2338 int
2339 vmeUniverseIntDisable(unsigned int level)
2340 {
2341     return intDoEnDis(level, -1);
2342 }
2343 
2344 int
2345 vmeUniverseIntIsEnabled(unsigned int level)
2346 {
2347     return intDoEnDis(level, 0);
2348 }
2349 
2350 /* Loopback test of VME/universe interrupts */
2351 
2352 typedef struct {
2353     rtems_id    q;
2354     int         l;
2355 } LoopbackTstArgs;
2356 
2357 static void
2358 loopbackTstIsr(void *arg, unsigned long vector)
2359 {
2360 LoopbackTstArgs *pa = arg;
2361     if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
2362         /* Overrun ? */
2363         printk("vmeUniverseIntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
2364         vmeUniverseIntDisable(pa->l);
2365     }
2366 }
2367 
2368 int
2369 vmeUniverseIntLoopbackTst(int level, unsigned vector)
2370 {
2371 DFLT_BASE;
2372 rtems_status_code   sc;
2373 rtems_id            q = 0;
2374 int                 installed = 0;
2375 int                 i, err = 0;
2376 int                 doDisable = 0;
2377 size_t              size;
2378 unsigned long       msg;
2379 char *              irqfmt  = "VME IRQ @vector %3i %s";
2380 char *              iackfmt = "VME IACK            %s";
2381 LoopbackTstArgs     a;
2382 
2383     CHECK_DFLT_BASE(base);
2384 
2385     /* arg check */
2386     if ( level < 1 || level > 7 || vector > 255 ) {
2387         fprintf(stderr,"Invalid level or vector argument\n");
2388         return -1;
2389     }
2390 
2391     if ( (vector & 1) ) {
2392         fprintf(stderr,"Software interrupts can only use even-numbered vectors, sorry.\n");
2393         return -1;
2394     }
2395 
2396     if ( UNIV_REV(base) < 2 && vector != 0 ) {
2397         fprintf(stderr,
2398             "vmeUniverseIntLoopbackTst(): Universe 1 has a bug. IACK in response to\n");
2399         fprintf(stderr,
2400             "self-generated VME interrupt yields always a zero vector. As a workaround,\n");
2401         fprintf(stderr,
2402             "use vector 0, please.\n");
2403         return -1;
2404     }
2405 
2406     /* Create message queue */
2407     if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
2408                                         rtems_build_name('t' ,'U','I','I'),
2409                                         4,
2410                                         sizeof(unsigned long),
2411                                         0,  /* default attributes: fifo, local */
2412                                         &q)) ) {
2413         rtems_error(sc, "vmeUniverseIntLoopbackTst: Unable to create message queue");
2414         goto bail;
2415     }
2416 
2417     a.q = q;
2418     a.l = level;
2419 
2420     /* Install handlers */
2421     if ( vmeUniverseInstallISR(vector, loopbackTstIsr, (void*)&a) ) {
2422         fprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
2423         goto bail;
2424     }
2425     installed++;
2426     if ( vmeUniverseInstallISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
2427         fprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",UNIV_VME_SW_IACK_INT_VEC);
2428         goto bail;
2429     }
2430     installed++;
2431 
2432     if ( !vmeUniverseIntIsEnabled(level) && 0==vmeUniverseIntEnable(level) )
2433         doDisable = 1;
2434 
2435     /* make sure there are no pending interrupts */
2436     vmeUniverseWriteReg( UNIV_LINT_STAT_SW_IACK,  UNIV_REGOFF_LINT_STAT );
2437 
2438     if ( vmeUniverseIntEnable( UNIV_VME_SW_IACK_INT_VEC ) ) {
2439         fprintf(stderr,"Unable to enable IACK interrupt\n");
2440         goto bail;
2441     }
2442 
2443     printf("vmeUniverse VME interrupt loopback test; STARTING...\n");
2444     printf(" --> asserting VME IRQ level %i\n", level);
2445     vmeUniverseIntRaise(level, vector);
2446 
2447     for ( i = 0; i< 3; i++ ) {
2448         sc = rtems_message_queue_receive(
2449                     q,
2450                     &msg,
2451                     &size,
2452                     RTEMS_WAIT,
2453                     20);
2454         if ( sc ) {
2455             if ( RTEMS_TIMEOUT == sc && i>1 ) {
2456                 /* OK; we dont' expect more to happen */
2457                 sc = 0;
2458             } else {
2459                 rtems_error(sc,"Error waiting for interrupts");
2460             }
2461             break;
2462         }
2463         if ( msg == vector ) {
2464             if ( !irqfmt ) {
2465                 printf("Excess VME IRQ received ?? -- BAD\n");
2466                 err = 1;
2467             } else {
2468                 printf(irqfmt, vector, "received -- PASSED\n");
2469                 irqfmt = 0;
2470             }
2471         } else if ( msg == UNIV_VME_SW_IACK_INT_VEC ) {
2472             if ( !iackfmt ) {
2473                 printf("Excess VME IACK received ?? -- BAD\n");
2474                 err = 1;
2475             } else {
2476                 printf(iackfmt, "received -- PASSED\n");
2477                 iackfmt = 0;
2478             }
2479         } else {
2480             printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
2481             err = 1;
2482         }
2483     }
2484 
2485 
2486     /* Missing anything ? */
2487     if ( irqfmt ) {
2488         printf(irqfmt,vector, "MISSED -- BAD\n");
2489         err = 1;
2490     }
2491     if ( iackfmt ) {
2492         printf(iackfmt, "MISSED -- BAD\n");
2493         err = 1;
2494     }
2495 
2496     printf("FINISHED.\n");
2497 
2498 bail:
2499     if ( doDisable )
2500         vmeUniverseIntDisable(level);
2501     vmeUniverseIntDisable( UNIV_VME_SW_IACK_INT_VEC );
2502     if ( installed > 0 )
2503         vmeUniverseRemoveISR(vector, loopbackTstIsr, (void*)&a);
2504     if ( installed > 1 )
2505         vmeUniverseRemoveISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
2506     if ( q )
2507         rtems_message_queue_delete(q);
2508 
2509     return sc ? sc : err;
2510 }
2511 
2512 #endif