📄 vmeuniverse.c
字号:
l->address = x; return 1; } } return 0;}static intmapOverAll(int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg){#define base vmeUniverse0BaseAddrvolatile LERegister *rptr;unsigned long port;int rval; /* get the universe base address */ if (!base && vmeUniverseInit()) { uprintf(stderr,"unable to find the universe in pci config space\n"); return -1; } 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;#undef base}static voidshowUniversePorts(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(ismaster,showUniversePort,f);}intvmeUniverseXlateAddr( 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(master,xlatePort,(void*)&l) - 1; *paOut = l.address; return rval;}voidvmeUniverseReset(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); /* disable VME bus image of VME CSR */ vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL); /* 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);}intvmeUniverseInit(void){int rval; if ((rval=vmeUniverseFindPciBase(0,&vmeUniverse0BaseAddr))) { uprintf(stderr,"unable to find the universe in pci config space\n"); } else { uprintf(stderr,"Universe II PCI-VME bridge detected at 0x%08x, IRQ %d\n", (unsigned int)vmeUniverse0BaseAddr, vmeUniverse0PciIrqLine); } return rval;}voidvmeUniverseMasterPortsShow(FILE *f){ showUniversePorts(1,f);}voidvmeUniverseSlavePortsShow(FILE *f){ showUniversePorts(0,f);}intvmeUniverseMasterPortCfg( unsigned long port, unsigned long address_space, unsigned long vme_address, unsigned long local_address, unsigned long length){ return cfgUniversePort(1,port,address_space,vme_address,local_address,length);}intvmeUniverseSlavePortCfg( unsigned long port, unsigned long address_space, unsigned long vme_address, unsigned long local_address, unsigned long length){ return cfgUniversePort(0,port,address_space,vme_address,local_address,length);}voidvmeUniverseDisableAllSlaves(void){ mapOverAll(0,disableUniversePort,0);}voidvmeUniverseDisableAllMasters(void){ mapOverAll(1,disableUniversePort,0);}intvmeUniverseStartDMA( unsigned long local_addr, unsigned long vme_addr, unsigned long count){ if (!vmeUniverse0BaseAddr && vmeUniverseInit()) return -1; if ((local_addr & 7) != (vme_addr & 7)) { uprintf(stderr,"vmeUniverseStartDMA: misaligned addresses\n"); return -1; } { /* help the compiler allocate registers */ register volatile LERegister *b=vmeUniverse0BaseAddr; 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(local_addr, b, UNIV_REGOFF_DLA); WRITE_LE(vme_addr, b, UNIV_REGOFF_DVA); WRITE_LE(count, 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;}unsigned longvmeUniverseReadReg(unsigned long offset){unsigned long rval; rval = READ_LE(vmeUniverse0BaseAddr,offset); return rval;}voidvmeUniverseWriteReg(unsigned long value, unsigned long offset){ WRITE_LE(value, vmeUniverse0BaseAddr, offset);}voidvmeUniverseCvtToLE(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) : "r"(p) : "r0" );#elif defined(__rtems__) p--; st_le32(p, *p);#else#error "vmeUniverse: endian conversion not implemented for this architecture"#endif }#endif}/* RTEMS interrupt subsystem */#ifdef __rtems__#include <bsp/irq.h>typedef structUniverseIRQEntryRec_ { VmeUniverseISR isr; void *usrData;} UniverseIRQEntryRec, *UniverseIRQEntry;static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0};int vmeUniverseIrqMgrInstalled=0;static int vmeIrqUnivOut=-1;static int specialIrqUnivOut=-1;VmeUniverseISRvmeUniverseISRGet(unsigned long vector, void **parg){ if (vector>=UNIV_NUM_INT_VECS || ! universeHdlTbl[vector]) return 0; if (parg) *parg=universeHdlTbl[vector]->usrData; return universeHdlTbl[vector]->isr;}static voiduniverseSpecialISR(void){register UniverseIRQEntry ip;register unsigned vec;register unsigned long status; status=vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT); /* scan all LINT bits except for the 'normal' VME interrupts */ /* 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 (status>>=8; status; status>>=1) { vec++; if ((status&1) && (ip=universeHdlTbl[vec])) ip->isr(ip->usrData,vec); } /* clear all special interrupts */ vmeUniverseWriteReg( ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1), UNIV_REGOFF_LINT_STAT );/* * 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 voiduniverseVMEISR(void){UniverseIRQEntry ip;unsigned long lvl,msk,lintstat,linten,status; /* determine the highest priority IRQ source */ lintstat=vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT); for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7; lvl>0; lvl--, msk>>=1) { if (lintstat & msk) break; } if (!lvl) { /* try the special handler */ universeSpecialISR(); /* * let the pic end this cycle */ BSP_PIC_DO_EOI; return; } linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN); /* mask this and all lower levels */ vmeUniverseWriteReg( linten & ~((msk<<1)-UNIV_LINT_STAT_VIRQ1), UNIV_REGOFF_LINT_EN ); /* end this interrupt * cycle on the PCI bus, so higher level interrupts can be * caught from now on... */ BSP_PIC_DO_EOI; /* 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 :-( */ } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) { /* TODO: log error message - RTEMS has no logger :-( */ } else { /* dispatch handler, it must clear the IRQ at the device */ ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK); } /* clear this interrupt level */ 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);*/ /* re-enable the previous level */ vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN);}/* STUPID API */static voidmy_no_op(const rtems_irq_connect_data * arg){}static intmy_isOn(const rtems_irq_connect_data *arg){ return (int)vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);}intvmeUniverseInstallIrqMgr(int vmeOut, int vmeIrqPicLine, int specialOut, int specialIrqPicLine){rtems_irq_connect_data aarrggh; /* check parameters */ if ((vmeIrqUnivOut=vmeOut) < 0 || vmeIrqUnivOut > 7) return -1; if ((specialIrqUnivOut=specialOut) > 7) return -2; if (specialOut >=0 && specialIrqPicLine < 0) return -3; /* give them a chance to override buggy PCI info */ if (vmeIrqPicLine >= 0) { uprintf(stderr,"Overriding main IRQ line PCI info with %d\n", vmeIrqPicLine); vmeUniverse0PciIrqLine=vmeIrqPicLine; } if (vmeUniverseIrqMgrInstalled) return -4; 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=universeVMEISR; aarrggh.name=vmeUniverse0PciIrqLine + BSP_PCI_IRQ0; if (!BSP_install_rtems_irq_handler(&aarrggh)) BSP_panic("unable to install vmeUniverse irq handler"); if (specialIrqUnivOut > 0) { /* install the special handler to a separate irq */ aarrggh.hdl=universeSpecialISR; aarrggh.name=specialIrqPicLine + BSP_PCI_IRQ0; if (!BSP_install_rtems_irq_handler(&aarrggh)) BSP_panic("unable to install vmeUniverse secondary irq handler"); } else { specialIrqUnivOut = vmeIrqUnivOut; } /* setup routing */ vmeUniverseWriteReg( (UNIV_LINT_MAP0_VIRQ7(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ6(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ5(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ4(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ3(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ2(vmeIrqUnivOut) | UNIV_LINT_MAP0_VIRQ1(vmeIrqUnivOut) | UNIV_LINT_MAP0_VOWN(specialIrqUnivOut) ), UNIV_REGOFF_LINT_MAP0); vmeUniverseWriteReg( (UNIV_LINT_MAP1_ACFAIL(specialIrqUnivOut) | UNIV_LINT_MAP1_SYSFAIL(specialIrqUnivOut) | UNIV_LINT_MAP1_SW_INT(specialIrqUnivOut) | UNIV_LINT_MAP1_SW_IACK(specialIrqUnivOut) | UNIV_LINT_MAP1_VERR(specialIrqUnivOut) | UNIV_LINT_MAP1_LERR(specialIrqUnivOut) | UNIV_LINT_MAP1_DMA(specialIrqUnivOut) ), UNIV_REGOFF_LINT_MAP1); vmeUniverseIrqMgrInstalled=1; return 0;}intvmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg){UniverseIRQEntry ip; if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled) return -1; ip=universeHdlTbl[vector]; if (ip || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec)))) return -1; ip->isr=hdl; ip->usrData=arg; universeHdlTbl[vector]=ip; return 0;}intvmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg){UniverseIRQEntry ip; if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled) return -1; ip=universeHdlTbl[vector]; if (!ip || ip->isr!=hdl || ip->usrData!=arg) return -1; universeHdlTbl[vector]=0; free(ip); return 0;}intvmeUniverseIntEnable(unsigned int level){ if (!vmeUniverseIrqMgrInstalled || level<1 || level>7) return -1; vmeUniverseWriteReg( (vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) | (UNIV_LINT_EN_VIRQ1 << (level-1)) ), UNIV_REGOFF_LINT_EN); return 0;}intvmeUniverseIntDisable(unsigned int level){ if (!vmeUniverseIrqMgrInstalled || level<1 || level>7) return -1; vmeUniverseWriteReg( (vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & ~ (UNIV_LINT_EN_VIRQ1 << (level-1)) ), UNIV_REGOFF_LINT_EN); return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -