diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-03 16:41:16 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-09 07:09:46 +0200 |
commit | 814eccb4cf0e5433bd884a48dfa8e219bb2d0dd0 (patch) | |
tree | 2e079ca82187e519b3be56eb25057330b8344648 /c/src/lib/libbsp/shared | |
parent | bsp: Move umon support to bsps (diff) | |
download | rtems-814eccb4cf0e5433bd884a48dfa8e219bb2d0dd0.tar.bz2 |
bsps: Move VME support to bsps
The VME support is only used by powerpc BSPs.
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'c/src/lib/libbsp/shared')
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/README.porting | 96 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/README.universe | 65 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c | 334 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h | 107 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/doxygen.h | 7 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c | 2695 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c | 2504 |
7 files changed, 0 insertions, 5808 deletions
diff --git a/c/src/lib/libbsp/shared/vmeUniverse/README.porting b/c/src/lib/libbsp/shared/vmeUniverse/README.porting deleted file mode 100644 index 6873f5b1d6..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/README.porting +++ /dev/null @@ -1,96 +0,0 @@ -# - -NOTE: (T.S, 2007/1) The information in this file is outdated - (but some portions may still be useful). Some more information - about how to use the Universe and Tsi148 drivers in new BSPs - can be found in - - README.universe, - libbsp/powerpc/shared/vme/VMEConfig.h, - - source files in this directory and libbsp/powerpc/shared/vme - -The vmeUniverse driver needs some support from the BSP for - -a) PCI configuration space access -b) PCI interrupt acknowledgement -c) PCI interrupt handler installation - -The driver was developed using the powerpc/shared/ BSP -(it also supports vxWorks) and by default uses that BSP's -a) PCI access API -b,c) irq handling API (AKA 'new' style BSP_install_rtems_irq_handler() - API). - -Some hooks exist in the driver to ease porting to other BSPs. -The following information has been assembled when answering a -question regarding a ppcn_60x BSP port: - -I looked through the ppcn_60x BSP. Here's what I found: - - - this BSP does NOT adhere to neither the 'old' nor the 'new' API - but provides its own (startup/setvec.c: set_vector()). - - the BSP has a 'driver' for vmeUniverse although mine is far more - complete (including support for VME interrupts, DMA etc.). - - Porting my driver to your BSP should not be too hard: - - 1) vmeUniverse needs PCI configuration space support from the - BSP: - a) a routine 'pciFindDevice' (need to be macro-aliased - to the proper routine/wrapper of your BSP) who scans - PCI config space for the universe bridge. - You could add 'libbsp/powerpc/shared/pci/pcifinddevice.c' - to your BSP substituting the pci_read_config_xxx calls - by the ones present on your BSP (see step 2)) - b) routines to read PCI config registers (byte and longword) - [on your BSP these are PCIConfigRead32/PCIConfigRead8; - hence you could replace the macros on top with - #define pciConfigInLong PCIConfigRead32 - 2) vmeUniverse needs to know how to acknowledge a PCI interrupt - In your case, nothing needs to be done - #define BSP_PIC_DO_EOI do {} while (0) - 3) Install the VME ISR dispatcher: replace the 'new' style - interrupt installer (BSP_install_rtems_irq_handler()) by - a proper call to 'set_vector()' - 4) I might have missed something... - -I attach the latest version of the vmeUniverse driver in case you want -to try to do the port (should be easy). - -For the sake of ease of maintenance, I just added a few hooks making it -possible to override some things without having to modify the driver code. - - 1,2) PCI config space access macros may be overriden via CFLAGS - when compiling vmeUniverse.c, hence: - CFLAGS += -DBSP_PIC_DO_EOI=do{}while(0) - CFLAGS += -DBSP_PCI_CONFIG_IN_LONG=PCIConfigRead32 - CFLAGS += -DBSP_PCI_CONFIG_IN_BYTE=PCIConfigRead8 - (you still need to supply pci_find_device) - 3) create your own version of vmeUniverseInstallIrqMgr(): - copy to a separate file and replace - BSP_rtems_install_irq_handler() by a proper call to set_vector. - - 4) Send me email :-) - -USAGE NOTE: To fully initialize the driver, the following steps can/must -be performed: - - vmeUniverseInit(); /* MANDATORY: Driver Initialization */ - vmeUniverseReset(); /* OPTIONAL: Reset most registers to a known state; - * if this step is omitted, firmware setup is - * preserved - */ - vmeUniverseMasterPortCfg(...); /* OPTIONAL: setup the master windows - * (current setup preserved if omitted) - */ - vmeUniverseSlavePortCfg(...); /* OPTIONAL: setup the slave windows - * (current setup preserved if omitted) - */ - vmeUniverseInstallIrqMgr(); /* NEEDED FOR VME INTERRUPT SUPPRORT - * initialize the interrupt manager. - * NOTE: you need to call your own - * version of this routine here - */ - -For an example of init/setup, consult libbsp/powerpc/shared/vme/vmeconfig.c - diff --git a/c/src/lib/libbsp/shared/vmeUniverse/README.universe b/c/src/lib/libbsp/shared/vmeUniverse/README.universe deleted file mode 100644 index 1059d8c806..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/README.universe +++ /dev/null @@ -1,65 +0,0 @@ -The tundra drivers are in a separate subdir -because they are maintained at SSRL outside of the -rtems CVS tree. The directory is called 'vmeUniverse' -for historic reasons. 'tundra' would be better -since we now support the tundra tsi148 as well... - -Till Straumann <strauman@slac.stanford.edu> 1/2002, 2005, 2007 - -A BSP that wants to use these drivers -must implement the following headers / functionality: - - <bsp/pci.h> offering an API like 'libbsp/powerpc/shared/pci' - - <bsp/irq.h> offering the 'new style' RTEMS irq API - (like 'libbsp/powerpc/shared/irq'). - - <libcpu/io.h> for the I/O operations (out_le32,in_le32, ..., out_be32,...) - - <libcpu/byteorder.h> for byte-swapping (st_le32, ld_le32, ..., st_be32,...) - - glue code that implements the 'VME.h' and 'VMEDMA.h' APIs - using the vmeUniverse and/or vmeTsi148 driver code. - The 'glue' code initializes appropriate VME/PCI windows when booting - and installs the VME interrupt manager. - - The 'glue' may also use the 'bspVmeDmaList' code to implement generic - parts of linked-list DMA. - - Boards with a 'universe' chip may use a pretty generic version of - the glue code that is defined in libbsp/powerpc/shared/vmeconfig.c, - libbsp/powerpc/shared/vme_universe.c, and - libbsp/powerpc/shared/vme_universe_dma.c. The board-specific parameters - are defined in a single BSP-specific file 'VMEConfig.h'. That's where - the actual addresses of VME/PCI windows are configured and where - interrupt wires can be assigned etc. - - Read libbsp/powerpc/shared/VMEConfig.h for more information and use - it as a template. Note that BSP implementors should try *not* to - clone 'vmeconfig.c' but use the constants in VMEConfig.h - - - The BSP should export 'VME.h' and 'VMEDMA.h' to applications - and encourage them to only use the API defined there in order - to make application code driver-independent. This will ensure - seamless portability of applications between the universe and Tsi148 - drivers. - - -TESTING: A valuable tool for testing are the (substitute XXX for - 'Universe' or 'Tsi148') routines: - vmeXXXMapCRG() - maps the controller registers to VME space so you - can test if you successfully can read/write from VME. - You can read or DMA the PCI configuration registers - and compare to what you expect (beware of endianness). - - vmeXXXIntLoopbackTest() - this installs an ISR and then asserts an IRQ on the VME - backplane so you can verify that your interrupt routing - and handling really works. - -NOTES: The universe may always issue MBLTs if a data width of 64-bit - is enabled (default for non-BLT addressing modes -- the - VME_AM_STD_xx_BLT / VME_AM_EXT_xx_BLT enforce 32-bit transfers). - - Therefore, if you want to setup a outbound window that always - uses single cycles then you must explicitely request a data - width < 64, e.g., - - vmeUniverseMasterPortCfg(port, VME_AM_EXT_SUP_DATA | VME_MODE_DBW32, vme_addr, pci_addr, size); - diff --git a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c deleted file mode 100644 index 73b398dda1..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c +++ /dev/null @@ -1,334 +0,0 @@ -/* bspVmeDmaList.c: - * implementation of generic parts of the 'linked-list VME DMA' API. - */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann <strauman@slac.stanford.edu>, 2006, 2007, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#define DEBUG -#include <bsp/VMEDMA.h> -#include <bsp/bspVmeDmaList.h> -#include "bspVmeDmaListP.h" - - -typedef struct VMEDmaListNodeRec_ { - VMEDmaListNode p, n; /* linkage */ - DmaDescriptor d; /* real descriptor */ - void *usrData; - VMEDmaListClass class; /* pointer to 'class' record */ -} VMEDmaListNodeRec; - -#define LCHUNK 10 - -#ifdef DEBUG -static void -lprint(VMEDmaListNode d) -{ - printf("n 0x%08lx, p: 0x%08lx, n: 0x%08lx d: 0x%08lx\n", - (uint32_t)d, (uint32_t)d->p, (uint32_t)d->n, (uint32_t)d->d); -} -#endif - -static VMEDmaListNode -lalloc(VMEDmaListClass pc) -{ -VMEDmaListNode rval; -int i; - - if ( !pc->freeList ) { - /* alloc block of 10 descriptors */ - pc->freeList = calloc( (LCHUNK), sizeof(*pc->freeList)); - - if ( ! (pc->freeList) ) { - return 0; - } - - /* link together and set 'class' pointer */ - for (i=0; i<(LCHUNK)-1; i++) { - pc->freeList[i].n = &pc->freeList[i+1]; - pc->freeList[i].class = pc; - } - pc->freeList[i].n = 0; - pc->freeList[i].class = pc; - - /* Allocate 'real' descriptor memory */ - if ( pc->desc_alloc ) { - for (i=0; i<(LCHUNK); i++) { - if ( ! (pc->freeList[i].d = pc->desc_alloc()) ) { - int j; - if ( pc->desc_free ) { - for (j=0; j<i; j++) - pc->desc_free(pc->freeList[i].d); - } - free(pc->freeList); - pc->freeList = 0; - return 0; - } - } - } else { - int blksize; - uint32_t algnmsk = pc->desc_align - 1; - char *memptr; - - /* ignore their 'free' method */ - pc->desc_free = 0; - - blksize = (pc->desc_size + algnmsk) & ~algnmsk; - - if ( ! (memptr = malloc(blksize*(LCHUNK) + pc->desc_align - 1)) ) { - free(pc->freeList); - pc->freeList = 0; - return 0; - } - - /* align memory ptr; must not be freed() anymore */ - memptr = (char*)( ((uint32_t)memptr + algnmsk) & ~ algnmsk ); - - for ( i = 0; i<(LCHUNK); i++, memptr+=blksize ) { - memset(memptr, 0, blksize); - pc->freeList[i].d = (DmaDescriptor)memptr; - } - } - } - rval = pc->freeList; - pc->freeList = pc->freeList->n; - rval->n = rval->p = 0; - return rval; -} - -static int -lfree(VMEDmaListNode d) -{ - if ( d->p || d->n ) - return -1; - d->n = d->class->freeList; - d->class->freeList = d; - return 0; -} - -static int -lenq(VMEDmaListNode a, VMEDmaListNode d) -{ - if ( a ) { - /* enqueue */ - if ( d->n || d->p ) - return -1; - if ( (d->n = a->n) ) - a->n->p = d; - d->p = a; - a->n = d; - } else { - /* dequeue */ - if ( d->n ) - d->n->p = d->p; - if ( d->p ) - d->p->n = d->n; - d->n = d->p = 0; - } - return 0; -} - - -int -BSP_VMEDmaListDescriptorStartTool(volatile void *controller, int channel, VMEDmaListNode n) -{ - if ( !n ) - return -1; - return n->class->desc_start(controller, channel, n->d); -} - -VMEDmaListNode -BSP_VMEDmaListDescriptorSetupTool( - VMEDmaListNode n, - uint32_t attr_mask, - uint32_t xfer_mode, - uint32_t pci_addr, - uint32_t vme_addr, - uint32_t n_bytes) -{ - if ( !n ) - return 0; - - if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) { - return 0; - } - - return n; -} - -VMEDmaListNode -BSP_VMEDmaListDescriptorNewTool( - VMEDmaListClass pc, - uint32_t attr_mask, - uint32_t xfer_mode, - uint32_t pci_addr, - uint32_t vme_addr, - uint32_t n_bytes) -{ -VMEDmaListNode n; - - if ( !(n=lalloc(pc)) ) - return 0; /* no memory */ - - if ( n->class->desc_init ) - n->class->desc_init(n->d); - - if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) { - BSP_VMEDmaListDescriptorDestroy(n); - return 0; - } - return n; -} - -int -BSP_VMEDmaListDescriptorDestroy(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; - return lfree(d); -} - -int -BSP_VMEDmaListDestroy(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; -VMEDmaListNode n; - while (d) { - n = d->n; - if ( BSP_VMEDmaListDescriptorEnq(0, d) || - BSP_VMEDmaListDescriptorDestroy(d) ) - return -1; - d = n; - } - return 0; -} - -int -BSP_VMEDmaListDescriptorEnq(BSP_VMEDmaListDescriptor p, BSP_VMEDmaListDescriptor q) -{ -VMEDmaListNode anchor = p; -VMEDmaListNode d = q; -DmaDescriptorSetNxt setnxt = d->class->desc_setnxt; - - if ( !anchor ) { - /* dequeue can't fail - we can update dnlal first (need d->p) */ - if ( d->p ) - setnxt(d->p->d, d->n ? d->n->d : 0); - /* paranoia */ - setnxt(d->d, 0); - } else { - if ( d->class != anchor->class ) - return -1; - } - if ( lenq(anchor, d) ) - return -1; - /* update descriptor pointers */ - if ( anchor ) { - setnxt(d->d, d->n ? d->n->d : 0); - setnxt(anchor->d, d->d); - } - return 0; -} - -BSP_VMEDmaListDescriptor -BSP_VMEDmaListDescriptorNext(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; - return d->n; -} - -BSP_VMEDmaListDescriptor -BSP_VMEDmaListDescriptorPrev(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; - return d->p; -} - -void -BSP_VMEDmaListDescriptorSetUsr(BSP_VMEDmaListDescriptor p, void *usrData) -{ -VMEDmaListNode d = p; - d->usrData = usrData; -} - -void * -BSP_VMEDmaListDescriptorGetUsr(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; - return d->usrData; -} - -int -BSP_VMEDmaListRefresh(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode anchor = p; -DmaDescriptorRefr desc_refr; -VMEDmaListNode n; - if ( (desc_refr = anchor->class->desc_refr) ) { - for ( n = anchor; n; n = n->n ) { - desc_refr(n->d); - } - } - return 0; -} - -#ifdef DEBUG -void -BSP_VMEDmaListDump(BSP_VMEDmaListDescriptor p) -{ -VMEDmaListNode d = p; - while (d) { - printf("----------\n"); - lprint(d); - if (d->class->desc_dump) - d->class->desc_dump(d->d); - d = d->n; - } -} -#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h deleted file mode 100644 index 1a1f97b9ad..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file - * - * @ingroup shared_bspvmedmalistp - * - * @brief Private Interface to the bspVmeDmaList facility - */ - -#ifndef BSP_VME_DMA_LIST_P_H -#define BSP_VME_DMA_LIST_P_H - -#include <bsp/bspVmeDmaList.h> - -/* - * This is used by chip drivers to implement the - * 'class' members so that 'bspVmeDmaList' can access - * the device in an abstract manner. - */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann <strauman@slac.stanford.edu>, 2006, 2007 - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ -#ifdef __cplusplus -extern "C" { -#endif - -typedef void *DmaDescriptor; - -/** - * @defgroup shared_bspvmedmalistp member functions - * - * @ingroup shared_vmeuniverse - * - * @brief Member functions to be implemented by chip drivers - */ - -typedef DmaDescriptor (*DmaDescriptorAlloc)(void); -typedef void (*DmaDescriptorFree) (DmaDescriptor d); -typedef void (*DmaDescriptorInit) (DmaDescriptor d); -/* Setup takes the parameters declared in VMEDMA.h */ -typedef int (*DmaDescriptorSetup)(DmaDescriptor d, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -typedef void (*DmaDescriptorSetNxt)(DmaDescriptor d, DmaDescriptor next); -typedef int (*DmaDescriptorStart)(volatile void *controller_addr, int channel, DmaDescriptor); -typedef int (*DmaDescriptorRefr) (DmaDescriptor); -typedef void (*DmaDescriptorDump) (DmaDescriptor); - - -typedef struct VMEDmaListClassRec_ { - int desc_size; /* size of a descritor */ - int desc_align; /* alignment of a descriptor */ - VMEDmaListNode freeList; /* list of free descriptors of this class, MUST be initialized to NULL */ - DmaDescriptorAlloc desc_alloc; /* [optional, may be NULL] allocator for one descriptor */ - DmaDescriptorFree desc_free; /* [optional, may be NULL] destructor for one descriptor */ - DmaDescriptorInit desc_init; /* [optional, may be NULL] set stuff that don't change during lifetime */ - DmaDescriptorSetNxt desc_setnxt;/* set 'NEXT' pointer in descriptor; mark as LAST if next == 0 */ - DmaDescriptorSetup desc_setup; /* setup a descriptor */ - DmaDescriptorStart desc_start; /* start list at a descriptor */ - DmaDescriptorRefr desc_refr; /* refresh a descriptor */ - DmaDescriptorDump desc_dump; /* dump a descriptor (for debugging) */ -} VMEDmaListClassRec; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/doxygen.h b/c/src/lib/libbsp/shared/vmeUniverse/doxygen.h deleted file mode 100644 index 88ded941ac..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/doxygen.h +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @defgroup shared_vmeuniverse SHARED VMEUNIVERSE Modules - * - * @ingroup bsp_shared - * - * @brief SHARED VMEUNIVERSE Modules - */
\ No newline at end of file diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c deleted file mode 100644 index 4e1893b593..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c +++ /dev/null @@ -1,2695 +0,0 @@ -/* Driver for the Tundra Tsi148 pci-vme bridge */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -#include <rtems.h> -#include <stdio.h> -#include <stdarg.h> -#include <bsp/irq.h> -#include <stdlib.h> -#include <rtems/bspIo.h> /* printk */ -#include <rtems/error.h> /* printk */ -#include <rtems/pci.h> -#include <bsp.h> -#include <libcpu/byteorder.h> - -#define __INSIDE_RTEMS_BSP__ -#define _VME_TSI148_DECLARE_SHOW_ROUTINES - -#include <bsp/vmeTsi148.h> -#include <bsp/VMEDMA.h> -#include <bsp/vmeTsi148DMA.h> -#include "bspVmeDmaListP.h" - - -#define DEBUG - -#ifdef DEBUG -#define STATIC -#else -#define STATIC static -#endif - -/* The tsi has 4 'local' wires that can be hooked to a PIC */ - -#define TSI_NUM_WIRES 4 - -#define TSI148_NUM_OPORTS 8 /* number of outbound ports */ -#define TSI148_NUM_IPORTS 8 /* number of inbound ports */ - -#define NUM_TSI_DEVS 2 /* number of instances supported */ - -#define PCI_VENDOR_TUNDRA 0x10e3 -#define PCI_DEVICE_TSI148 0x0148 - -#define TSI_OTSAU_SPACING 0x020 - -#define TSI_OTSAU0_REG 0x100 -#define TSI_OTSAL0_REG 0x104 -#define TSI_OTEAU0_REG 0x108 -#define TSI_OTEAL0_REG 0x10c -#define TSI_OTOFU0_REG 0x110 -#define TSI_OTOFL0_REG 0x114 -#define TSI_OTBS0_REG 0x118 /* 2eSST broadcast select */ -#define TSI_OTAT0_REG 0x11c -#define TSI_OTSAU_REG(port) (TSI_OTSAU0_REG + ((port)<<5)) -#define TSI_OTSAL_REG(port) (TSI_OTSAL0_REG + ((port)<<5)) -#define TSI_OTEAU_REG(port) (TSI_OTEAU0_REG + ((port)<<5)) -#define TSI_OTEAL_REG(port) (TSI_OTEAL0_REG + ((port)<<5)) -#define TSI_OTOFU_REG(port) (TSI_OTOFU0_REG + ((port)<<5)) -#define TSI_OTOFL_REG(port) (TSI_OTOFL0_REG + ((port)<<5)) -#define TSI_OTBS_REG(port) (TSI_OTBS0_REG + ((port)<<5)) -#define TSI_OTAT_REG(port) (TSI_OTAT0_REG + ((port)<<5)) -# define TSI_OTAT_EN (1<<31) -# define TSI_OTAT_MRPFD (1<<18) -# define TSI_OTAT_PFS(x) (((x)&3)<<16) -# define TSI_OTAT_2eSSTM(x) (((x)&7)<<11) -# define TSI_OTAT_2eSSTM_160 TSI_OTAT_2eSSTM(0) -# define TSI_OTAT_2eSSTM_267 TSI_OTAT_2eSSTM(1) -# define TSI_OTAT_2eSSTM_320 TSI_OTAT_2eSSTM(2) -# define TSI_OTAT_TM(x) (((x)&7)<<8) -# define TSI_TM_SCT_IDX 0 -# define TSI_TM_BLT_IDX 1 -# define TSI_TM_MBLT_IDX 2 -# define TSI_TM_2eVME_IDX 3 -# define TSI_TM_2eSST_IDX 4 -# define TSI_TM_2eSSTB_IDX 5 -# define TSI_OTAT_DBW(x) (((x)&3)<<6) -# define TSI_OTAT_SUP (1<<5) -# define TSI_OTAT_PGM (1<<4) -# define TSI_OTAT_ADMODE(x) (((x)&0xf)) -# define TSI_OTAT_ADMODE_A16 0 -# define TSI_OTAT_ADMODE_A24 1 -# define TSI_OTAT_ADMODE_A32 2 -# define TSI_OTAT_ADMODE_A64 4 -# define TSI_OTAT_ADMODE_CSR 5 -# define TSI_OTAT_ADMODE_USR1 8 -# define TSI_OTAT_ADMODE_USR2 9 -# define TSI_OTAT_ADMODE_USR3 0xa -# define TSI_OTAT_ADMODE_USR4 0xb - -#define TSI_VIACK_1_REG 0x204 - -#define TSI_VMCTRL_REG 0x234 -# define TSI_VMCTRL_VSA (1<<27) -# define TSI_VMCTRL_VS (1<<26) -# define TSI_VMCTRL_DHB (1<<25) -# define TSI_VMCTRL_DWB (1<<24) -# define TSI_VMCTRL_RMWEN (1<<20) -# define TSI_VMCTRL_A64DS (1<<16) -# define TSI_VMCTRL_VTOFF_MSK (7<<12) -# define TSI_VMCTRL_VTOFF_0us (0<<12) -# define TSI_VMCTRL_VTOFF_1us (1<<12) -# define TSI_VMCTRL_VTOFF_2us (2<<12) -# define TSI_VMCTRL_VTOFF_4us (3<<12) -# define TSI_VMCTRL_VTOFF_8us (4<<12) -# define TSI_VMCTRL_VTOFF_16us (5<<12) -# define TSI_VMCTRL_VTOFF_32us (6<<12) -# define TSI_VMCTRL_VTOFF_64us (7<<12) -# define TSI_VMCTRL_VTON_MSK (7<< 8) -# define TSI_VMCTRL_VTON_4us (0<< 8) -# define TSI_VMCTRL_VTON_8us (1<< 8) -# define TSI_VMCTRL_VTON_16us (2<< 8) -# define TSI_VMCTRL_VTON_32us (3<< 8) -# define TSI_VMCTRL_VTON_64us (4<< 8) -# define TSI_VMCTRL_VTON_128us (5<< 8) -# define TSI_VMCTRL_VTON_256us (6<< 8) -# define TSI_VMCTRL_VTON_512us (7<< 8) -# define TSI_VMCTRL_VREL_MSK (3<< 3) -# define TSI_VMCTRL_VREL_TON_or_DONE (0<< 3) -# define TSI_VMCTRL_VREL_TONandREQ_or_DONE (1<< 3) -# define TSI_VMCTRL_VREL_TONandBCLR_or_DONE (2<< 3) -# define TSI_VMCTRL_VREL_TONorDONE_and_REQ (3<< 3) -# define TSI_VMCTRL_VFAIR (1<< 2) -# define TSI_VMCTRL_VREQL_MSK (3<< 0) -# define TSI_VMCTRL_VREQL(x) ((x)&3) - -#define TSI_VCTRL_REG 0x238 -#define TSI_VCTRL_DLT_MSK (0xf<<24) -#define TSI_VCTRL_NELBB (1<<20) -#define TSI_VCTRL_SRESET (1<<17) -#define TSI_VCTRL_LRESET (1<<16) -#define TSI_VCTRL_SFAILAI (1<<15) -#define TSI_VCTRL_BID_MSK (0x1f<<8) -#define TSI_VCTRL_ATOEN (1<< 7) -#define TSI_VCTRL_ROBIN (1<< 6) -#define TSI_VCTRL_GTO_MSK (7<< 0) - - -#define TSI_VSTAT_REG 0x23c -# define TSI_VSTAT_CPURST (1<<15) /* clear power-up reset bit */ -# define TSI_VSTAT_BDFAIL (1<<14) -# define TSI_VSTAT_PURSTS (1<<12) -# define TSI_VSTAT_BDFAILS (1<<11) -# define TSI_VSTAT_SYSFLS (1<<10) -# define TSI_VSTAT_ACFAILS (1<< 9) -# define TSI_VSTAT_SCONS (1<< 8) -# define TSI_VSTAT_GAP (1<< 5) -# define TSI_VSTAT_GA_MSK (0x1f) - -#define TSI_VEAU_REG 0x260 -#define TSI_VEAL_REG 0x264 -#define TSI_VEAT_REG 0x268 - -#define TSI_ITSAU_SPACING 0x020 - -#define TSI_ITSAU0_REG 0x300 -#define TSI_ITSAL0_REG 0x304 -#define TSI_ITEAU0_REG 0x308 -#define TSI_ITEAL0_REG 0x30c -#define TSI_ITOFU0_REG 0x310 -#define TSI_ITOFL0_REG 0x314 -#define TSI_ITAT0_REG 0x318 -#define TSI_ITSAU_REG(port) (TSI_ITSAU0_REG + ((port)<<5)) -#define TSI_ITSAL_REG(port) (TSI_ITSAL0_REG + ((port)<<5)) -#define TSI_ITEAU_REG(port) (TSI_ITEAU0_REG + ((port)<<5)) -#define TSI_ITEAL_REG(port) (TSI_ITEAL0_REG + ((port)<<5)) -#define TSI_ITOFU_REG(port) (TSI_ITOFU0_REG + ((port)<<5)) -#define TSI_ITOFL_REG(port) (TSI_ITOFL0_REG + ((port)<<5)) -#define TSI_ITAT_REG(port) (TSI_ITAT0_REG + ((port)<<5)) - -# define TSI_ITAT_EN (1<<31) -# define TSI_ITAT_TH (1<<18) -# define TSI_ITAT_VFS(x) (((x)&3)<<16) -# define TSI_ITAT_2eSSTM(x) (((x)&7)<<12) -# define TSI_ITAT_2eSSTM_160 TSI_ITAT_2eSSTM(0) -# define TSI_ITAT_2eSSTM_267 TSI_ITAT_2eSSTM(1) -# define TSI_ITAT_2eSSTM_320 TSI_ITAT_2eSSTM(2) -# define TSI_ITAT_2eSSTB (1<<11) -# define TSI_ITAT_2eSST (1<<10) -# define TSI_ITAT_2eVME (1<<9) -# define TSI_ITAT_MBLT (1<<8) -# define TSI_ITAT_BLT (1<<7) -# define TSI_ITAT_AS(x) (((x)&7)<<4) -# define TSI_ITAT_ADMODE_A16 (0<<4) -# define TSI_ITAT_ADMODE_A24 (1<<4) -# define TSI_ITAT_ADMODE_A32 (2<<4) -# define TSI_ITAT_ADMODE_A64 (4<<4) -# define TSI_ITAT_SUP (1<<3) -# define TSI_ITAT_USR (1<<2) -# define TSI_ITAT_PGM (1<<1) -# define TSI_ITAT_DATA (1<<0) - -#define TSI_CBAU_REG 0x40c -#define TSI_CBAL_REG 0x410 -#define TSI_CRGAT_REG 0x414 -# define TSI_CRGAT_EN (1<<7) -# define TSI_CRGAT_AS_MSK (7<<4) -# define TSI_CRGAT_A16 (0<<4) -# define TSI_CRGAT_A24 (1<<4) -# define TSI_CRGAT_A32 (2<<4) -# define TSI_CRGAT_A64 (4<<4) -# define TSI_CRGAT_SUP (1<<3) -# define TSI_CRGAT_USR (1<<2) -# define TSI_CRGAT_PGM (1<<1) -# define TSI_CRGAT_DATA (1<<0) - -#define TSI_VICR_REG 0x440 -# define TSI_VICR_CNTS(v) (((v)&3)<<30) -# define TSI_VICR_CNTS_DIS (0<<30) -# define TSI_VICR_CNTS_IRQ1 (1<<30) -# define TSI_VICR_CNTS_IRQ2 (2<<30) -# define TSI_VICR_EDGIS(v) (((v)&3)<<28) -# define TSI_VICR_EDGIS_DIS (0<<28) -# define TSI_VICR_EDGIS_IRQ1 (1<<28) -# define TSI_VICR_EDGIS_IRQ2 (2<<28) -# define TSI_VICR_IRQ1F(v) (((v)&3)<<26) -# define TSI_VICR_IRQ1F_NORML (0<<26) -# define TSI_VICR_IRQ1F_PULSE (1<<26) -# define TSI_VICR_IRQ1F_CLOCK (2<<26) -# define TSI_VICR_IRQ1F_1MHZ (3<<26) -# define TSI_VICR_IRQ2F(v) (((v)&3)<<24) -# define TSI_VICR_IRQ2F_NORML (0<<24) -# define TSI_VICR_IRQ2F_PULSE (1<<24) -# define TSI_VICR_IRQ2F_CLOCK (2<<24) -# define TSI_VICR_IRQ2F_1MHZ (3<<24) -# define TSI_VICR_BIP (1<<23) -# define TSI_VICR_BIPS (1<<22) -# define TSI_VICR_IRQC (1<<15) -# define TSI_VICR_IRQLS(v) (((v)&7)<<12) -# define TSI_VICR_IRQS (1<<11) -# define TSI_VICR_IRQL(v) (((v)&7)<<8) -# define TSI_VICR_STID(v) ((v)&0xff) -#define TSI_INTEN_REG 0x448 -#define TSI_INTEO_REG 0x44c -#define TSI_INTS_REG 0x450 -# define TSI_INTS_IRQ1S (1<<1) -# define TSI_INTS_IRQ2S (1<<2) -# define TSI_INTS_IRQ3S (1<<3) -# define TSI_INTS_IRQ4S (1<<4) -# define TSI_INTS_IRQ5S (1<<5) -# define TSI_INTS_IRQ6S (1<<6) -# define TSI_INTS_IRQ7S (1<<7) -# define TSI_INTS_ACFLS (1<<8) -# define TSI_INTS_SYSFLS (1<<9) -# define TSI_INTS_IACKS (1<<10) -# define TSI_INTS_VIES (1<<11) -# define TSI_INTS_VERRS (1<<12) -# define TSI_INTS_PERRS (1<<13) -# define TSI_INTS_MB0S (1<<16) -# define TSI_INTS_MB1S (1<<17) -# define TSI_INTS_MB2S (1<<18) -# define TSI_INTS_MB3S (1<<19) -# define TSI_INTS_LM0S (1<<20) -# define TSI_INTS_LM1S (1<<21) -# define TSI_INTS_LM2S (1<<22) -# define TSI_INTS_LM3S (1<<23) -# define TSI_INTS_DMA0S (1<<24) -# define TSI_INTS_DMA1S (1<<25) -#define TSI_INTC_REG 0x454 -# define TSI_INTC_ACFLC (1<<8) -# define TSI_INTC_SYSFLC (1<<9) -# define TSI_INTC_IACKC (1<<10) -# define TSI_INTC_VIEC (1<<11) -# define TSI_INTC_VERRC (1<<12) -# define TSI_INTC_PERRC (1<<13) -# define TSI_INTC_MB0C (1<<16) -# define TSI_INTC_MB1C (1<<17) -# define TSI_INTC_MB2C (1<<18) -# define TSI_INTC_MB3C (1<<19) -# define TSI_INTC_LM0C (1<<20) -# define TSI_INTC_LM1C (1<<21) -# define TSI_INTC_LM2C (1<<22) -# define TSI_INTC_LM3C (1<<23) -# define TSI_INTC_DMA0C (1<<24) -# define TSI_INTC_DMA1C (1<<25) -#define TSI_INTM1_REG 0x458 -#define TSI_INTM2_REG 0x45c - -#define TSI_CBAR_REG 0xffc - -#define TSI_CSR_OFFSET 0x7f000 - -#define TSI_CRG_SIZE (1<<12) /* 4k */ - - -#define TSI_RD(base, reg) in_be32((volatile uint32_t *)((base) + (reg)/sizeof(*base))) -#define TSI_RD16(base, reg) in_be16((volatile uint16_t *)(base) + (reg)/sizeof(uint16_t)) -#define TSI_LE_RD16(base, reg) in_le16((volatile uint16_t *)(base) + (reg)/sizeof(uint16_t)) -#define TSI_LE_RD32(base, reg) in_le32((volatile uint32_t *)(base) + (reg)/sizeof(*base)) -#define TSI_RD8(base, reg) in_8((volatile uint8_t *)(base) + (reg)) -#define TSI_WR(base, reg, val) out_be32((volatile uint32_t *)((base) + (reg)/sizeof(*base)), val) - -#define UNIV_SCTL_AM_MASK (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER) - - -/* allow the BSP to override the default routines */ -#ifndef BSP_PCI_FIND_DEVICE -#define BSP_PCI_FIND_DEVICE pci_find_device -#endif -#ifndef BSP_PCI_CONFIG_IN_LONG -#define BSP_PCI_CONFIG_IN_LONG pci_read_config_dword -#endif -#ifndef BSP_PCI_CONFIG_IN_SHORT -#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word -#endif -#ifndef BSP_PCI_CONFIG_OUT_SHORT -#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word -#endif -#ifndef BSP_PCI_CONFIG_IN_BYTE -#define BSP_PCI_CONFIG_IN_BYTE pci_read_config_byte -#endif - -typedef uint32_t pci_ulong; - -#ifdef __BIG_ENDIAN__ - static inline void st_be32( uint32_t *a, uint32_t v) - { - *a = v; - } - static inline uint32_t ld_be32( uint32_t *a ) - { - return *a; - } -#elif defined(__LITTLE_ENDIAN__) -#error "You need to implement st_be32/ld_be32" -#else -#error "Undefined endianness??" -#endif - -#ifndef BSP_LOCAL2PCI_ADDR -/* try legacy PCI_DRAM_OFFSET */ -#ifndef PCI_DRAM_OFFSET -#define PCI_DRAM_OFFSET 0 -#endif -#define BSP_LOCAL2PCI_ADDR(l) (((uint32_t)l)+PCI_DRAM_OFFSET) -#endif - -/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses. - * Should be defined by the BSP. - */ -#ifndef BSP_PCI2LOCAL_ADDR -#ifndef PCI_MEM_BASE -#define PCI_MEM_BASE 0 -#endif -#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE) -#endif - -typedef uint32_t BEValue; - -typedef struct { - BERegister *base; - int irqLine; - int pic_pin[TSI_NUM_WIRES]; -} Tsi148Dev; - -static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}}; - -#define THEBASE (devs[0].base) - -/* forward decl */ -extern int vmeTsi148RegPort; -extern int vmeTsi148RegCSR; - -/* registers should be mapped to guarded, non-cached memory; hence - * subsequent stores are ordered. eieio is only needed to enforce - * ordering of loads with respect to stores. - */ - -/* private printing wrapper */ -static void -uprintf(FILE *f, char *fmt, ...) -{ -va_list ap; - va_start(ap, fmt); - if (!f || !_impure_ptr->__sdidinit) { - /* Might be called at an early stage when - * to a buffer. - */ - vprintk(fmt,ap); - } else - { - vfprintf(f,fmt,ap); - } - va_end(ap); -} - -#define CHECK_BASE(base,quiet,rval) \ - do { \ - if ( !base ) { \ - if ( !quiet ) { \ - uprintf(stderr,"Tsi148: Driver not initialized\n"); \ - } \ - return rval; \ - } \ - } while (0) - -int -vmeTsi148FindPciBase( - int instance, - BERegister **pbase - ) -{ -int bus,dev,fun; -pci_ulong busaddr; -unsigned char irqline; -unsigned short wrd; - - if (BSP_PCI_FIND_DEVICE( - PCI_VENDOR_TUNDRA, - PCI_DEVICE_TSI148, - instance, - &bus, - &dev, - &fun)) - return -1; - if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr)) - return -1; - /* Assume upper BAR is zero */ - - *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff); - - if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline)) - return -1; - - /* Enable PCI master and memory access */ - BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd); - BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - - return irqline; -} - -int -vmeTsi148InitInstance(unsigned instance) -{ -int irq; -BERegister *base; - - if ( instance >= NUM_TSI_DEVS ) - return -1; - if ( devs[instance].base ) - return -1; - - if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) { - uprintf(stderr,"unable to find a Tsi148 in pci config space\n"); - } else { - uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n", - (unsigned int)base, irq); - } - devs[0].base = base; - devs[0].irqLine = irq; - - return irq < 0 ? -1 : 0; -} - -int -vmeTsi148Init(void) -{ - return vmeTsi148InitInstance(0); -} - - -void -vmeTsi148ResetXX(BERegister *base) -{ -int port; -uint32_t v; - - CHECK_BASE(base,0, ); - - vmeTsi148DisableAllOutboundPortsXX(base); - for ( port=0; port < TSI148_NUM_OPORTS; port++ ) - TSI_WR(base, TSI_OTBS_REG(port), 0); - TSI_WR(base, TSI_INTEO_REG, 0); - TSI_WR(base, TSI_INTEN_REG, 0); - TSI_WR(base, TSI_INTC_REG, 0xffffffff); - TSI_WR(base, TSI_INTM1_REG, 0); - TSI_WR(base, TSI_INTM2_REG, 0); - TSI_WR(base, TSI_VICR_REG, 0); - TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL); - /* Clear BDFAIL / (--> SYSFAIL) */ -# define TSI_VSTAT_BDFAIL (1<<14) - TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL); - /* Set (long) bus master timeout; the timeout actually overrides - * the DMA block size so that the DMA settings would effectively - * not be used. - * Also, we enable 'release on request' mode so that we normally - * don't have to rearbitrate the bus for every transfer. - */ - v = TSI_RD(base, TSI_VMCTRL_REG); - v &= ~( TSI_VMCTRL_VTON_MSK | TSI_VMCTRL_VREL_MSK ); - v |= (TSI_VMCTRL_VTON_512us | TSI_VMCTRL_VREL_TONorDONE_and_REQ ); - TSI_WR(base, TSI_VMCTRL_REG, v); -} - -void -vmeTsi148Reset(void) -{ - vmeTsi148ResetXX(THEBASE); -} - -void -vmeTsi148ResetBusXX(BERegister *base) -{ -unsigned long flags; -uint32_t v; - - rtems_interrupt_disable(flags); - v = TSI_RD(base, TSI_VCTRL_REG); - TSI_WR(base, TSI_VCTRL_REG, v | TSI_VCTRL_SRESET); - rtems_interrupt_enable(flags); -} - -void -vmeTsi148ResetBus(void) -{ - vmeTsi148ResetBusXX(THEBASE); -} - - -/* convert an address space selector to a corresponding - * Tsi148 control mode word - */ - -static unsigned long ck2esst(unsigned long am) -{ - if ( VME_AM_IS_2eSST(am) ) { - /* make sure 2eVME is selected */ - am &= ~VME_AM_MASK; - am |= VME_AM_2eVME_6U; - } - return am; -} - -static int -am2omode(unsigned long address_space, unsigned long *pmode) -{ -unsigned long mode = 0; -unsigned long tm = TSI_TM_SCT_IDX; - - switch ( VME_MODE_DBW_MSK & address_space ) { - case VME_MODE_DBW8: - return -1; /* unsupported */ - - case VME_MODE_DBW16: - break; - - default: - case VME_MODE_DBW32: - mode |= TSI_OTAT_DBW(1); - break; - } - - if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) ) - mode |= TSI_OTAT_MRPFD; - else { - mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ); - } - - address_space = ck2esst(address_space); - - switch (address_space & VME_AM_MASK) { - case VME_AM_STD_SUP_PGM: - case VME_AM_STD_USR_PGM: - - mode |= TSI_OTAT_PGM; - - /* fall thru */ - case VME_AM_STD_SUP_BLT: - case VME_AM_STD_SUP_MBLT: - - case VME_AM_STD_USR_BLT: - case VME_AM_STD_USR_MBLT: - switch ( address_space & 3 ) { - case 0: tm = TSI_TM_MBLT_IDX; break; - case 3: tm = TSI_TM_BLT_IDX; break; - default: break; - } - - case VME_AM_STD_SUP_DATA: - case VME_AM_STD_USR_DATA: - - mode |= TSI_OTAT_ADMODE_A24; - break; - - case VME_AM_EXT_SUP_PGM: - case VME_AM_EXT_USR_PGM: - mode |= TSI_OTAT_PGM; - - /* fall thru */ - case VME_AM_EXT_SUP_BLT: - case VME_AM_EXT_SUP_MBLT: - - case VME_AM_EXT_USR_BLT: - case VME_AM_EXT_USR_MBLT: - switch ( address_space & 3 ) { - case 0: tm = TSI_TM_MBLT_IDX; break; - case 3: tm = TSI_TM_BLT_IDX; break; - default: break; - } - - case VME_AM_EXT_SUP_DATA: - case VME_AM_EXT_USR_DATA: - - mode |= TSI_OTAT_ADMODE_A32; - break; - - case VME_AM_SUP_SHORT_IO: - case VME_AM_USR_SHORT_IO: - mode |= TSI_OTAT_ADMODE_A16; - break; - - case VME_AM_CSR: - mode |= TSI_OTAT_ADMODE_CSR; - break; - - case VME_AM_2eVME_6U: - case VME_AM_2eVME_3U: - mode |= TSI_OTAT_ADMODE_A32; - if ( VME_AM_IS_2eSST(address_space) ) { - tm = ( VME_AM_2eSST_BCST & address_space ) ? - TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX; - switch ( VME_AM_IS_2eSST(address_space) ) { - default: - case VME_AM_2eSST_LO: mode |= TSI_OTAT_2eSSTM_160; break; - case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break; - case VME_AM_2eSST_HI: mode |= TSI_OTAT_2eSSTM_320; break; - } - } else { - tm = TSI_TM_2eVME_IDX; - } - break; - - case 0: /* disable the port alltogether */ - break; - - default: - return -1; - } - - mode |= TSI_OTAT_TM(tm); - - if ( VME_AM_IS_SUP(address_space) ) - mode |= TSI_OTAT_SUP; - *pmode = mode; - return 0; -} - -static int -am2imode(unsigned long address_space, unsigned long *pmode) -{ -unsigned long mode=0; -unsigned long pgm = 0; - - mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ); - - if ( VME_AM_IS_2eSST(address_space) ) { - mode |= TSI_ITAT_2eSST; - if ( VME_AM_2eSST_BCST & address_space ) - mode |= TSI_ITAT_2eSSTB; - switch ( VME_AM_IS_2eSST(address_space) ) { - default: - case VME_AM_2eSST_LO: mode |= TSI_ITAT_2eSSTM_160; break; - case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break; - case VME_AM_2eSST_HI: mode |= TSI_ITAT_2eSSTM_320; break; - } - address_space = ck2esst(address_space); - } - - mode |= TSI_ITAT_BLT; - mode |= TSI_ITAT_MBLT; - - mode |= TSI_ITAT_PGM; /* always allow PGM access */ - mode |= TSI_ITAT_USR; /* always allow USR access */ - - switch (address_space & VME_AM_MASK) { - case VME_AM_STD_SUP_PGM: - case VME_AM_STD_USR_PGM: - - pgm = 1; - - /* fall thru */ - case VME_AM_STD_SUP_BLT: - case VME_AM_STD_SUP_MBLT: - case VME_AM_STD_USR_BLT: - case VME_AM_STD_USR_MBLT: - case VME_AM_STD_SUP_DATA: - case VME_AM_STD_USR_DATA: - - mode |= TSI_ITAT_ADMODE_A24; - break; - - case VME_AM_EXT_SUP_PGM: - case VME_AM_EXT_USR_PGM: - pgm = 1; - - /* fall thru */ - case VME_AM_2eVME_6U: - case VME_AM_2eVME_3U: - case VME_AM_EXT_SUP_BLT: - case VME_AM_EXT_SUP_MBLT: - case VME_AM_EXT_USR_BLT: - case VME_AM_EXT_USR_MBLT: - case VME_AM_EXT_SUP_DATA: - case VME_AM_EXT_USR_DATA: - mode |= TSI_ITAT_ADMODE_A32; - break; - - case VME_AM_SUP_SHORT_IO: - case VME_AM_USR_SHORT_IO: - mode |= TSI_ITAT_ADMODE_A16; - break; - - case 0: /* disable the port alltogether */ - *pmode = 0; - return 0; - - default: - return -1; - } - - if ( VME_AM_IS_SUP(address_space) ) - mode |= TSI_ITAT_SUP; - - if ( !pgm ) - mode |= TSI_ITAT_DATA; - - *pmode = mode; - return 0; -} - -static void -readTriple( - BERegister *base, - unsigned reg, - unsigned long long *ps, - unsigned long long *pl, - unsigned long long *po) -{ - *ps = TSI_RD(base, reg); - *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000); - *pl = TSI_RD(base, (reg+8)); - *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000); - *po = TSI_RD(base, (reg+0x10)); - *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000); -} - - -static unsigned long -inboundGranularity(unsigned long itat) -{ - switch ( itat & TSI_ITAT_AS(-1) ) { - case TSI_ITAT_ADMODE_A16: return 0xf; - case TSI_ITAT_ADMODE_A24: return 0xfff; - default: - break; - } - return 0xffff; -} - -static int -configTsiPort( - BERegister *base, - int isout, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long pci_address, - unsigned long length) -{ -unsigned long long start, limit, offst; -unsigned long mode, mask, tat_reg, tsau_reg; -char *name = (isout ? "Outbound" : "Inbound"); -int i,s,l; - - CHECK_BASE(base,0,-1); - - mode = 0; /* silence warning */ - - if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) { - uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name); - return -1; - } - - if ( base == THEBASE && isout && vmeTsi148RegPort == port ) { - uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name); - return -1; - } - - if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) { - uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name); - return -1; - } - - - if ( isout ) { - start = pci_address; - offst = (unsigned long long)vme_address - start; - mask = 0xffff; - tat_reg = TSI_OTAT_REG(port); - tsau_reg = TSI_OTSAU_REG(port); - mode |= TSI_OTAT_EN; - - /* check for overlap */ - for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) { - /* ignore 'this' port */ - if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) ) - continue; - - /* check requested PCI range against current port 'i' config */ - s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */ - l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */ - if ( ! ( start + length <= s || start > s + l ) ) { - uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l); - return -1; - } - } - } else { - start = vme_address; - offst = (unsigned long long)pci_address - start; - mask = inboundGranularity(mode); - tat_reg = TSI_ITAT_REG(port); - tsau_reg = TSI_ITSAU_REG(port); - mode |= TSI_ITAT_EN; - - /* check for overlap */ - for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) { - /* ignore 'this' port */ - if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) ) - continue; - - if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) { - /* different address space */ - continue; - } - - if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) { - /* orthogonal privileges */ - continue; - } - - /* check requested VME range against current port 'i' config */ - s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */ - l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */ - if ( ! ( start + length <= s || start > s + l ) ) { - uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l); - return -1; - } - } - } - - /* If they pass 'length==0' just disable */ - if ( 0 == length ) { - TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN)); - return 0; - } - - - if ( (vme_address & mask) - || (pci_address & mask) - || (length & mask) ) { - uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n", - name, - mask+1); - return -1; - } - - limit = start + length - 1; - - if ( limit >= (unsigned long long)1<<32 ) { - uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name); - return -1; - } - - /* Disable port */ - TSI_WR(base, tat_reg, 0); - - /* Force to 32-bits */ - TSI_WR(base, tsau_reg , 0); - TSI_WR(base, tsau_reg + 0x04, (uint32_t)start); - TSI_WR(base, tsau_reg + 0x08, 0); - TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit); - TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32)); - TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst); - - /* (outbound only:) leave 2eSST broadcast register alone for user to program */ - - /* Set mode and enable */ - TSI_WR(base, tat_reg, mode); - return 0; -} - -static int -disableTsiPort( - BERegister *base, - int isout, - unsigned long port) -{ - return configTsiPort(base, isout, port, 0, 0, 0, 0); -} - -int -vmeTsi148InboundPortCfgXX( - BERegister *base, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long pci_address, - unsigned long length) -{ - return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length); -} - -int -vmeTsi148InboundPortCfg( - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long pci_address, - unsigned long length) -{ - return configTsiPort(THEBASE, 0, port, address_space, vme_address, pci_address, length); -} - - -int -vmeTsi148OutboundPortCfgXX( - BERegister *base, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long pci_address, - unsigned long length) -{ - return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length); -} - -int -vmeTsi148OutboundPortCfg( - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long pci_address, - unsigned long length) -{ - return configTsiPort(THEBASE, 1, port, address_space, vme_address, pci_address, length); -} - - -static int -xlateFindPort( - BERegister *base, /* TSI 148 base address */ - int outbound, /* look in the outbound windows */ - int reverse, /* reverse mapping; for outbound ports: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ -unsigned long mode, mode_msk; -int port; -unsigned long long start, limit, offst, a; -unsigned long tsau_reg, tat_reg, gran, skip; - - CHECK_BASE(base,0,-1); - - mode = 0; /* silence warning */ - - switch ( as & VME_MODE_MATCH_MASK ) { - case VME_MODE_EXACT_MATCH: - mode_msk = ~0; - break; - - case VME_MODE_AS_MATCH: - if ( outbound ) - mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN; - else - mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN; - break; - - default: - if ( outbound ) - mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN; - else - mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN; - break; - } - - as &= ~VME_MODE_MATCH_MASK; - - if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) { - uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument"); - return -2; - } - - if (outbound ) { - tsau_reg = TSI_OTSAU_REG(0); - tat_reg = TSI_OTAT_REG(0); - skip = TSI_OTSAU_SPACING; - mode |= TSI_OTAT_EN; - gran = 0x10000; - } else { - tsau_reg = TSI_ITSAU_REG(0); - tat_reg = TSI_ITAT_REG(0); - skip = TSI_ITSAU_SPACING; - mode |= TSI_ITAT_EN; - gran = inboundGranularity(mode) + 1; - } - - for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) { - - if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) { - - /* found a window with of the right mode; now check the range */ - readTriple(base, tsau_reg, &start, &limit, &offst); - limit += gran; - - if ( !reverse ) { - start += offst; - limit += offst; - offst = -offst; - } - a = aIn; - if ( aIn >= start && aIn <= limit ) { - /* found it */ - *paOut = (unsigned long)(a + offst); - return port; - } - } - } - - uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n"); - return -1; -} - -int -vmeTsi148XlateAddrXX( - BERegister *base, /* TSI 148 base address */ - int outbound, /* look in the outbound windows */ - int reverse, /* reverse mapping; for outbound ports: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ -int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut ); - return port < 0 ? -1 : 0; -} - -int -vmeTsi148XlateAddr( - int outbound, /* look in the outbound windows */ - int reverse, /* reverse mapping; for outbound ports: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ - return vmeTsi148XlateAddrXX(THEBASE, outbound, reverse, as, aIn, paOut); -} - - -/* printk cannot format %llx */ -static void uprintfllx(FILE *f, unsigned long long v) -{ - if ( v >= ((unsigned long long)1)<<32 ) - uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff)); - else - uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff)); -} - -void -vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f) -{ -int port; -unsigned long mode; -char tit = 0; - -unsigned long long start, limit, offst; - - CHECK_BASE(base,0, ); - - if (!f) f=stdout; - uprintf(f,"Tsi148 Outbound Ports:\n"); - - for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) { - mode = TSI_RD(base, TSI_OTAT_REG(port)); - if ( ! (TSI_OTAT_EN & mode) ) - continue; /* skip disabled ports */ - - readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst); - - /* convert limit to size */ - limit = limit-start+0x10000; - if ( !tit ) { - uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n"); - tit = 1; - } - uprintf(f,"%d: ", port); - uprintfllx(f,start+offst); - uprintfllx(f,limit); - uprintfllx(f,start); - switch( mode & TSI_OTAT_ADMODE(-1) ) { - case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break; - case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break; - case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break; - case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break; - case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break; - default: uprintf(f,"A??"); break; - } - - if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM"); - if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP"); - if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH"); - - switch ( mode & TSI_OTAT_DBW(-1) ) { - case TSI_OTAT_DBW(0): uprintf(f,", D16"); break; - case TSI_OTAT_DBW(1): uprintf(f,", D32"); break; - default: uprintf(f,", D??"); break; - } - - switch( mode & TSI_OTAT_TM(-1) ) { - case TSI_OTAT_TM(0): uprintf(f,", SCT"); break; - case TSI_OTAT_TM(1): uprintf(f,", BLT"); break; - case TSI_OTAT_TM(2): uprintf(f,", MBLT"); break; - case TSI_OTAT_TM(3): uprintf(f,", 2eVME"); break; - case TSI_OTAT_TM(4): uprintf(f,", 2eSST"); break; - case TSI_OTAT_TM(5): uprintf(f,", 2eSST_BCST"); break; - default: uprintf(f," TM??"); break; - } - - uprintf(f,"\n"); - } -} - -void -vmeTsi148OutboundPortsShow(FILE *f) -{ - vmeTsi148OutboundPortsShowXX(THEBASE, f); -} - -void -vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f) -{ -int port; -unsigned long mode; -char tit = 0; - -unsigned long long start, limit, offst; - - CHECK_BASE(base,0, ); - - if (!f) f=stdout; - uprintf(f,"Tsi148 Inbound Ports:\n"); - - for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) { - mode = TSI_RD(base, TSI_ITAT_REG(port)); - if ( ! (TSI_ITAT_EN & mode) ) - continue; /* skip disabled ports */ - - readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst); - - /* convert limit to size */ - limit = limit - start + inboundGranularity(mode) + 1; - if ( !tit ) { - uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n"); - tit = 1; - } - uprintf(f,"%d: ", port); - uprintfllx(f,start); - uprintfllx(f,limit); - uprintfllx(f,start+offst); - switch( mode & TSI_ITAT_AS(-1) ) { - case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break; - case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break; - case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break; - case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break; - default: uprintf(f,"A??"); break; - } - - if ( mode & TSI_ITAT_PGM ) uprintf(f,", PGM"); - if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT"); - if ( mode & TSI_ITAT_SUP ) uprintf(f,", SUP"); - if ( mode & TSI_ITAT_USR ) uprintf(f,", USR"); - - if ( mode & TSI_ITAT_2eSSTB ) uprintf(f,", 2eSSTB"); - if ( mode & TSI_ITAT_2eSST ) uprintf(f,", 2eSST"); - if ( mode & TSI_ITAT_2eVME ) uprintf(f,", 2eVME"); - if ( mode & TSI_ITAT_MBLT ) uprintf(f,", MBLT"); - if ( mode & TSI_ITAT_BLT ) uprintf(f,", BLT"); - - uprintf(f,"\n"); - } -} - -void -vmeTsi148InboundPortsShow(FILE *f) -{ - vmeTsi148InboundPortsShowXX(THEBASE, f); -} - - -void -vmeTsi148DisableAllInboundPortsXX(BERegister *base) -{ -int port; - - for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) - if ( disableTsiPort(base, 0, port) ) - break; -} - -void -vmeTsi148DisableAllInboundPorts(void) -{ - vmeTsi148DisableAllInboundPortsXX(THEBASE); -} - -void -vmeTsi148DisableAllOutboundPortsXX(BERegister *base) -{ -int port; - - for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) - if ( disableTsiPort(base, 1, port) ) - break; -} - -void -vmeTsi148DisableAllOutboundPorts(void) -{ - vmeTsi148DisableAllOutboundPortsXX(THEBASE); -} - - -/* Map internal register block to VME */ - -int -vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as ) -{ -uint32_t mode; - - CHECK_BASE( b, 0, -1 ); - - if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) { - uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n"); - return -1; - } - - /* enable all, SUP/USR/PGM/DATA accesses */ - mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM | TSI_CRGAT_DATA; - - if ( VME_AM_IS_SHORT(as) ) { - mode |= TSI_CRGAT_A16; - } else - if ( VME_AM_IS_STD(as) ) { - mode |= TSI_CRGAT_A24; - } else - if ( VME_AM_IS_EXT(as) ) { - mode |= TSI_CRGAT_A32; - } else { - return -2; - } - - /* map CRG to VME bus */ - TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1))); - TSI_WR( b, TSI_CRGAT_REG, mode ); - - return 0; -} - -int -vmeTsi148MapCRG(uint32_t vme_base, uint32_t as ) -{ - return vmeTsi148MapCRGXX( THEBASE, vme_base, as ); -} - -/* Interrupt Subsystem */ - -typedef struct -IRQEntryRec_ { - VmeTsi148ISR isr; - void *usrData; -} IRQEntryRec, *IRQEntry; - -static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0}; - -int vmeTsi148IrqMgrInstalled = 0; -int vmeTsi148RegPort = -1; -int vmeTsi148RegCSR = 0; -BERegister *vmeTsi148RegBase = 0; - -static volatile unsigned long wire_mask[TSI_NUM_WIRES] = {0}; -/* wires are offset by 1 so we can initialize the wire table to all zeros */ -static int tsi_wire[TSI_NUM_WIRES] = {0}; - -/* how should we iack a given level, 1,2,4 bytes? */ -static unsigned char tsi_iack_width[7] = { - 1,1,1,1,1,1,1 -}; - -/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */ -static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = { - /* 256 no VOWN interrupt */ -1, - /* TSI_DMA_INT_VEC 257 */ 256 + 24 - 8, - /* TSI_LERR_INT_VEC 258 */ 256 + 13 - 8, - /* TSI_VERR_INT_VEC 259 */ 256 + 12 - 8, - /* 260 is reserved */ -1, - /* TSI_VME_SW_IACK_INT_VEC 261 */ 256 + 10 - 8, - /* 262 no PCI SW IRQ */ -1, - /* TSI_SYSFAIL_INT_VEC 263 */ 256 + 9 - 8, - /* TSI_ACFAIL_INT_VEC 264 */ 256 + 8 - 8, - /* TSI_MBOX0_INT_VEC 265 */ 256 + 16 - 8, - /* TSI_MBOX1_INT_VEC 266 */ 256 + 17 - 8, - /* TSI_MBOX2_INT_VEC 267 */ 256 + 18 - 8, - /* TSI_MBOX3_INT_VEC 268 */ 256 + 19 - 8, - /* TSI_LM0_INT_VEC 269 */ 256 + 20 - 8, - /* TSI_LM1_INT_VEC 270 */ 256 + 21 - 8, - /* TSI_LM2_INT_VEC 271 */ 256 + 22 - 8, - /* TSI_LM3_INT_VEC 272 */ 256 + 23 - 8, -/* New vectors; only on TSI148 */ - /* TSI_VIES_INT_VEC 273 */ 256 + 11 - 8, - /* TSI_DMA1_INT_VEC 274 */ 256 + 25 - 8, -}; - -/* and the reverse; map tsi bit number to universe compatible 'special' vector number */ -static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = { - TSI_ACFAIL_INT_VEC, - TSI_SYSFAIL_INT_VEC, - TSI_VME_SW_IACK_INT_VEC, - TSI_VIES_INT_VEC, - TSI_VERR_INT_VEC, - TSI_LERR_INT_VEC, - -1, - -1, - TSI_MBOX0_INT_VEC, - TSI_MBOX1_INT_VEC, - TSI_MBOX2_INT_VEC, - TSI_MBOX3_INT_VEC, - TSI_LM0_INT_VEC, - TSI_LM1_INT_VEC, - TSI_LM2_INT_VEC, - TSI_LM3_INT_VEC, - TSI_DMA_INT_VEC, - TSI_DMA1_INT_VEC, - -1, -}; - -static inline int -uni2tsivec(int v) -{ - if ( v < 0 || v >= TSI_NUM_INT_VECS ) - return -1; - return v < 256 ? v : uni2tsi_vec_map[v-256]; -} - -static int -lvl2bitno(unsigned int level) -{ - if ( level >= 256 ) - return uni2tsivec(level) + 8 - 256; - else if ( level < 8 && level > 0 ) - return level; - return -1; -} - -int -vmeTsi148IntRoute(unsigned int level, unsigned int pin) -{ -int i; -unsigned long mask, shift, mapreg, flags, wire; - - if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled ) - return -1; - - if ( level >= 256 ) { - if ( (i = uni2tsivec(level)) < 0 ) - return -1; - shift = 8 + (i-256); - } else if ( 1 <= level && level <=7 ) { - shift = level; - } else { - return -1; /* invalid level */ - } - - mask = 1<<shift; - - /* calculate the mapping register and contents */ - if ( shift < 16 ) { - mapreg = TSI_INTM2_REG; - } else if ( shift < 32 ) { - shift -= 16; - mapreg = TSI_INTM1_REG; - } else { - return -1; - } - - shift <<=1; - - /* wires are offset by 1 so we can initialize the wire table to all zeros */ - wire = (tsi_wire[pin]-1) << shift; - -rtems_interrupt_disable(flags); - - for ( i = 0; i<TSI_NUM_WIRES; i++ ) { - wire_mask[i] &= ~mask; - } - wire_mask[pin] |= mask; - - mask = TSI_RD(THEBASE, mapreg) & ~ (0x3<<shift); - mask |= wire; - TSI_WR( THEBASE, mapreg, mask ); - -rtems_interrupt_enable(flags); - return 0; -} - -VmeTsi148ISR -vmeTsi148ISRGet(unsigned long vector, void **parg) -{ -VmeTsi148ISR rval = 0; -unsigned long flags; -volatile IRQEntry *p; -int v = uni2tsivec(vector); - - - if ( v < 0 ) - return rval; - - p = irqHdlTbl + v; - - rtems_interrupt_disable(flags); - if ( *p ) { - if ( parg ) - *parg = (*p)->usrData; - rval = (*p)->isr; - } - rtems_interrupt_enable(flags); - - return rval; -} - -static void -tsiVMEISR(rtems_irq_hdl_param arg) -{ -int pin = (int)arg; -BERegister *b = THEBASE; -IRQEntry ip; -unsigned long msk,lintstat,vector, vecarg; -int lvl; - - /* only handle interrupts routed to this pin */ - - /* NOTE: we read the status register over VME, thus flushing the FIFO - * where the user ISR possibly left write commands to clear - * the interrupt condition at the device. - * This is very important - otherwise, the IRQ level may still be - * asserted and we would detect an interrupt here but the subsequent - * IACK would fail since the write operation was flushed to the - * device in the mean time. - */ - while ( (lintstat = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) { - - /* bit 0 is never set since it is never set in wire_mask */ - - do { - /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */ -#ifdef __PPC__ - asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat)); - lvl = 31-lvl; - msk = 1<<lvl; -#else - { static unsigned long m[] = { - 0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa - }; - int i; - unsigned tmp; - - /* lintstat has already been checked... - if ( !lintstat ) { - lvl = -1; msk = 0; - } else - */ - for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) { - lvl <<= 1; - if ( (tmp = msk & m[i]) ) { - lvl++; - msk = tmp; - } else - msk = msk & ~m[i]; - } - } -#endif - - if ( lvl > 7 ) { - /* clear this interrupt level */ - TSI_WR(b, TSI_INTC_REG, msk); - vector = 256 + lvl - 8; - vecarg = tsi2uni_vec_map[lvl-8]; - } else { - /* need to do get the vector for this level */ - switch ( tsi_iack_width[lvl-1] ) { - default: - case 1: - vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3); - break; - - case 2: - vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2); - break; - - case 4: - vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2)); - break; - } - vecarg = vector; - } - - if ( !(ip=irqHdlTbl[vector])) { - /* TODO: log error message - RTEMS has no logger :-( */ - vmeTsi148IntDisable(lvl); - printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08lx -- DISABLING level %i\n", - lvl, vector, lvl); - } else { - /* dispatch handler, it must clear the IRQ at the device */ - ip->isr(ip->usrData, vecarg); - /* convenience for disobedient users who don't use in_xxx/out_xxx; make - * sure we order the subsequent read from the status register after - * their business. - */ - iobarrier_rw(); - } - } while ( (lintstat &= ~msk) ); - /* check if a new irq is pending already */ - } -} - - -static void -my_no_op(const rtems_irq_connect_data * arg) -{} - -static int -my_isOn(const rtems_irq_connect_data *arg) -{ - return (int)(TSI_RD(THEBASE, TSI_INTEO_REG) & TSI_RD(THEBASE, TSI_INTEN_REG)); -} - -static void -connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot) -{ -rtems_irq_connect_data xx; - xx.on = my_no_op; /* at _least_ they could check for a 0 pointer */ - xx.off = my_no_op; - xx.isOn = my_isOn; - xx.hdl = isr; - xx.handle = (rtems_irq_hdl_param)slot; - xx.name = pic_line; - - if ( shared ) { -#if BSP_SHARED_HANDLER_SUPPORT > 0 - if (!BSP_install_rtems_shared_irq_handler(&xx)) - rtems_panic("unable to install vmeTsi148 shared irq handler"); -#else - uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n"); - if (!BSP_install_rtems_irq_handler(&xx)) - rtems_panic("unable to install vmeTsi148 irq handler"); -#endif - } else { - if (!BSP_install_rtems_irq_handler(&xx)) - rtems_panic("unable to install vmeTsi148 irq handler"); - } -} - -int -vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...) -{ -int rval; -va_list ap; - va_start(ap, pic_pin0); - rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap); - va_end(ap); - return rval; -} - -#ifndef BSP_EARLY_PROBE_VME -#define BSP_EARLY_PROBE_VME(addr) \ - ( \ - vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ), \ - ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 ) \ - && 0 == vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ) ) \ - ) -#endif - -/* Check if there is a vme address/as is mapped in any of the outbound windows - * and look for the PCI vendordevice ID there. - * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7) - * on success. Address translated into CPU address is returned in *pcpu_addr. - */ -static int -mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr) -{ -int j; -char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG"; - - /* try to find mapping */ - if ( 0 > (j = xlateFindPort( - THEBASE, - 1, 0, - as | VME_MODE_AS_MATCH, - vme_addr, - pcpu_addr ) ) ) { - uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr); - uprintf(stderr," in outbound windows.\n"); - } - else { - /* found a slot number; probe it */ - *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr ); - if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) { - uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype); - return j; - } else { - uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype); - } - } - return -1; -} - -int -vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap) -{ -int i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES]; -unsigned long cpu_base, vme_reg_base; - - if (vmeTsi148IrqMgrInstalled) return -4; - - /* check parameters */ - - if ( tsi_pin0 < 0 || tsi_pin0 > 3 ) return -1; - - tsi_pin[0] = tsi_pin0; - pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0; - i = 1; - while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) { - - if ( i >= TSI_NUM_WIRES ) { - return -5; - } - - pic_pin[i] = va_arg(ap,int); - - if ( tsi_pin[i] > 3 ) return -2; - if ( pic_pin[i] < 0 ) return -3; - i++; - } - - /* all routings must be different */ - for ( i=0; tsi_pin[i] >= 0; i++ ) { - for ( j=i+1; tsi_pin[j] >= 0; j++ ) { - if ( tsi_pin[j] == tsi_pin[i] ) return -6; - if ( pic_pin[j] == pic_pin[i] ) return -7; - } - } - - i = -1; - - /* first try VME CSR space; do we have a base address set ? */ - - uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n"); - - if ( ( i = ((TSI_RD( THEBASE, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) { - uprintf(stderr,"Trying to find CSR on VME...\n"); - vme_reg_base = i*0x80000 + TSI_CSR_OFFSET; - i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base); - if ( i >= 0 ) - vmeTsi148RegCSR = 1; - } else { - i = -1; - } - - if ( -1 == i ) { - - uprintf(stderr,"Trying to find CRG on VME...\n"); - - /* Next we see if the CRG block is mapped to VME */ - - if ( (TSI_CRGAT_EN & (j = TSI_RD( THEBASE, TSI_CRGAT_REG ))) ) { - switch ( j & TSI_CRGAT_AS_MSK ) { - case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break; - case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break; - case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break; - default: - break; - } - vme_reg_base = TSI_RD( THEBASE, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1); - } - - if ( -1 == i ) { - } else { - i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base ); - } - } - - if ( i < 0 ) { - uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n"); - uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n"); - uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n"); - uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n"); - cpu_base = (unsigned long)THEBASE; - i = -1; - } - - vmeTsi148RegBase = (BERegister*)cpu_base; - vmeTsi148RegPort = i; - - /* give them a chance to override buggy PCI info */ - if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) { - uprintf(stderr,"Overriding main IRQ line PCI info with %d\n", - pic_pin[0]); - devs[0].irqLine = pic_pin[0]; - } - - for ( i = 0; tsi_pin[i] >= 0; i++ ) { - /* offset wire # by one so we can initialize to 0 == invalid */ - tsi_wire[i] = tsi_pin[i] + 1; - connectIsr(shared, tsiVMEISR, pic_pin[i], i); - } - - specialPin = tsi_pin[1] >= 0 ? 1 : 0; - - /* setup routing */ - - /* IntRoute checks for mgr being installed */ - vmeTsi148IrqMgrInstalled=1; - - /* route 7 VME irqs to first / 'normal' pin */ - for ( i=1; i<8; i++ ) - vmeTsi148IntRoute( i, 0 ); - for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ ) - vmeTsi148IntRoute( i, specialPin ); - - for ( i = 0; i<TSI_NUM_WIRES; i++ ) { - /* remember (for unloading the driver) */ - devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 ); - } - - return 0; -} - -int -vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg) -{ -IRQEntry ip; -int v; -unsigned long flags; -volatile IRQEntry *p; - - if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 ) - return -1; - - p = irqHdlTbl + v; - - if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec)))) - return -1; - - ip->isr=hdl; - ip->usrData=arg; - - rtems_interrupt_disable(flags); - if (*p) { - rtems_interrupt_enable(flags); - free(ip); - return -1; - } - *p = ip; - rtems_interrupt_enable(flags); - return 0; -} - -int -vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg) -{ -int v; -IRQEntry ip; -unsigned long flags; -volatile IRQEntry *p; - - if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 ) - return -1; - - p = irqHdlTbl + v; - - rtems_interrupt_disable(flags); - ip = *p; - if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) { - rtems_interrupt_enable(flags); - return -1; - } - *p = 0; - rtems_interrupt_enable(flags); - - free(ip); - return 0; -} - -static int -intDoEnDis(unsigned int level, int dis) -{ -BERegister *b = THEBASE; -unsigned long flags, v; -int shift; - - if ( ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 ) - return -1; - - v = 1<<shift; - - if ( !dis ) - return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0; - - rtems_interrupt_disable(flags); - if ( dis<0 ) { - TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v); - TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v); - } else { - TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) | v); - TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) | v); - } - rtems_interrupt_enable(flags); - return 0; -} - -int -vmeTsi148IntEnable(unsigned int level) -{ - return intDoEnDis(level, 1); -} - -int -vmeTsi148IntDisable(unsigned int level) -{ - return intDoEnDis(level, -1); -} - -int -vmeTsi148IntIsEnabled(unsigned int level) -{ - return intDoEnDis(level, 0); -} - -/* Set IACK width (1,2, or 4 bytes) for a given interrupt level. - * - * 'width' arg may be 0,1,2 or 4. If zero, the currently active - * value is returned but not modified. - * - * RETURNS: old width or -1 if invalid argument. - */ - -int -vmeTsi148SetIackWidth(int level, int width) -{ -int rval; - if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled ) - return -1; - - switch ( width ) { - default: return -1; - case 0: - case 1: - case 2: - case 4: - break; - } - - rval = tsi_iack_width[level-1]; - if ( width ) - tsi_iack_width[level-1] = width; - return rval; -} - -int -vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector) -{ -unsigned long v; - - CHECK_BASE(base,0,-1); - - if ( level < 1 || level > 7 || vector > 255 ) - return -1; /* invalid argument */ - - /* Check if already asserted */ - if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) { - return -2; /* already asserted */ - } - - v &= ~255; - - v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector); - - /* Write Vector */ - TSI_WR(base, TSI_VICR_REG, v); - - return 0; - -} - -int -vmeTsi148IntRaise(int level, unsigned vector) -{ - return vmeTsi148IntRaiseXX(THEBASE, level, vector); -} - -/* Loopback test of VME/Tsi148 internal interrupts */ - -typedef struct { - rtems_id q; - int l; -} LoopbackTstArgs; - -static void -loopbackTstIsr(void *arg, unsigned long vector) -{ -LoopbackTstArgs *pa = arg; - if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) { - /* Overrun ? */ - printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l); - vmeTsi148IntDisable(pa->l); - } -} - -int -vmeTsi148IntLoopbackTst(int level, unsigned vector) -{ -BERegister *b = THEBASE; -rtems_status_code sc; -rtems_id q = 0; -int installed = 0; -int i, err = 0; -int doDisable = 0; -size_t size; -unsigned long msg; -char * irqfmt = "VME IRQ @vector %3i %s"; -char * iackfmt = "VME IACK %s"; -LoopbackTstArgs a; - - CHECK_BASE(b,0,-1); - - /* arg check */ - if ( level < 1 || level > 7 || vector > 255 ) - return -1; - - /* Create message queue */ - if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create( - rtems_build_name('t' ,'U','I','I'), - 4, - sizeof(unsigned long), - 0, /* default attributes: fifo, local */ - &q)) ) { - rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue"); - goto bail; - } - - a.q = q; - a.l = level; - - /* Install handlers */ - if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) { - uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector); - goto bail; - } - installed++; - if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) { - uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC); - goto bail; - } - installed++; - - if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) ) - doDisable = 1; - - /* make sure there are no pending interrupts */ - TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC); - - if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) { - uprintf(stderr,"Unable to enable IACK interrupt\n"); - goto bail; - } - - printf("vmeTsi148 VME interrupt loopback test; STARTING...\n"); - printf(" --> asserting VME IRQ level %i\n", level); - vmeTsi148IntRaise(level, vector); - - for ( i = 0; i< 3; i++ ) { - sc = rtems_message_queue_receive( - q, - &msg, - &size, - RTEMS_WAIT, - 20); - if ( sc ) { - if ( RTEMS_TIMEOUT == sc && i>1 ) { - /* OK; we dont' expect more to happen */ - sc = 0; - } else { - rtems_error(sc,"Error waiting for interrupts"); - } - break; - } - if ( msg == vector ) { - if ( !irqfmt ) { - printf("Excess VME IRQ received ?? -- BAD\n"); - err = 1; - } else { - printf(irqfmt, vector, "received -- PASSED\n"); - irqfmt = 0; - } - } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) { - if ( !iackfmt ) { - printf("Excess VME IACK received ?? -- BAD\n"); - err = 1; - } else { - printf(iackfmt, "received -- PASSED\n"); - iackfmt = 0; - } - } else { - printf("Unknown IRQ (vector %lu) received -- BAD\n", msg); - err = 1; - } - } - - - /* Missing anything ? */ - if ( irqfmt ) { - printf(irqfmt,vector, "MISSED -- BAD\n"); - err = 1; - } - if ( iackfmt ) { - printf(iackfmt, "MISSED -- BAD\n"); - err = 1; - } - - printf("FINISHED.\n"); - -bail: - if ( doDisable ) - vmeTsi148IntDisable(level); - vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC ); - if ( installed > 0 ) - vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a); - if ( installed > 1 ) - vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a); - if ( q ) - rtems_message_queue_delete(q); - - return sc ? sc : err; -} - -unsigned long -vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr) -{ -unsigned long rval; - - CHECK_BASE(base,1,-1); - - rval = TSI_RD(base, TSI_VEAT_REG); - if ( rval & TSI_VEAT_VES ) { - if ( paddr ) { -#if 0 /* no 64-bit support yet */ - *paddr = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32; - *paddr |= TSI_RD(base, TSI_VEAL_REG); -#else - *paddr = TSI_RD(base, TSI_VEAL_REG); -#endif - } - /* clear errors */ - TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL); - } else { - rval = 0; - } - return rval; -} - -unsigned long -vmeTsi148ClearVMEBusErrors(uint32_t *paddr) -{ - return vmeTsi148ClearVMEBusErrorsXX(THEBASE, paddr); -} - -/** DMA Support **/ - -/* descriptor must be 8-byte aligned */ -typedef struct VmeTsi148DmaListDescriptorRec_ { - BEValue dsau, dsal; - BEValue ddau, ddal; - BEValue dsat, ddat; - BEValue dnlau, dnlal; - BEValue dcnt, ddbs; -} VmeTsi148DmaListDescriptorRec; - -static void tsi_desc_init (DmaDescriptor); -static int tsi_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -static void tsi_desc_setnxt(DmaDescriptor, DmaDescriptor); -static void tsi_desc_dump (DmaDescriptor); -static int tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p); - -VMEDmaListClassRec vmeTsi148DmaListClass = { - desc_size: sizeof(VmeTsi148DmaListDescriptorRec), - desc_align: 8, - freeList: 0, - desc_alloc: 0, - desc_free: 0, - desc_init: tsi_desc_init, - desc_setnxt:tsi_desc_setnxt, - desc_setup: tsi_desc_setup, - desc_start: tsi_desc_start, - desc_refr: 0, - desc_dump: tsi_desc_dump, -}; - -/* DMA Control */ -#define TSI_DMA_REG(off,i) ((off)+(((i)&1)<<7)) - -#define TSI_DCTL_REG(i) TSI_DMA_REG(0x500,i) -#define TSI_DCTL0_REG 0x500 -#define TSI_DCTL1_REG 0x580 -# define TSI_DCTL_ABT (1<<27) /* abort */ -# define TSI_DCTL_PAU (1<<26) /* pause */ -# define TSI_DCTL_DGO (1<<25) /* GO */ -# define TSI_DCTL_MOD (1<<23) /* linked list: 0, direct: 1 */ -# define TSI_DCTL_VFAR (1<<17) /* flush FIFO on VME error: 1 (discard: 0) */ -# define TSI_DCTL_PFAR (1<<16) /* flush FIFO on PCI error: 1 (discard: 0) */ - -# define TSI_DCTL_VBKS(i) (((i)&7)<<12) /* VME block size */ -# define TSI_DCTL_VBKS_32 TSI_DCTL_VBKS(0) -# define TSI_DCTL_VBKS_64 TSI_DCTL_VBKS(1) -# define TSI_DCTL_VBKS_128 TSI_DCTL_VBKS(2) -# define TSI_DCTL_VBKS_256 TSI_DCTL_VBKS(3) -# define TSI_DCTL_VBKS_512 TSI_DCTL_VBKS(4) -# define TSI_DCTL_VBKS_1024 TSI_DCTL_VBKS(5) -# define TSI_DCTL_VBKS_2048 TSI_DCTL_VBKS(6) -# define TSI_DCTL_VBKS_4096 TSI_DCTL_VBKS(7) - -# define TSI_DCTL_VBOT(i) (((i)&7)<< 8) /* VME back-off time */ -# define TSI_DCTL_VBOT_0us TSI_DCTL_VBOT(0) -# define TSI_DCTL_VBOT_1us TSI_DCTL_VBOT(1) -# define TSI_DCTL_VBOT_2us TSI_DCTL_VBOT(2) -# define TSI_DCTL_VBOT_4us TSI_DCTL_VBOT(3) -# define TSI_DCTL_VBOT_8us TSI_DCTL_VBOT(4) -# define TSI_DCTL_VBOT_16us TSI_DCTL_VBOT(5) -# define TSI_DCTL_VBOT_32us TSI_DCTL_VBOT(6) -# define TSI_DCTL_VBOT_64us TSI_DCTL_VBOT(7) - -# define TSI_DCTL_PBKS(i) (((i)&7)<< 4) /* PCI block size */ -# define TSI_DCTL_PBKS_32 TSI_DCTL_PBKS(0) -# define TSI_DCTL_PBKS_64 TSI_DCTL_PBKS(1) -# define TSI_DCTL_PBKS_128 TSI_DCTL_PBKS(2) -# define TSI_DCTL_PBKS_256 TSI_DCTL_PBKS(3) -# define TSI_DCTL_PBKS_512 TSI_DCTL_PBKS(4) -# define TSI_DCTL_PBKS_1024 TSI_DCTL_PBKS(5) -# define TSI_DCTL_PBKS_2048 TSI_DCTL_PBKS(6) -# define TSI_DCTL_PBKS_4096 TSI_DCTL_PBKS(7) - -# define TSI_DCTL_PBOT(i) (((i)&7)<< 0) /* PCI back-off time */ -# define TSI_DCTL_PBOT_0us TSI_DCTL_PBOT(0) -# define TSI_DCTL_PBOT_1us TSI_DCTL_PBOT(1) -# define TSI_DCTL_PBOT_2us TSI_DCTL_PBOT(2) -# define TSI_DCTL_PBOT_4us TSI_DCTL_PBOT(3) -# define TSI_DCTL_PBOT_8us TSI_DCTL_PBOT(4) -# define TSI_DCTL_PBOT_16us TSI_DCTL_PBOT(5) -# define TSI_DCTL_PBOT_32us TSI_DCTL_PBOT(6) -# define TSI_DCTL_PBOT_64us TSI_DCTL_PBOT(7) - -/* DMA Status */ -#define TSI_DSTA_REG(i) TSI_DMA_REG(0x504,i) -#define TSI_DSTA0_REG 0x504 -#define TSI_DSTA1_REG 0x584 -# define TSI_DSTA_ERR (1<<28) -# define TSI_DSTA_ABT (1<<27) -# define TSI_DSTA_PAU (1<<26) -# define TSI_DSTA_DON (1<<25) -# define TSI_DSTA_BSY (1<<24) -# define TSI_DSTA_ERRS (1<<20) /* Error source; PCI:1, VME:0 */ -# define TSI_DSTA_ERT_MSK (3<<16) /* Error type */ -# define TSI_DSTA_ERT_BERR_E (0<<16) /* 2eVME even or other bus error */ -# define TSI_DSTA_ERT_BERR_O (1<<16) /* 2eVME odd bus error */ -# define TSI_DSTA_ERT_SLVE_E (2<<16) /* 2eVME even or other slave termination */ -# define TSI_DSTA_ERT_SLVE_O (3<<16) /* 2eVME odd slave termination; 2eSST read last word invalid */ - -/* DMA Current source address upper */ -#define TSI_DCSAU_REG(i) TSI_DMA_REG(0x508,i) -#define TSI_DCSAU0_REG 0x508 -#define TSI_DCSAU1_REG 0x588 - -/* DMA Current source address lower */ -#define TSI_DCSAL_REG(i) TSI_DMA_REG(0x50c,i) -#define TSI_DCSAL0_REG 0x50c -#define TSI_DCSAL1_REG 0x58c - -/* DMA Current destination address upper */ -#define TSI_DCDAU_REG(i) TSI_DMA_REG(0x510,i) -#define TSI_DCDAU0_REG 0x510 -#define TSI_DCDAU1_REG 0x590 - -/* DMA Current destination address lower */ -#define TSI_DCDAL_REG(i) TSI_DMA_REG(0x514,i) -#define TSI_DCDAL0_REG 0x514 -#define TSI_DCDAL1_REG 0x594 - -/* DMA Current link address upper */ -#define TSI_DCLAU_REG(i) TSI_DMA_REG(0x518,i) -#define TSI_DCLAU0_REG 0x518 -#define TSI_DCLAU1_REG 0x598 - -/* DMA Current link address lower */ -#define TSI_DCLAL_REG(i) TSI_DMA_REG(0x51c,i) -#define TSI_DCLAL0_REG 0x51c -#define TSI_DCLAL1_REG 0x59c - -/* DMA Source address upper */ -#define TSI_DSAU_REG(i) TSI_DMA_REG(0x520,i) -#define TSI_DSAU0_REG 0x520 -#define TSI_DSAU1_REG 0x5a0 - -/* DMA Source address lower */ -#define TSI_DSAL_REG(i) TSI_DMA_REG(0x524,i) -#define TSI_DSAL0_REG 0x524 -#define TSI_DSAL1_REG 0x5a4 - -/* DMA Destination address upper */ -#define TSI_DDAU_REG(i) TSI_DMA_REG(0x528,i) -#define TSI_DDAU0_REG 0x528 -#define TSI_DDAU1_REG 0x5a8 - -/* DMA Destination address lower */ -#define TSI_DDAL_REG(i) TSI_DMA_REG(0x52c,i) -#define TSI_DDAL0_REG 0x52c -#define TSI_DDAL1_REG 0x5ac - -/* DMA Source Attribute */ -#define TSI_DSAT_REG(i) TSI_DMA_REG(0x530,i) -#define TSI_DSAT0_REG 0x530 -#define TSI_DSAT1_REG 0x5b0 - -/* DMA Destination Attribute */ -#define TSI_DDAT_REG(i) TSI_DMA_REG(0x534,i) -#define TSI_DDAT0_REG 0x534 -#define TSI_DDAT1_REG 0x5b4 - -# define TSI_DXAT_TYP(i) (((i)&3)<<28) /* Xfer type */ -# define TSI_DXAT_TYP_PCI TSI_DXAT_TYP(0) -# define TSI_DXAT_TYP_VME TSI_DXAT_TYP(1) -# define TSI_DSAT_TYP_PAT TSI_DXAT_TYP(2) /* pattern */ - -# define TSI_DSAT_PSZ (1<<25) /* pattern size 32-bit: 0, 8-bit: 1 */ -# define TSI_DSAT_NIN (1<<24) /* no-increment */ - -# define TSI_DXAT_OTAT_MSK ((1<<13)-1) /* get bits compatible with OTAT */ - -# define TSI_DXAT_SSTM(i) (((i)&3)<<11) /* 2eSST Xfer rate (MB/s) */ -# define TSI_DXAT_SSTM_116 TSI_DXAT_SSTM(0) -# define TSI_DXAT_SSTM_267 TSI_DXAT_SSTM(1) -# define TSI_DXAT_SSTM_320 TSI_DXAT_SSTM(2) - -# define TSI_DXAT_TM(i) (((i)&7)<< 8) /* VME Xfer mode */ -# define TSI_DXAT_TM_SCT TSI_DXAT_TM(0) -# define TSI_DXAT_TM_BLT TSI_DXAT_TM(1) -# define TSI_DXAT_TM_MBLT TSI_DXAT_TM(2) -# define TSI_DXAT_TM_2eVME TSI_DXAT_TM(3) -# define TSI_DXAT_TM_2eSST TSI_DXAT_TM(4) -# define TSI_DSAT_TM_2eSST_B TSI_DXAT_TM(5) /* 2eSST broadcast */ - -# define TSI_DXAT_DBW(i) (((i)&3)<< 6) /* VME Data width */ -# define TSI_DXAT_DBW_16 TSI_DXAT_DBW(0) -# define TSI_DXAT_DBW_32 TSI_DXAT_DBW(1) - -# define TSI_DXAT_SUP (1<<5) /* supervisor access */ -# define TSI_DXAT_PGM (1<<4) /* program access */ - -# define TSI_DXAT_AM(i) (((i)&15)<<0) /* VME Address mode */ -# define TSI_DXAT_AM_A16 TSI_DXAT_AM(0) -# define TSI_DXAT_AM_A24 TSI_DXAT_AM(1) -# define TSI_DXAT_AM_A32 TSI_DXAT_AM(2) -# define TSI_DXAT_AM_A64 TSI_DXAT_AM(4) -# define TSI_DXAT_AM_CSR TSI_DXAT_AM(5) - -/* DMA Next link address upper */ -#define TSI_DNLAU_REG(i) TSI_DMA_REG(0x538,i) -#define TSI_DNLAU0_REG 0x538 -#define TSI_DNLAU1_REG 0x5b8 - -/* DMA Next link address lower */ -#define TSI_DNLAL_REG(i) TSI_DMA_REG(0x53c,i) -#define TSI_DNLAL0_REG 0x53c -#define TSI_DNLAL1_REG 0x5bc - -# define TSI_DNLAL_LLA 1 /* last element in chain */ - -/* DMA Byte Count */ -#define TSI_DCNT_REG(i) TSI_DMA_REG(0x540,i) -#define TSI_DCNT0_REG 0x540 -#define TSI_DCNT1_REG 0x54c - -/* DMA 2eSST destination broadcast select */ -#define TSI_DDBS_REG(i) TSI_DMA_REG(0x544,i) -#define TSI_DDBS0_REG 0x544 -#define TSI_DDBS1_REG 0x5c4 - -/* Convert canonical xfer_mode into Tsi148 bits; return -1 if invalid */ -static uint32_t -vme_attr(uint32_t xfer_mode) -{ -uint32_t vme_mode; - if ( am2omode(xfer_mode, &vme_mode) ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* am2omode may set prefetch and other bits */ - vme_mode &= TSI_DXAT_OTAT_MSK; - vme_mode |= TSI_DXAT_TYP_VME; - - if ( BSP_VMEDMA_MODE_NOINC_VME & xfer_mode ) { - /* no-incr. only supported on source address */ - if ( (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) ) - return BSP_VMEDMA_STATUS_UNSUP; - vme_mode |= TSI_DSAT_NIN; - } - - return vme_mode; -} - -static uint32_t -pci_attr(uint32_t xfer_mode) -{ -uint32_t pci_mode = 0; - if ( BSP_VMEDMA_MODE_NOINC_PCI & xfer_mode ) { - /* no-incr. only supported on source address */ - if ( ! (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) ) - return BSP_VMEDMA_STATUS_UNSUP; - pci_mode |= TSI_DSAT_NIN; - } - return pci_mode; -} - -static void tsi_desc_init(DmaDescriptor p) -{ -VmeTsi148DmaListDescriptor d = p; - st_be32( &d->dnlau, 0 ); - st_be32( &d->dnlal, TSI_DNLAL_LLA ); - st_be32( &d->ddbs, (1<<22)-1 ); /* SSTB broadcast not yet fully supported */ -} - -static void -tsi_desc_setnxt(DmaDescriptor p, DmaDescriptor n) -{ -VmeTsi148DmaListDescriptor d = p; - if ( 0 == n ) { - st_be32( &d->dnlal, TSI_DNLAL_LLA ); - } else { - st_be32( &d->dnlal, BSP_LOCAL2PCI_ADDR((uint32_t)n) ); - } -} - -static void -tsi_desc_dump(DmaDescriptor p) -{ -VmeTsi148DmaListDescriptor d = p; - printf(" DSA: 0x%08lx%08lx\n", ld_be32(&d->dsau), ld_be32(&d->dsal)); - printf(" DDA: 0x%08lx%08lx\n", ld_be32(&d->ddau), ld_be32(&d->ddal)); - printf(" NLA: 0x%08lx%08lx\n", ld_be32(&d->dnlau), ld_be32(&d->dnlal)); - printf(" SAT: 0x%08lx DAT: 0x%08lx\n", ld_be32(&d->dsat), ld_be32(&d->ddat)); - printf(" CNT: 0x%08lx\n", ld_be32(&d->dcnt)); -} - - -int -vmeTsi148DmaSetupXX(BERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom) -{ -uint32_t ctl = 0; -uint32_t vmeatt, pciatt, sat, dat; - - if ( channel < 0 || channel > 1 ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* Check bus mode */ - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (vmeatt = vme_attr(xfer_mode)) ) - return -2; - - /* Check PCI bus mode */ - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (pciatt = pci_attr(xfer_mode)) ) - return -3; - - /* Compute control word; bottleneck is VME; */ - ctl |= TSI_DCTL_PBKS_32; - ctl |= (BSP_VMEDMA_OPT_THROUGHPUT == mode ? TSI_DCTL_PBOT_0us : TSI_DCTL_PBOT_1us); - - switch ( mode ) { - case BSP_VMEDMA_OPT_THROUGHPUT: - ctl |= TSI_DCTL_VBKS_1024; - ctl |= TSI_DCTL_VBOT_0us; - break; - - case BSP_VMEDMA_OPT_LOWLATENCY: - ctl |= TSI_DCTL_VBKS_32; - ctl |= TSI_DCTL_VBOT_0us; - break; - - case BSP_VMEDMA_OPT_SHAREDBUS: - ctl |= TSI_DCTL_VBKS_128; - ctl |= TSI_DCTL_VBOT_64us; - break; - - case BSP_VMEDMA_OPT_CUSTOM: - ctl = *(uint32_t*)custom; - break; - - default: - case BSP_VMEDMA_OPT_DEFAULT: - ctl = 0; - break; - } - TSI_WR(base, TSI_DCTL_REG(channel), ctl); - if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) { - dat = vmeatt; sat = pciatt; - } else { - sat = vmeatt; dat = pciatt; - } - TSI_WR(base, TSI_DSAT_REG(channel), sat); - TSI_WR(base, TSI_DDAT_REG(channel), dat); - return 0; -} - -int -vmeTsi148DmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom) -{ -BERegister *base = THEBASE; - return vmeTsi148DmaSetupXX(base, channel, mode, xfer_mode, custom); -} - - -int -vmeTsi148DmaListStartXX(BERegister *base, int channel, VmeTsi148DmaListDescriptor d) -{ -uint32_t ctl; - - if ( d ) { - /* Set list pointer and start */ - if ( channel < 0 || channel > 1 ) - return BSP_VMEDMA_STATUS_UNSUP; - - if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) ) - return BSP_VMEDMA_STATUS_BUSY; /* channel busy */ - - TSI_WR(base, TSI_DNLAL_REG(channel), (uint32_t)BSP_LOCAL2PCI_ADDR(d)); - - asm volatile("":::"memory"); - - /* Start transfer */ - ctl = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO; - ctl &= ~TSI_DCTL_MOD; - TSI_WR(base, TSI_DCTL_REG(channel), ctl); - } - /* else: list vs. direct mode is set by the respective start commands */ - return 0; -} - -int -vmeTsi148DmaListStart(int channel, VmeTsi148DmaListDescriptor d) -{ -BERegister *base = THEBASE; - return vmeTsi148DmaListStartXX(base, channel, d); -} - -int -vmeTsi148DmaStartXX(BERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) -{ -uint32_t src, dst, ctl; - - if ( channel < 0 || channel > 1 ) - return BSP_VMEDMA_STATUS_UNSUP; - - if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) ) - return BSP_VMEDMA_STATUS_BUSY; /* channel busy */ - - /* retrieve direction from dst attribute */ - if ( TSI_DXAT_TYP_VME & TSI_RD(base, TSI_DDAT_REG(channel)) ) { - dst = vme_addr; - src = pci_addr; - } else { - src = vme_addr; - dst = pci_addr; - } - /* FIXME: we leave the 'upper' registers (topmost 32bits) alone. - * Probably, we should reset them at init... - */ - TSI_WR(base, TSI_DSAL_REG(channel), src); - TSI_WR(base, TSI_DDAL_REG(channel), dst); - TSI_WR(base, TSI_DCNT_REG(channel), n_bytes); - - asm volatile("":::"memory"); - - /* Start transfer */ - ctl = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO | TSI_DCTL_MOD; - TSI_WR(base, TSI_DCTL_REG(channel), ctl); - - return 0; -} - -int -vmeTsi148DmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) -{ -BERegister *base = THEBASE; - return vmeTsi148DmaStartXX(base, channel, pci_addr, vme_addr, n_bytes); -} - -uint32_t -vmeTsi148DmaStatusXX(BERegister *base, int channel) -{ -uint32_t st = TSI_RD(base, TSI_DSTA_REG(channel)); - - if ( channel < 0 || channel > 1 ) - return BSP_VMEDMA_STATUS_UNSUP; - - st = TSI_RD(base, TSI_DSTA_REG(channel)); - - /* Status can be zero if an empty list (all counts == 0) is executed */ - if ( (TSI_DSTA_DON & st) || 0 == st ) - return BSP_VMEDMA_STATUS_OK; - - if ( TSI_DSTA_BSY & st ) - return BSP_VMEDMA_STATUS_BUSY; /* channel busy */ - - if ( TSI_DSTA_ERR & st ) { - if ( TSI_DSTA_ERRS & st ) - return BSP_VMEDMA_STATUS_BERR_PCI; - if ( ! (TSI_DSTA_ERT_SLVE_E & st) ) - return BSP_VMEDMA_STATUS_BERR_VME; - } - - return BSP_VMEDMA_STATUS_OERR; -} - -uint32_t -vmeTsi148DmaStatus(int channel) -{ -BERegister *base = THEBASE; - return vmeTsi148DmaStatusXX(base, channel); -} - -#define ALL_BITS_NEEDED (BSP_VMEDMA_MSK_ATTR | BSP_VMEDMA_MSK_PCIA | BSP_VMEDMA_MSK_VMEA) - -static int -tsi_desc_setup ( - DmaDescriptor p, - uint32_t attr_mask, - uint32_t xfer_mode, - uint32_t pci_addr, - uint32_t vme_addr, - uint32_t n_bytes) -{ -VmeTsi148DmaListDescriptor d = p; -uint32_t vmeatt = 0, pciatt = 0, tmp, src, dst, dat, sat; - - /* argument check */ - - /* since we must vme/pci into src/dst we need the direction - * bit. Reject requests that have only part of the mask - * bits set. It would be possible to be more sophisticated - * by caching more information but we try to be simple here... - */ - tmp = attr_mask & ALL_BITS_NEEDED; - if ( tmp != 0 && tmp != ALL_BITS_NEEDED ) - return -1; - - if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) { - /* Check VME bus mode */ - vmeatt = vme_attr(xfer_mode); - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == vmeatt ) - return -1; - - /* Check PCI bus mode */ - pciatt = pci_attr(xfer_mode); - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == pciatt ) - return -1; - } - - if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) { - if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) { - dat = vmeatt; sat = pciatt; - dst = vme_addr; src = pci_addr; - } else { - sat = vmeatt; dat = pciatt; - src = vme_addr; dst = pci_addr; - } - st_be32( &d->dsau, 0 ); st_be32( &d->dsal, src ); - st_be32( &d->ddau, 0 ); st_be32( &d->ddal, dst ); - st_be32( &d->dsat, sat ); st_be32( &d->ddat, dat ); - } - - if ( BSP_VMEDMA_MSK_BCNT & attr_mask ) - st_be32( &d->dcnt, n_bytes); - - return 0; -} - -static int -tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p) -{ -VmeTsi148DmaListDescriptor d = p; - if ( !controller_addr ) - controller_addr = THEBASE; - return vmeTsi148DmaListStartXX((BERegister*)controller_addr, channel, d); -} - -#ifdef DEBUG_MODULAR -void -_cexpModuleInitialize(void* unused) -{ - vmeTsi148Init(); - vmeTsi148Reset(); -} - -int -_cexpModuleFinalize(void *unused) -{ -int i; -int rval = 1; -void (*isrs[TSI_NUM_WIRES])() = { - isr_pin0, - isr_pin1, - isr_pin2, - isr_pin3, -}; - -rtems_irq_connect_data xx; - xx.on = my_no_op; /* at _least_ they could check for a 0 pointer */ - xx.off = my_no_op; - xx.isOn = my_isOn; - - TSI_WR(THEBASE, TSI_INTEO_REG, 0); - - for ( i=0; i<TSI_NUM_INT_VECS; i++) { - /* Dont even bother to uninstall handlers */ - } - if ( vmeTsi148IrqMgrInstalled ) { - for ( i=0; i<TSI_NUM_WIRES; i++ ) { - if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) { - xx.hdl = isrs[i]; - rval = rval && BSP_remove_rtems_irq_handler(&xx); - } - } - } - return !rval; -} -#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c deleted file mode 100644 index c7373b4e51..0000000000 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c +++ /dev/null @@ -1,2504 +0,0 @@ -/* Driver for the Tundra Universe II pci-vme bridge */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann <strauman@slac.stanford.edu>, 2000-2007, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -#include <stdio.h> -#include <inttypes.h> - -#if defined(__rtems__) -#ifndef __INSIDE_RTEMS_BSP__ -#define __INSIDE_RTEMS_BSP__ -#endif -#endif - -#include <bsp/vmeUniverse.h> -#include <bsp/vmeUniverseDMA.h> - -#define UNIV_NUM_MPORTS 8 /* number of master ports */ -#define UNIV_NUM_SPORTS 8 /* number of slave ports */ - -#define PCI_VENDOR_TUNDRA 0x10e3 -#define PCI_DEVICE_UNIVERSEII 0 -#define PCI_UNIVERSE_BASE0 0x10 -#define PCI_UNIVERSE_BASE1 0x14 - -#define UNIV_REGOFF_PCITGT0_CTRL 0x100 -#define UNIV_REGOFF_PCITGT4_CTRL 0x1a0 -#define UNIV_REGOFF_VMESLV0_CTRL 0xf00 -#define UNIV_REGOFF_VMESLV4_CTRL 0xf90 - -#define UNIV_CTL_VAS16 (0x00000000) -#define UNIV_CTL_VAS24 (0x00010000) -#define UNIV_CTL_VAS32 (0x00020000) -#define UNIV_MCTL_VASCSR (0x00050000) -#define UNIV_CTL_VAS (0x00070000) - -#define UNIV_MCTL_EN (0x80000000) -#define UNIV_MCTL_PWEN (0x40000000) -#define UNIV_MCTL_PGM (0x00004000) -#define UNIV_MCTL_VCT (0x00000100) -#define UNIV_MCTL_SUPER (0x00001000) -#define UNIV_MCTL_VDW16 (0x00400000) -#define UNIV_MCTL_VDW32 (0x00800000) -#define UNIV_MCTL_VDW64 (0x00c00000) - -#define UNIV_MCTL_AM_MASK (UNIV_CTL_VAS | UNIV_MCTL_PGM | UNIV_MCTL_SUPER) - -#define UNIV_SCTL_EN (0x80000000) -#define UNIV_SCTL_PWEN (0x40000000) -#define UNIV_SCTL_PREN (0x20000000) -#define UNIV_SCTL_PGM (0x00800000) -#define UNIV_SCTL_DAT (0x00400000) -#define UNIV_SCTL_SUPER (0x00200000) -#define UNIV_SCTL_USER (0x00100000) - -#define UNIV_SCTL_AM_MASK (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER) - -#ifdef __rtems__ - -#include <stdlib.h> -#include <rtems/bspIo.h> /* printk */ -#include <rtems/error.h> -#include <rtems/pci.h> -#include <bsp.h> -#include <libcpu/byteorder.h> - -/* allow the BSP to override the default routines */ -#ifndef BSP_PCI_FIND_DEVICE -#define BSP_PCI_FIND_DEVICE pci_find_device -#endif -#ifndef BSP_PCI_CONFIG_IN_LONG -#define BSP_PCI_CONFIG_IN_LONG pci_read_config_dword -#endif -#ifndef BSP_PCI_CONFIG_IN_BYTE -#define BSP_PCI_CONFIG_IN_BYTE pci_read_config_byte -#endif -#ifndef BSP_PCI_CONFIG_IN_SHORT -#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word -#endif -#ifndef BSP_PCI_CONFIG_OUT_SHORT -#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word -#endif - -/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses. - * Should be defined by the BSP. - */ -typedef uint32_t pci_ulong; - -#ifndef BSP_PCI2LOCAL_ADDR -#ifndef PCI_MEM_BASE -#define PCI_MEM_BASE 0 -#endif -#define BSP_PCI2LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE) -#endif - -#ifndef BSP_LOCAL2PCI_ADDR -#ifndef PCI_DRAM_OFFSET -#define PCI_DRAM_OFFSET 0 -#endif -#define BSP_LOCAL2PCI_ADDR(pciaddr) ((uint32_t)(pciaddr) + PCI_DRAM_OFFSET) -#endif - - -#elif defined(__vxworks) -typedef unsigned long pci_ulong; -#define BSP_PCI2LOCAL_ADDR(memaddr) (memaddr) -#define BSP_PCI_FIND_DEVICE pciFindDevice -#define BSP_PCI_CONFIG_IN_LONG pciConfigInLong -#define BSP_PCI_CONFIG_IN_BYTE pciConfigInByte -#else -#error "vmeUniverse not ported to this architecture yet" -#endif - -#ifndef PCI_INTERRUPT_LINE -#define PCI_INTERRUPT_LINE 0x3c -#endif - -volatile LERegister *vmeUniverse0BaseAddr=0; -int vmeUniverse0PciIrqLine=-1; - -#ifdef __rtems__ -int vmeUniverseRegPort = -1; -int vmeUniverseRegCSR = 0; -#endif - -#define DFLT_BASE volatile LERegister *base = vmeUniverse0BaseAddr - -#define CHECK_DFLT_BASE(base) \ - do { \ - /* get the universe base address */ \ - if (!base) { \ - if (vmeUniverseInit()) { \ - uprintf(stderr,"unable to find the universe in pci config space\n"); \ - return -1; \ - } else { \ - base = vmeUniverse0BaseAddr; \ - } \ - } \ - } while (0) - -#if 0 -/* public access functions */ -volatile LERegister * -vmeUniverseBaseAddr(void) -{ - if (!vmeUniverse0BaseAddr) vmeUniverseInit(); - return vmeUniverse0BaseAddr; -} - -int -vmeUniversePciIrqLine(void) -{ - if (vmeUniverse0PciIrqLine<0) vmeUniverseInit(); - return vmeUniverse0PciIrqLine; -} -#endif - -static inline void -WRITE_LE( - unsigned long val, - volatile LERegister *adrs, - unsigned long off) -{ -#if (__LITTLE_ENDIAN__ == 1) - *(volatile unsigned long*)(((unsigned long)adrs)+off)=val; -#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) - /* offset is in bytes and MUST not end up in r0 */ - __asm__ __volatile__("stwbrx %1, %0, %2" :: "b"(off),"r"(val),"r"(adrs)); -#elif defined(__rtems__) - st_le32((volatile uint32_t *)(((uint32_t)adrs)+off), val); -#else -#error "little endian register writing not implemented" -#endif -} - -#if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) -#define SYNC __asm__ __volatile__("sync") -#else -#define SYNC -#warning "SYNC instruction unknown for this architecture" -#endif - -/* registers should be mapped to guarded, non-cached memory; hence - * subsequent stores are ordered. eieio is only needed to enforce - * ordering of loads with respect to stores. - */ -#define EIEIO_REG - -static inline unsigned long -READ_LE0(volatile LERegister *adrs) -{ -#if (__LITTLE_ENDIAN__ == 1) - return *(volatile unsigned long *)adrs; -#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) -register unsigned long rval; -__asm__ __volatile__("lwbrx %0, 0, %1":"=r"(rval):"r"(adrs)); - return rval; -#elif defined(__rtems__) - return ld_le32((volatile uint32_t*)adrs); -#else -#error "little endian register reading not implemented" -#endif -} - -static inline unsigned long -READ_LE(volatile LERegister *adrs, unsigned long off) -{ -#if (__LITTLE_ENDIAN__ == 1) - return *((volatile LERegister *)(((unsigned long)adrs)+off)); -#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) -register unsigned long rval; - /* offset is in bytes and MUST not end up in r0 */ -__asm__ __volatile__("lwbrx %0, %2, %1" - : "=r"(rval) - : "r"(adrs), "b"(off)); -#if 0 -__asm__ __volatile__("eieio"); -#endif -return rval; -#else -return READ_LE0((volatile LERegister *)(((unsigned long)adrs)+off)); -#endif -} - -#define PORT_UNALIGNED(addr,port) \ - ( (port)%4 ? ((addr) & 0xffff) : ((addr) & 4095) ) - - -#define UNIV_REV(base) (READ_LE(base,2*sizeof(LERegister)) & 0xff) - -#if defined(__rtems__) && 0 -static int -uprintk(char *fmt, va_list ap) -{ -int rval; -extern int k_vsprintf(char *, char *, va_list); -/* during bsp init, there is no malloc and no stdio, - * hence we assemble the message on the stack and revert - * to printk - */ -char buf[200]; - rval = k_vsprintf(buf,fmt,ap); - if (rval > sizeof(buf)) - rtems_panic("vmeUniverse/uprintk: buffer overrun"); - printk(buf); - return rval; -} -#endif - - -/* private printing wrapper */ -static void -uprintf(FILE *f, char *fmt, ...) -{ -va_list ap; - va_start(ap, fmt); -#ifdef __rtems__ - if (!f || !_impure_ptr->__sdidinit) { - /* Might be called at an early stage when - * stdio is not yet initialized. - * There is no vprintk, hence we must assemble - * to a buffer. - */ - vprintk(fmt,ap); - } else -#endif - { - vfprintf(f,fmt,ap); - } - va_end(ap); -} - -static int -vmeUniverseFindPciBase( - int instance, - volatile LERegister **pbase - ) -{ -int bus,dev,fun; -unsigned short wrd; -pci_ulong busaddr; -unsigned char irqline; - - if (BSP_PCI_FIND_DEVICE( - PCI_VENDOR_TUNDRA, - PCI_DEVICE_UNIVERSEII, - instance, - &bus, - &dev, - &fun)) - return -1; - if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr)) - return -1; - if ((unsigned long)(busaddr) & 1) { - /* it's IO space, try BASE1 */ - if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr) - || ((unsigned long)(busaddr) & 1)) - return -1; - } - *pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr); - - if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline)) - return -1; - - /* Enable PCI master and memory access */ - BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd); - BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - - return irqline; -} - -/* convert an address space selector to a corresponding - * universe control mode word - */ - -static int -am2mode(int ismaster, unsigned long address_space, unsigned long *pmode) -{ -unsigned long mode=0; -unsigned long vdw =0; - - /* NOTE: reading the CY961 (Echotek ECDR814) with VDW32 - * generated bus errors when reading 32-bit words - * - very weird, because the registers are 16-bit - * AFAIK. - * - 32-bit accesses worked fine on vxWorks which - * has the port set to 64-bit. - * ???????? - */ - - address_space &= ~VME_MODE_MATCH_MASK; - - if (!ismaster) { - mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM; - mode |= UNIV_SCTL_USER; - if ( VME_AM_IS_MEMORY & address_space ) - mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN; - mode |= UNIV_SCTL_EN; - } else { - switch ( VME_MODE_DBW_MSK & address_space ) { - default: - vdw = UNIV_MCTL_VDW64; - break; - - case VME_MODE_DBW8: - break; - - case VME_MODE_DBW16: - vdw = UNIV_MCTL_VDW16; - break; - - case VME_MODE_DBW32: - vdw = UNIV_MCTL_VDW32; - break; - } - if ( VME_AM_IS_MEMORY & address_space ) - mode |= UNIV_MCTL_PWEN; - mode |= UNIV_MCTL_EN; - } - - address_space &= ~VME_AM_IS_MEMORY; - - switch (address_space & VME_AM_MASK) { - case VME_AM_STD_SUP_PGM: - case VME_AM_STD_USR_PGM: - if (ismaster) - mode |= UNIV_MCTL_PGM ; - else { - mode &= ~UNIV_SCTL_DAT; - } - - /* fall thru */ - - case VME_AM_STD_SUP_DATA: - case VME_AM_STD_USR_DATA: - case VME_AM_STD_SUP_BLT: - case VME_AM_STD_SUP_MBLT: - case VME_AM_STD_USR_BLT: - case VME_AM_STD_USR_MBLT: - - if ( ismaster ) { - switch ( address_space & 3 ) { - case 0: /* mblt */ - if ( UNIV_MCTL_VDW64 != vdw ) - return -1; - break; - - case 3: /* blt */ - mode |= UNIV_MCTL_VCT; - /* universe may do mblt anyways so go back to - * 32-bit width - */ - vdw = UNIV_MCTL_VDW32; - } - } - - mode |= UNIV_CTL_VAS24; - break; - - - case VME_AM_EXT_SUP_PGM: - case VME_AM_EXT_USR_PGM: - if (ismaster) - mode |= UNIV_MCTL_PGM ; - else { - mode &= ~UNIV_SCTL_DAT; - } - /* fall thru */ - - case VME_AM_EXT_SUP_DATA: - case VME_AM_EXT_USR_DATA: - case VME_AM_EXT_SUP_BLT: - case VME_AM_EXT_SUP_MBLT: - case VME_AM_EXT_USR_BLT: - case VME_AM_EXT_USR_MBLT: - - if ( ismaster ) { - switch ( address_space & 3 ) { - case 0: /* mblt */ - if ( UNIV_MCTL_VDW64 != vdw ) - return -1; - break; - - case 3: /* blt */ - mode |= UNIV_MCTL_VCT; - /* universe may do mblt anyways so go back to - * 32-bit width - */ - vdw = UNIV_MCTL_VDW32; - } - } - - mode |= UNIV_CTL_VAS32; - - break; - - case VME_AM_SUP_SHORT_IO: - case VME_AM_USR_SHORT_IO: - mode |= UNIV_CTL_VAS16; - break; - - case VME_AM_CSR: - if ( !ismaster ) - return -1; - mode |= UNIV_MCTL_VASCSR; - break; - - case 0: /* disable the port alltogether */ - break; - - default: - return -1; - } - if ( VME_AM_IS_SUP(address_space) ) - mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER); - - mode |= vdw; /* vdw still 0 in slave mode */ - *pmode = mode; - return 0; -} - -static int -disableUniversePort(int ismaster, int portno, volatile unsigned long *preg, void *param) -{ -unsigned long cntrl; - cntrl=READ_LE0(preg); - cntrl &= ~(ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN); - WRITE_LE(cntrl,preg,0); - SYNC; /* make sure this command completed */ - return 0; -} - -static int -cfgUniversePort( - volatile LERegister *base, - unsigned long ismaster, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long local_address, - unsigned long length) -{ -volatile LERegister *preg; -unsigned long p=port; -unsigned long mode=0; - - CHECK_DFLT_BASE(base); - - /* check parameters */ - if (port >= (ismaster ? UNIV_NUM_MPORTS : UNIV_NUM_SPORTS)) { - uprintf(stderr,"invalid port\n"); - return -1; - } - /* port start, bound addresses and offset must lie on 64k boundary - * (4k for port 0 and 4) - */ - if ( PORT_UNALIGNED(local_address,port) ) { - uprintf(stderr,"local address misaligned\n"); - return -1; - } - if ( PORT_UNALIGNED(vme_address,port) ) { - uprintf(stderr,"vme address misaligned\n"); - return -1; - } - if ( PORT_UNALIGNED(length,port) ) { - uprintf(stderr,"length misaligned\n"); - return -1; - } - - /* check address space validity */ - if (am2mode(ismaster,address_space,&mode)) { - uprintf(stderr,"invalid address space\n"); - return -1; - } - - /* get the universe base address */ - if (!base && vmeUniverseInit()) { - return -1; - } - - preg=base; - - /* find out if we have a rev. II chip */ - if ( UNIV_REV(base) < 2 ) { - if (port>3) { - uprintf(stderr,"Universe rev. < 2 has only 4 ports\n"); - return -1; - } - } - - /* finally, configure the port */ - - /* find the register set for our port */ - if (port<4) { - preg += (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister); - } else { - preg += (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister); - p-=4; - } - preg += 5 * p; - - /* temporarily disable the port */ - disableUniversePort(ismaster,port,preg,0); - - /* address_space == 0 means disable */ - if (address_space != 0) { - unsigned long start,offst; - /* set the port starting address; - * this is the local address for the master - * and the VME address for the slave - */ - if (ismaster) { - start=local_address; - /* let it overflow / wrap around 0 */ - offst=vme_address-local_address; - } else { - start=vme_address; - /* let it overflow / wrap around 0 */ - offst=local_address-vme_address; - } -#undef TSILL -#ifdef TSILL - uprintf(stderr,"writing 0x%08x to 0x%08x + 4\n",start,preg); -#else - WRITE_LE(start,preg,4); -#endif - /* set bound address */ - length+=start; -#ifdef TSILL - uprintf(stderr,"writing 0x%08x to 0x%08x + 8\n",length,preg); -#else - WRITE_LE(length,preg,8); -#endif - /* set offset */ -#ifdef TSILL - uprintf(stderr,"writing 0x%08x to 0x%08x + 12\n",offst,preg); -#else - WRITE_LE(offst,preg,12); -#endif - -#ifdef TSILL - uprintf(stderr,"writing 0x%08x to 0x%08x + 0\n",mode,preg); -#else - EIEIO_REG; /* make sure mode is written last */ - WRITE_LE(mode,preg,0); - SYNC; /* enforce completion */ -#endif - -#ifdef TSILL - uprintf(stderr, - "universe %s port %lu successfully configured\n", - ismaster ? "master" : "slave", - port); -#endif - -#ifdef __vxworks - if (ismaster) - uprintf(stderr, - "WARNING: on the synergy, sysMasterPortsShow() may show incorrect settings (it uses cached values)\n"); -#endif - } - return 0; -} - -static int -showUniversePort( - int ismaster, - int portno, - volatile LERegister *preg, - void *parm) -{ - FILE *f=parm ? (FILE *)parm : stdout; - unsigned long cntrl, start, bound, offst, mask; - - cntrl = READ_LE0(preg++); -#undef TSILL -#ifdef TSILL - uprintf(stderr,"showUniversePort: *(0x%08x): 0x%08x\n",preg-1,cntrl); -#endif -#undef TSILL - - /* skip this port if disabled */ - if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN))) - return 0; - - /* for the master `start' is the PCI address, - * for the slave `start' is the VME address - */ - mask = ~PORT_UNALIGNED(0xffffffff,portno); - - start = READ_LE0(preg++)&mask; - bound = READ_LE0(preg++)&mask; - offst = READ_LE0(preg++)&mask; - - offst+=start; /* calc start on the other bus */ - - if (ismaster) { - uprintf(f,"%d: 0x%08lx 0x%08lx 0x%08lx ", - portno,offst,bound-start,start); - } else { - uprintf(f,"%d: 0x%08lx 0x%08lx 0x%08lx ", - portno,start,bound-start,offst); - } - - switch (cntrl & UNIV_CTL_VAS) { - case UNIV_CTL_VAS16: uprintf(f,"A16, "); break; - case UNIV_CTL_VAS24: uprintf(f,"A24, "); break; - case UNIV_CTL_VAS32: uprintf(f,"A32, "); break; - case UNIV_MCTL_VASCSR: if ( ismaster ) { uprintf(f,"CSR, "); break; } - /* else fallthru */ - default: uprintf(f,"A??, "); break; - } - - if (ismaster) { - unsigned vdw; - switch ( cntrl & UNIV_MCTL_VDW64 ) { - case UNIV_MCTL_VDW64: - vdw = 64; - break; - - case UNIV_MCTL_VDW32: - vdw = 32; - break; - - case UNIV_MCTL_VDW16: - vdw = 16; - break; - - default: - vdw = 8; - break; - } - - if ( 64 == vdw ) { - switch ( UNIV_CTL_VAS & cntrl ) { - case UNIV_CTL_VAS24: - case UNIV_CTL_VAS32: - uprintf(f,"D64 [MBLT], "); - break; - - default: - uprintf(f,"D64, "); - break; - } - } else { - uprintf(f, "D%u%s, ", vdw, (cntrl & UNIV_MCTL_VCT) ? " [BLT]" : ""); - } - - uprintf(f,"%s, %s", - cntrl&UNIV_MCTL_PGM ? "Pgm" : "Dat", - cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr"); - if ( cntrl & UNIV_MCTL_PWEN ) - uprintf(f,", PWEN"); - } else { - uprintf(f,"%s %s %s %s", - cntrl&UNIV_SCTL_PGM ? "Pgm," : " ", - cntrl&UNIV_SCTL_DAT ? "Dat," : " ", - cntrl&UNIV_SCTL_SUPER ? "Sup," : " ", - cntrl&UNIV_SCTL_USER ? "Usr" : ""); - if ( cntrl & UNIV_SCTL_PWEN ) - uprintf(f,", PWEN"); - if ( cntrl & UNIV_SCTL_PREN ) - uprintf(f,", PREN"); - } - uprintf(f,"\n"); - return 0; -} - -typedef struct XlatRec_ { - unsigned long address; - unsigned long aspace; - unsigned reverse; /* find reverse mapping of this port */ -} XlatRec, *Xlat; - -/* try to translate an address through the bridge - * - * IN: l->address, l->aspace - * OUT: l->address (translated address) - * - * RETURNS: -1: invalid space - * 0: invalid address (not found in range) - * port+1: success - */ - -static int -xlatePort(int ismaster, int port, volatile LERegister *preg, void *parm) -{ -Xlat l=(Xlat)parm; -unsigned long cntrl, start, bound, offst, mask, x; - - cntrl = READ_LE0(preg++); - - /* skip this port if disabled */ - if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN))) - return 0; - - /* check for correct address space */ - if ( am2mode(ismaster,l->aspace,&offst) ) { - uprintf(stderr,"vmeUniverse WARNING: invalid adressing mode 0x%x\n", - l->aspace); - return -1; - } - - - switch (VME_MODE_MATCH_MASK & l->aspace) { - case VME_MODE_EXACT_MATCH: - mask = -1 & ~VME_MODE_MATCH_MASK; - break; - - case VME_MODE_AS_MATCH: - mask = UNIV_CTL_VAS; - break; - - default: - mask = (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK); - break; - } - - cntrl &= mask; - offst &= mask; - - if ( cntrl != offst ) - return 0; /* mode doesn't match requested AM */ - - /* OK, we found a matching mode, now we must check the address range */ - mask = ~PORT_UNALIGNED(0xffffffff,port); - - /* for the master `start' is the PCI address, - * for the slave `start' is the VME address - */ - start = READ_LE0(preg++) & mask; - bound = READ_LE0(preg++) & mask; - offst = READ_LE0(preg++) & mask; - - /* translate address to the other bus */ - if (l->reverse) { - /* reverse mapping, i.e. for master ports we map from - * VME to PCI, for slave ports we map from VME to PCI - */ - if (l->address >= start && l->address < bound) { - l->address+=offst; - return 1 + port; - } - } else { - x = l->address - offst; - - if (x >= start && x < bound) { - /* valid address found */ - l->address = x; - return 1 + port; - } - } - return 0; -} - -/* check if there is any active window with write posting enabled */ -static int -hasPWENWindow( - int ismaster, - int portno, - volatile LERegister *preg, - void *parm) -{ -unsigned long cntrl = READ_LE0(preg); -unsigned long mask = ismaster ? (UNIV_MCTL_EN|UNIV_MCTL_PWEN) : (UNIV_SCTL_EN|UNIV_SCTL_PWEN); - return (cntrl & mask) == mask ? -1 : 0; -} - -static int -mapOverAll(volatile LERegister *base, int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg) -{ -volatile LERegister *rptr; -unsigned long port; -int rval; - - CHECK_DFLT_BASE(base); - - rptr = (base + - (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister)); -#undef TSILL -#ifdef TSILL - uprintf(stderr,"mapoverall: base is 0x%08x, rptr 0x%08x\n",base,rptr); -#endif -#undef TSILL - for (port=0; port<4; port++) { - if ((rval=func(ismaster,port,rptr,arg))) return rval; - rptr+=5; /* register block spacing */ - } - - /* only rev. 2 has 8 ports */ - if (UNIV_REV(base)<2) return -1; - - rptr = (base + - (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister)); - for (port=4; port<UNIV_NUM_MPORTS; port++) { - if ((rval=func(ismaster,port,rptr,arg))) return rval; - rptr+=5; /* register block spacing */ - } - return 0; -} - -static void -showUniversePorts(volatile LERegister *base, int ismaster, FILE *f) -{ - if (!f) f=stdout; - uprintf(f,"Universe %s Ports:\n",ismaster ? "Master" : "Slave"); - uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n"); - mapOverAll(base,ismaster,showUniversePort,f); -} - -static int -xlateFindPort( - volatile LERegister *base, /* Universe base address */ - int master, /* look in the master windows */ - int reverse, /* reverse mapping; for masters: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ -int rval; -XlatRec l; - l.aspace = as; - l.address = aIn; - l.reverse = reverse; - /* map result -1/0/1 to -2/-1/0 with 0 on success */ - rval = mapOverAll(base,master,xlatePort,(void*)&l) - 1; - *paOut = l.address; - return rval; -} - -int -vmeUniverseXlateAddrXX( - volatile LERegister *base, /* Universe base address */ - int master, /* look in the master windows */ - int reverse, /* reverse mapping; for masters: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ - return xlateFindPort(base, master, reverse, as, aIn, paOut) >= 0 ? 0 : -1; -} - -int -vmeUniverseXlateAddr( - int master, /* look in the master windows */ - int reverse, /* reverse mapping; for masters: map local to VME */ - unsigned long as, /* address space */ - unsigned long aIn, /* address to look up */ - unsigned long *paOut/* where to put result */ - ) -{ - DFLT_BASE; - return vmeUniverseXlateAddrXX(base, master, reverse, as, aIn, paOut); -} - - -void -vmeUniverseReset(void) -{ - /* disable/reset special cycles (ADOH, RMW) */ - vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_CTL); - vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_ADDR); - vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_EN); - - /* set coupled window timeout to 0 (release VME after each transaction) - * CRT (coupled request timeout) is unused by Universe II - */ - vmeUniverseWriteReg(UNIV_LMISC_CRT_128_US, UNIV_REGOFF_LMISC); - - /* disable/reset DMA engine */ - vmeUniverseWriteReg(0, UNIV_REGOFF_DCTL); - vmeUniverseWriteReg(0, UNIV_REGOFF_DTBC); - vmeUniverseWriteReg(0, UNIV_REGOFF_DLA); - vmeUniverseWriteReg(0, UNIV_REGOFF_DVA); - vmeUniverseWriteReg(0, UNIV_REGOFF_DCPP); - - /* disable location monitor */ - vmeUniverseWriteReg(0, UNIV_REGOFF_LM_CTL); - - /* disable universe register access from VME bus */ - vmeUniverseWriteReg(0, UNIV_REGOFF_VRAI_CTL); - -#if 0 /* leave CSR bus image alone; IRQ manager can use it */ - /* disable VME bus image of VME CSR */ - vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL); -#endif - - - /* I had problems with a Joerger vtr10012_8 card who would - * only be accessible after tweaking the U2SPEC register - * (the t27 parameter helped). - * I use the same settings here that are used by the - * Synergy VGM-powerpc BSP for vxWorks. - */ - if (2==UNIV_REV(vmeUniverse0BaseAddr)) - vmeUniverseWriteReg(UNIV_U2SPEC_DTKFLTR | - UNIV_U2SPEC_MASt11 | - UNIV_U2SPEC_READt27_NODELAY | - UNIV_U2SPEC_POSt28_FAST | - UNIV_U2SPEC_PREt28_FAST, - UNIV_REGOFF_U2SPEC); - - /* disable interrupts, reset routing */ - vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_EN); - vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP0); - vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP1); - - vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_EN); - vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP0); - vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP1); - - vmeUniverseDisableAllSlaves(); - - vmeUniverseDisableAllMasters(); - - vmeUniverseWriteReg(UNIV_VCSR_CLR_SYSFAIL, UNIV_REGOFF_VCSR_CLR); - - /* clear interrupt status bits */ - vmeUniverseWriteReg(UNIV_LINT_STAT_CLR, UNIV_REGOFF_LINT_STAT); - vmeUniverseWriteReg(UNIV_VINT_STAT_CLR, UNIV_REGOFF_VINT_STAT); - - vmeUniverseWriteReg(UNIV_V_AMERR_V_STAT, UNIV_REGOFF_V_AMERR); - - vmeUniverseWriteReg( - vmeUniverseReadReg(UNIV_REGOFF_PCI_CSR) | - UNIV_PCI_CSR_D_PE | UNIV_PCI_CSR_S_SERR | UNIV_PCI_CSR_R_MA | - UNIV_PCI_CSR_R_TA | UNIV_PCI_CSR_S_TA, - UNIV_REGOFF_PCI_CSR); - - vmeUniverseWriteReg(UNIV_L_CMDERR_L_STAT, UNIV_REGOFF_L_CMDERR); - - vmeUniverseWriteReg( - UNIV_DGCS_STOP | UNIV_DGCS_HALT | UNIV_DGCS_DONE | - UNIV_DGCS_LERR | UNIV_DGCS_VERR | UNIV_DGCS_P_ERR, - UNIV_REGOFF_DGCS); -} - -int -vmeUniverseInit(void) -{ -int rval; - if ( (rval=vmeUniverseFindPciBase(0,&vmeUniverse0BaseAddr)) < 0 ) { - uprintf(stderr,"unable to find the universe in pci config space\n"); - } else { - vmeUniverse0PciIrqLine = rval; - rval = 0; - uprintf(stderr,"Universe II PCI-VME bridge detected at 0x%08x, IRQ %d\n", - (unsigned int)vmeUniverse0BaseAddr, vmeUniverse0PciIrqLine); - } - return rval; -} - -void -vmeUniverseMasterPortsShowXX(volatile LERegister *base, FILE *f) -{ - showUniversePorts(base,1,f); -} - -void -vmeUniverseMasterPortsShow(FILE *f) -{ - DFLT_BASE; - showUniversePorts(base,1,f); -} - -void -vmeUniverseSlavePortsShowXX(volatile LERegister *base, FILE *f) -{ - showUniversePorts(base,0,f); -} - -void -vmeUniverseSlavePortsShow(FILE *f) -{ - DFLT_BASE; - showUniversePorts(base,0,f); -} - -int -vmeUniverseMasterPortCfgXX( - volatile LERegister *base, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long local_address, - unsigned long length) -{ - return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length); -} - -int -vmeUniverseMasterPortCfg( - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long local_address, - unsigned long length) -{ - DFLT_BASE; - return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length); -} - -int -vmeUniverseSlavePortCfgXX( - volatile LERegister *base, - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long local_address, - unsigned long length) -{ - return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length); -} - -int -vmeUniverseSlavePortCfg( - unsigned long port, - unsigned long address_space, - unsigned long vme_address, - unsigned long local_address, - unsigned long length) -{ - DFLT_BASE; - return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length); -} - - -void -vmeUniverseDisableAllSlavesXX(volatile LERegister *base) -{ - mapOverAll(base,0,disableUniversePort,0); -} - -void -vmeUniverseDisableAllSlaves(void) -{ - DFLT_BASE; - mapOverAll(base,0,disableUniversePort,0); -} - -void -vmeUniverseDisableAllMastersXX(volatile LERegister *base) -{ - mapOverAll(base,1,disableUniversePort,0); -} - -void -vmeUniverseDisableAllMasters(void) -{ - DFLT_BASE; - mapOverAll(base,1,disableUniversePort,0); -} - -unsigned long -vmeUniverseReadRegXX(volatile LERegister *base, unsigned long offset) -{ -unsigned long rval; - rval = READ_LE(base,offset); - return rval; -} - - -unsigned long -vmeUniverseReadReg(unsigned long offset) -{ -unsigned long rval; - rval = READ_LE(vmeUniverse0BaseAddr,offset); - return rval; -} - -void -vmeUniverseWriteRegXX(volatile LERegister *base, unsigned long value, unsigned long offset) -{ - WRITE_LE(value, base, offset); -} - -void -vmeUniverseWriteReg(unsigned long value, unsigned long offset) -{ - WRITE_LE(value, vmeUniverse0BaseAddr, offset); -} - -void -vmeUniverseResetBus(void) -{ - vmeUniverseWriteReg( - vmeUniverseReadReg(UNIV_REGOFF_MISC_CTL) | UNIV_MISC_CTL_SW_SYSRST, - UNIV_REGOFF_MISC_CTL); -} - -void -vmeUniverseCvtToLE(unsigned long *ptr, unsigned long num) -{ -#if !defined(__LITTLE_ENDIAN__) || (__LITTLE_ENDIAN__ != 1) -register unsigned long *p=ptr+num; - while (p > ptr) { -#if (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) - __asm__ __volatile__( - "lwzu 0, -4(%0)\n" - "stwbrx 0, 0, %0\n" - : "=r"(p) : "0"(p) : "r0" - ); -#elif defined(__rtems__) - p--; st_le32(p, *p); -#else -#error "vmeUniverse: endian conversion not implemented for this architecture" -#endif - } -#endif -} - -int -vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector) -{ -unsigned long v; -unsigned long b; - - CHECK_DFLT_BASE(base); - - if ( level < 1 || level > 7 || vector > 255 ) - return -1; /* invalid argument */ - - if ( vector & 1 ) /* SW interrupts always ACK an even vector (pp 2-67) */ - return -1; - - - /* Check if already asserted */ - if ( vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_STAT ) & UNIV_VINT_STAT_SWINT(level) ) { - return -2; /* already asserted */ - } - - /* Write Vector */ - vmeUniverseWriteRegXX(base, UNIV_VINT_STATID(vector), UNIV_REGOFF_VINT_STATID ); - - if ( UNIV_REV(base) >= 2 ) { - /* universe II has individual bits for individual levels */ - b = UNIV_VINT_STAT_SWINT(level); - } else { - /* version that is compatible with universe I */ - v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_MAP1); - v &= ~UNIV_VINT_MAP1_SWINT(0x7); - v |= UNIV_VINT_MAP1_SWINT(level); - vmeUniverseWriteRegXX(base, v, UNIV_REGOFF_VINT_MAP1); - b = UNIV_VINT_EN_SWINT; - } - v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_EN); - /* make sure it is clear, then assert */ - vmeUniverseWriteRegXX(base, v & ~b, UNIV_REGOFF_VINT_EN ); - vmeUniverseWriteRegXX(base, v | b, UNIV_REGOFF_VINT_EN ); - - return 0; - -} - -int -vmeUniverseIntRaise(int level, unsigned vector) -{ - return vmeUniverseIntRaiseXX(vmeUniverse0BaseAddr, level, vector); -} - - -/* Map internal register block to VME */ -#define UNIV_CRG_SIZE (1<<12) - -int -vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long as ) -{ -uint32_t mode; - - CHECK_DFLT_BASE(base); - -#ifdef __rtems__ - if ( vmeUniverseRegPort > -1 && ! vmeUniverseRegCSR ) { - uprintf(stderr,"vmeUniverse: CRG already mapped and in use by interrupt manager\n"); - return -1; - } -#endif - - /* enable all, SUP/USR/PGM/DATA accesses */ - mode = UNIV_VRAI_CTL_EN | UNIV_VRAI_CTL_PGM | UNIV_VRAI_CTL_DATA | UNIV_VRAI_CTL_SUPER | UNIV_VRAI_CTL_USER; - - if ( VME_AM_IS_SHORT(as) ) { - mode |= UNIV_VRAI_CTL_VAS_A16; - } else - if ( VME_AM_IS_STD(as) ) { - mode |= UNIV_VRAI_CTL_VAS_A24; - } else - if ( VME_AM_IS_EXT(as) ) { - mode |= UNIV_VRAI_CTL_VAS_A32; - } else { - return -2; - } - - /* map CRG to VME bus */ - WRITE_LE( (vme_base & ~(UNIV_CRG_SIZE-1)), base, UNIV_REGOFF_VRAI_BS ); - WRITE_LE( mode, base, UNIV_REGOFF_VRAI_CTL ); - - return 0; -} - -int -vmeUniverseMapCRG(unsigned long vme_base, unsigned long as ) -{ - return vmeUniverseMapCRGXX( vmeUniverse0BaseAddr, vme_base, as ); -} - -#ifdef __rtems__ -/* DMA Support -- including linked-list implementation */ -#include "bspVmeDmaListP.h" -#include <bsp/vmeUniverseDMA.h> - -/* Filter valid bits of DCTL */ -#define DCTL_MODE_MASK \ - ( UNIV_DCTL_VDW_MSK | UNIV_DCTL_VAS_MSK | UNIV_DCTL_PGM | UNIV_DCTL_SUPER | UNIV_DCTL_VCT ) - -static uint32_t -xfer_mode2dctl(uint32_t xfer_mode) -{ -uint32_t dctl; - - /* Check requested bus mode */ - - /* Universe does not support 'non-incrementing' DMA */ - - /* NOTE: Universe IIb/d *does* support NOINC_VME but states - * that the VME address needs to be reprogrammed - * when re-issuing a transfer - */ - if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_PCI ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* ignore memory hint */ - xfer_mode &= ~VME_AM_IS_MEMORY; - - if ( VME_AM_IS_2eSST(xfer_mode) ) - return BSP_VMEDMA_STATUS_UNSUP; - - if ( ! VME_AM_IS_SHORT(xfer_mode) && ! VME_AM_IS_STD(xfer_mode) && ! VME_AM_IS_EXT(xfer_mode) ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* Luckily DCTL bits match MCTL bits so we can use am2mode */ - if ( am2mode( 1, xfer_mode, &dctl ) ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* However, the book says that for DMA VAS==5 [which would - * be a CSR access] is reserved. Tests indicate that - * CSR access works on the IIb/d but not really (odd 32-bit - * addresses read 0) on the II. - * Nevertheless, we disallow DMA CSR access at this point - * in order to play it safe... - */ - switch ( UNIV_DCTL_VAS_MSK & dctl ) { - case UNIV_DCTL_VAS_A24: - case UNIV_DCTL_VAS_A32: - /* fixup the data width; universe may always use MBLT - * if data width is 64-bit so we go back to 32-bit - * if they didn't explicitely ask for MBLT cycles - */ - if ( (xfer_mode & 0xb) != 8 /* MBLT */ - && ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) ) { - dctl &= ~UNIV_DCTL_VDW_MSK; - dctl |= UNIV_DCTL_VDW_32; - } - break; - - case UNIV_DCTL_VAS_A16: - break; - - default: - return BSP_VMEDMA_STATUS_UNSUP; - } - - /* Make sure other MCTL bits are masked */ - dctl &= DCTL_MODE_MASK; - - if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) { - /* If they want NOINC_VME then we have to do some - * fixup :-( ('errata' [in this case: feature addition] doc. pp. 11+) - */ - dctl &= ~UNIV_DCTL_VCT; /* clear block xfer flag */ - dctl |= UNIV_DCTL_NO_VINC; - /* cannot do 64 bit transfers; go back to 32 */ - if ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) { - dctl &= ~UNIV_DCTL_VDW_MSK; - dctl |= UNIV_DCTL_VDW_32; - } - } - - /* Set direction flag */ - - if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) - dctl |= UNIV_DCTL_L2V; - - return dctl; -} - -/* Convert canonical xfer_mode into Universe setup bits; return -1 if request - * cannot be satisfied (unsupported features) - */ -int -vmeUniverseDmaSetupXX(volatile LERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom) -{ -uint32_t dctl, dgcs; - - if ( channel != 0 ) - return BSP_VMEDMA_STATUS_UNSUP; - - dctl = xfer_mode2dctl(xfer_mode); - - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl ) - return BSP_VMEDMA_STATUS_UNSUP; - - /* Enable all interrupts at the controller */ - dgcs = UNIV_DGCS_INT_MSK; - - switch ( mode ) { - case BSP_VMEDMA_OPT_THROUGHPUT: - dgcs |= UNIV_DGCS_VON_1024 | UNIV_DGCS_VOFF_0_US; - /* VON counts are different in NO_VINC mode :-( */ - dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ? - UNIV_DGCS_VON_2048 : UNIV_DGCS_VON_1024; - break; - - case BSP_VMEDMA_OPT_LOWLATENCY: - dgcs |= UNIV_DGCS_VOFF_0_US; - /* VON counts are different in NO_VINC mode :-( */ - dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ? - UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256; - break; - - case BSP_VMEDMA_OPT_SHAREDBUS: - dgcs |= UNIV_DGCS_VOFF_512_US; - /* VON counts are different in NO_VINC mode :-( */ - dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ? - UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256; - break; - - case BSP_VMEDMA_OPT_CUSTOM: - dctl = ((uint32_t*)custom)[0]; - dgcs = ((uint32_t*)custom)[1]; - break; - - default: - case BSP_VMEDMA_OPT_DEFAULT: - break; - } - - /* clear status bits */ - dgcs |= UNIV_DGCS_STATUS_CLEAR; - - vmeUniverseWriteRegXX(base, dctl, UNIV_REGOFF_DCTL); - vmeUniverseWriteRegXX(base, dgcs, UNIV_REGOFF_DGCS); - - return BSP_VMEDMA_STATUS_OK; -} - -int -vmeUniverseDmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom) -{ -DFLT_BASE; - return vmeUniverseDmaSetupXX(base, channel, mode, xfer_mode, custom); -} - -int -vmeUniverseDmaStartXX(volatile LERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) -{ - if ( channel != 0 ) - return BSP_VMEDMA_STATUS_UNSUP; - - if ((pci_addr & 7) != (vme_addr & 7)) { - uprintf(stderr,"vmeUniverseDmaStartXX: misaligned addresses\n"); - return -1; - } - - { - /* help the compiler allocate registers */ - register volatile LERegister *b=base; - register unsigned long dgcsoff=UNIV_REGOFF_DGCS,dgcs; - - dgcs=READ_LE(b, dgcsoff); - - /* clear status and make sure CHAIN is clear */ - dgcs &= ~UNIV_DGCS_CHAIN; - WRITE_LE(dgcs, - b, dgcsoff); - WRITE_LE(pci_addr, - b, UNIV_REGOFF_DLA); - WRITE_LE(vme_addr, - b, UNIV_REGOFF_DVA); - WRITE_LE(n_bytes, - b, UNIV_REGOFF_DTBC); - dgcs |= UNIV_DGCS_GO; - EIEIO_REG; /* make sure GO is written after everything else */ - WRITE_LE(dgcs, - b, dgcsoff); - } - SYNC; /* enforce command completion */ - return 0; -} - -/* This entry point is deprecated */ -int -vmeUniverseStartDMAXX( - volatile LERegister *base, - unsigned long local_addr, - unsigned long vme_addr, - unsigned long count) -{ - return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count); -} - -int -vmeUniverseDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) -{ - DFLT_BASE; /* vmeUniverseDmaStartXX doesn't check for a valid base address for efficiency reasons */ - return vmeUniverseDmaStartXX(base, channel, pci_addr, vme_addr, n_bytes); -} - -/* This entry point is deprecated */ -int -vmeUniverseStartDMA( - unsigned long local_addr, - unsigned long vme_addr, - unsigned long count) -{ - DFLT_BASE; /* vmeUniverseStartDMAXX doesn't check for a valid base address for efficiency reasons */ - return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count); -} - -uint32_t -vmeUniverseDmaStatusXX(volatile LERegister *base, int channel) -{ -uint32_t dgcs; - if ( channel != 0 ) - return BSP_VMEDMA_STATUS_UNSUP; - - dgcs = vmeUniverseReadRegXX(base, UNIV_REGOFF_DGCS); - - dgcs &= UNIV_DGCS_STATUS_CLEAR; - - if ( 0 == dgcs || UNIV_DGCS_DONE == dgcs ) - return BSP_VMEDMA_STATUS_OK; - - if ( UNIV_DGCS_ACT & dgcs ) - return BSP_VMEDMA_STATUS_BUSY; - - if ( UNIV_DGCS_LERR & dgcs ) - return BSP_VMEDMA_STATUS_BERR_PCI; - - if ( UNIV_DGCS_VERR & dgcs ) - return BSP_VMEDMA_STATUS_BERR_VME; - - return BSP_VMEDMA_STATUS_OERR; -} - -uint32_t -vmeUniverseDmaStatus(int channel) -{ -DFLT_BASE; - return vmeUniverseDmaStatusXX(base, channel); -} - -/* bspVmeDmaList driver interface implementation */ - -/* Cannot use VmeUniverseDMAPacketRec because st_le32 expects unsigned * - * and we get 'alias' warnings when we submit uint32_t * - */ - -typedef volatile uint32_t LERegister1; - -typedef struct VmeUniverseDmaListDescRec_ { - LERegister1 dctl; - LERegister1 dtbc; - LERegister1 dla; - LERegister1 dummy1; - LERegister1 dva; - LERegister1 dummy2; - LERegister1 dcpp; - LERegister1 dummy3; -} __attribute__((aligned(32), __may_alias__)) -VmeUniverseDmaListDescRec; - -typedef VmeUniverseDmaListDescRec *VmeUniverseDmaListDesc; - -static void uni_desc_init (DmaDescriptor); -static int uni_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -static void uni_desc_setnxt(DmaDescriptor, DmaDescriptor); -static void uni_desc_dump (DmaDescriptor); -static int uni_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p); - -VMEDmaListClassRec vmeUniverseDmaListClass = { - desc_size: sizeof(VmeUniverseDMAPacketRec), - desc_align: 32, - freeList: 0, - desc_alloc: 0, - desc_free: 0, - desc_init: uni_desc_init, - desc_setnxt:uni_desc_setnxt, - desc_setup: uni_desc_setup, - desc_start: uni_desc_start, - desc_refr: 0, - desc_dump: uni_desc_dump, -}; - -static void uni_desc_init (DmaDescriptor p) -{ -VmeUniverseDmaListDesc d = p; - st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL ); -} - -static void uni_desc_setnxt(DmaDescriptor p, DmaDescriptor n) -{ -VmeUniverseDmaListDesc d = p; - if ( 0 == n ) { - st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL ); - } else { - st_le32( &d->dcpp, BSP_LOCAL2PCI_ADDR( (uint32_t)n)); - } -} - -static int -uni_desc_setup ( - DmaDescriptor p, - uint32_t attr_mask, - uint32_t xfer_mode, - uint32_t pci_addr, - uint32_t vme_addr, - uint32_t n_bytes) -{ -VmeUniverseDmaListDesc d = p; -LERegister1 dctl; - - if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) { - dctl = xfer_mode2dctl(xfer_mode); - - if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl ) - return -1; - - st_le32( &d->dctl, dctl ); - } - - /* Last 3 bits of src & destination addresses must be the same. - * For sake of simplicity we enforce (stricter) 8-byte alignment - */ - - if ( BSP_VMEDMA_MSK_PCIA & attr_mask ) { - if ( pci_addr & 0x7 ) - return -1; - - st_le32( &d->dla, pci_addr ); - } - - if ( BSP_VMEDMA_MSK_VMEA & attr_mask ) { - if ( vme_addr & 0x7 ) - return -1; - - st_le32( &d->dva, vme_addr ); - } - - if ( BSP_VMEDMA_MSK_BCNT & attr_mask ) { - st_le32( &d->dtbc, n_bytes ); - } - - return 0; -} - -static int uni_desc_start -(volatile void *controller_addr, int channel, DmaDescriptor p) -{ -volatile LERegister *base = controller_addr; -uint32_t dgcs; - - if ( !base ) - base = vmeUniverse0BaseAddr; - - dgcs = vmeUniverseReadRegXX( base, UNIV_REGOFF_DGCS ); - - if ( UNIV_DGCS_ACT & dgcs ) - return BSP_VMEDMA_STATUS_BUSY; - - if ( !p ) { - /* Chain bit is cleared by non-linked-list start command - * but do this anyways... - */ - dgcs &= ~UNIV_DGCS_CHAIN; - vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs); - return 0; - } - - /* clear status and set CHAIN bit */ - dgcs |= UNIV_DGCS_CHAIN; - - vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs); - - /* make sure count is 0 for linked list DMA */ - vmeUniverseWriteRegXX( base, 0x0, UNIV_REGOFF_DTBC); - - /* set the address of the descriptor chain */ - vmeUniverseWriteRegXX( base, BSP_LOCAL2PCI_ADDR((uint32_t)p), UNIV_REGOFF_DCPP); - - /* and GO */ - dgcs |= UNIV_DGCS_GO; - vmeUniverseWriteReg(dgcs, UNIV_REGOFF_DGCS); - - return 0; -} - -static void -uni_desc_dump(DmaDescriptor p) -{ -VmeUniverseDmaListDesc d = p; -LERegister1 dcpp = ld_le32(&d->dcpp); - - printf(" DLA: 0x%08x\n", ld_le32(&d->dla)); - printf(" DVA: 0x%08x\n", ld_le32(&d->dva)); - printf(" DCPP: 0x%08"PRIx32"%s\n", dcpp, (dcpp & UNIV_DCPP_IMG_NULL) ? " (LAST)" : ""); - printf(" CTL: 0x%08x\n", ld_le32(&d->dctl)); - printf(" TBC: 0x%08x\n", ld_le32(&d->dtbc)); -} - -/* RTEMS interrupt subsystem */ - -#include <bsp/irq.h> - -typedef struct -UniverseIRQEntryRec_ { - VmeUniverseISR isr; - void *usrData; -} UniverseIRQEntryRec, *UniverseIRQEntry; - -static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0}; - -int vmeUniverseIrqMgrInstalled = 0; - -volatile LERegister *vmeUniverseRegBase = 0; - -/* We support 4 wires between universe + PIC */ - -#define UNIV_NUM_WIRES 4 - -static volatile unsigned long wire_mask[UNIV_NUM_WIRES] = {0}; -/* wires are offset by 1 so we can initialize the wire table to all zeros */ -static int universe_wire[UNIV_NUM_WIRES] = {0}; - -static int -lvl2bit(unsigned int level) -{ -int shift = -1; - if ( level >= UNIV_DMA_INT_VEC && level <= UNIV_LM3_INT_VEC ) { - shift = 8 + (level-UNIV_DMA_INT_VEC); - } else if ( UNIV_VOWN_INT_VEC == level ) { - shift = 0; - } else if ( 1 <= level && level <=7 ) { - shift = level; - } else { - /* invalid level */ - } - return shift; -} - -int -vmeUniverseIntRoute(unsigned int level, unsigned int pin) -{ -int i, shift; -unsigned long mask, mapreg, flags, wire; - - if ( pin >= UNIV_NUM_WIRES || ! universe_wire[pin] || !vmeUniverseIrqMgrInstalled ) - return -1; - - if ( (shift = lvl2bit(level)) < 0 ) { - return -1; /* invalid level */ - } - - mask = 1<<shift; - - /* calculate the mapping register and contents */ - if ( shift < 8 ) { - mapreg = UNIV_REGOFF_LINT_MAP0; - } else if ( shift < 16 ) { - shift -= 8; - mapreg = UNIV_REGOFF_LINT_MAP1; - } else if ( shift < 24 ) { - shift -= 16; - mapreg = UNIV_REGOFF_LINT_MAP2; - } else { - return -1; - } - - shift <<=2; - - /* wires are offset by 1 so we can initialize the wire table to all zeros */ - wire = (universe_wire[pin]-1) << shift; - -rtems_interrupt_disable(flags); - - for ( i = 0; i<UNIV_NUM_WIRES; i++ ) { - wire_mask[i] &= ~mask; - } - wire_mask[pin] |= mask; - - mask = vmeUniverseReadReg(mapreg) & ~ (0xf<<shift); - mask |= wire; - vmeUniverseWriteReg( mask, mapreg ); - -rtems_interrupt_enable(flags); - return 0; -} - -VmeUniverseISR -vmeUniverseISRGet(unsigned long vector, void **parg) -{ -unsigned long flags; -VmeUniverseISR rval = 0; -volatile UniverseIRQEntry *pe = universeHdlTbl + vector; - - if ( vector>=UNIV_NUM_INT_VECS || ! *pe ) - return 0; - - rtems_interrupt_disable(flags); - if ( *pe ) { - if (parg) - *parg=(*pe)->usrData; - rval = (*pe)->isr; - } - rtems_interrupt_enable(flags); - return rval; -} - -#define SPECIAL_IRQ_MSK ( ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1) ) - -static void -universeSpecialISR(unsigned long status) -{ -register UniverseIRQEntry ip; -register unsigned vec; -register unsigned long s; - - /* handle all LINT bits except for the 'normal' VME interrupts */ - - /* clear all detected special interrupts */ - vmeUniverseWriteReg( (status & SPECIAL_IRQ_MSK), UNIV_REGOFF_LINT_STAT ); - - /* do VOWN first */ - vec=UNIV_VOWN_INT_VEC; - if ( (status & UNIV_LINT_STAT_VOWN) && (ip=universeHdlTbl[vec])) - ip->isr(ip->usrData,vec); - - /* now continue with DMA and scan through all bits; - * we assume the vectors are in the right order! - * - * The initial right shift brings the DMA bit into position 0; - * the loop is left early if there are no more bits set. - */ - for ( s = status>>8; s; s >>= 1) { - vec++; - if ( (s&1) && (ip=universeHdlTbl[vec]) ) - ip->isr(ip->usrData,vec); - } - -/* - * clear our line in the VINT_STAT register - * seems to be not neccessary... - vmeUniverseWriteReg( - UNIV_VINT_STAT_LINT(specialIrqUnivOut), - UNIV_REGOFF_VINT_STAT); - */ -} - -/* - * interrupts from VME to PCI seem to be processed more or less - * like this: - * - * - * VME IRQ ------ - * & ----- LINT_STAT ---- - * | & ---------- PCI LINE - * | | - * | | - * LINT_EN --------------------------- - * - * I.e. - * - if LINT_EN is disabled, a VME IRQ will not set LINT_STAT. - * - while LINT_STAT is set, it will pull the PCI line unless - * masked by LINT_EN. - * - VINT_STAT(lint_bit) seems to have no effect beyond giving - * status info. - * - * Hence, it is possible to - * - arm (set LINT_EN, routing etc.) - * - receive an irq (sets. LINT_STAT) - * - the ISR then: - * * clears LINT_EN, results in masking LINT_STAT (which - * is still set to prevent another VME irq at the same - * level to be ACKEd by the universe. - * * do PCI_EOI to allow nesting of higher VME irqs. - * (previous step also cleared LINT_EN of lower levels) - * * when the handler returns, clear LINT_STAT - * * re-enable setting LINT_EN. - */ - -static void -universeVMEISR(rtems_irq_hdl_param arg) -{ -int pin = (int)arg; -UniverseIRQEntry ip; -unsigned long msk,lintstat,status; -int lvl; -#if defined(BSP_PIC_DO_EOI) -unsigned long linten; -#endif - - /* determine the highest priority IRQ source */ - lintstat = vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT); - - /* only handle interrupts routed to this pin */ - lintstat &= wire_mask[pin]; - -#ifdef __PPC__ - asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat & ~SPECIAL_IRQ_MSK)); - lvl = 31-lvl; - msk = 1<<lvl; -#else - for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7; - lvl>0; - lvl--, msk>>=1) { - if (lintstat & msk) break; - } -#endif - -#ifndef BSP_PIC_DO_EOI /* Software priorities not supported */ - - if ( (status = (lintstat & SPECIAL_IRQ_MSK)) ) - universeSpecialISR( status ); - - if ( lvl <= 0) - return; - -#else - if ( lvl <= 0 ) { - /* try the special handler */ - universeSpecialISR( lintstat & SPECIAL_IRQ_MSK ); - - /* - * let the pic end this cycle - */ - if ( 0 == pin ) - BSP_PIC_DO_EOI; - - return; - } - linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN); - - /* mask this and all lower levels that are routed to the same pin */ - vmeUniverseWriteReg( - linten & ~( ((msk<<1)-UNIV_LINT_STAT_VIRQ1) & wire_mask[pin]), - UNIV_REGOFF_LINT_EN - ); - - /* end this interrupt - * cycle on the PCI bus, so higher level interrupts can be - * caught from now on... - */ - if ( 0 == pin ) - BSP_PIC_DO_EOI; -#endif - - /* get vector and dispatch handler */ - status = vmeUniverseReadReg(UNIV_REGOFF_VIRQ1_STATID - 4 + (lvl<<2)); - /* determine the highest priority IRQ source */ - - if (status & UNIV_VIRQ_ERR) { - /* TODO: log error message - RTEMS has no logger :-( */ -#ifdef BSP_PIC_DO_EOI - linten &= ~msk; -#else - vmeUniverseIntDisable(lvl); -#endif - printk("vmeUniverse ISR: error read from STATID register; (level: %i) STATID: 0x%08" PRIx32 " -- DISABLING\n", lvl, status); - } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) { -#ifdef BSP_PIC_DO_EOI - linten &= ~msk; -#else - vmeUniverseIntDisable(lvl); -#endif - /* TODO: log error message - RTEMS has no logger :-( */ - printk("vmeUniverse ISR: no handler installed for this vector; (level: %i) STATID: 0x%08" PRIx32 " -- DISABLING\n", lvl, status); - } else { - /* dispatch handler, it must clear the IRQ at the device */ - ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK); - - /* insert a VME read operation to flush fifo, making sure all user write-ops complete */ -#ifdef __PPC__ - /* courtesy to disobedient users who don't use I/O ops */ - asm volatile("eieio"); -#endif - READ_LE0(vmeUniverseRegBase); -#ifdef __PPC__ - /* make sure this is ordered before re-enabling */ - asm volatile("eieio"); -#endif - } - - /* clear this interrupt level; allow the universe to handler further interrupts */ - vmeUniverseWriteReg(msk, UNIV_REGOFF_LINT_STAT); - -/* - * this seems not to be necessary; we just leave the - * bit set to save a couple of instructions... - vmeUniverseWriteReg( - UNIV_VINT_STAT_LINT(vmeIrqUnivOut), - UNIV_REGOFF_VINT_STAT); -*/ - -#ifdef BSP_PIC_DO_EOI - - /* re-enable the previous level */ - vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN); -#endif -} - - -/* STUPID API */ -static void -my_no_op(const rtems_irq_connect_data * arg) -{} - -static int -my_isOn(const rtems_irq_connect_data *arg) -{ - return (int)vmeUniverseReadReg(UNIV_REGOFF_LINT_EN); -} - -typedef struct { - int uni_pin, pic_pin; -} IntRoute; - -static void -connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int pic_pin) -{ -rtems_irq_connect_data aarrggh; - aarrggh.on = my_no_op; /* at _least_ they could check for a 0 pointer */ - aarrggh.off = my_no_op; - aarrggh.isOn = my_isOn; - aarrggh.hdl = isr; - aarrggh.handle = (rtems_irq_hdl_param)pic_pin; - aarrggh.name = pic_line; - - if ( shared ) { -#if BSP_SHARED_HANDLER_SUPPORT > 0 - if (!BSP_install_rtems_shared_irq_handler(&aarrggh)) - rtems_panic("unable to install vmeUniverse shared irq handler"); -#else - uprintf(stderr,"vmeUniverse: WARNING: your BSP doesn't support sharing interrupts\n"); - if (!BSP_install_rtems_irq_handler(&aarrggh)) - rtems_panic("unable to install vmeUniverse irq handler"); -#endif - } else { - if (!BSP_install_rtems_irq_handler(&aarrggh)) - rtems_panic("unable to install vmeUniverse irq handler"); - } -} - -#ifndef BSP_EARLY_PROBE_VME -#define BSP_EARLY_PROBE_VME(addr) \ - ( \ - ((PCI_DEVICE_UNIVERSEII << 16) | PCI_VENDOR_TUNDRA ) == READ_LE( ((volatile LERegister*)(addr)), 0 ) \ - ) -#endif - -/* Check if there is a vme address/as is mapped in any of the outbound windows - * and look for the PCI vendordevice ID there. - * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7) - * on success. Address translated into CPU address is returned in *pcpu_addr. - */ -static int -mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr) -{ -int j; -char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG"; - - /* try to find mapping */ - if ( 0 > (j = xlateFindPort( - vmeUniverse0BaseAddr, - 1, 0, - as | VME_MODE_AS_MATCH, - vme_addr, - pcpu_addr ) ) ) { - uprintf(stderr,"vmeUniverse - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr); - uprintf(stderr," in outbound windows.\n"); - } else { - /* found a slot number; probe it */ - *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr ); - if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) { - uprintf(stderr,"vmeUniverse - IRQ manager using VME %s to flush FIFO\n", regtype); - return j; - } else { - uprintf(stderr,"vmeUniverse - Found slot info but detection of universe in VME %s space failed\n", regtype); - } - } - return -1; -} - - -int -vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...) -{ -int rval; -va_list ap; - va_start(ap, pic_pin0); - rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap); - va_end(ap); - return rval; -} - -int -vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap) -{ -int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES]; -unsigned long cpu_base, vme_reg_base; - - if (vmeUniverseIrqMgrInstalled) return -4; - - /* check parameters */ - - if ( uni_pin0 < 0 || uni_pin0 > 7 ) return -1; - - uni_pin[0] = uni_pin0; - pic_pin[0] = pic_pin0 < 0 ? vmeUniverse0PciIrqLine : pic_pin0; - i = 1; - while ( (uni_pin[i] = va_arg(ap, int)) >= 0 ) { - - if ( i >= UNIV_NUM_WIRES ) { - return -5; - } - - pic_pin[i] = va_arg(ap,int); - - if ( uni_pin[i] > 7 ) { - return -2; - } - if ( pic_pin[i] < 0 ) { - return -3; - } - i++; - } - - /* all routings must be different */ - for ( i=0; uni_pin[i] >= 0; i++ ) { - for ( j=i+1; uni_pin[j] >= 0; j++ ) { - if ( uni_pin[j] == uni_pin[i] ) return -6; - if ( pic_pin[j] == pic_pin[i] ) return -7; - } - } - - if ( flags & VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND ) { - - /* Find registers on VME so the ISR can issue a read to flush the FIFO */ - uprintf(stderr,"vmeUniverse IRQ manager: looking for registers on VME...\n"); - - /* NOTE: The universe [unlike the Tsi148] doesn't know about geographical - * addressing but the MotLoad firmware [mvme5500] is kind enough to - * program VCSR_BS based on the board's geographical address for us :-) - */ - if ( ( i = ((READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VCSR_BS ) >> 27) & 0x1f ) ) > 0 ) { - uprintf(stderr,"Trying to find CSR on VME...\n"); - vme_reg_base = i*0x80000 + UNIV_CSR_OFFSET; - i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base); - if ( i >= 0 ) - vmeUniverseRegCSR = 1; - } else { - i = -1; - } - - if ( -1 == i ) { - - uprintf(stderr,"Trying to find CRG on VME...\n"); - - /* Next we see if the CRG block is mapped to VME */ - - if ( UNIV_VRAI_CTL_EN & (j = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_CTL )) ) { - switch ( j & UNIV_VRAI_CTL_VAS_MSK ) { - case UNIV_VRAI_CTL_VAS_A16 : i = VME_AM_SUP_SHORT_IO; break; - case UNIV_VRAI_CTL_VAS_A24 : i = VME_AM_STD_SUP_DATA; break; - case UNIV_VRAI_CTL_VAS_A32 : i = VME_AM_EXT_SUP_DATA; break; - default: - break; - } - vme_reg_base = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_BS ) & ~(UNIV_CRG_SIZE - 1); - } - - if ( -1 == i ) { - } else { - i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base ); - } - } - - if ( i < 0 ) { - if ( mapOverAll( vmeUniverse0BaseAddr, 1, hasPWENWindow, 0 ) ) { - uprintf(stderr,"vmeUniverse IRQ manager - BSP configuration error: registers not found on VME\n"); - uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeUniverseMapCRG()])\n"); - uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n"); - uprintf(stderr,"back from user ISR to flush universe FIFO as a work-around or\n"); - uprintf(stderr,"make sure ISR accesses device using a window with posted-writes disabled\n"); - } else { - uprintf(stderr,"vmeUniverse IRQ manager - registers not found on VME; falling back to PCI\n"); - } - vmeUniverseRegBase = vmeUniverse0BaseAddr; - vmeUniverseRegPort = -1; - } else { - vmeUniverseRegBase = (volatile LERegister*)cpu_base; - vmeUniverseRegPort = i; - } - } else { - vmeUniverseRegBase = vmeUniverse0BaseAddr; - vmeUniverseRegPort = -1; - } - - /* give them a chance to override buggy PCI info */ - if ( pic_pin[0] >= 0 && vmeUniverse0PciIrqLine != pic_pin[0] ) { - uprintf(stderr,"Overriding main IRQ line PCI info with %d\n", - pic_pin[0]); - vmeUniverse0PciIrqLine=pic_pin[0]; - } - - for ( i = 0; uni_pin[i] >= 0; i++ ) { - /* offset wire # by one so we can initialize to 0 == invalid */ - universe_wire[i] = uni_pin[i] + 1; - connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i); - } - - specialPin = uni_pin[1] >= 0 ? 1 : 0; - - /* setup routing */ - - /* IntRoute checks for mgr being installed */ - vmeUniverseIrqMgrInstalled=1; - - /* route 7 VME irqs to first / 'normal' pin */ - for ( i=1; i<8; i++ ) - vmeUniverseIntRoute( i, 0 ); - for ( i=UNIV_VOWN_INT_VEC; i<=UNIV_LM3_INT_VEC; i++ ) { - if ( vmeUniverseIntRoute( i, specialPin ) ) - printk("Routing lvl %i -> wire # %i failed\n", i, specialPin); - } - - return 0; -} - -int -vmeUniverseInstallIrqMgr(int vmeIrqUnivOut, - int vmeIrqPicLine, - int specialIrqUnivOut, - int specialIrqPicLine) -{ - return vmeUniverseInstallIrqMgrAlt( - 0, /* bwds compat. */ - vmeIrqUnivOut, vmeIrqPicLine, - specialIrqUnivOut, specialIrqPicLine, - -1); -} - -int -vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg) -{ -UniverseIRQEntry ip; -unsigned long flags; -volatile UniverseIRQEntry *pe; - - if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled) - return -1; - - pe = universeHdlTbl + vector; - - if (*pe || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec)))) - return -1; - - ip->isr=hdl; - ip->usrData=arg; - - rtems_interrupt_disable(flags); - if ( *pe ) { - /* oops; someone intervened */ - rtems_interrupt_enable(flags); - free(ip); - return -1; - } - *pe = ip; - rtems_interrupt_enable(flags); - return 0; -} - -int -vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg) -{ -UniverseIRQEntry ip; -unsigned long flags; -volatile UniverseIRQEntry *pe; - - if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled) - return -1; - - pe = universeHdlTbl + vector; - - rtems_interrupt_disable(flags); - ip = *pe; - if (!ip || ip->isr!=hdl || ip->usrData!=arg) { - rtems_interrupt_enable(flags); - return -1; - } - *pe = 0; - rtems_interrupt_enable(flags); - free(ip); - return 0; -} - -static int -intDoEnDis(unsigned int level, int dis) -{ -unsigned long flags, v; -int shift; - - if ( ! vmeUniverseIrqMgrInstalled || (shift = lvl2bit(level)) < 0 ) - return -1; - - v = 1<<shift; - - if ( !dis ) - return vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & v ? 1 : 0; - - rtems_interrupt_disable(flags); - if ( dis<0 ) - vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & ~v, UNIV_REGOFF_LINT_EN ); - else { - vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) | v, UNIV_REGOFF_LINT_EN ); - } - rtems_interrupt_enable(flags); - return 0; -} - -int -vmeUniverseIntEnable(unsigned int level) -{ - return intDoEnDis(level, 1); -} - -int -vmeUniverseIntDisable(unsigned int level) -{ - return intDoEnDis(level, -1); -} - -int -vmeUniverseIntIsEnabled(unsigned int level) -{ - return intDoEnDis(level, 0); -} - -/* Loopback test of VME/universe interrupts */ - -typedef struct { - rtems_id q; - int l; -} LoopbackTstArgs; - -static void -loopbackTstIsr(void *arg, unsigned long vector) -{ -LoopbackTstArgs *pa = arg; - if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) { - /* Overrun ? */ - printk("vmeUniverseIntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l); - vmeUniverseIntDisable(pa->l); - } -} - -int -vmeUniverseIntLoopbackTst(int level, unsigned vector) -{ -DFLT_BASE; -rtems_status_code sc; -rtems_id q = 0; -int installed = 0; -int i, err = 0; -int doDisable = 0; -size_t size; -unsigned long msg; -char * irqfmt = "VME IRQ @vector %3i %s"; -char * iackfmt = "VME IACK %s"; -LoopbackTstArgs a; - - CHECK_DFLT_BASE(base); - - /* arg check */ - if ( level < 1 || level > 7 || vector > 255 ) { - fprintf(stderr,"Invalid level or vector argument\n"); - return -1; - } - - if ( (vector & 1) ) { - fprintf(stderr,"Software interrupts can only use even-numbered vectors, sorry.\n"); - return -1; - } - - if ( UNIV_REV(base) < 2 && vector != 0 ) { - fprintf(stderr, - "vmeUniverseIntLoopbackTst(): Universe 1 has a bug. IACK in response to\n"); - fprintf(stderr, - "self-generated VME interrupt yields always a zero vector. As a workaround,\n"); - fprintf(stderr, - "use vector 0, please.\n"); - return -1; - } - - /* Create message queue */ - if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create( - rtems_build_name('t' ,'U','I','I'), - 4, - sizeof(unsigned long), - 0, /* default attributes: fifo, local */ - &q)) ) { - rtems_error(sc, "vmeUniverseIntLoopbackTst: Unable to create message queue"); - goto bail; - } - - a.q = q; - a.l = level; - - /* Install handlers */ - if ( vmeUniverseInstallISR(vector, loopbackTstIsr, (void*)&a) ) { - fprintf(stderr,"Unable to install VME ISR to vector %i\n",vector); - goto bail; - } - installed++; - if ( vmeUniverseInstallISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) { - fprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",UNIV_VME_SW_IACK_INT_VEC); - goto bail; - } - installed++; - - if ( !vmeUniverseIntIsEnabled(level) && 0==vmeUniverseIntEnable(level) ) - doDisable = 1; - - /* make sure there are no pending interrupts */ - vmeUniverseWriteReg( UNIV_LINT_STAT_SW_IACK, UNIV_REGOFF_LINT_STAT ); - - if ( vmeUniverseIntEnable( UNIV_VME_SW_IACK_INT_VEC ) ) { - fprintf(stderr,"Unable to enable IACK interrupt\n"); - goto bail; - } - - printf("vmeUniverse VME interrupt loopback test; STARTING...\n"); - printf(" --> asserting VME IRQ level %i\n", level); - vmeUniverseIntRaise(level, vector); - - for ( i = 0; i< 3; i++ ) { - sc = rtems_message_queue_receive( - q, - &msg, - &size, - RTEMS_WAIT, - 20); - if ( sc ) { - if ( RTEMS_TIMEOUT == sc && i>1 ) { - /* OK; we dont' expect more to happen */ - sc = 0; - } else { - rtems_error(sc,"Error waiting for interrupts"); - } - break; - } - if ( msg == vector ) { - if ( !irqfmt ) { - printf("Excess VME IRQ received ?? -- BAD\n"); - err = 1; - } else { - printf(irqfmt, vector, "received -- PASSED\n"); - irqfmt = 0; - } - } else if ( msg == UNIV_VME_SW_IACK_INT_VEC ) { - if ( !iackfmt ) { - printf("Excess VME IACK received ?? -- BAD\n"); - err = 1; - } else { - printf(iackfmt, "received -- PASSED\n"); - iackfmt = 0; - } - } else { - printf("Unknown IRQ (vector %lu) received -- BAD\n", msg); - err = 1; - } - } - - - /* Missing anything ? */ - if ( irqfmt ) { - printf(irqfmt,vector, "MISSED -- BAD\n"); - err = 1; - } - if ( iackfmt ) { - printf(iackfmt, "MISSED -- BAD\n"); - err = 1; - } - - printf("FINISHED.\n"); - -bail: - if ( doDisable ) - vmeUniverseIntDisable(level); - vmeUniverseIntDisable( UNIV_VME_SW_IACK_INT_VEC ); - if ( installed > 0 ) - vmeUniverseRemoveISR(vector, loopbackTstIsr, (void*)&a); - if ( installed > 1 ) - vmeUniverseRemoveISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a); - if ( q ) - rtems_message_queue_delete(q); - - return sc ? sc : err; -} - -#endif |