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

Last change on this file since a175c1f was a175c1f, checked in by Till Straumann <strauman@…>, on 12/13/06 at 20:39:29
  • 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.7 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 <rtems.h>
9#include <stdio.h>
10#include <stdarg.h>
11#include <bsp/irq.h>
12#include <stdlib.h>
13#include <rtems/bspIo.h>        /* printk */
14#include <rtems/error.h>        /* printk */
15#include <bsp/pci.h>
16#include <bsp.h>
17#include <libcpu/byteorder.h>
18
19#define __INSIDE_RTEMS_BSP__
20
21#include "vmeTsi148.h"
22
23#define STATIC static
24
25/* The tsi has 4 'local' wires that can be hooked to a PIC */
26
27#define TSI_NUM_WIRES                   4
28
29#define TSI148_NUM_OPORTS               8 /* number of outbound ports */
30#define TSI148_NUM_IPORTS               8 /* number of inbound  ports */
31
32#define NUM_TSI_DEVS                    2 /* number of instances supported */
33
34#define PCI_VENDOR_TUNDRA       0x10e3
35#define PCI_DEVICE_TSI148       0x0148
36
37#define TSI_OTSAU_SPACING       0x020
38
39#define TSI_OTSAU0_REG          0x100
40#define TSI_OTSAL0_REG          0x104
41#define TSI_OTEAU0_REG          0x108
42#define TSI_OTEAL0_REG          0x10c
43#define TSI_OTOFU0_REG          0x110
44#define TSI_OTOFL0_REG          0x114
45#define TSI_OTBS0_REG           0x118   /* 2eSST broadcast select */
46#define TSI_OTAT0_REG           0x11c
47#define TSI_OTSAU_REG(port)     (TSI_OTSAU0_REG + ((port)<<5))
48#define TSI_OTSAL_REG(port)     (TSI_OTSAL0_REG + ((port)<<5))
49#define TSI_OTEAU_REG(port)     (TSI_OTEAU0_REG + ((port)<<5))
50#define TSI_OTEAL_REG(port)     (TSI_OTEAL0_REG + ((port)<<5))
51#define TSI_OTOFU_REG(port)     (TSI_OTOFU0_REG + ((port)<<5))
52#define TSI_OTOFL_REG(port)     (TSI_OTOFL0_REG + ((port)<<5))
53#define TSI_OTBS_REG(port)      (TSI_OTBS0_REG + ((port)<<5))
54#define TSI_OTAT_REG(port)      (TSI_OTAT0_REG + ((port)<<5))
55#       define TSI_OTAT_EN                      (1<<31)
56#       define TSI_OTAT_MRPFD           (1<<18)
57#       define TSI_OTAT_PFS(x)          (((x)&3)<<16)
58#       define TSI_OTAT_2eSSTM(x)       (((x)&7)<<11)
59#       define TSI_OTAT_2eSSTM_160      TSI_OTAT_2eSSTM(0)
60#       define TSI_OTAT_2eSSTM_267      TSI_OTAT_2eSSTM(1)
61#       define TSI_OTAT_2eSSTM_320      TSI_OTAT_2eSSTM(2)
62#       define TSI_OTAT_TM(x)           (((x)&7)<<8)
63#               define TSI_TM_SCT_IDX           0
64#               define TSI_TM_BLT_IDX           1
65#               define TSI_TM_MBLT_IDX          2
66#               define TSI_TM_2eVME_IDX         3
67#               define TSI_TM_2eSST_IDX         4
68#               define TSI_TM_2eSSTB_IDX        5
69#       define TSI_OTAT_DBW(x)          (((x)&3)<<6)
70#       define TSI_OTAT_SUP                     (1<<5)
71#       define TSI_OTAT_PGM                     (1<<4)
72#       define TSI_OTAT_ADMODE(x)       (((x)&0xf))
73#       define TSI_OTAT_ADMODE_A16      0
74#       define TSI_OTAT_ADMODE_A24      1
75#       define TSI_OTAT_ADMODE_A32      2
76#       define TSI_OTAT_ADMODE_A64      4
77#       define TSI_OTAT_ADMODE_CSR      5
78#       define TSI_OTAT_ADMODE_USR1     8
79#       define TSI_OTAT_ADMODE_USR2     9
80#       define TSI_OTAT_ADMODE_USR3     0xa
81#       define TSI_OTAT_ADMODE_USR4     0xb
82
83#define TSI_VIACK_1_REG         0x204
84
85#define TSI_VSTAT_REG           0x23c
86#       define TSI_VSTAT_CPURST         (1<<15) /* clear power-up reset bit */
87#       define TSI_VSTAT_BDFAIL         (1<<14)
88#       define TSI_VSTAT_PURSTS         (1<<12)
89#       define TSI_VSTAT_BDFAILS        (1<<11)
90#       define TSI_VSTAT_SYSFLS         (1<<10)
91#       define TSI_VSTAT_ACFAILS        (1<< 9)
92#       define TSI_VSTAT_SCONS          (1<< 8)
93#       define TSI_VSTAT_GAP            (1<< 5)
94#       define TSI_VSTAT_GA_MSK         (0x1f)
95
96#define TSI_VEAU_REG            0x260
97#define TSI_VEAL_REG            0x264
98#define TSI_VEAT_REG            0x268
99
100#define TSI_ITSAU_SPACING       0x020
101
102#define TSI_ITSAU0_REG          0x300
103#define TSI_ITSAL0_REG          0x304
104#define TSI_ITEAU0_REG          0x308
105#define TSI_ITEAL0_REG          0x30c
106#define TSI_ITOFU0_REG          0x310
107#define TSI_ITOFL0_REG          0x314
108#define TSI_ITAT0_REG           0x318
109#define TSI_ITSAU_REG(port)     (TSI_ITSAU0_REG + ((port)<<5))
110#define TSI_ITSAL_REG(port)     (TSI_ITSAL0_REG + ((port)<<5))
111#define TSI_ITEAU_REG(port)     (TSI_ITEAU0_REG + ((port)<<5))
112#define TSI_ITEAL_REG(port)     (TSI_ITEAL0_REG + ((port)<<5))
113#define TSI_ITOFU_REG(port)     (TSI_ITOFU0_REG + ((port)<<5))
114#define TSI_ITOFL_REG(port)     (TSI_ITOFL0_REG + ((port)<<5))
115#define TSI_ITAT_REG(port)      (TSI_ITAT0_REG + ((port)<<5))
116
117#       define TSI_ITAT_EN                      (1<<31)
118#       define TSI_ITAT_TH                      (1<<18)
119#       define TSI_ITAT_VFS(x)          (((x)&3)<<16)
120#       define TSI_ITAT_2eSSTM(x)       (((x)&7)<<12)
121#       define TSI_ITAT_2eSSTM_160      TSI_ITAT_2eSSTM(0)
122#       define TSI_ITAT_2eSSTM_267      TSI_ITAT_2eSSTM(1)
123#       define TSI_ITAT_2eSSTM_320      TSI_ITAT_2eSSTM(2)
124#       define TSI_ITAT_2eSSTB          (1<<11)
125#       define TSI_ITAT_2eSST           (1<<10)
126#       define TSI_ITAT_2eVME           (1<<9)
127#       define TSI_ITAT_MBLT            (1<<8)
128#       define TSI_ITAT_BLT                     (1<<7)
129#       define TSI_ITAT_AS(x)           (((x)&7)<<4)
130#       define TSI_ITAT_ADMODE_A16      (0<<4)
131#       define TSI_ITAT_ADMODE_A24      (1<<4)
132#       define TSI_ITAT_ADMODE_A32      (2<<4)
133#       define TSI_ITAT_ADMODE_A64      (4<<4)
134#       define TSI_ITAT_SUP                     (1<<3)
135#       define TSI_ITAT_USR                     (1<<2)
136#       define TSI_ITAT_PGM                     (1<<1)
137#       define TSI_ITAT_DATA            (1<<0)
138
139#define TSI_CBAU_REG            0x40c
140#define TSI_CBAL_REG            0x410
141#define TSI_CRGAT_REG           0x414
142#   define TSI_CRGAT_EN         (1<<7)
143#       define TSI_CRGAT_AS_MSK (7<<4)
144#       define TSI_CRGAT_A16    (0<<4)
145#       define TSI_CRGAT_A24    (1<<4)
146#       define TSI_CRGAT_A32    (2<<4)
147#       define TSI_CRGAT_A64    (4<<4)
148#   define TSI_CRGAT_SUP        (1<<3)
149#   define TSI_CRGAT_USR        (1<<2)
150#   define TSI_CRGAT_PGM        (1<<1)
151#   define TSI_CRGAT_DATA       (1<<0)
152
153#define TSI_VICR_REG            0x440
154#   define TSI_VICR_CNTS(v)             (((v)&3)<<30)
155#   define TSI_VICR_CNTS_DIS    (0<<30)
156#   define TSI_VICR_CNTS_IRQ1   (1<<30)
157#   define TSI_VICR_CNTS_IRQ2   (2<<30)
158#   define TSI_VICR_EDGIS(v)    (((v)&3)<<28)
159#   define TSI_VICR_EDGIS_DIS   (0<<28)
160#   define TSI_VICR_EDGIS_IRQ1  (1<<28)
161#   define TSI_VICR_EDGIS_IRQ2  (2<<28)
162#   define TSI_VICR_IRQ1F(v)    (((v)&3)<<26)
163#   define TSI_VICR_IRQ1F_NORML (0<<26)
164#   define TSI_VICR_IRQ1F_PULSE (1<<26)
165#   define TSI_VICR_IRQ1F_CLOCK (2<<26)
166#   define TSI_VICR_IRQ1F_1MHZ  (3<<26)
167#   define TSI_VICR_IRQ2F(v)    (((v)&3)<<24)
168#   define TSI_VICR_IRQ2F_NORML (0<<24)
169#   define TSI_VICR_IRQ2F_PULSE (1<<24)
170#   define TSI_VICR_IRQ2F_CLOCK (2<<24)
171#   define TSI_VICR_IRQ2F_1MHZ  (3<<24)
172#   define TSI_VICR_BIP                 (1<<23)
173#   define TSI_VICR_BIPS                (1<<22)
174#   define TSI_VICR_IRQC                (1<<15)
175#   define TSI_VICR_IRQLS(v)    (((v)&7)<<12)
176#   define TSI_VICR_IRQS                (1<<11)
177#   define TSI_VICR_IRQL(v)             (((v)&7)<<8)
178#   define TSI_VICR_STID(v)             ((v)&0xff)
179#define TSI_INTEN_REG           0x448
180#define TSI_INTEO_REG           0x44c
181#define TSI_INTS_REG            0x450
182#   define TSI_INTS_IRQ1S       (1<<1)
183#   define TSI_INTS_IRQ2S       (1<<2)
184#   define TSI_INTS_IRQ3S       (1<<3)
185#   define TSI_INTS_IRQ4S       (1<<4)
186#   define TSI_INTS_IRQ5S       (1<<5)
187#   define TSI_INTS_IRQ6S       (1<<6)
188#   define TSI_INTS_IRQ7S       (1<<7)
189#   define TSI_INTS_ACFLS       (1<<8)
190#   define TSI_INTS_SYSFLS      (1<<9)
191#   define TSI_INTS_IACKS       (1<<10)
192#   define TSI_INTS_VIES        (1<<11)
193#   define TSI_INTS_VERRS       (1<<12)
194#   define TSI_INTS_PERRS       (1<<13)
195#   define TSI_INTS_MB0S        (1<<16)
196#   define TSI_INTS_MB1S        (1<<17)
197#   define TSI_INTS_MB2S        (1<<18)
198#   define TSI_INTS_MB3S        (1<<19)
199#   define TSI_INTS_LM0S        (1<<20)
200#   define TSI_INTS_LM1S        (1<<21)
201#   define TSI_INTS_LM2S        (1<<22)
202#   define TSI_INTS_LM3S        (1<<23)
203#   define TSI_INTS_DMA0S       (1<<24)
204#   define TSI_INTS_DMA1S       (1<<25)
205#define TSI_INTC_REG            0x454
206#   define TSI_INTC_ACFLC       (1<<8)
207#   define TSI_INTC_SYSFLC      (1<<9)
208#   define TSI_INTC_IACKC       (1<<10)
209#   define TSI_INTC_VIEC        (1<<11)
210#   define TSI_INTC_VERRC       (1<<12)
211#   define TSI_INTC_PERRC       (1<<13)
212#   define TSI_INTC_MB0C        (1<<16)
213#   define TSI_INTC_MB1C        (1<<17)
214#   define TSI_INTC_MB2C        (1<<18)
215#   define TSI_INTC_MB3C        (1<<19)
216#   define TSI_INTC_LM0C        (1<<20)
217#   define TSI_INTC_LM1C        (1<<21)
218#   define TSI_INTC_LM2C        (1<<22)
219#   define TSI_INTC_LM3C        (1<<23)
220#   define TSI_INTC_DMA0C       (1<<24)
221#   define TSI_INTC_DMA1C       (1<<25)
222#define TSI_INTM1_REG           0x458
223#define TSI_INTM2_REG           0x45c
224
225#define TSI_CBAR_REG            0xffc
226
227#define TSI_CSR_OFFSET          0x7f000
228
229#define TSI_CRG_SIZE            (1<<12)         /* 4k */
230
231
232#define TSI_RD(base, reg)                               in_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)))
233#define TSI_RD16(base, reg)                             in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short))
234#define TSI_LE_RD16(base, reg)                  in_le16((volatile unsigned short *)(base) + (reg)/sizeof(short))
235#define TSI_LE_RD32(base, reg)                  in_le32((volatile unsigned *)(base) + (reg)/sizeof(*base))
236#define TSI_RD8(base, reg)                              in_8((volatile unsigned char *)(base) + (reg))
237#define TSI_WR(base, reg, val)                  out_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)), val)
238
239#define UNIV_SCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
240
241
242/* allow the BSP to override the default routines */
243#ifndef BSP_PCI_FIND_DEVICE
244#define BSP_PCI_FIND_DEVICE             pci_find_device
245#endif
246#ifndef BSP_PCI_CONFIG_IN_LONG
247#define BSP_PCI_CONFIG_IN_LONG  pci_read_config_dword
248#endif
249#ifndef BSP_PCI_CONFIG_IN_SHORT
250#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
251#endif
252#ifndef BSP_PCI_CONFIG_OUT_SHORT
253#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
254#endif
255#ifndef BSP_PCI_CONFIG_IN_BYTE
256#define BSP_PCI_CONFIG_IN_BYTE  pci_read_config_byte
257#endif
258
259typedef unsigned int pci_ulong;
260
261/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
262 * Should be defined by the BSP.
263 */
264#ifndef BSP_PCI2LOCAL_ADDR
265#ifndef PCI_MEM_BASE
266#define PCI_MEM_BASE 0
267#endif
268#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE)
269#endif
270
271typedef struct {
272        BERegister *base;
273        int                     irqLine;
274        int                     pic_pin[TSI_NUM_WIRES];
275} Tsi148Dev;
276
277static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
278
279/* forward decl */
280extern int vmeTsi148RegPort;
281extern int vmeTsi148RegCSR;
282
283/* registers should be mapped to guarded, non-cached memory; hence
284 * subsequent stores are ordered. eieio is only needed to enforce
285 * ordering of loads with respect to stores.
286 */
287
288/* private printing wrapper */
289static void
290uprintf(FILE *f, char *fmt, ...)
291{
292va_list ap;
293        va_start(ap, fmt);
294        if (!f || !_impure_ptr->__sdidinit) {
295                /* Might be called at an early stage when
296                 * to a buffer.
297                 */
298                vprintk(fmt,ap);
299        } else
300        {
301                vfprintf(f,fmt,ap);
302        }
303        va_end(ap);
304}
305
306#define CHECK_BASE(base,quiet,rval)     \
307        do {                                                    \
308                if ( !base ) {                          \
309                        if ( !quiet ) {                 \
310                                uprintf(stderr,"Tsi148: Driver not initialized\n");     \
311                        }                                               \
312                        return rval;                    \
313                }                                                       \
314        } while (0)
315
316int
317vmeTsi148FindPciBase(
318        int instance,
319        BERegister **pbase
320        )
321{
322int                                     bus,dev,fun;
323pci_ulong                       busaddr;
324unsigned char           irqline;
325unsigned short          wrd;
326
327        if (BSP_PCI_FIND_DEVICE(
328                        PCI_VENDOR_TUNDRA,
329                        PCI_DEVICE_TSI148,
330                        instance,
331                        &bus,
332                        &dev,
333                        &fun))
334                return -1;
335        if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr))
336                return -1;
337        /* Assume upper BAR is zero */
338
339        *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff);
340
341        if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
342                return -1;
343
344        /* Enable PCI master and memory access */
345        BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
346        BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
347
348        return irqline;
349}
350
351int
352vmeTsi148InitInstance(unsigned instance)
353{
354int                                     irq;
355BERegister *base;
356
357        if ( instance >= NUM_TSI_DEVS )
358                return  -1;
359        if ( devs[instance].base )
360                return  -1;
361
362        if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) {
363                uprintf(stderr,"unable to find a Tsi148 in pci config space\n");
364        } else {
365                uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n",
366                                (unsigned int)base, irq);
367        }
368        devs[0].base    = base;
369        devs[0].irqLine = irq;
370
371        return irq < 0 ? -1 : 0;
372}
373
374int
375vmeTsi148Init(void)
376{
377        return vmeTsi148InitInstance(0);
378}
379
380
381void
382vmeTsi148ResetXX(BERegister *base)
383{
384int port;
385
386        CHECK_BASE(base,0, );
387
388        vmeTsi148DisableAllOutboundPortsXX(base);
389        for ( port=0; port < TSI148_NUM_OPORTS; port++ )
390                TSI_WR(base, TSI_OTBS_REG(port), 0);
391        TSI_WR(base, TSI_INTEO_REG, 0);
392        TSI_WR(base, TSI_INTEN_REG, 0);
393        TSI_WR(base, TSI_INTC_REG, 0xffffffff);
394        TSI_WR(base, TSI_INTM1_REG, 0);
395        TSI_WR(base, TSI_INTM2_REG, 0);
396        TSI_WR(base, TSI_VICR_REG, 0);
397        TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
398        /* Clear BDFAIL / (--> SYSFAIL) */
399#       define TSI_VSTAT_BDFAIL         (1<<14)
400        TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL);
401}
402
403void
404vmeTsi148Reset()
405{
406        vmeTsi148ResetXX(devs[0].base);
407}
408
409/* convert an address space selector to a corresponding
410 * Tsi148 control mode word
411 */
412
413static unsigned long ck2esst(unsigned long am)
414{
415        if ( VME_AM_IS_2eSST(am) ) {
416                /* make sure 2eVME is selected */
417                am &= ~VME_AM_MASK;
418                am |= VME_AM_2eVME_6U;
419        }
420        return am;
421}
422
423STATIC int
424am2omode(unsigned long address_space, unsigned long *pmode)
425{
426unsigned long mode = 0;
427unsigned long tm   = TSI_TM_SCT_IDX;
428
429        if ( ! (VME_MODE_DBW16  & address_space ) )
430                mode |= TSI_OTAT_DBW(1);
431        if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
432                mode |= TSI_OTAT_MRPFD;
433        else {
434                mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
435        }
436
437        address_space = ck2esst(address_space);
438
439        switch (address_space & VME_AM_MASK) {
440                case VME_AM_STD_SUP_PGM:
441                case VME_AM_STD_USR_PGM:
442
443                        mode |= TSI_OTAT_PGM;
444
445                        /* fall thru */
446                case VME_AM_STD_SUP_BLT:
447                case VME_AM_STD_SUP_MBLT:
448
449                case VME_AM_STD_USR_BLT:
450                case VME_AM_STD_USR_MBLT:
451                        switch ( address_space & 3 ) {
452                                case 0: tm = TSI_TM_MBLT_IDX; break;
453                                case 3: tm = TSI_TM_BLT_IDX; break;
454                                default: break;
455                        }
456
457                case VME_AM_STD_SUP_DATA:
458                case VME_AM_STD_USR_DATA:
459
460                        mode |= TSI_OTAT_ADMODE_A24;
461                        break;
462
463                case VME_AM_EXT_SUP_PGM:
464                case VME_AM_EXT_USR_PGM:
465                        mode |= TSI_OTAT_PGM;
466
467                        /* fall thru */
468                case VME_AM_EXT_SUP_BLT:
469                case VME_AM_EXT_SUP_MBLT:
470
471                case VME_AM_EXT_USR_BLT:
472                case VME_AM_EXT_USR_MBLT:
473                        switch ( address_space & 3 ) {
474                                case 0: tm = TSI_TM_MBLT_IDX; break;
475                                case 3: tm = TSI_TM_BLT_IDX; break;
476                                default: break;
477                        }
478
479                case VME_AM_EXT_SUP_DATA:
480                case VME_AM_EXT_USR_DATA:
481
482                        mode |= TSI_OTAT_ADMODE_A32;
483                        break;
484
485                case VME_AM_SUP_SHORT_IO:
486                case VME_AM_USR_SHORT_IO:
487                        mode |= TSI_OTAT_ADMODE_A16;
488                        break;
489
490                case VME_AM_CSR:
491                        mode |= TSI_OTAT_ADMODE_CSR;
492                        break;
493
494                case VME_AM_2eVME_6U:
495                case VME_AM_2eVME_3U:
496                        mode |= TSI_OTAT_ADMODE_A32;
497                        if ( VME_AM_IS_2eSST(address_space) ) {
498                                tm = ( VME_AM_2eSST_BCST & address_space ) ?
499                                                TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX;
500                                switch ( VME_AM_IS_2eSST(address_space) ) {
501                                        default:
502                                        case VME_AM_2eSST_LO:  mode |= TSI_OTAT_2eSSTM_160; break;
503                                        case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break;
504                                        case VME_AM_2eSST_HI:  mode |= TSI_OTAT_2eSSTM_320; break;
505                                }
506                        } else {
507                                tm    = TSI_TM_2eVME_IDX;
508                        }
509                break;
510
511                case 0: /* disable the port alltogether */
512                        break;
513
514                default:
515                        return -1;
516        }
517
518        mode |= TSI_OTAT_TM(tm);
519
520        if ( VME_AM_IS_SUP(address_space) )
521                mode |= TSI_OTAT_SUP;
522        *pmode = mode;
523        return 0;
524}
525
526STATIC int
527am2imode(unsigned long address_space, unsigned long *pmode)
528{
529unsigned long mode=0;
530unsigned long pgm = 0;
531
532        mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
533
534        if ( VME_AM_IS_2eSST(address_space) ) {
535                        mode |= TSI_ITAT_2eSST;
536                if ( VME_AM_2eSST_BCST & address_space )
537                        mode |= TSI_ITAT_2eSSTB;
538                switch ( VME_AM_IS_2eSST(address_space) ) {
539                        default:
540                        case VME_AM_2eSST_LO:  mode |= TSI_ITAT_2eSSTM_160; break;
541                        case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break;
542                        case VME_AM_2eSST_HI:  mode |= TSI_ITAT_2eSSTM_320; break;
543                }
544                address_space = ck2esst(address_space);
545        }
546
547        mode |= TSI_ITAT_BLT;
548        mode |= TSI_ITAT_MBLT;
549
550        mode |= TSI_ITAT_PGM; /* always allow PGM access */
551        mode |= TSI_ITAT_USR; /* always allow USR access */
552
553        switch (address_space & VME_AM_MASK) {
554                case VME_AM_STD_SUP_PGM:
555                case VME_AM_STD_USR_PGM:
556
557                        pgm = 1;
558
559                        /* fall thru */
560                case VME_AM_STD_SUP_BLT:
561                case VME_AM_STD_SUP_MBLT:
562                case VME_AM_STD_USR_BLT:
563                case VME_AM_STD_USR_MBLT:
564                case VME_AM_STD_SUP_DATA:
565                case VME_AM_STD_USR_DATA:
566
567                        mode |= TSI_ITAT_ADMODE_A24;
568                        break;
569
570                case VME_AM_EXT_SUP_PGM:
571                case VME_AM_EXT_USR_PGM:
572                        pgm = 1;
573
574                        /* fall thru */
575                case VME_AM_2eVME_6U:
576                case VME_AM_2eVME_3U:
577                case VME_AM_EXT_SUP_BLT:
578                case VME_AM_EXT_SUP_MBLT:
579                case VME_AM_EXT_USR_BLT:
580                case VME_AM_EXT_USR_MBLT:
581                case VME_AM_EXT_SUP_DATA:
582                case VME_AM_EXT_USR_DATA:
583                        mode |= TSI_ITAT_ADMODE_A32;
584                        break;
585
586                case VME_AM_SUP_SHORT_IO:
587                case VME_AM_USR_SHORT_IO:
588                        mode |= TSI_ITAT_ADMODE_A16;
589                        break;
590
591                case 0: /* disable the port alltogether */
592                        *pmode = 0;
593                        return 0;
594
595                default:
596                        return -1;
597        }
598
599        if ( VME_AM_IS_SUP(address_space) )
600                mode |= TSI_ITAT_SUP;
601
602        if ( !pgm )
603                mode |= TSI_ITAT_DATA;
604
605        *pmode = mode;
606        return 0;
607}
608
609static void
610readTriple(
611        BERegister *base,
612        unsigned reg,
613        unsigned long long *ps,
614        unsigned long long *pl,
615        unsigned long long *po)
616{
617        *ps = TSI_RD(base, reg);
618        *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000);
619        *pl = TSI_RD(base, (reg+8));
620        *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000);
621        *po = TSI_RD(base, (reg+0x10));
622        *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000);
623}
624
625
626static unsigned long
627inboundGranularity(unsigned long itat)
628{
629        switch ( itat & TSI_ITAT_AS(-1) ) {
630                case TSI_ITAT_ADMODE_A16:       return 0xf;
631                case TSI_ITAT_ADMODE_A24:       return 0xfff;
632                default:
633                break;
634        }
635        return 0xffff;
636}
637
638static int
639configTsiPort(
640        BERegister              *base,
641        int                             isout,
642        unsigned long   port,
643        unsigned long   address_space,
644        unsigned long   vme_address,
645        unsigned long   pci_address,
646        unsigned long   length)
647{
648unsigned long long      start, limit, offst;
649unsigned long           mode, mask, tat_reg, tsau_reg;
650char                            *name = (isout ? "Outbound" : "Inbound");
651int                                     i,s,l;
652
653        CHECK_BASE(base,0,-1);
654
655        mode = 0; /* silence warning */
656
657        if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) {
658                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name);
659                return -1;
660        }
661
662        if ( base == devs[0].base && isout && vmeTsi148RegPort == port ) {
663                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name);
664                return -1;
665        }
666
667        if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) {
668                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name);
669                return -1;
670        }
671
672
673        if ( isout ) {
674                start     = pci_address;
675                offst     = (unsigned long long)vme_address - start;
676                mask      = 0xffff;
677                tat_reg   = TSI_OTAT_REG(port);
678                tsau_reg  = TSI_OTSAU_REG(port);
679                mode     |= TSI_OTAT_EN;
680
681                /* check for overlap */
682                for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) {
683                        /* ignore 'this' port */
684                        if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) )
685                                continue;
686
687                        /* check requested PCI range against current port 'i' config */
688                        s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */
689                        l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */
690                        if ( ! ( start + length <= s || start > s + l ) ) {
691                                uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
692                                return -1;
693                        }
694                }
695        } else {
696                start     = vme_address;
697                offst     = (unsigned long long)pci_address - start;
698                mask      = inboundGranularity(mode);
699                tat_reg   = TSI_ITAT_REG(port);
700                tsau_reg  = TSI_ITSAU_REG(port);
701                mode     |= TSI_ITAT_EN;
702
703                /* check for overlap */
704                for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) {
705                        /* ignore 'this' port */
706                        if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) )
707                                continue;
708
709                        if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) {
710                                /* different address space */
711                                continue;
712                        }
713
714                        if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) {
715                                /* orthogonal privileges */
716                                continue;
717                        }
718
719                        /* check requested VME range against current port 'i' config */
720                        s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */
721                        l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */
722                        if ( ! ( start + length <= s || start > s + l ) ) {
723                                uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
724                                return -1;
725                        }
726                }
727        }
728
729        /* If they pass 'length==0' just disable */
730        if ( 0 == length ) {
731                TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN));
732                return 0;
733        }
734
735
736        if (   (vme_address & mask)
737            || (pci_address & mask)
738            || (length      & mask) ) {
739                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n",
740                                name,
741                                mask+1);
742                return -1;
743        }
744
745        limit  = start + length - 1;
746
747        if ( limit >= (unsigned long long)1<<32 ) {
748                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name);
749                return -1;
750        }
751
752        /* Disable port */
753        TSI_WR(base, tat_reg, 0);
754
755        /* Force to 32-bits */
756        TSI_WR(base, tsau_reg       , 0);
757        TSI_WR(base, tsau_reg + 0x04, (uint32_t)start);
758        TSI_WR(base, tsau_reg + 0x08, 0);
759        TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit);
760        TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32));
761        TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst);
762
763        /* (outbound only:) leave 2eSST broadcast register alone for user to program */
764
765        /* Set mode and enable */
766        TSI_WR(base, tat_reg, mode);
767        return 0;
768}
769
770static int
771disableTsiPort(
772        BERegister              *base,
773        int                             isout,
774        unsigned long   port)
775{
776        return configTsiPort(base, isout, port, 0, 0, 0, 0);
777}
778
779int
780vmeTsi148InboundPortCfgXX(
781        BERegister              *base,
782        unsigned long   port,
783        unsigned long   address_space,
784        unsigned long   vme_address,
785        unsigned long   pci_address,
786        unsigned long   length)
787{
788        return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length);
789}
790
791int
792vmeTsi148InboundPortCfg(
793        unsigned long   port,
794        unsigned long   address_space,
795        unsigned long   vme_address,
796        unsigned long   pci_address,
797        unsigned long   length)
798{
799        return configTsiPort(devs[0].base, 0, port, address_space, vme_address, pci_address, length);
800}
801
802
803int
804vmeTsi148OutboundPortCfgXX(
805        BERegister              *base,
806        unsigned long   port,
807        unsigned long   address_space,
808        unsigned long   vme_address,
809        unsigned long   pci_address,
810        unsigned long   length)
811{
812        return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length);
813}
814
815int
816vmeTsi148OutboundPortCfg(
817        unsigned long   port,
818        unsigned long   address_space,
819        unsigned long   vme_address,
820        unsigned long   pci_address,
821        unsigned long   length)
822{
823        return configTsiPort(devs[0].base, 1, port, address_space, vme_address, pci_address, length);
824}
825
826
827static int
828xlateFindPort(
829        BERegister *base,       /* TSI 148 base address */
830        int outbound,           /* look in the outbound windows */
831        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
832        unsigned long as,       /* address space */
833        unsigned long aIn,      /* address to look up */
834        unsigned long *paOut/* where to put result */
835        )
836{
837unsigned long           mode, mode_msk;
838int                                     port;
839unsigned long long      start, limit, offst, a;
840unsigned long           tsau_reg, tat_reg, gran, skip;
841
842        CHECK_BASE(base,0,-1);
843
844        mode = 0; /* silence warning */
845
846        switch ( as & VME_MODE_MATCH_MASK ) {
847                case VME_MODE_EXACT_MATCH:
848                        mode_msk = ~0;
849                break;
850
851                case VME_MODE_AS_MATCH:
852                        if ( outbound )
853                                mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
854                        else
855                                mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN;
856                break;
857
858                default:
859                        if ( outbound )
860                                mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
861                        else
862                                mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN;
863                break;
864        }
865
866        as &= ~VME_MODE_MATCH_MASK;
867
868        if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
869                uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
870                return -2;
871        }
872
873        if (outbound ) {
874                tsau_reg = TSI_OTSAU_REG(0);
875                tat_reg  = TSI_OTAT_REG(0);
876                skip     = TSI_OTSAU_SPACING;
877                mode    |= TSI_OTAT_EN;
878                gran     = 0x10000;
879        } else {
880                tsau_reg = TSI_ITSAU_REG(0);
881                tat_reg  = TSI_ITAT_REG(0);
882                skip     = TSI_ITSAU_SPACING;
883                mode    |= TSI_ITAT_EN;
884                gran     = inboundGranularity(mode) + 1;
885        }
886
887        for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) {
888
889                if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) {
890
891                        /* found a window with of the right mode; now check the range */
892                        readTriple(base, tsau_reg, &start, &limit, &offst);
893                        limit += gran;
894
895                        if ( !reverse ) {
896                                start += offst;
897                                limit += offst;
898                                offst  = -offst;
899                        }
900                        a = aIn;
901                        if ( aIn >= start && aIn <= limit ) {
902                                /* found it */
903                                *paOut = (unsigned long)(a + offst);
904                                return port;
905                        }
906                }
907        }
908
909        uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n");
910        return -1;
911}
912
913int
914vmeTsi148XlateAddrXX(
915        BERegister *base,       /* TSI 148 base address */
916        int outbound,           /* look in the outbound windows */
917        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
918        unsigned long as,       /* address space */
919        unsigned long aIn,      /* address to look up */
920        unsigned long *paOut/* where to put result */
921        )
922{
923int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut );
924        return port < 0 ? -1 : 0;
925}
926
927int
928vmeTsi148XlateAddr(
929        int outbound,           /* look in the outbound windows */
930        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
931        unsigned long as,       /* address space */
932        unsigned long aIn,      /* address to look up */
933        unsigned long *paOut/* where to put result */
934        )
935{
936        return vmeTsi148XlateAddrXX(devs[0].base, outbound, reverse, as, aIn, paOut);
937}
938
939
940/* printk cannot format %llx */
941static void uprintfllx(FILE *f, unsigned long long v)
942{
943        if ( v >= ((unsigned long long)1)<<32 )
944                uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff));
945        else
946                uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff));
947}
948
949void
950vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f)
951{
952int                             port;
953unsigned long   mode;
954char                    tit = 0;
955
956unsigned long long      start, limit, offst;
957
958        CHECK_BASE(base,0, );
959
960        if (!f) f=stdout;
961        uprintf(f,"Tsi148 Outbound Ports:\n");
962
963        for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) {
964                mode = TSI_RD(base, TSI_OTAT_REG(port));
965                if ( ! (TSI_OTAT_EN & mode) )
966                        continue; /* skip disabled ports */
967
968                readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst);
969
970                /* convert limit to size */
971                limit = limit-start+0x10000;
972                if ( !tit ) {
973                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
974                        tit = 1;
975                }
976                uprintf(f,"%d:    ", port);
977                uprintfllx(f,start+offst);
978                uprintfllx(f,limit);
979                uprintfllx(f,start);
980                switch( mode & TSI_OTAT_ADMODE(-1) ) {
981                        case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break;
982                        case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break;
983                        case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break;
984                        case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break;
985                        case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break;
986                        default:                  uprintf(f,"A??"); break;
987                }
988
989                if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM");
990                if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP");
991                if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH");
992
993                switch ( mode & TSI_OTAT_DBW(-1) ) {
994                        case TSI_OTAT_DBW(0):   uprintf(f,", D16"); break;
995                        case TSI_OTAT_DBW(1):   uprintf(f,", D32"); break;
996                        default:                                uprintf(f,", D??"); break;
997                }
998
999                switch( mode & TSI_OTAT_TM(-1) ) {
1000                        case TSI_OTAT_TM(0):    uprintf(f,", SCT");             break;
1001                        case TSI_OTAT_TM(1):    uprintf(f,", BLT");             break;
1002                        case TSI_OTAT_TM(2):    uprintf(f,", MBLT");            break;
1003                        case TSI_OTAT_TM(3):    uprintf(f,", 2eVME");           break;
1004                        case TSI_OTAT_TM(4):    uprintf(f,", 2eSST");           break;
1005                        case TSI_OTAT_TM(5):    uprintf(f,", 2eSST_BCST");      break;
1006                        default:                                uprintf(f," TM??");             break;
1007                }
1008
1009                uprintf(f,"\n");
1010        }
1011}
1012
1013void
1014vmeTsi148OutboundPortsShow(FILE *f)
1015{
1016        vmeTsi148OutboundPortsShowXX(devs[0].base, f);
1017}
1018
1019void
1020vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f)
1021{
1022int                             port;
1023unsigned long   mode;
1024char                    tit = 0;
1025
1026unsigned long long      start, limit, offst;
1027
1028        CHECK_BASE(base,0, );
1029
1030        if (!f) f=stdout;
1031        uprintf(f,"Tsi148 Inbound Ports:\n");
1032
1033        for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) {
1034                mode = TSI_RD(base, TSI_ITAT_REG(port));
1035                if ( ! (TSI_ITAT_EN & mode) )
1036                        continue; /* skip disabled ports */
1037
1038                readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst);
1039
1040                /* convert limit to size */
1041                limit = limit - start + inboundGranularity(mode) + 1;
1042                if ( !tit ) {
1043                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
1044                        tit = 1;
1045                }
1046                uprintf(f,"%d:    ", port);
1047                uprintfllx(f,start);
1048                uprintfllx(f,limit);
1049                uprintfllx(f,start+offst);
1050                switch( mode & TSI_ITAT_AS(-1) ) {
1051                        case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break;
1052                        case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break;
1053                        case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break;
1054                        case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break;
1055                        default:                  uprintf(f,"A??"); break;
1056                }
1057
1058                if ( mode & TSI_ITAT_PGM )  uprintf(f,", PGM");
1059                if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT");
1060                if ( mode & TSI_ITAT_SUP )  uprintf(f,", SUP");
1061                if ( mode & TSI_ITAT_USR )  uprintf(f,", USR");
1062
1063                if ( mode & TSI_ITAT_2eSSTB )  uprintf(f,", 2eSSTB");
1064                if ( mode & TSI_ITAT_2eSST  )  uprintf(f,", 2eSST");
1065                if ( mode & TSI_ITAT_2eVME  )  uprintf(f,", 2eVME");
1066                if ( mode & TSI_ITAT_MBLT   )  uprintf(f,", MBLT");
1067                if ( mode & TSI_ITAT_BLT    )  uprintf(f,", BLT");
1068
1069                uprintf(f,"\n");
1070        }
1071}
1072
1073void
1074vmeTsi148InboundPortsShow(FILE *f)
1075{
1076        vmeTsi148InboundPortsShowXX(devs[0].base, f);
1077}
1078
1079
1080void
1081vmeTsi148DisableAllInboundPortsXX(BERegister *base)
1082{
1083int port;
1084
1085        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1086                if ( disableTsiPort(base, 0, port) )
1087                        break;
1088}
1089
1090void
1091vmeTsi148DisableAllInboundPorts(void)
1092{
1093        vmeTsi148DisableAllInboundPortsXX(devs[0].base);
1094}
1095
1096void
1097vmeTsi148DisableAllOutboundPortsXX(BERegister *base)
1098{
1099int port;
1100
1101        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1102                if ( disableTsiPort(base, 1, port) )
1103                        break;
1104}
1105
1106void
1107vmeTsi148DisableAllOutboundPorts(void)
1108{
1109        vmeTsi148DisableAllOutboundPortsXX(devs[0].base);
1110}
1111
1112
1113/* Map internal register block to VME */
1114
1115int
1116vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as )
1117{
1118uint32_t mode;
1119
1120        CHECK_BASE( b, 0, -1 );
1121
1122        if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) {
1123        uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n");
1124                return -1;
1125        }
1126
1127        /* enable all, SUP/USR/PGM/DATA accesses */
1128        mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM |  TSI_CRGAT_DATA;
1129
1130        if ( VME_AM_IS_SHORT(as) ) {
1131                mode |= TSI_CRGAT_A16;
1132        } else
1133        if ( VME_AM_IS_STD(as) ) {
1134                mode |= TSI_CRGAT_A24;
1135        } else
1136        if ( VME_AM_IS_EXT(as) ) {
1137                mode |= TSI_CRGAT_A32;
1138        } else {
1139                return -2;
1140        }
1141
1142        /* map CRG to VME bus */
1143        TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1)));
1144        TSI_WR( b, TSI_CRGAT_REG, mode );
1145
1146        return 0;
1147}
1148
1149int
1150vmeTsi148MapCRG(uint32_t vme_base, uint32_t as )
1151{
1152        return vmeTsi148MapCRGXX( devs[0].base, vme_base, as );
1153}
1154
1155/* Interrupt Subsystem */
1156
1157typedef struct
1158IRQEntryRec_ {
1159                VmeTsi148ISR    isr;
1160                void                    *usrData;
1161} IRQEntryRec, *IRQEntry;
1162
1163static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
1164
1165int        vmeTsi148IrqMgrInstalled = 0;
1166int        vmeTsi148RegPort         = -1;
1167int        vmeTsi148RegCSR                      = 0;
1168BERegister *vmeTsi148RegBase        = 0;
1169
1170static volatile unsigned long   wire_mask[TSI_NUM_WIRES]     = {0};
1171/* wires are offset by 1 so we can initialize the wire table to all zeros */
1172static int                                              tsi_wire[TSI_NUM_WIRES] = {0};
1173
1174/* how should we iack a given level, 1,2,4 bytes? */
1175static unsigned char tsi_iack_width[7] = {
1176        1,1,1,1,1,1,1
1177};
1178
1179/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */
1180static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = {
1181        /* 256 no VOWN interrupt */                     -1,
1182        /* TSI_DMA_INT_VEC                      257 */  256 + 24 - 8,
1183        /* TSI_LERR_INT_VEC                     258 */  256 + 13 - 8,
1184        /* TSI_VERR_INT_VEC                     259 */  256 + 12 - 8,
1185        /* 260 is reserved       */                     -1,
1186        /* TSI_VME_SW_IACK_INT_VEC      261 */  256 + 10 - 8,
1187        /* 262 no PCI SW IRQ     */                     -1,
1188        /* TSI_SYSFAIL_INT_VEC          263 */  256 +  9 - 8,
1189        /* TSI_ACFAIL_INT_VEC           264 */  256 +  8 - 8,
1190        /* TSI_MBOX0_INT_VEC            265 */  256 + 16 - 8,
1191        /* TSI_MBOX1_INT_VEC            266 */  256 + 17 - 8,
1192        /* TSI_MBOX2_INT_VEC            267 */  256 + 18 - 8,
1193        /* TSI_MBOX3_INT_VEC            268 */  256 + 19 - 8,
1194        /* TSI_LM0_INT_VEC                      269 */  256 + 20 - 8,
1195        /* TSI_LM1_INT_VEC                      270 */  256 + 21 - 8,
1196        /* TSI_LM2_INT_VEC                      271 */  256 + 22 - 8,
1197        /* TSI_LM3_INT_VEC                      272 */  256 + 23 - 8,
1198/* New vectors; only on TSI148 */
1199        /* TSI_VIES_INT_VEC                     273 */  256 + 11 - 8,
1200        /* TSI_DMA1_INT_VEC                     274 */  256 + 25 - 8,
1201};
1202
1203/* and the reverse; map tsi bit number to universe compatible 'special' vector number */
1204static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = {
1205        TSI_ACFAIL_INT_VEC,
1206        TSI_SYSFAIL_INT_VEC,
1207        TSI_VME_SW_IACK_INT_VEC,
1208        TSI_VIES_INT_VEC,
1209        TSI_VERR_INT_VEC,
1210        TSI_LERR_INT_VEC,
1211        -1,
1212        -1,
1213        TSI_MBOX0_INT_VEC,
1214        TSI_MBOX1_INT_VEC,
1215        TSI_MBOX2_INT_VEC,
1216        TSI_MBOX3_INT_VEC,
1217        TSI_LM0_INT_VEC,
1218        TSI_LM1_INT_VEC,
1219        TSI_LM2_INT_VEC,
1220        TSI_LM3_INT_VEC,
1221        TSI_DMA_INT_VEC,
1222        TSI_DMA1_INT_VEC,
1223        -1,
1224};
1225
1226static inline int
1227uni2tsivec(int v)
1228{
1229        if ( v < 0 || v >= TSI_NUM_INT_VECS )
1230                return -1;
1231        return v < 256 ? v : uni2tsi_vec_map[v-256];
1232}
1233
1234static int
1235lvl2bitno(unsigned int level)
1236{
1237        if ( level >= 256 )
1238                return uni2tsivec(level) + 8 - 256;
1239        else if ( level < 8 && level > 0 )
1240                return level;
1241        return -1;
1242}
1243
1244int
1245vmeTsi148IntRoute(unsigned int level, unsigned int pin)
1246{
1247int                             i;
1248unsigned long   mask, shift, mapreg, flags, wire;
1249
1250        if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled )
1251                return -1;
1252
1253        if ( level >= 256 ) {
1254                if ( (i = uni2tsivec(level)) < 0 )
1255                        return -1;
1256                shift = 8 + (i-256);
1257        } else if ( 1 <= level && level <=7 ) {
1258                shift = level;
1259        } else {
1260                return -1;      /* invalid level */
1261        }
1262
1263        mask = 1<<shift;
1264
1265        /* calculate the mapping register and contents */
1266        if ( shift < 16 ) {
1267                mapreg = TSI_INTM2_REG;
1268        } else if ( shift < 32 ) {
1269                shift -= 16;
1270                mapreg = TSI_INTM1_REG;
1271        } else {
1272                return -1;
1273        }
1274
1275        shift <<=1;
1276
1277        /* wires are offset by 1 so we can initialize the wire table to all zeros */
1278        wire = (tsi_wire[pin]-1) << shift;
1279
1280rtems_interrupt_disable(flags);
1281
1282        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1283                wire_mask[i] &= ~mask;
1284        }
1285        wire_mask[pin] |= mask;
1286
1287        mask = TSI_RD(devs[0].base, mapreg) & ~ (0x3<<shift);
1288        mask |= wire;
1289        TSI_WR( devs[0].base, mapreg, mask );
1290
1291rtems_interrupt_enable(flags);
1292        return 0;
1293}
1294
1295VmeTsi148ISR
1296vmeTsi148ISRGet(unsigned long vector, void **parg)
1297{
1298VmeTsi148ISR      rval = 0;
1299unsigned long     flags;
1300volatile IRQEntry *p;
1301int               v = uni2tsivec(vector);
1302
1303
1304        if ( v < 0 )
1305                return rval;
1306
1307        p = irqHdlTbl + v;
1308
1309        rtems_interrupt_disable(flags);
1310                if ( *p ) {
1311                        if ( parg )
1312                                *parg = (*p)->usrData;
1313                        rval = (*p)->isr;
1314                }
1315        rtems_interrupt_enable(flags);
1316
1317        return rval;
1318}
1319
1320static void
1321tsiVMEISR(rtems_irq_hdl_param arg)
1322{
1323int                                     pin = (int)arg;
1324BERegister                      *b  = devs[0].base;
1325IRQEntry                        ip;
1326unsigned long           msk,lintstat,vector, vecarg;
1327int                                     lvl;
1328
1329        /* only handle interrupts routed to this pin */
1330
1331        /* NOTE: we read the status register over VME, thus flushing the FIFO
1332         *       where the user ISR possibly left write commands to clear
1333         *       the interrupt condition at the device.
1334         *       This is very important - otherwise, the IRQ level may still be
1335         *       asserted and we would detect an interrupt here but the subsequent
1336         *       IACK would fail since the write operation was flushed to the
1337         *       device in the mean time.
1338         */
1339        while ( (lintstat  = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) {
1340
1341                /* bit 0 is never set since it is never set in wire_mask */
1342
1343                do {
1344                        /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */
1345#ifdef __PPC__
1346                        asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat));
1347                        lvl = 31-lvl;
1348                        msk = 1<<lvl;
1349#else
1350                        { static unsigned long m[] = {
1351                                                                                         0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa
1352                                                                                 };
1353                        int      i;
1354                        unsigned tmp;
1355
1356                        /* lintstat has already been checked...
1357                        if ( !lintstat ) {
1358                           lvl = -1; msk = 0;
1359                        } else
1360                         */
1361                        for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) {
1362                                lvl <<= 1;
1363                                if ( (tmp = msk & m[i]) ) {
1364                                        lvl++;
1365                                        msk = tmp;
1366                                } else
1367                                        msk = msk & ~m[i];
1368                        }
1369                        }
1370#endif
1371
1372                        if ( lvl > 7 ) {
1373                                /* clear this interrupt level */
1374                                TSI_WR(b, TSI_INTC_REG, msk);
1375                                vector = 256 + lvl - 8;
1376                                vecarg = tsi2uni_vec_map[lvl-8];
1377                        } else {
1378                                /* need to do get the vector for this level */
1379                                switch ( tsi_iack_width[lvl-1] ) {
1380                                        default:
1381                                        case  1:
1382                                                vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3);
1383                                                break;
1384
1385                                        case  2:
1386                                                vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2);
1387                                                break;
1388
1389                                        case  4:
1390                                                vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2));
1391                                                break;
1392                                }
1393                                vecarg = vector;
1394                        }
1395
1396                        if ( !(ip=irqHdlTbl[vector])) {
1397                                /* TODO: log error message - RTEMS has no logger :-( */
1398                                vmeTsi148IntDisable(lvl);
1399                                printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABLING level %i\n",
1400                                                lvl, vector, lvl);
1401                        } else {
1402                                /* dispatch handler, it must clear the IRQ at the device */
1403                                ip->isr(ip->usrData, vecarg);
1404                                /* convenience for disobedient users who don't use in_xxx/out_xxx; make
1405                                 * sure we order the subsequent read from the status register after
1406                                 * their business.
1407                                 */
1408                                iobarrier_rw();
1409                        }
1410                } while ( (lintstat &= ~msk) );
1411                /* check if a new irq is pending already */
1412        }
1413}
1414
1415
1416static void
1417my_no_op(const rtems_irq_connect_data * arg)
1418{}
1419
1420static int
1421my_isOn(const rtems_irq_connect_data *arg)
1422{
1423                return (int)(TSI_RD(devs[0].base, TSI_INTEO_REG) & TSI_RD(devs[0].base, TSI_INTEN_REG));
1424}
1425
1426static void
1427connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot)
1428{
1429rtems_irq_connect_data  xx;
1430        xx.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
1431        xx.off    = my_no_op;
1432        xx.isOn   = my_isOn;
1433        xx.hdl    = isr;
1434        xx.handle = (rtems_irq_hdl_param)slot;
1435        xx.name   = pic_line;
1436
1437        if ( shared ) {
1438#if BSP_SHARED_HANDLER_SUPPORT > 0
1439                if (!BSP_install_rtems_shared_irq_handler(&xx))
1440                        BSP_panic("unable to install vmeTsi148 shared irq handler");
1441#else
1442        uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n");
1443                if (!BSP_install_rtems_irq_handler(&xx))
1444                        BSP_panic("unable to install vmeTsi148 irq handler");
1445#endif
1446        } else {
1447                if (!BSP_install_rtems_irq_handler(&xx))
1448                        BSP_panic("unable to install vmeTsi148 irq handler");
1449        }
1450}
1451
1452int
1453vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...)
1454{
1455int             rval;
1456va_list ap;
1457        va_start(ap, pic_pin0);
1458        rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap);
1459        va_end(ap);
1460        return rval;
1461}
1462
1463#ifndef BSP_EARLY_PROBE_VME
1464#define BSP_EARLY_PROBE_VME(addr)       \
1465        (                                                                                                                                                                                                       \
1466                vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ),                                                                                                \
1467                ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 )   \
1468                 && 0 == vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ) )                                                                              \
1469        )
1470#endif
1471
1472/* Check if there is a vme address/as is mapped in any of the outbound windows
1473 * and look for the PCI vendordevice ID there.
1474 * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
1475 *          on success. Address translated into CPU address is returned in *pcpu_addr.
1476 */
1477static int
1478mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
1479{
1480int j;
1481char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
1482
1483        /* try to find mapping */
1484        if ( 0 > (j = xlateFindPort(
1485                                devs[0].base,
1486                                1, 0,
1487                                as | VME_MODE_AS_MATCH,
1488                                vme_addr,
1489                                pcpu_addr ) ) ) {
1490                        uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
1491                        uprintf(stderr,"            in outbound windows.\n");
1492        }
1493        else {
1494                        /* found a slot number; probe it */
1495                        *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
1496                        if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
1497                                uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype);
1498                                return j;
1499                        } else {
1500                                uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype);
1501                        }
1502        }
1503        return -1;
1504}
1505
1506int
1507vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap)
1508{
1509int     i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
1510unsigned long cpu_base, vme_reg_base;
1511
1512        if (vmeTsi148IrqMgrInstalled)                  return -4;
1513
1514        /* check parameters */
1515
1516        if ( tsi_pin0 < 0 || tsi_pin0 > 3 )            return -1;
1517
1518        tsi_pin[0] = tsi_pin0;
1519        pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0;
1520        i = 1;
1521        while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) {
1522               
1523                if ( i >= TSI_NUM_WIRES ) {
1524                                                               return -5;
1525                }
1526
1527                pic_pin[i] = va_arg(ap,int);
1528
1529                if ( tsi_pin[i] > 3 )                      return -2;
1530                if ( pic_pin[i] < 0 )                      return -3;
1531                i++;
1532        }
1533
1534        /* all routings must be different */
1535        for ( i=0; tsi_pin[i] >= 0; i++ ) {
1536                for ( j=i+1; tsi_pin[j] >= 0; j++ ) {
1537                        if ( tsi_pin[j] == tsi_pin[i] )        return -6;
1538                        if ( pic_pin[j] == pic_pin[i] )        return -7;
1539                }
1540        }
1541
1542        i        = -1;
1543
1544        /* first try VME CSR space; do we have a base address set ? */
1545
1546        uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n");
1547
1548        if ( ( i = ((TSI_RD( devs[0].base, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) {
1549                uprintf(stderr,"Trying to find CSR on VME...\n");
1550                vme_reg_base = i*0x80000 + TSI_CSR_OFFSET;
1551                i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
1552                if ( i >= 0 )
1553                        vmeTsi148RegCSR = 1;
1554        } else {
1555                i = -1;
1556        }
1557
1558        if ( -1 == i ) {
1559
1560                uprintf(stderr,"Trying to find CRG on VME...\n");
1561
1562                /* Next we see if the CRG block is mapped to VME */
1563
1564                if ( (TSI_CRGAT_EN & (j = TSI_RD( devs[0].base, TSI_CRGAT_REG ))) ) {
1565                        switch ( j & TSI_CRGAT_AS_MSK ) {
1566                                case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break;
1567                                case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break;
1568                                case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break;
1569                                default:
1570                                break;
1571                        }
1572                        vme_reg_base = TSI_RD( devs[0].base, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1);
1573                }
1574
1575                if ( -1 == i ) {
1576                } else {
1577                        i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
1578                }
1579        }
1580
1581        if ( i < 0 ) {
1582                        uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n");
1583                        uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n");
1584                        uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
1585                        uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n");
1586                        cpu_base = (unsigned long)devs[0].base;
1587                        i        = -1;
1588        }
1589
1590        vmeTsi148RegBase = (BERegister*)cpu_base;
1591        vmeTsi148RegPort = i;
1592
1593        /* give them a chance to override buggy PCI info */
1594        if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) {
1595                uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
1596                                pic_pin[0]);
1597                devs[0].irqLine = pic_pin[0];
1598        }
1599
1600        for ( i = 0; tsi_pin[i] >= 0; i++ ) {
1601                /* offset wire # by one so we can initialize to 0 == invalid */
1602                tsi_wire[i] = tsi_pin[i] + 1;
1603                connectIsr(shared, tsiVMEISR, pic_pin[i], i);
1604        }
1605
1606        specialPin = tsi_pin[1] >= 0 ? 1 : 0;
1607
1608        /* setup routing */
1609       
1610        /* IntRoute checks for mgr being installed */
1611        vmeTsi148IrqMgrInstalled=1;
1612
1613        /* route 7 VME irqs to first / 'normal' pin */
1614        for ( i=1; i<8; i++ )
1615                vmeTsi148IntRoute( i, 0 );
1616        for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ )
1617                vmeTsi148IntRoute( i, specialPin );
1618
1619        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1620                /* remember (for unloading the driver) */
1621                devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 );
1622        }
1623
1624        return 0;
1625}
1626
1627int
1628vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1629{
1630IRQEntry          ip;
1631int                               v;
1632unsigned long     flags;
1633volatile IRQEntry *p;
1634
1635                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1636                        return -1;
1637
1638                p = irqHdlTbl + v;
1639
1640                if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec))))
1641                                return -1;
1642
1643                ip->isr=hdl;
1644                ip->usrData=arg;
1645
1646                rtems_interrupt_disable(flags);
1647                if (*p) {
1648                        rtems_interrupt_enable(flags);
1649                        free(ip);
1650                        return -1;
1651                }
1652                *p = ip;
1653                rtems_interrupt_enable(flags);
1654                return 0;
1655}
1656
1657int
1658vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1659{
1660int               v;
1661IRQEntry          ip;
1662unsigned long     flags;
1663volatile IRQEntry *p;
1664
1665                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1666                        return -1;
1667
1668                p = irqHdlTbl + v;
1669
1670                rtems_interrupt_disable(flags);
1671                ip = *p;
1672                if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) {
1673                                rtems_interrupt_enable(flags);
1674                                return -1;
1675                }
1676                *p = 0;
1677                rtems_interrupt_enable(flags);
1678
1679                free(ip);
1680                return 0;
1681}
1682
1683static int
1684intDoEnDis(unsigned int level, int dis)
1685{
1686BERegister              *b = devs[0].base;
1687unsigned long   flags, v;
1688int                             shift;
1689
1690        if (  ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 )
1691                return -1;
1692
1693        v = 1<<shift;
1694
1695        if ( !dis )
1696                return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0;
1697
1698        rtems_interrupt_disable(flags);
1699        if ( dis<0 ) {
1700                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v);
1701                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v);
1702        } else {
1703                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) |  v);
1704                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) |  v);
1705        }
1706        rtems_interrupt_enable(flags);
1707        return 0;
1708}
1709
1710int
1711vmeTsi148IntEnable(unsigned int level)
1712{
1713        return intDoEnDis(level, 1);
1714}
1715
1716int
1717vmeTsi148IntDisable(unsigned int level)
1718{
1719        return intDoEnDis(level, -1);
1720}
1721
1722int
1723vmeTsi148IntIsEnabled(unsigned int level)
1724{
1725        return intDoEnDis(level, 0);
1726}
1727
1728/* Set IACK width (1,2, or 4 bytes) for a given interrupt level.
1729 *
1730 * 'width' arg may be 0,1,2 or 4. If zero, the currently active
1731 * value is returned but not modified.
1732 *
1733 * RETURNS: old width or -1 if invalid argument.
1734 */
1735
1736int
1737vmeTsi148SetIackWidth(int level, int width)
1738{
1739int rval;
1740        if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled )
1741                return -1;
1742
1743        switch ( width ) {
1744                default: return -1;
1745                case 0:
1746                case 1:
1747                case 2:
1748                case 4:
1749                break;
1750        }
1751
1752        rval = tsi_iack_width[level-1];
1753        if ( width )
1754                tsi_iack_width[level-1] = width;
1755        return rval;
1756}
1757
1758int
1759vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector)
1760{
1761unsigned long v;
1762
1763        CHECK_BASE(base,0,-1);
1764
1765        if ( level < 1 || level > 7 || vector > 255 )
1766                return -1;      /* invalid argument */
1767
1768        /* Check if already asserted */
1769        if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) {
1770                return -2;  /* already asserted */
1771        }
1772
1773        v &= ~255;
1774
1775        v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector);
1776
1777        /* Write Vector */
1778        TSI_WR(base, TSI_VICR_REG, v);
1779
1780        return 0;
1781       
1782}
1783
1784int
1785vmeTsi148IntRaise(int level, unsigned vector)
1786{
1787        return vmeTsi148IntRaiseXX(devs[0].base, level, vector);
1788}
1789
1790/* Loopback test of VME/Tsi148 internal interrupts */
1791
1792typedef struct {
1793        rtems_id        q;
1794        int                     l;
1795} LoopbackTstArgs;
1796
1797static void
1798loopbackTstIsr(void *arg, unsigned long vector)
1799{
1800LoopbackTstArgs *pa = arg;
1801        if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
1802                /* Overrun ? */
1803                printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
1804                vmeTsi148IntDisable(pa->l);
1805        }
1806}
1807
1808int
1809vmeTsi148IntLoopbackTst(int level, unsigned vector)
1810{
1811BERegister                      *b = devs[0].base;
1812rtems_status_code       sc;
1813rtems_id                        q = 0;
1814int                                     installed = 0;
1815int                                     i, err = 0;
1816int                                     doDisable = 0;
1817uint32_t                        size;
1818unsigned long           msg;
1819char *                          irqfmt  = "VME IRQ @vector %3i %s";
1820char *                          iackfmt = "VME IACK            %s";
1821LoopbackTstArgs         a;
1822
1823        CHECK_BASE(b,0,-1);
1824
1825        /* arg check */
1826        if ( level < 1 || level > 7 || vector > 255 )
1827                return -1;
1828
1829        /* Create message queue */
1830        if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
1831                                                                        rtems_build_name('t' ,'U','I','I'),
1832                                                                        4,
1833                                                                        sizeof(unsigned long),
1834                                                                        0,  /* default attributes: fifo, local */
1835                                                                        &q)) ) {
1836                rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue");
1837                goto bail;
1838        }
1839
1840        a.q = q;
1841        a.l = level;
1842
1843        /* Install handlers */
1844        if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) {
1845                uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
1846                goto bail;
1847        }
1848        installed++;
1849        if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
1850                uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC);
1851                goto bail;
1852        }
1853        installed++;
1854
1855        if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) )
1856                doDisable = 1;
1857       
1858        /* make sure there are no pending interrupts */
1859        TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC);
1860
1861        if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) {
1862                uprintf(stderr,"Unable to enable IACK interrupt\n");
1863                goto bail;
1864        }
1865
1866        printf("vmeTsi148 VME interrupt loopback test; STARTING...\n");
1867        printf(" --> asserting VME IRQ level %i\n", level);
1868        vmeTsi148IntRaise(level, vector);
1869
1870        for ( i = 0; i< 3; i++ ) {
1871        sc = rtems_message_queue_receive(
1872                            q,
1873                            &msg,
1874                            &size,
1875                            RTEMS_WAIT,
1876                            20);
1877                if ( sc ) {
1878                        if ( RTEMS_TIMEOUT == sc && i>1 ) {
1879                                /* OK; we dont' expect more to happen */
1880                                sc = 0;
1881                        } else {
1882                                rtems_error(sc,"Error waiting for interrupts");
1883                        }
1884                        break;
1885                }
1886                if ( msg == vector ) {
1887                        if ( !irqfmt ) {
1888                                printf("Excess VME IRQ received ?? -- BAD\n");
1889                                err = 1;
1890                        } else {
1891                                printf(irqfmt, vector, "received -- PASSED\n");
1892                                irqfmt = 0;
1893                        }
1894                } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) {
1895                        if ( !iackfmt ) {
1896                                printf("Excess VME IACK received ?? -- BAD\n");
1897                                err = 1;
1898                        } else {
1899                                printf(iackfmt, "received -- PASSED\n");
1900                                iackfmt = 0;
1901                        }
1902                } else {
1903                        printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
1904                        err = 1;
1905                }
1906        }
1907
1908
1909        /* Missing anything ? */
1910        if ( irqfmt ) {
1911                printf(irqfmt,vector, "MISSED -- BAD\n");
1912                err = 1;
1913        }
1914        if ( iackfmt ) {
1915                printf(iackfmt, "MISSED -- BAD\n");
1916                err = 1;
1917        }
1918
1919        printf("FINISHED.\n");
1920
1921bail:
1922        if ( doDisable )
1923                vmeTsi148IntDisable(level);
1924        vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC );
1925        if ( installed > 0 )
1926                vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a);
1927        if ( installed > 1 )
1928                vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
1929        if ( q )
1930                rtems_message_queue_delete(q);
1931
1932        return sc ? sc : err;
1933}
1934
1935unsigned long
1936vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr)
1937{
1938unsigned long rval;
1939
1940        CHECK_BASE(base,1,-1);
1941
1942        rval = TSI_RD(base, TSI_VEAT_REG);
1943        if ( rval & TSI_VEAT_VES ) {
1944                if ( paddr ) {
1945#if 0 /* no 64-bit support yet */
1946                        *paddr  = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32;
1947                        *paddr |= TSI_RD(base, TSI_VEAL_REG);
1948#else
1949                        *paddr = TSI_RD(base, TSI_VEAL_REG);
1950#endif
1951                }
1952                /* clear errors */
1953                TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
1954        } else {
1955                rval = 0;
1956        }
1957        return rval;
1958}
1959
1960unsigned long
1961vmeTsi148ClearVMEBusErrors(uint32_t *paddr)
1962{
1963        return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, paddr);
1964}
1965
1966#ifdef DEBUG_MODULAR
1967void
1968_cexpModuleInitialize(void* unused)
1969{
1970        vmeTsi148Init();
1971        vmeTsi148Reset();
1972}
1973
1974int
1975_cexpModuleFinalize(void *unused)
1976{
1977int             i;
1978int             rval = 1;
1979void    (*isrs[TSI_NUM_WIRES])() = {
1980        isr_pin0,
1981        isr_pin1,
1982        isr_pin2,
1983        isr_pin3,
1984};
1985
1986rtems_irq_connect_data  xx;
1987        xx.on   = my_no_op; /* at _least_ they could check for a 0 pointer */
1988        xx.off  = my_no_op;
1989        xx.isOn = my_isOn;
1990
1991        TSI_WR(devs[0].base, TSI_INTEO_REG, 0);
1992
1993        for ( i=0; i<TSI_NUM_INT_VECS; i++) {
1994                /* Dont even bother to uninstall handlers */
1995        }
1996        if ( vmeTsi148IrqMgrInstalled ) {
1997                for ( i=0; i<TSI_NUM_WIRES; i++ ) {
1998                        if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) {
1999                                xx.hdl  = isrs[i];
2000                                rval    = rval && BSP_remove_rtems_irq_handler(&xx);
2001                        }
2002                }
2003        }
2004        return !rval;
2005}
2006#endif
Note: See TracBrowser for help on using the repository browser.