source: rtems/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c @ afd4c7b

4.104.114.84.9
Last change on this file since afd4c7b was afd4c7b, checked in by Till Straumann <strauman@…>, on Dec 13, 2006 at 8:04:05 PM
  • 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).
  • Property mode set to 100644
File size: 49.4 KB
Line 
1/* $Id$ */
2
3/* Routines to configure the VME interface
4 * Author: Till Straumann <strauman@slac.stanford.edu>
5 *         Nov 2000, Oct 2001, Jan 2002
6 */
7
8#include <stdio.h>
9
10#if defined(__rtems__)
11#define __INSIDE_RTEMS_BSP__
12#endif
13
14#include "vmeUniverse.h"
15
16#define UNIV_NUM_MPORTS         8 /* number of master ports */
17#define UNIV_NUM_SPORTS         8 /* number of slave ports */
18
19#define PCI_VENDOR_TUNDRA       0x10e3
20#define PCI_DEVICE_UNIVERSEII   0
21#define PCI_UNIVERSE_BASE0      0x10
22#define PCI_UNIVERSE_BASE1      0x14
23
24#define UNIV_REGOFF_PCITGT0_CTRL 0x100
25#define UNIV_REGOFF_PCITGT4_CTRL 0x1a0
26#define UNIV_REGOFF_VMESLV0_CTRL 0xf00
27#define UNIV_REGOFF_VMESLV4_CTRL 0xf90
28
29#define UNIV_CTL_VAS16          (0x00000000)
30#define UNIV_CTL_VAS24          (0x00010000)
31#define UNIV_CTL_VAS32          (0x00020000)
32#define UNIV_MCTL_VASCSR        (0x00050000)
33#define UNIV_CTL_VAS            (0x00070000)
34
35#define UNIV_MCTL_EN            (0x80000000)
36#define UNIV_MCTL_PWEN          (0x40000000)
37#define UNIV_MCTL_PGM           (0x00004000)
38#define UNIV_MCTL_VCT           (0x00000100)
39#define UNIV_MCTL_SUPER         (0x00001000)
40#define UNIV_MCTL_VDW16         (0x00400000)
41#define UNIV_MCTL_VDW32         (0x00800000)
42#define UNIV_MCTL_VDW64         (0x00c00000)
43
44#define UNIV_MCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_MCTL_PGM | UNIV_MCTL_SUPER)
45
46#define UNIV_SCTL_EN            (0x80000000)
47#define UNIV_SCTL_PWEN          (0x40000000)
48#define UNIV_SCTL_PREN          (0x20000000)
49#define UNIV_SCTL_PGM           (0x00800000)
50#define UNIV_SCTL_DAT           (0x00400000)
51#define UNIV_SCTL_SUPER         (0x00200000)
52#define UNIV_SCTL_USER          (0x00100000)
53
54#define UNIV_SCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
55
56#ifdef __rtems__
57
58#include <stdlib.h>
59#include <rtems/bspIo.h>        /* printk */
60#include <rtems/error.h>
61#include <bsp/pci.h>
62#include <bsp.h>
63
64/* allow the BSP to override the default routines */
65#ifndef BSP_PCI_FIND_DEVICE
66#define BSP_PCI_FIND_DEVICE                     pci_find_device
67#endif
68#ifndef BSP_PCI_CONFIG_IN_LONG
69#define BSP_PCI_CONFIG_IN_LONG          pci_read_config_dword
70#endif
71#ifndef BSP_PCI_CONFIG_IN_BYTE
72#define BSP_PCI_CONFIG_IN_BYTE          pci_read_config_byte
73#endif
74#ifndef BSP_PCI_CONFIG_IN_SHORT
75#define BSP_PCI_CONFIG_IN_SHORT         pci_read_config_word
76#endif
77#ifndef BSP_PCI_CONFIG_OUT_SHORT
78#define BSP_PCI_CONFIG_OUT_SHORT        pci_write_config_word
79#endif
80
81/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
82 * Should be defined by the BSP.
83 */
84typedef unsigned int pci_ulong;
85
86#ifndef BSP_PCI2LOCAL_ADDR
87#ifndef PCI_MEM_BASE
88#define PCI_MEM_BASE 0
89#endif
90#define BSP_PCI2LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
91#endif
92
93
94#elif defined(__vxworks)
95typedef unsigned long pci_ulong;
96#define BSP_PCI2LOCAL_ADDR(memaddr) (memaddr)
97#define BSP_PCI_FIND_DEVICE             pciFindDevice
98#define BSP_PCI_CONFIG_IN_LONG  pciConfigInLong
99#define BSP_PCI_CONFIG_IN_BYTE  pciConfigInByte
100#else
101#error "vmeUniverse not ported to this architecture yet"
102#endif
103
104#ifndef PCI_INTERRUPT_LINE
105#define PCI_INTERRUPT_LINE              0x3c
106#endif
107
108volatile LERegister *vmeUniverse0BaseAddr=0;
109int vmeUniverse0PciIrqLine=-1;
110
111#ifdef __rtems__
112int vmeUniverseRegPort = -1;
113int vmeUniverseRegCSR  = 0;
114#endif
115
116#define DFLT_BASE       volatile LERegister *base = vmeUniverse0BaseAddr
117
118#define CHECK_DFLT_BASE(base) \
119        do { \
120                /* get the universe base address */ \
121                if (!base) { \
122                        if (vmeUniverseInit()) { \
123                                uprintf(stderr,"unable to find the universe in pci config space\n"); \
124                                return -1; \
125                        } else { \
126                                base = vmeUniverse0BaseAddr; \
127                        } \
128                } \
129        } while (0)
130
131#if 0
132/* public access functions */
133volatile LERegister *
134vmeUniverseBaseAddr(void)
135{
136        if (!vmeUniverse0BaseAddr) vmeUniverseInit();
137        return vmeUniverse0BaseAddr;
138}
139
140int
141vmeUniversePciIrqLine(void)
142{
143        if (vmeUniverse0PciIrqLine<0) vmeUniverseInit();
144        return vmeUniverse0PciIrqLine;
145}
146#endif
147
148static inline void
149WRITE_LE(
150        unsigned long val,
151        volatile LERegister    *adrs,
152        unsigned long off)
153{
154#if (__LITTLE_ENDIAN__ == 1)
155        *(volatile unsigned long*)(((unsigned long)adrs)+off)=val;
156#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
157        /* offset is in bytes and MUST not end up in r0 */
158        __asm__ __volatile__("stwbrx %1, %0, %2" :: "b"(off),"r"(val),"r"(adrs));
159#elif defined(__rtems__)
160        st_le32((volatile unsigned long*)(((unsigned long)adrs)+off), val);
161#else
162#error "little endian register writing not implemented"
163#endif
164}
165
166#if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)
167#define SYNC __asm__ __volatile__("sync")
168#else
169#define SYNC
170#warning "SYNC instruction unknown for this architecture"
171#endif
172
173/* registers should be mapped to guarded, non-cached memory; hence
174 * subsequent stores are ordered. eieio is only needed to enforce
175 * ordering of loads with respect to stores.
176 */
177#define EIEIO_REG
178
179static inline unsigned long
180READ_LE0(volatile LERegister *adrs)
181{
182#if (__LITTLE_ENDIAN__ == 1)
183        return *(volatile unsigned long *)adrs;
184#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
185register unsigned long rval;
186__asm__ __volatile__("lwbrx %0, 0, %1":"=r"(rval):"r"(adrs));
187        return rval;
188#elif defined(__rtems__)
189        return ld_le32((volatile unsigned long*)adrs);
190#else
191#error "little endian register reading not implemented"
192#endif
193}
194
195static inline unsigned long
196READ_LE(volatile LERegister *adrs, unsigned long off)
197{
198#if (__LITTLE_ENDIAN__ == 1)
199        return  *((volatile LERegister *)(((unsigned long)adrs)+off));
200#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
201register unsigned long rval;
202        /* offset is in bytes and MUST not end up in r0 */
203__asm__ __volatile__("lwbrx %0, %2, %1"
204                                : "=r"(rval)
205                                : "r"(adrs), "b"(off));
206#if 0
207__asm__ __volatile__("eieio");
208#endif
209return rval;
210#else
211return READ_LE0((volatile LERegister *)(((unsigned long)adrs)+off));
212#endif
213}
214
215#define PORT_UNALIGNED(addr,port) \
216        ( (port)%4 ? ((addr) & 0xffff) : ((addr) & 4095) )
217
218
219#define UNIV_REV(base) (READ_LE(base,2*sizeof(LERegister)) & 0xff)
220       
221#if defined(__rtems__) && 0
222static int
223uprintk(char *fmt, va_list ap)
224{
225int             rval;
226extern int k_vsprintf(char *, char *, va_list);
227/* during bsp init, there is no malloc and no stdio,
228 * hence we assemble the message on the stack and revert
229 * to printk
230 */
231char    buf[200];
232        rval = k_vsprintf(buf,fmt,ap);
233        if (rval > sizeof(buf))
234                        BSP_panic("vmeUniverse/uprintk: buffer overrun");
235        printk(buf);
236        return rval;
237}
238#endif
239
240
241/* private printing wrapper */
242static void
243uprintf(FILE *f, char *fmt, ...)
244{
245va_list ap;
246        va_start(ap, fmt);
247#ifdef __rtems__
248        if (!f || !_impure_ptr->__sdidinit) {
249                /* Might be called at an early stage when
250                 * stdio is not yet initialized.
251                 * There is no vprintk, hence we must assemble
252                 * to a buffer.
253                 */
254                vprintk(fmt,ap);
255        } else 
256#endif
257        {
258                vfprintf(f,fmt,ap);
259        }
260        va_end(ap);
261}
262
263int
264vmeUniverseFindPciBase(
265        int instance,
266        volatile LERegister **pbase
267        )
268{
269int bus,dev,fun;
270unsigned short wrd;
271pci_ulong busaddr;
272unsigned char irqline;
273
274        if (BSP_PCI_FIND_DEVICE(
275                        PCI_VENDOR_TUNDRA,
276                        PCI_DEVICE_UNIVERSEII,
277                        instance,
278                        &bus,
279                        &dev,
280                        &fun))
281                return -1;
282        if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr))
283                return -1;
284        if ((unsigned long)(busaddr) & 1) {
285                /* it's IO space, try BASE1 */
286                if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr)
287                   || ((unsigned long)(busaddr) & 1))
288                        return -1;
289        }
290        *pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr);
291
292        if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
293                return -1;
294
295        /* Enable PCI master and memory access */
296        BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
297        BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
298
299        return irqline;
300}
301
302/* convert an address space selector to a corresponding
303 * universe control mode word
304 */
305
306static int
307am2mode(int ismaster, unsigned long address_space, unsigned long *pmode)
308{
309unsigned long mode=0;
310
311    /* NOTE: reading the CY961 (Echotek ECDR814) with VDW32
312     *       generated bus errors when reading 32-bit words
313     *       - very weird, because the registers are 16-bit
314     *         AFAIK.
315     *       - 32-bit accesses worked fine on vxWorks which
316     *         has the port set to 64-bit.
317     *       ????????
318     */
319
320        address_space &= ~VME_MODE_MATCH_MASK;
321
322        if (!ismaster) {
323                mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM;
324                mode |= UNIV_SCTL_USER;
325                if ( VME_AM_IS_MEMORY & address_space )
326                        mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN;
327                mode |= UNIV_SCTL_EN;
328        } else {
329                if ( VME_MODE_DBW16 & address_space )
330                        mode |= UNIV_MCTL_VDW16;
331                else
332                        mode |= UNIV_MCTL_VDW64;
333                mode |= UNIV_MCTL_VCT /* enable block transfers */;
334                if ( VME_AM_IS_MEMORY & address_space )
335                        mode |= UNIV_MCTL_PWEN;
336                mode |= UNIV_MCTL_EN;
337        }
338
339        address_space &= ~VME_AM_IS_MEMORY;
340
341        switch (address_space & VME_AM_MASK) {
342                case VME_AM_STD_SUP_PGM:
343                case VME_AM_STD_USR_PGM:
344                        if (ismaster)
345                                mode |= UNIV_MCTL_PGM ;
346                        else {
347                                mode &= ~UNIV_SCTL_DAT;
348                        }
349                        /* fall thru */
350                case VME_AM_STD_SUP_DATA:
351                case VME_AM_STD_USR_DATA:
352                        mode |= UNIV_CTL_VAS24;
353                        break;
354
355                case VME_AM_EXT_SUP_PGM:
356                case VME_AM_EXT_USR_PGM:
357                        if (ismaster)
358                                mode |= UNIV_MCTL_PGM ;
359                        else {
360                                mode &= ~UNIV_SCTL_DAT;
361                        }
362                        /* fall thru */
363                case VME_AM_EXT_SUP_DATA:
364                case VME_AM_EXT_USR_DATA:
365                        mode |= UNIV_CTL_VAS32;
366                        break;
367
368                case VME_AM_SUP_SHORT_IO:
369                case VME_AM_USR_SHORT_IO:
370                        mode |= UNIV_CTL_VAS16;
371                        break;
372
373                case VME_AM_CSR:
374                        if ( !ismaster )
375                                return -1;
376                        mode |= UNIV_MCTL_VASCSR;
377                        break;
378
379                case 0: /* disable the port alltogether */
380                        break;
381
382                default:
383                        return -1;
384        }
385        if ( VME_AM_IS_SUP(address_space) )
386                mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER);
387        *pmode = mode;
388        return 0;
389}
390
391static int
392disableUniversePort(int ismaster, int portno, volatile unsigned long *preg, void *param)
393{
394unsigned long cntrl;
395        cntrl=READ_LE0(preg);
396        cntrl &= ~(ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN);
397        WRITE_LE(cntrl,preg,0);
398        SYNC; /* make sure this command completed */
399        return 0;
400}
401
402static int
403cfgUniversePort(
404        volatile LERegister *base,
405        unsigned long   ismaster,
406        unsigned long   port,
407        unsigned long   address_space,
408        unsigned long   vme_address,
409        unsigned long   local_address,
410        unsigned long   length)
411{
412volatile LERegister *preg;
413unsigned long   p=port;
414unsigned long   mode=0;
415
416        CHECK_DFLT_BASE(base);
417
418        /* check parameters */
419        if (port >= (ismaster ? UNIV_NUM_MPORTS : UNIV_NUM_SPORTS)) {
420                uprintf(stderr,"invalid port\n");
421                return -1;
422        }
423        /* port start, bound addresses and offset must lie on 64k boundary
424         * (4k for port 0 and 4)
425         */
426        if ( PORT_UNALIGNED(local_address,port) ) {
427                uprintf(stderr,"local address misaligned\n");
428                return -1;
429        }
430        if ( PORT_UNALIGNED(vme_address,port) ) {
431                uprintf(stderr,"vme address misaligned\n");
432                return -1;
433        }
434        if ( PORT_UNALIGNED(length,port) ) {
435                uprintf(stderr,"length misaligned\n");
436                return -1;
437        }
438
439        /* check address space validity */
440        if (am2mode(ismaster,address_space,&mode)) {
441                uprintf(stderr,"invalid address space\n");
442                return -1;
443        }
444
445        /* get the universe base address */
446        if (!base && vmeUniverseInit()) {
447                return -1;
448        }
449
450        preg=base;
451
452        /* find out if we have a rev. II chip */
453        if ( UNIV_REV(base) < 2 ) {
454                if (port>3) {
455                        uprintf(stderr,"Universe rev. < 2 has only 4 ports\n");
456                        return -1;
457                }
458        }
459
460        /* finally, configure the port */
461
462        /* find the register set for our port */
463        if (port<4) {
464                preg += (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister);
465        } else {
466                preg += (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister);
467                p-=4;
468        }
469        preg += 5 * p;
470
471        /* temporarily disable the port */
472        disableUniversePort(ismaster,port,preg,0);
473
474        /* address_space == 0 means disable */
475        if (address_space != 0) {
476                unsigned long start,offst;
477                /* set the port starting address;
478                 * this is the local address for the master
479                 * and the VME address for the slave
480                 */
481                if (ismaster) {
482                        start=local_address;
483                        /* let it overflow / wrap around 0 */
484                        offst=vme_address-local_address;
485                } else {
486                        start=vme_address;
487                        /* let it overflow / wrap around 0 */
488                        offst=local_address-vme_address;
489                }
490#undef TSILL
491#ifdef TSILL
492                uprintf(stderr,"writing 0x%08x to 0x%08x + 4\n",start,preg);
493#else
494                WRITE_LE(start,preg,4);
495#endif
496                /* set bound address */
497                length+=start;
498#ifdef TSILL
499                uprintf(stderr,"writing 0x%08x to 0x%08x + 8\n",length,preg);
500#else
501                WRITE_LE(length,preg,8);
502#endif
503                /* set offset */
504#ifdef TSILL
505                uprintf(stderr,"writing 0x%08x to 0x%08x + 12\n",offst,preg);
506#else
507                WRITE_LE(offst,preg,12);
508#endif
509
510#ifdef TSILL
511                uprintf(stderr,"writing 0x%08x to 0x%08x + 0\n",mode,preg);
512#else
513                EIEIO_REG;      /* make sure mode is written last */
514                WRITE_LE(mode,preg,0);
515                SYNC;           /* enforce completion */
516#endif
517
518#ifdef TSILL
519                uprintf(stderr,
520                        "universe %s port %lu successfully configured\n",
521                                ismaster ? "master" : "slave",
522                                port);
523#endif
524
525#ifdef __vxworks
526                if (ismaster)
527                        uprintf(stderr,
528                        "WARNING: on the synergy, sysMasterPortsShow() may show incorrect settings (it uses cached values)\n");
529#endif
530        }
531        return 0;
532}
533
534static int
535showUniversePort(
536                int             ismaster,
537                int             portno,
538                volatile LERegister *preg,
539                void            *parm)
540{
541        FILE *f=parm ? (FILE *)parm : stdout;
542        unsigned long cntrl, start, bound, offst, mask;
543
544        cntrl = READ_LE0(preg++);
545#undef TSILL
546#ifdef TSILL
547        uprintf(stderr,"showUniversePort: *(0x%08x): 0x%08x\n",preg-1,cntrl);
548#endif
549#undef TSILL
550
551        /* skip this port if disabled */
552        if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))
553                return 0;
554
555        /* for the master `start' is the PCI address,
556         * for the slave  `start' is the VME address
557         */
558        mask = ~PORT_UNALIGNED(0xffffffff,portno);
559
560        start = READ_LE0(preg++)&mask;
561        bound = READ_LE0(preg++)&mask;
562        offst = READ_LE0(preg++)&mask;
563
564        offst+=start; /* calc start on the other bus */
565
566        if (ismaster) {
567                uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",
568                        portno,offst,bound-start,start);
569        } else {
570                uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",
571                        portno,start,bound-start,offst);
572        }
573
574        switch (cntrl & UNIV_CTL_VAS) {
575                case UNIV_CTL_VAS16:   uprintf(f,"A16, "); break;
576                case UNIV_CTL_VAS24:   uprintf(f,"A24, "); break;
577                case UNIV_CTL_VAS32:   uprintf(f,"A32, "); break;
578                case UNIV_MCTL_VASCSR: if ( ismaster ) { uprintf(f,"CSR, "); break; }
579                                       /* else fallthru */
580                default: uprintf(f,"A??, "); break;
581        }
582
583        if (ismaster) {
584                uprintf(f,"%s, %s",
585                        cntrl&UNIV_MCTL_PGM ?   "Pgm" : "Dat",
586                        cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr");
587                if ( cntrl & UNIV_MCTL_PWEN )
588                        uprintf(f,", PWEN");
589        } else {
590                uprintf(f,"%s %s %s %s", 
591                        cntrl&UNIV_SCTL_PGM ?   "Pgm," : "    ",
592                        cntrl&UNIV_SCTL_DAT ?   "Dat," : "    ",
593                        cntrl&UNIV_SCTL_SUPER ? "Sup," : "    ",
594                        cntrl&UNIV_SCTL_USER  ? "Usr" :  "");
595                if ( cntrl & UNIV_SCTL_PWEN )
596                        uprintf(f,", PWEN");
597                if ( cntrl & UNIV_SCTL_PREN )
598                        uprintf(f,", PREN");
599        }
600        uprintf(f,"\n");
601        return 0;
602}
603
604typedef struct XlatRec_ {
605        unsigned long   address;
606        unsigned long   aspace;
607        unsigned                reverse; /* find reverse mapping of this port */
608} XlatRec, *Xlat;
609
610/* try to translate an address through the bridge
611 *
612 * IN:  l->address, l->aspace
613 * OUT: l->address (translated address)
614 *
615 * RETURNS: -1: invalid space
616 *           0: invalid address (not found in range)
617 *      port+1: success
618 */
619
620static int
621xlatePort(int ismaster, int port, volatile LERegister *preg, void *parm)
622{
623Xlat    l=(Xlat)parm;
624unsigned long cntrl, start, bound, offst, mask, x;
625
626        cntrl = READ_LE0(preg++);
627
628        /* skip this port if disabled */
629        if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))
630                return 0;
631
632        /* check for correct address space */
633        if ( am2mode(ismaster,l->aspace,&offst) ) {
634                uprintf(stderr,"vmeUniverse WARNING: invalid adressing mode 0x%x\n",
635                               l->aspace);
636                return -1;
637        }
638
639
640        switch (VME_MODE_MATCH_MASK & l->aspace) {
641                case VME_MODE_EXACT_MATCH:
642                        mask = -1 & ~VME_MODE_MATCH_MASK;
643                        break;
644
645                case VME_MODE_AS_MATCH:
646                        mask = UNIV_CTL_VAS;
647                        break;
648
649                default:
650                        mask = (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK);
651                        break;
652        }
653
654        cntrl &= mask;
655        offst &= mask;
656
657        if ( cntrl != offst )
658                return 0; /* mode doesn't match requested AM */
659
660        /* OK, we found a matching mode, now we must check the address range */
661        mask = ~PORT_UNALIGNED(0xffffffff,port);
662
663        /* for the master `start' is the PCI address,
664         * for the slave  `start' is the VME address
665         */
666        start = READ_LE0(preg++) & mask;
667        bound = READ_LE0(preg++) & mask;
668        offst = READ_LE0(preg++) & mask;
669
670        /* translate address to the other bus */
671        if (l->reverse) {
672                /* reverse mapping, i.e. for master ports we map from
673                 * VME to PCI, for slave ports we map from VME to PCI
674                 */
675                if (l->address >= start && l->address < bound) {
676                                l->address+=offst;
677                                return 1 + port;
678                }
679        } else {
680                x = l->address - offst;
681
682                if (x >= start && x < bound) {
683                        /* valid address found */
684                        l->address = x;
685                        return 1 + port;
686                }
687        }
688        return 0;
689}
690
691/* check if there is any active window with write posting enabled */
692static int
693hasPWENWindow(
694                int             ismaster,
695                int             portno,
696                volatile LERegister *preg,
697                void            *parm)
698{
699unsigned long cntrl = READ_LE0(preg);
700unsigned long mask  = ismaster ? (UNIV_MCTL_EN|UNIV_MCTL_PWEN) : (UNIV_SCTL_EN|UNIV_SCTL_PWEN);
701        return (cntrl & mask) == mask ? -1 : 0;
702}
703
704static int
705mapOverAll(volatile LERegister *base, int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg)
706{
707volatile LERegister     *rptr;
708unsigned long   port;
709int     rval;
710
711        CHECK_DFLT_BASE(base);
712
713        rptr = (base + 
714                (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister));
715#undef TSILL
716#ifdef TSILL
717        uprintf(stderr,"mapoverall: base is 0x%08x, rptr 0x%08x\n",base,rptr);
718#endif
719#undef TSILL
720        for (port=0; port<4; port++) {
721                if ((rval=func(ismaster,port,rptr,arg))) return rval;
722                rptr+=5; /* register block spacing */
723        }
724
725        /* only rev. 2 has 8 ports */
726        if (UNIV_REV(base)<2) return -1;
727
728        rptr = (base + 
729                (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister));
730        for (port=4; port<UNIV_NUM_MPORTS; port++) {
731                if ((rval=func(ismaster,port,rptr,arg))) return rval;
732                rptr+=5; /* register block spacing */
733        }
734        return 0;
735}
736
737static void
738showUniversePorts(volatile LERegister *base, int ismaster, FILE *f)
739{
740        if (!f) f=stdout;
741        uprintf(f,"Universe %s Ports:\n",ismaster ? "Master" : "Slave");
742        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
743        mapOverAll(base,ismaster,showUniversePort,f);
744}
745
746static int
747xlateFindPort(
748        volatile LERegister *base,      /* Universe base address */
749        int master,             /* look in the master windows */
750        int reverse,            /* reverse mapping; for masters: map local to VME */
751        unsigned long as,       /* address space */
752        unsigned long aIn,      /* address to look up */
753        unsigned long *paOut/* where to put result */
754        )
755{
756int     rval;
757XlatRec l;
758        l.aspace  = as;
759        l.address = aIn;
760        l.reverse = reverse;
761        /* map result -1/0/1 to -2/-1/0 with 0 on success */
762        rval = mapOverAll(base,master,xlatePort,(void*)&l) - 1;
763        *paOut = l.address;
764        return rval;
765}
766
767int
768vmeUniverseXlateAddrXX(
769        volatile LERegister *base,      /* Universe base address */
770        int master,             /* look in the master windows */
771        int reverse,            /* reverse mapping; for masters: map local to VME */
772        unsigned long as,       /* address space */
773        unsigned long aIn,      /* address to look up */
774        unsigned long *paOut/* where to put result */
775        )
776{
777        return xlateFindPort(base, master, reverse, as, aIn, paOut) >= 0 ? 0 : -1;
778}
779
780int
781vmeUniverseXlateAddr(
782        int master,             /* look in the master windows */
783        int reverse,            /* reverse mapping; for masters: map local to VME */
784        unsigned long as,       /* address space */
785        unsigned long aIn,      /* address to look up */
786        unsigned long *paOut/* where to put result */
787        )
788{
789        DFLT_BASE;
790        return vmeUniverseXlateAddrXX(base, master, reverse, as, aIn, paOut);
791}
792
793
794void
795vmeUniverseReset(void)
796{
797        /* disable/reset special cycles (ADOH, RMW) */
798        vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_CTL);
799        vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_ADDR);
800        vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_EN);
801
802        /* set coupled window timeout to 0 (release VME after each transaction)
803         * CRT (coupled request timeout) is unused by Universe II
804         */
805        vmeUniverseWriteReg(UNIV_LMISC_CRT_128_US, UNIV_REGOFF_LMISC);
806
807        /* disable/reset DMA engine */
808        vmeUniverseWriteReg(0, UNIV_REGOFF_DCTL);
809        vmeUniverseWriteReg(0, UNIV_REGOFF_DTBC);
810        vmeUniverseWriteReg(0, UNIV_REGOFF_DLA);
811        vmeUniverseWriteReg(0, UNIV_REGOFF_DVA);
812        vmeUniverseWriteReg(0, UNIV_REGOFF_DCPP);
813
814        /* disable location monitor */
815        vmeUniverseWriteReg(0, UNIV_REGOFF_LM_CTL);
816
817        /* disable universe register access from VME bus */
818        vmeUniverseWriteReg(0, UNIV_REGOFF_VRAI_CTL);
819
820#if 0   /* leave CSR bus image alone; IRQ manager can use it */
821        /* disable VME bus image of VME CSR */
822        vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL);
823#endif
824
825
826        /* I had problems with a Joerger vtr10012_8 card who would
827         * only be accessible after tweaking the U2SPEC register
828         * (the t27 parameter helped).
829         * I use the same settings here that are used by the
830         * Synergy VGM-powerpc BSP for vxWorks.
831         */
832        if (2==UNIV_REV(vmeUniverse0BaseAddr))
833                vmeUniverseWriteReg(UNIV_U2SPEC_DTKFLTR |
834                                                UNIV_U2SPEC_MASt11   |
835                                                UNIV_U2SPEC_READt27_NODELAY |
836                                                UNIV_U2SPEC_POSt28_FAST |
837                                                UNIV_U2SPEC_PREt28_FAST,
838                                                UNIV_REGOFF_U2SPEC);
839
840        /* disable interrupts, reset routing */
841        vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_EN);
842        vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP0);
843        vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP1);
844
845        vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_EN);
846        vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP0);
847        vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP1);
848
849        vmeUniverseDisableAllSlaves();
850
851        vmeUniverseDisableAllMasters();
852       
853        vmeUniverseWriteReg(UNIV_VCSR_CLR_SYSFAIL, UNIV_REGOFF_VCSR_CLR);
854
855        /* clear interrupt status bits */
856        vmeUniverseWriteReg(UNIV_LINT_STAT_CLR, UNIV_REGOFF_LINT_STAT);
857        vmeUniverseWriteReg(UNIV_VINT_STAT_CLR, UNIV_REGOFF_VINT_STAT);
858
859        vmeUniverseWriteReg(UNIV_V_AMERR_V_STAT, UNIV_REGOFF_V_AMERR);
860
861        vmeUniverseWriteReg(
862                vmeUniverseReadReg(UNIV_REGOFF_PCI_CSR) |
863                UNIV_PCI_CSR_D_PE | UNIV_PCI_CSR_S_SERR | UNIV_PCI_CSR_R_MA |
864                UNIV_PCI_CSR_R_TA | UNIV_PCI_CSR_S_TA,
865                UNIV_REGOFF_PCI_CSR);
866
867        vmeUniverseWriteReg(UNIV_L_CMDERR_L_STAT, UNIV_REGOFF_L_CMDERR);
868
869        vmeUniverseWriteReg(
870                UNIV_DGCS_STOP | UNIV_DGCS_HALT | UNIV_DGCS_DONE |
871                UNIV_DGCS_LERR | UNIV_DGCS_VERR | UNIV_DGCS_P_ERR,
872                UNIV_REGOFF_DGCS);
873}
874
875int
876vmeUniverseInit(void)
877{
878int rval;
879        if ( (rval=vmeUniverseFindPciBase(0,&vmeUniverse0BaseAddr)) < 0 ) {
880                uprintf(stderr,"unable to find the universe in pci config space\n");
881        } else {
882                vmeUniverse0PciIrqLine = rval;
883                rval                   = 0;
884                uprintf(stderr,"Universe II PCI-VME bridge detected at 0x%08x, IRQ %d\n",
885                                (unsigned int)vmeUniverse0BaseAddr, vmeUniverse0PciIrqLine);
886        }
887        return rval;
888}
889
890void
891vmeUniverseMasterPortsShowXX(volatile LERegister *base, FILE *f)
892{
893        showUniversePorts(base,1,f);
894}
895
896void
897vmeUniverseMasterPortsShow(FILE *f)
898{
899        DFLT_BASE;
900        showUniversePorts(base,1,f);
901}
902
903void
904vmeUniverseSlavePortsShowXX(volatile LERegister *base, FILE *f)
905{
906        showUniversePorts(base,0,f);
907}
908
909void
910vmeUniverseSlavePortsShow(FILE *f)
911{
912        DFLT_BASE;
913        showUniversePorts(base,0,f);
914}
915
916int
917vmeUniverseMasterPortCfgXX(
918        volatile LERegister *base,
919        unsigned long   port,
920        unsigned long   address_space,
921        unsigned long   vme_address,
922        unsigned long   local_address,
923        unsigned long   length)
924{
925        return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
926}
927
928int
929vmeUniverseMasterPortCfg(
930        unsigned long   port,
931        unsigned long   address_space,
932        unsigned long   vme_address,
933        unsigned long   local_address,
934        unsigned long   length)
935{
936        DFLT_BASE;
937        return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
938}
939
940int
941vmeUniverseSlavePortCfgXX(
942        volatile LERegister *base,
943        unsigned long   port,
944        unsigned long   address_space,
945        unsigned long   vme_address,
946        unsigned long   local_address,
947        unsigned long   length)
948{
949        return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
950}
951
952int
953vmeUniverseSlavePortCfg(
954        unsigned long   port,
955        unsigned long   address_space,
956        unsigned long   vme_address,
957        unsigned long   local_address,
958        unsigned long   length)
959{
960        DFLT_BASE;
961        return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
962}
963
964
965void
966vmeUniverseDisableAllSlavesXX(volatile LERegister *base)
967{
968        mapOverAll(base,0,disableUniversePort,0);
969}
970
971void
972vmeUniverseDisableAllSlaves(void)
973{
974        DFLT_BASE;
975        mapOverAll(base,0,disableUniversePort,0);
976}
977
978void
979vmeUniverseDisableAllMastersXX(volatile LERegister *base)
980{
981        mapOverAll(base,1,disableUniversePort,0);
982}
983
984void
985vmeUniverseDisableAllMasters(void)
986{
987        DFLT_BASE;
988        mapOverAll(base,1,disableUniversePort,0);
989}
990
991int
992vmeUniverseStartDMAXX(
993        volatile LERegister *base,
994        unsigned long local_addr,
995        unsigned long vme_addr,
996        unsigned long count)
997{
998        if ((local_addr & 7) != (vme_addr & 7)) {
999                uprintf(stderr,"vmeUniverseStartDMA: misaligned addresses\n");
1000                return -1;
1001        }
1002
1003        {
1004        /* help the compiler allocate registers */
1005        register volatile LERegister *b=base;;
1006        register unsigned long dgcsoff=UNIV_REGOFF_DGCS,dgcs;
1007
1008        dgcs=READ_LE(b, dgcsoff);
1009
1010        /* clear status and make sure CHAIN is clear */
1011        dgcs &= ~UNIV_DGCS_CHAIN;
1012        WRITE_LE(dgcs,
1013                      b, dgcsoff);
1014        WRITE_LE(local_addr,
1015                      b, UNIV_REGOFF_DLA);
1016        WRITE_LE(vme_addr,
1017                      b, UNIV_REGOFF_DVA);
1018        WRITE_LE(count,
1019                      b, UNIV_REGOFF_DTBC);
1020        dgcs |= UNIV_DGCS_GO;
1021        EIEIO_REG; /* make sure GO is written after everything else */
1022        WRITE_LE(dgcs,
1023                      b, dgcsoff);
1024        }
1025        SYNC; /* enforce command completion */
1026        return 0;
1027}
1028
1029int
1030vmeUniverseStartDMA(
1031        unsigned long local_addr,
1032        unsigned long vme_addr,
1033        unsigned long count)
1034{
1035        DFLT_BASE; /* vmeUniverseStartDMAXX doesn't check for a valid base address for efficiency reasons */
1036        return vmeUniverseStartDMAXX(base, local_addr, vme_addr, count);
1037}
1038
1039unsigned long
1040vmeUniverseReadRegXX(volatile LERegister *base, unsigned long offset)
1041{
1042unsigned long rval;
1043        rval = READ_LE(base,offset);
1044        return rval;
1045}
1046
1047
1048unsigned long
1049vmeUniverseReadReg(unsigned long offset)
1050{
1051unsigned long rval;
1052        rval = READ_LE(vmeUniverse0BaseAddr,offset);
1053        return rval;
1054}
1055
1056void
1057vmeUniverseWriteRegXX(volatile LERegister *base, unsigned long value, unsigned long offset)
1058{
1059        WRITE_LE(value, base, offset);
1060}
1061
1062void
1063vmeUniverseWriteReg(unsigned long value, unsigned long offset)
1064{
1065        WRITE_LE(value, vmeUniverse0BaseAddr, offset);
1066}
1067
1068void
1069vmeUniverseResetBus(void)
1070{
1071        vmeUniverseWriteReg(
1072                vmeUniverseReadReg(UNIV_REGOFF_MISC_CTL) | UNIV_MISC_CTL_SW_SYSRST,
1073                UNIV_REGOFF_MISC_CTL);
1074}
1075
1076void
1077vmeUniverseCvtToLE(unsigned long *ptr, unsigned long num)
1078{
1079#if !defined(__LITTLE_ENDIAN__) || (__LITTLE_ENDIAN__ != 1)
1080register unsigned long *p=ptr+num;
1081        while (p > ptr) {
1082#if (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)
1083                __asm__ __volatile__(
1084                        "lwzu 0, -4(%0)\n"
1085                        "stwbrx 0, 0, %0\n"
1086                        : "=r"(p) : "0"(p) : "r0"
1087                        );
1088#elif defined(__rtems__)
1089                p--; st_le32(p, *p);
1090#else
1091#error  "vmeUniverse: endian conversion not implemented for this architecture"
1092#endif
1093        }
1094#endif
1095}
1096
1097int
1098vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector)
1099{
1100unsigned long v;
1101unsigned long b;
1102
1103        CHECK_DFLT_BASE(base);
1104
1105        if ( level < 1 || level > 7 || vector > 255 )
1106                return -1;      /* invalid argument */
1107
1108        if ( vector & 1 ) /* SW interrupts always ACK an even vector (pp 2-67) */
1109                return -1;
1110
1111
1112        /* Check if already asserted */
1113        if ( vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_STAT ) & UNIV_VINT_STAT_SWINT(level) ) {
1114                return -2;  /* already asserted */
1115        }
1116
1117        /* Write Vector */
1118        vmeUniverseWriteRegXX(base, UNIV_VINT_STATID(vector), UNIV_REGOFF_VINT_STATID );
1119
1120        if ( UNIV_REV(base) >= 2 ) {
1121                /* universe II has individual bits for individual levels */
1122                b = UNIV_VINT_STAT_SWINT(level);
1123        } else {
1124                /* version that is compatible with universe I */
1125                v  = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_MAP1);
1126                v &= ~UNIV_VINT_MAP1_SWINT(0x7);
1127                v |=  UNIV_VINT_MAP1_SWINT(level);
1128                vmeUniverseWriteRegXX(base, v, UNIV_REGOFF_VINT_MAP1);
1129                b  = UNIV_VINT_EN_SWINT;
1130        }
1131        v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_EN);
1132        /* make sure it is clear, then assert */
1133        vmeUniverseWriteRegXX(base, v & ~b, UNIV_REGOFF_VINT_EN );
1134        vmeUniverseWriteRegXX(base, v |  b, UNIV_REGOFF_VINT_EN );
1135
1136        return 0;
1137       
1138}
1139
1140int
1141vmeUniverseIntRaise(int level, unsigned vector)
1142{
1143        return vmeUniverseIntRaiseXX(vmeUniverse0BaseAddr, level, vector);
1144}
1145
1146
1147/* Map internal register block to VME */
1148#define UNIV_CRG_SIZE (1<<12)
1149
1150int
1151vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long as )
1152{
1153uint32_t mode;
1154
1155        CHECK_DFLT_BASE(base);
1156
1157#ifdef __rtems__
1158        if ( vmeUniverseRegPort > -1 && ! vmeUniverseRegCSR ) {
1159        uprintf(stderr,"vmeUniverse: CRG already mapped and in use by interrupt manager\n");
1160                return -1;
1161        }
1162#endif
1163
1164        /* enable all, SUP/USR/PGM/DATA accesses */
1165        mode = UNIV_VRAI_CTL_EN | UNIV_VRAI_CTL_PGM | UNIV_VRAI_CTL_DATA | UNIV_VRAI_CTL_SUPER | UNIV_VRAI_CTL_USER;
1166
1167        if ( VME_AM_IS_SHORT(as) ) {
1168                mode |= UNIV_VRAI_CTL_VAS_A16;
1169        } else 
1170        if ( VME_AM_IS_STD(as) ) {
1171                mode |= UNIV_VRAI_CTL_VAS_A24;
1172        } else 
1173        if ( VME_AM_IS_EXT(as) ) {
1174                mode |= UNIV_VRAI_CTL_VAS_A32;
1175        } else {
1176                return -2;
1177        }
1178
1179        /* map CRG to VME bus */
1180        WRITE_LE( (vme_base & ~(UNIV_CRG_SIZE-1)), base, UNIV_REGOFF_VRAI_BS );
1181        WRITE_LE( mode, base, UNIV_REGOFF_VRAI_CTL );
1182
1183        return 0;
1184}
1185
1186int
1187vmeUniverseMapCRG(unsigned long vme_base, unsigned long as )
1188{
1189        return vmeUniverseMapCRGXX( vmeUniverse0BaseAddr, vme_base, as );
1190}
1191
1192
1193/* RTEMS interrupt subsystem */
1194
1195#ifdef __rtems__
1196
1197#include <bsp/irq.h>
1198
1199typedef struct
1200UniverseIRQEntryRec_ {
1201                VmeUniverseISR  isr;
1202                void                    *usrData;
1203} UniverseIRQEntryRec, *UniverseIRQEntry;
1204
1205static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0};
1206
1207int          vmeUniverseIrqMgrInstalled = 0;
1208
1209volatile LERegister *vmeUniverseRegBase = 0;
1210
1211/* We support 4 wires between universe + PIC */
1212
1213#define UNIV_NUM_WIRES 4
1214
1215static volatile unsigned long   wire_mask[UNIV_NUM_WIRES]     = {0};
1216/* wires are offset by 1 so we can initialize the wire table to all zeros */
1217static int                                              universe_wire[UNIV_NUM_WIRES] = {0};
1218
1219static int
1220lvl2bit(unsigned int level)
1221{
1222int shift = -1;
1223        if ( level >= UNIV_DMA_INT_VEC && level <= UNIV_LM3_INT_VEC ) {
1224                shift = 8 + (level-UNIV_DMA_INT_VEC);
1225        } else if ( UNIV_VOWN_INT_VEC == level ) {
1226                shift = 0;
1227        } else if ( 1 <= level && level <=7 ) {
1228                shift = level;
1229        } else {
1230                /* invalid level */
1231        }
1232        return shift;
1233}
1234
1235int
1236vmeUniverseIntRoute(unsigned int level, unsigned int pin)
1237{
1238int                             i, shift;
1239unsigned long   mask, mapreg, flags, wire;
1240
1241        if ( pin >= UNIV_NUM_WIRES || ! universe_wire[pin] || !vmeUniverseIrqMgrInstalled )
1242                return -1;
1243
1244        if ( (shift = lvl2bit(level)) < 0 ) {
1245                return -1; /* invalid level */
1246        }
1247
1248        mask = 1<<shift;
1249
1250        /* calculate the mapping register and contents */
1251        if ( shift < 8 ) {
1252                mapreg = UNIV_REGOFF_LINT_MAP0;
1253        } else if ( shift < 16 ) {
1254                shift -= 8;
1255                mapreg = UNIV_REGOFF_LINT_MAP1;
1256        } else if ( shift < 24 ) {
1257                shift -= 16;
1258                mapreg = UNIV_REGOFF_LINT_MAP2;
1259        } else {
1260                return -1;
1261        }
1262
1263        shift <<=2;
1264
1265        /* wires are offset by 1 so we can initialize the wire table to all zeros */
1266        wire = (universe_wire[pin]-1) << shift;
1267
1268rtems_interrupt_disable(flags);
1269
1270        for ( i = 0; i<UNIV_NUM_WIRES; i++ ) {
1271                wire_mask[i] &= ~mask;
1272        }
1273        wire_mask[pin] |= mask;
1274
1275        mask = vmeUniverseReadReg(mapreg) & ~ (0xf<<shift);
1276        mask |= wire;
1277        vmeUniverseWriteReg( mask, mapreg );
1278
1279rtems_interrupt_enable(flags);
1280        return 0;
1281}
1282
1283VmeUniverseISR
1284vmeUniverseISRGet(unsigned long vector, void **parg)
1285{
1286unsigned long             flags;
1287VmeUniverseISR                    rval = 0;
1288volatile UniverseIRQEntry *pe  = universeHdlTbl + vector;
1289
1290        if ( vector>=UNIV_NUM_INT_VECS || ! *pe )
1291                return 0;
1292
1293        rtems_interrupt_disable(flags);
1294                if ( *pe ) {
1295                        if (parg)
1296                                *parg=(*pe)->usrData;
1297                        rval = (*pe)->isr;
1298                }
1299        rtems_interrupt_enable(flags);
1300        return rval;
1301}
1302
1303#define SPECIAL_IRQ_MSK  ( ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1) )
1304
1305static void
1306universeSpecialISR(unsigned long status)
1307{
1308register UniverseIRQEntry       ip;
1309register unsigned                       vec;
1310register unsigned long          s;
1311
1312        /* handle all LINT bits except for the 'normal' VME interrupts */
1313
1314        /* clear all detected special interrupts */
1315        vmeUniverseWriteReg( (status & SPECIAL_IRQ_MSK), UNIV_REGOFF_LINT_STAT );
1316
1317        /* do VOWN first */
1318        vec=UNIV_VOWN_INT_VEC;
1319        if ( (status & UNIV_LINT_STAT_VOWN) && (ip=universeHdlTbl[vec]))
1320                ip->isr(ip->usrData,vec);
1321
1322        /* now continue with DMA and scan through all bits;
1323         * we assume the vectors are in the right order!
1324         *
1325         * The initial right shift brings the DMA bit into position 0;
1326         * the loop is left early if there are no more bits set.
1327         */
1328        for ( s = status>>8; s; s >>= 1) {
1329                vec++;
1330                if ( (s&1) && (ip=universeHdlTbl[vec]) )
1331                        ip->isr(ip->usrData,vec);
1332        }
1333
1334/*
1335 *      clear our line in the VINT_STAT register
1336 *  seems to be not neccessary...
1337        vmeUniverseWriteReg(
1338                                        UNIV_VINT_STAT_LINT(specialIrqUnivOut),
1339                                        UNIV_REGOFF_VINT_STAT);
1340 */
1341}
1342
1343/*
1344 * interrupts from VME to PCI seem to be processed more or less
1345 * like this:
1346 *
1347 *
1348 *   VME IRQ ------
1349 *                  & ----- LINT_STAT ----
1350 *                  |                       &  ---------- PCI LINE
1351 *                  |                       |
1352 *                  |                       |
1353 *       LINT_EN ---------------------------
1354 *
1355 *  I.e.
1356 *   - if LINT_EN is disabled, a VME IRQ will not set LINT_STAT.
1357 *   - while LINT_STAT is set, it will pull the PCI line unless
1358 *     masked by LINT_EN.
1359 *   - VINT_STAT(lint_bit) seems to have no effect beyond giving
1360 *     status info.
1361 *
1362 *  Hence, it is possible to
1363 *    - arm (set LINT_EN, routing etc.)
1364 *    - receive an irq (sets. LINT_STAT)
1365 *    - the ISR then:
1366 *                * clears LINT_EN, results in masking LINT_STAT (which
1367 *                  is still set to prevent another VME irq at the same
1368 *                  level to be ACKEd by the universe.
1369 *                * do PCI_EOI to allow nesting of higher VME irqs.
1370 *                  (previous step also cleared LINT_EN of lower levels)
1371 *                * when the handler returns, clear LINT_STAT
1372 *                * re-enable setting LINT_EN.
1373 */
1374
1375static void
1376universeVMEISR(rtems_irq_hdl_param arg)
1377{
1378int                                     pin = (int)arg;
1379UniverseIRQEntry        ip;
1380unsigned long           msk,lintstat,status;
1381int                                     lvl;
1382#ifdef BSP_PIC_DO_EOI
1383unsigned long           linten;
1384#endif
1385
1386                /* determine the highest priority IRQ source */
1387                lintstat  = vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT);
1388
1389                /* only handle interrupts routed to this pin */
1390                lintstat &= wire_mask[pin];
1391
1392#ifdef __PPC__
1393                asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat & ~SPECIAL_IRQ_MSK));
1394                lvl = 31-lvl;
1395                msk = 1<<lvl;
1396#else
1397                for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7;
1398                         lvl>0;
1399                         lvl--, msk>>=1) {
1400                        if (lintstat & msk) break;
1401                }
1402#endif
1403
1404#ifndef BSP_PIC_DO_EOI /* Software priorities not supported */
1405
1406                if ( (status = (lintstat & SPECIAL_IRQ_MSK)) )
1407                        universeSpecialISR( status );
1408
1409                if ( lvl <= 0)
1410                        return;
1411
1412#else
1413                if ( lvl <= 0 ) {
1414                                /* try the special handler */
1415                                universeSpecialISR( lintstat & SPECIAL_IRQ_MSK );
1416
1417                                /*
1418                                 * let the pic end this cycle
1419                                 */
1420                                if ( 0 == pin )
1421                                        BSP_PIC_DO_EOI;
1422
1423                                return;
1424                }
1425                linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);
1426
1427                /* mask this and all lower levels that are routed to the same pin */
1428                vmeUniverseWriteReg(
1429                                                linten & ~( ((msk<<1)-UNIV_LINT_STAT_VIRQ1) & wire_mask[pin]),
1430                                                UNIV_REGOFF_LINT_EN
1431                                                );
1432
1433                /* end this interrupt
1434                 * cycle on the PCI bus, so higher level interrupts can be
1435                 * caught from now on...
1436                 */
1437                if ( 0 == pin )
1438                        BSP_PIC_DO_EOI;
1439#endif
1440
1441                /* get vector and dispatch handler */
1442                status = vmeUniverseReadReg(UNIV_REGOFF_VIRQ1_STATID - 4 + (lvl<<2));
1443                /* determine the highest priority IRQ source */
1444
1445                if (status & UNIV_VIRQ_ERR) {
1446                                /* TODO: log error message - RTEMS has no logger :-( */
1447#ifdef BSP_PIC_DO_EOI
1448                        linten &= ~msk;
1449#else
1450                        vmeUniverseIntDisable(lvl);
1451#endif
1452                        printk("vmeUniverse ISR: error read from STATID register; (level: %i) STATID: 0x%08x -- DISABLING\n", lvl, status);
1453                } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) {
1454#ifdef BSP_PIC_DO_EOI
1455                        linten &= ~msk;
1456#else
1457                        vmeUniverseIntDisable(lvl);
1458#endif
1459                                /* TODO: log error message - RTEMS has no logger :-( */
1460                        printk("vmeUniverse ISR: no handler installed for this vector; (level: %i) STATID: 0x%08x -- DISABLING\n", lvl, status);
1461                } else {
1462                                /* dispatch handler, it must clear the IRQ at the device */
1463                                ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK);
1464
1465                                /* insert a VME read operation to flush fifo, making sure all user write-ops complete */
1466#ifdef __PPC__
1467                                /* courtesy to disobedient users who don't use I/O ops */
1468                                asm volatile("eieio");
1469#endif
1470                                READ_LE0(vmeUniverseRegBase);
1471#ifdef __PPC__
1472                                /* make sure this is ordered before re-enabling */
1473                                asm volatile("eieio");
1474#endif
1475                }
1476
1477                /* clear this interrupt level; allow the universe to handler further interrupts */
1478                vmeUniverseWriteReg(msk, UNIV_REGOFF_LINT_STAT);
1479
1480/*
1481 *  this seems not to be necessary; we just leave the
1482 *  bit set to save a couple of instructions...
1483                vmeUniverseWriteReg(
1484                                        UNIV_VINT_STAT_LINT(vmeIrqUnivOut),
1485                                        UNIV_REGOFF_VINT_STAT);
1486*/
1487
1488#ifdef BSP_PIC_DO_EOI
1489
1490                /* re-enable the previous level */
1491                vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN);
1492#endif
1493}
1494
1495
1496/* STUPID API */
1497static void
1498my_no_op(const rtems_irq_connect_data * arg)
1499{}
1500
1501static int
1502my_isOn(const rtems_irq_connect_data *arg)
1503{
1504                return (int)vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);
1505}
1506
1507typedef struct {
1508        int uni_pin, pic_pin;
1509} IntRoute;
1510
1511static void
1512connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int pic_pin)
1513{
1514rtems_irq_connect_data  aarrggh;
1515        aarrggh.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
1516        aarrggh.off    = my_no_op;
1517        aarrggh.isOn   = my_isOn;
1518        aarrggh.hdl    = isr;
1519        aarrggh.handle = (rtems_irq_hdl_param)pic_pin;
1520        aarrggh.name   = pic_line;
1521
1522        if ( shared ) {
1523#if BSP_SHARED_HANDLER_SUPPORT > 0
1524                if (!BSP_install_rtems_shared_irq_handler(&aarrggh))
1525                        BSP_panic("unable to install vmeUniverse shared irq handler");
1526#else
1527                uprintf(stderr,"vmeUniverse: WARNING: your BSP doesn't support sharing interrupts\n");
1528                if (!BSP_install_rtems_irq_handler(&aarrggh))
1529                        BSP_panic("unable to install vmeUniverse irq handler");
1530#endif
1531        } else {
1532                if (!BSP_install_rtems_irq_handler(&aarrggh))
1533                        BSP_panic("unable to install vmeUniverse irq handler");
1534        }
1535}
1536
1537#ifndef BSP_EARLY_PROBE_VME
1538#define BSP_EARLY_PROBE_VME(addr)       \
1539        (                                                                                                                                                                                                                       \
1540                ((PCI_DEVICE_UNIVERSEII << 16) | PCI_VENDOR_TUNDRA ) == READ_LE( ((volatile LERegister*)(addr)), 0 )    \
1541        )
1542#endif
1543
1544/* Check if there is a vme address/as is mapped in any of the outbound windows
1545 * and look for the PCI vendordevice ID there.
1546 * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
1547 *          on success. Address translated into CPU address is returned in *pcpu_addr.
1548 */
1549static int
1550mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
1551{
1552int j;
1553char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
1554
1555        /* try to find mapping */
1556        if ( 0 > (j = xlateFindPort(
1557                                vmeUniverse0BaseAddr,
1558                                1, 0,
1559                                as | VME_MODE_AS_MATCH,
1560                                vme_addr,
1561                                pcpu_addr ) ) ) {
1562                        uprintf(stderr,"vmeUniverse - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
1563                        uprintf(stderr,"              in outbound windows.\n");
1564        } else {
1565                        /* found a slot number; probe it */
1566                        *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
1567                        if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
1568                                uprintf(stderr,"vmeUniverse - IRQ manager using VME %s to flush FIFO\n", regtype);
1569                                return j;
1570                        } else {
1571                                uprintf(stderr,"vmeUniverse - Found slot info but detection of universe in VME %s space failed\n", regtype);
1572                        }
1573        }
1574        return -1;
1575}
1576
1577
1578int
1579vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...)
1580{
1581int             rval;
1582va_list ap;
1583        va_start(ap, pic_pin0);
1584        rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap);
1585        va_end(ap);
1586        return rval;
1587}
1588
1589int
1590vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap)
1591{
1592int     i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES];
1593unsigned long cpu_base, vme_reg_base;
1594
1595        if (vmeUniverseIrqMgrInstalled)                return -4;
1596
1597        /* check parameters */
1598
1599        if ( uni_pin0 < 0 || uni_pin0 > 7 )            return -1;
1600
1601        uni_pin[0] = uni_pin0;
1602        pic_pin[0] = pic_pin0 < 0 ? vmeUniverse0PciIrqLine : pic_pin0;
1603        i = 1;
1604        while ( (uni_pin[i] = va_arg(ap, int)) >= 0 ) {
1605               
1606                if ( i >= UNIV_NUM_WIRES ) {
1607                                                               return -5;
1608                }
1609
1610                pic_pin[i] = va_arg(ap,int);
1611
1612                if ( uni_pin[i] > 7 ) {
1613                                                   return -2;
1614                }
1615                if ( pic_pin[i] < 0 ) {
1616                                                   return -3;
1617                }
1618                i++;
1619        }
1620
1621        /* all routings must be different */
1622        for ( i=0; uni_pin[i] >= 0; i++ ) {
1623                for ( j=i+1; uni_pin[j] >= 0; j++ ) {
1624                        if ( uni_pin[j] == uni_pin[i] )        return -6;
1625                        if ( pic_pin[j] == pic_pin[i] )        return -7;
1626                }
1627        }
1628
1629        if ( flags & VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND ) {
1630
1631                /* Find registers on VME so the ISR can issue a read to flush the FIFO */
1632                uprintf(stderr,"vmeUniverse IRQ manager: looking for registers on VME...\n");
1633
1634                /* NOTE: The universe [unlike the Tsi148] doesn't know about geographical
1635                 *       addressing but the MotLoad firmware [mvme5500] is kind enough to
1636                 *       program VCSR_BS based on the board's geographical address for us :-)
1637                 */
1638                if ( ( i = ((READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VCSR_BS ) >> 27) & 0x1f ) ) > 0 ) {
1639                        uprintf(stderr,"Trying to find CSR on VME...\n");
1640                        vme_reg_base = i*0x80000 + UNIV_CSR_OFFSET;
1641                        i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
1642                        if ( i >= 0 )
1643                                vmeUniverseRegCSR = 1;
1644                } else {
1645                        i = -1;
1646                }
1647
1648                if ( -1 == i ) {
1649
1650                        uprintf(stderr,"Trying to find CRG on VME...\n");
1651
1652                        /* Next we see if the CRG block is mapped to VME */
1653
1654                        if ( UNIV_VRAI_CTL_EN & (j = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_CTL )) ) {
1655                                switch ( j & UNIV_VRAI_CTL_VAS_MSK ) {
1656                                        case UNIV_VRAI_CTL_VAS_A16 : i = VME_AM_SUP_SHORT_IO; break;
1657                                        case UNIV_VRAI_CTL_VAS_A24 : i = VME_AM_STD_SUP_DATA; break;
1658                                        case UNIV_VRAI_CTL_VAS_A32 : i = VME_AM_EXT_SUP_DATA; break;
1659                                        default:
1660                                                                                                 break;
1661                                }
1662                                vme_reg_base = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_BS ) & ~(UNIV_CRG_SIZE - 1);
1663                        }
1664
1665                        if ( -1 == i ) {
1666                        } else {
1667                                i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
1668                        }
1669                }
1670
1671                if ( i < 0 ) {
1672                        if ( mapOverAll( vmeUniverse0BaseAddr, 1, hasPWENWindow, 0 ) ) {
1673                                uprintf(stderr,"vmeUniverse IRQ manager - BSP configuration error: registers not found on VME\n");
1674                                uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeUniverseMapCRG()])\n");
1675                                uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
1676                                uprintf(stderr,"back from user ISR to flush universe FIFO as a work-around or\n");
1677                                uprintf(stderr,"make sure ISR accesses device using a window with posted-writes disabled\n");
1678                        } else {
1679                                uprintf(stderr,"vmeUniverse IRQ manager - registers not found on VME; falling back to PCI\n");
1680                        }
1681                        vmeUniverseRegBase = vmeUniverse0BaseAddr;
1682                        vmeUniverseRegPort = -1;
1683                } else {
1684                        vmeUniverseRegBase = (volatile LERegister*)cpu_base;
1685                        vmeUniverseRegPort = i;
1686                }
1687        } else {
1688                vmeUniverseRegBase = vmeUniverse0BaseAddr;
1689                vmeUniverseRegPort = -1;
1690        }
1691
1692        /* give them a chance to override buggy PCI info */
1693        if ( pic_pin[0] >= 0 && vmeUniverse0PciIrqLine != pic_pin[0] ) {
1694                uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
1695                                pic_pin[0]);
1696                vmeUniverse0PciIrqLine=pic_pin[0];
1697        }
1698
1699        for ( i = 0; uni_pin[i] >= 0; i++ ) {
1700                /* offset wire # by one so we can initialize to 0 == invalid */
1701                universe_wire[i] = uni_pin[i] + 1;
1702                connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i);
1703        }
1704
1705        specialPin = uni_pin[1] >= 0 ? 1 : 0;
1706
1707        /* setup routing */
1708
1709        /* IntRoute checks for mgr being installed */
1710        vmeUniverseIrqMgrInstalled=1;
1711
1712        /* route 7 VME irqs to first / 'normal' pin */
1713        for ( i=1; i<8; i++ )
1714                vmeUniverseIntRoute( i, 0 );
1715        for ( i=UNIV_VOWN_INT_VEC; i<=UNIV_LM3_INT_VEC; i++ ) {
1716                if ( vmeUniverseIntRoute( i, specialPin ) )
1717                        printk("Routing lvl %i -> wire # %i failed\n", i, specialPin);
1718        }
1719
1720        return 0;
1721}
1722
1723int
1724vmeUniverseInstallIrqMgr(int vmeIrqUnivOut,
1725                                                 int vmeIrqPicLine,
1726                                                 int specialIrqUnivOut,
1727                                                 int specialIrqPicLine)
1728{
1729        return vmeUniverseInstallIrqMgrAlt(
1730                                0,      /* bwds compat. */
1731                                vmeIrqUnivOut, vmeIrqPicLine,
1732                                specialIrqUnivOut, specialIrqPicLine,
1733                                -1);
1734}
1735
1736int
1737vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
1738{
1739UniverseIRQEntry          ip;
1740unsigned long             flags;
1741volatile UniverseIRQEntry *pe;
1742
1743                if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
1744                                return -1;
1745
1746                pe = universeHdlTbl + vector;
1747
1748                if (*pe || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec))))
1749                                return -1;
1750
1751                ip->isr=hdl;
1752                ip->usrData=arg;
1753
1754        rtems_interrupt_disable(flags);
1755                if ( *pe ) {
1756                        /* oops; someone intervened */
1757                        rtems_interrupt_enable(flags);
1758                        free(ip);
1759                        return -1;
1760                }
1761                *pe = ip;
1762        rtems_interrupt_enable(flags);
1763                return 0;
1764}
1765
1766int
1767vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
1768{
1769UniverseIRQEntry          ip;
1770unsigned long             flags;
1771volatile UniverseIRQEntry *pe;
1772
1773                if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
1774                                return -1;
1775
1776                pe = universeHdlTbl + vector;
1777
1778        rtems_interrupt_disable(flags);
1779                ip = *pe;
1780                if (!ip || ip->isr!=hdl || ip->usrData!=arg) {
1781                        rtems_interrupt_enable(flags);
1782                        return -1;
1783                }
1784                *pe = 0;
1785        rtems_interrupt_enable(flags);
1786                free(ip);
1787                return 0;
1788}
1789
1790static int
1791intDoEnDis(unsigned int level, int dis)
1792{
1793unsigned long   flags, v;
1794int                             shift;
1795
1796        if (  ! vmeUniverseIrqMgrInstalled || (shift = lvl2bit(level)) < 0 )
1797                return -1;
1798
1799        v = 1<<shift;
1800
1801        if ( !dis )
1802                return vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & v ? 1 : 0;
1803
1804        rtems_interrupt_disable(flags);
1805        if ( dis<0 )
1806                vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & ~v, UNIV_REGOFF_LINT_EN ); 
1807        else {
1808                vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) |  v, UNIV_REGOFF_LINT_EN  ); 
1809        }
1810        rtems_interrupt_enable(flags);
1811                return 0;
1812}
1813
1814int
1815vmeUniverseIntEnable(unsigned int level)
1816{
1817        return intDoEnDis(level, 1);
1818}
1819
1820int
1821vmeUniverseIntDisable(unsigned int level)
1822{
1823        return intDoEnDis(level, -1);
1824}
1825
1826int
1827vmeUniverseIntIsEnabled(unsigned int level)
1828{
1829        return intDoEnDis(level, 0);
1830}
1831
1832/* Loopback test of VME/universe interrupts */
1833
1834typedef struct {
1835        rtems_id        q;
1836        int                     l;
1837} LoopbackTstArgs;
1838
1839static void
1840loopbackTstIsr(void *arg, unsigned long vector)
1841{
1842LoopbackTstArgs *pa = arg;
1843        if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
1844                /* Overrun ? */
1845                printk("vmeUniverseIntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
1846                vmeUniverseIntDisable(pa->l);
1847        }
1848}
1849
1850int
1851vmeUniverseIntLoopbackTst(int level, unsigned vector)
1852{
1853DFLT_BASE;
1854rtems_status_code       sc;
1855rtems_id                        q = 0;
1856int                                     installed = 0;
1857int                                     i, err = 0;
1858int                                     doDisable = 0;
1859uint32_t                size;
1860unsigned long           msg;
1861char *                          irqfmt  = "VME IRQ @vector %3i %s";
1862char *                          iackfmt = "VME IACK            %s";
1863LoopbackTstArgs         a;
1864
1865        CHECK_DFLT_BASE(base);
1866
1867        /* arg check */
1868        if ( level < 1 || level > 7 || vector > 255 )
1869                return -1;
1870
1871        if ( UNIV_REV(base) < 2 && vector != 0 ) {
1872                fprintf(stderr,
1873                        "vmeUniverseIntLoopbackTst(): Universe 1 has a bug. IACK in response to\n");
1874                fprintf(stderr,
1875                        "self-generated VME interrupt yields always a zero vector. As a workaround,\n");
1876                fprintf(stderr,
1877                        "use vector 0, please.\n");
1878                return -1;
1879        }
1880
1881        /* Create message queue */
1882        if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
1883                                                                        rtems_build_name('t' ,'U','I','I'),
1884                                                                        4,
1885                                                                        sizeof(unsigned long),
1886                                                                        0,  /* default attributes: fifo, local */
1887                                                                        &q)) ) {
1888                rtems_error(sc, "vmeUniverseIntLoopbackTst: Unable to create message queue");
1889                goto bail;
1890        }
1891
1892        a.q = q;
1893        a.l = level;
1894
1895        /* Install handlers */
1896        if ( vmeUniverseInstallISR(vector, loopbackTstIsr, (void*)&a) ) {
1897                fprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
1898                goto bail;
1899        }
1900        installed++;
1901        if ( vmeUniverseInstallISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
1902                fprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",UNIV_VME_SW_IACK_INT_VEC);
1903                goto bail;
1904        }
1905        installed++;
1906
1907        if ( !vmeUniverseIntIsEnabled(level) && 0==vmeUniverseIntEnable(level) )
1908                doDisable = 1;
1909       
1910        /* make sure there are no pending interrupts */
1911        vmeUniverseWriteReg( UNIV_LINT_STAT_SW_IACK,  UNIV_REGOFF_LINT_STAT );
1912
1913        if ( vmeUniverseIntEnable( UNIV_VME_SW_IACK_INT_VEC ) ) {
1914                fprintf(stderr,"Unable to enable IACK interrupt\n");
1915                goto bail;
1916        }       
1917
1918        printf("vmeUniverse VME interrupt loopback test; STARTING...\n");
1919        printf(" --> asserting VME IRQ level %i\n", level);
1920        vmeUniverseIntRaise(level, vector);
1921
1922        for ( i = 0; i< 3; i++ ) {
1923        sc = rtems_message_queue_receive(
1924                            q,
1925                            &msg,
1926                            &size,
1927                            RTEMS_WAIT,
1928                            20);
1929                if ( sc ) {
1930                        if ( RTEMS_TIMEOUT == sc && i>1 ) {
1931                                /* OK; we dont' expect more to happen */
1932                                sc = 0;
1933                        } else {
1934                                rtems_error(sc,"Error waiting for interrupts");
1935                        }
1936                        break;
1937                }
1938                if ( msg == vector ) {
1939                        if ( !irqfmt ) {
1940                                printf("Excess VME IRQ received ?? -- BAD\n");
1941                                err = 1;
1942                        } else {
1943                                printf(irqfmt, vector, "received -- PASSED\n");
1944                                irqfmt = 0;
1945                        }
1946                } else if ( msg == UNIV_VME_SW_IACK_INT_VEC ) {
1947                        if ( !iackfmt ) {
1948                                printf("Excess VME IACK received ?? -- BAD\n");
1949                                err = 1;
1950                        } else {
1951                                printf(iackfmt, "received -- PASSED\n");
1952                                iackfmt = 0;
1953                        }
1954                } else {
1955                        printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
1956                        err = 1;
1957                }
1958        }
1959
1960
1961        /* Missing anything ? */
1962        if ( irqfmt ) {
1963                printf(irqfmt,vector, "MISSED -- BAD\n");
1964                err = 1;
1965        }
1966        if ( iackfmt ) {
1967                printf(iackfmt, "MISSED -- BAD\n");
1968                err = 1;
1969        }
1970
1971        printf("FINISHED.\n");
1972
1973bail:
1974        if ( doDisable )
1975                vmeUniverseIntDisable(level);
1976        vmeUniverseIntDisable( UNIV_VME_SW_IACK_INT_VEC );
1977        if ( installed > 0 )
1978                vmeUniverseRemoveISR(vector, loopbackTstIsr, (void*)&a);
1979        if ( installed > 1 )
1980                vmeUniverseRemoveISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
1981        if ( q )
1982                rtems_message_queue_delete(q);
1983
1984        return sc ? sc : err;
1985}
1986
1987#endif
Note: See TracBrowser for help on using the repository browser.