📄 universe.c
字号:
UNIV_IN_LONG(UNIVERSE_STATID, &statidReg); vector >>= 1; statidReg = (statidReg & STATID_MASK) | (vector << 25); UNIV_OUT_LONG(UNIVERSE_STATID, statidReg); /* Generate a SW interrupt on the VMEbus at the requested level */ UNIV_IN_LONG(UNIVERSE_VINT_EN, &enReg); enReg |= ((1 << level) << 24); UNIV_OUT_LONG(UNIVERSE_VINT_EN, enReg); /* unlock the interrupt */ CPU_INT_UNLOCK(lockKey); return (OK); }/********************************************************************************* sysUnivIntEnable - enable Universe-supported interrupt(s)** This routine enables the specified type(s) of interrupt supported by the* Universe VME-to-PCI bridge.** RETURNS: OK, or ERROR if invalid interrupt type(s).** SEE ALSO: sysUnivIntDisable()**/STATUS sysUnivIntEnable ( int univIntType /* interrupt type */ ) { /* make sure the interrupt type is valid */ if ((univIntType & UNIVERSE_INT_MASK) == 0 || (univIntType & UNIVERSE_RESERVED_INT) != 0 ) return(ERROR); /* clear any pending intr. for the type */ UNIV_OUT_LONG(UNIVERSE_LINT_STAT, univIntType); /* enable the interrupt */ sysUnivIntsEnabled |= univIntType; UNIV_OUT_LONG(UNIVERSE_LINT_EN, sysUnivIntsEnabled); /* map the interrupt. Currently all VME ints are mapped to LINT#0 */ UNIV_OUT_LONG(UNIVERSE_LINT_MAP1, 0); return (OK); }/********************************************************************************* sysUnivIntDisable - disable Universe-supported interrupt(s)** This routine disables the specified type(s) of interrupt supported by the * Universe VME-to-PCI bridge.** RETURNS: OK, or ERROR if invalid interrupt type(s).** SEE ALSO: sysUnivIntEnable()**/STATUS sysUnivIntDisable ( int univIntType /* interrupt type */ ) { /* make sure the interrupt type is valid */ if ((univIntType & UNIVERSE_INT_MASK) == 0 || (univIntType & UNIVERSE_RESERVED_INT) != 0 ) return (ERROR); /* disable the interrupt */ sysUnivIntsEnabled &= ~univIntType; UNIV_OUT_LONG(UNIVERSE_LINT_EN, sysUnivIntsEnabled); /* clear any pending intr. for the type */ UNIV_OUT_LONG(UNIVERSE_LINT_STAT, univIntType); return (OK); }/********************************************************************************* sysUnivIntLevelSet - set a Universe-supported interrupt level** This routine disables all interrupts supported by the Universe at and below* the specified level. The lowest level is 0, the highest is 15. The* priority mapping is:* .CS* 0 no interrupts masked* 1 UNIVERSE_VOWN_INT* 2 VMEBUS_LVL1* 3 VMEBUS_LVL2* 4 VMEBUS_LVL3* 5 VMEBUS_LVL4* 6 VMEBUS_LVL5* 7 VMEBUS_LVL6* 8 VMEBUS_LVL7* 9 UNIVERSE_DMA_INT* 10 UNIVERSE_LERR_INT* 11 UNIVERSE_VERR_INT* 12 UNIVERSE_VME_SW_IACK_INT* 13 UNIVERSE_PCI_SW_INT* 14 UNIVERSE_SYSFAIL_INT* 15 UNIVERSE_ACFAIL_INT* .CE** If the level specified is -1, the level is not changed, just the current* level is returned.** RETURNS: previous interrupt level.** SEE ALSO: sysUnivIntDisable(), sysUnivIntEnable()*/int sysUnivIntLevelSet ( int univIntLvl /* Universe interrupt level */ ) { int intLvl; int key; /* Just return current level if so requested */ if (univIntLvl == -1) return (sysUnivIntLevel); /* Lock out interrupts during level change */ CPU_INT_LOCK(&key); /* disable the interrupt levels at and below the current level */ intLvl = univIntTable[univIntLvl].intMask; intLvl &= sysUnivIntsEnabled; UNIV_OUT_LONG(UNIVERSE_LINT_EN, intLvl); /* save current level for return */ intLvl = sysUnivIntLevel; /* set new mask */ sysUnivIntLevel = univIntLvl; /* Unlock interrupts */ CPU_INT_UNLOCK(key); /* return previous mask */ return (intLvl); }/******************************************************************************** sysUnivIntConnect - connect an interrupt handler for an interrupt type** This routine connects an interrupt handler for a specified interrupt type * to the system vector table of the Universe VME-to-PCI bridge.** RETURNS: OK, or ERROR if any argument is invalid or memory cannot be* allocated.*/STATUS sysUnivIntConnect ( int univIntType, /* the interrupt type to connect with */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { int univVecNum = 0; /* make sure the interrupt type is valid */ if ((univIntType & UNIVERSE_INT_MASK) == 0) return (ERROR); /* determine the vector number for the interrupt */ switch(univIntType) { case UNIVERSE_DMA_INT: univVecNum = UNIV_DMA_INT_VEC; break; case UNIVERSE_LERR_INT: univVecNum = UNIV_LERR_INT_VEC; break; case UNIVERSE_VERR_INT: univVecNum = UNIV_VERR_INT_VEC; break; case UNIVERSE_SYSFAIL_INT: univVecNum = UNIV_SYSFAIL_INT_VEC; break; case UNIVERSE_ACFAIL_INT: univVecNum = UNIV_ACFAIL_INT_VEC; break; case UNIVERSE_PCI_SW_INT: univVecNum = UNIV_PCI_SW_INT_VEC; break; case UNIVERSE_VME_SW_IACK_INT: univVecNum = UNIV_VME_SW_IACK_INT_VEC; break; case UNIVERSE_VOWN_INT: univVecNum = UNIV_VOWN_INT_VEC; break; default: /* doesn't match one of the intr. types, so return an error */ return(ERROR); } /* install the handler in the vector table */ if (intConnect (INUM_TO_IVEC(univVecNum), routine, parameter) == ERROR) return(ERROR); return (OK); }/********************************************************************************* sysMailboxInt - mailbox interrupt handler** This routine calls the installed mailbox routine, if it exists.*/LOCAL void sysMailboxInt (void) { unsigned char sigLmIntr; sigLmIntr = *((unsigned char *)CPU_SIG_LM_STATUS_REG); /* make sure the interrupt is a mailbox interrupt */ if ((sigLmIntr & SIG1_INTR_ENABL) && (sigLmIntr & SIG1_INTR_STATUS)) { /* clear the mailbox intr */ UNIV_OUT_BYTE(CPU_SIG_LM_CONTROL_REG, SIG1_INTR_CLEAR); if (sysMailboxRoutine != NULL) sysMailboxRoutine (sysMailboxArg); } }/********************************************************************************* sysMailboxConnect - connect a routine to the mailbox interrupt** This routine specifies the interrupt service routine to be called at each* mailbox interrupt.** NOTE: The mailbox interrupt is SIG1.** RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.** SEE ALSO: intConnect(), sysMailboxEnable()*/STATUS sysMailboxConnect ( FUNCPTR routine, /* routine called at each mailbox interrupt */ int arg /* argument with which to call routine */ ) { static BOOL sysMailboxConnected = FALSE; if (!sysMailboxConnected && intConnect (INUM_TO_IVEC (INT_VEC_IRQ0 + LM_SIG_INT_LVL), sysMailboxInt, 0) == ERROR) { return (ERROR); } sysMailboxConnected = TRUE; sysMailboxRoutine = routine; sysMailboxArg = arg; /* clear the mailbox intr */ UNIV_OUT_BYTE(CPU_SIG_LM_CONTROL_REG, SIG1_INTR_CLEAR); return (OK); }/********************************************************************************* sysMailboxEnable - enable the mailbox interrupt** This routine enables the mailbox interrupt.** NOTE: The mailbox interrupt is SIG1.** RETURNS: OK, always.** SEE ALSO: sysMailboxConnect(), sysMailboxDisable()*/STATUS sysMailboxEnable ( char *mailboxAdrs /* address of mailbox (ignored) */ ) { UCHAR status; /* enable the SIG1 interrupt */ UNIV_IN_BYTE(CPU_SIG_LM_STATUS_REG, &status); UNIV_OUT_BYTE(CPU_SIG_LM_STATUS_REG, SIG1_INTR_ENABL | (0xF0 & status)); intEnable (LM_SIG_INT_LVL); return (OK); }/********************************************************************************* sysMailboxDisable - disable the mailbox interrupt** This routine disables the mailbox interrupt.** NOTE: The mailbox interrupt is SIG1.** RETURNS: OK, always.** SEE ALSO: sysMailboxConnect(), sysMailboxEnable()*/STATUS sysMailboxDisable ( char *mailboxAdrs /* address of mailbox (ignored) */ ) { /* clear and disable the mailbox interrupts */ UNIV_OUT_BYTE(CPU_SIG_LM_CONTROL_REG, SIG1_INTR_CLEAR); UNIV_OUT_BYTE(CPU_SIG_LM_STATUS_REG, ~SIG1_INTR_ENABL); intDisable (LM_SIG_INT_LVL); return (OK); }/********************************************************************************* sysUnivVERRClr - Universe VMEbus Error Clear routine** This is the VMEbus Error clear routine for the Tundra Universe PCI to VME* Bridge. It counts the ocuurances at the specified counter and clears the* error condition in the three registers associated with VME Bus Errors:* LINT_STAT, VINT_STAT, and V_AMERR.** RETURNS: N/A*/void sysUnivVERRClr (void) { UINT32 status; /* Count occurances */ ++sysUnivVERRCnt; /* Get current address error status */ UNIV_IN_LONG(UNIVERSE_V_AMERR, &status); /* Clear any error */ status &= V_AMERR_V_STAT; UNIV_OUT_LONG(UNIVERSE_V_AMERR, status); /* Get current VME error status */ UNIV_IN_LONG(UNIVERSE_VINT_STAT, &status); /* Clear any error */ status &= VINT_STAT_VERR; UNIV_OUT_LONG(UNIVERSE_VINT_STAT, status); /* Get current PCI error status */ UNIV_IN_LONG(UNIVERSE_LINT_STAT, &status); /* Clear any error */ status &= LINT_STAT_VERR; UNIV_OUT_LONG(UNIVERSE_LINT_STAT, status); /* Force write due to Write-Posting and get updated status */ UNIV_IN_LONG(UNIVERSE_PCI_CSR, &status); }/********************************************************************************* sysUnivLevelDecode - decode highest pending priority Universe interrupt** This routine decodes the highest pending priority Universe interrupt from a* bit field of interrupts and returns the associated interrupt vector, priority* level and priority level bit mask.** RETURNS: highest pending interrupt priority level bit mask** SEE ALSO: register and bit field defs in universe.h*/int sysUnivLevelDecode ( int bitField, /* one interrupt per bit, up to 15 bits */ int * vecNum, /* where to return associated vector */ int * intLvl /* where to return associated Universe int level */ ) { int bitLvlMsk; int i; int vector; /* Compare bits in order of highest priority first */ for (i = UNIV_NUM_INT; i >= 0; --i) { if (bitField & univIntTable[i].bitMask) break; } /* Determine and return interrupt vector, priority level and level mask */ bitLvlMsk = univIntTable[i].bitMask; if (univIntTable[i].vector != -1) *vecNum = univIntTable[i].vector; else { switch (bitLvlMsk) { case LVL7: UNIV_IN_LONG(UNIVERSE_V7_STATID, &vector); break; case LVL6: UNIV_IN_LONG(UNIVERSE_V6_STATID, &vector); break; case LVL5: UNIV_IN_LONG(UNIVERSE_V5_STATID, &vector); break; case LVL4: UNIV_IN_LONG(UNIVERSE_V4_STATID, &vector); break; case LVL3: UNIV_IN_LONG(UNIVERSE_V3_STATID, &vector); break; case LVL2: UNIV_IN_LONG(UNIVERSE_V2_STATID, &vector); break; case LVL1: UNIV_IN_LONG(UNIVERSE_V1_STATID, &vector); break; } /* * Check for errors * At this point, if a VME bus error has occured, it must be * cleared by the sysUnivVERRClr() routine and the vector discarded. * The vector returned during a VME bus error is bogus. */ if ((vector & V1_STATID_ERR) != 0) { /* Clear VME bus error */ sysUnivVERRClr (); /* Discard bad vector */ *vecNum = 0; } else *vecNum = vector & 0xFF; /* only eight bits of useful info */ } *intLvl = i; return (bitLvlMsk); }/********************************************************************************* sysUnivVmeIntr - Hawk VMEbus interrupt handler** This is the VMEbus interrupt handler for the Motorola Hawk PCI Host* Bridge (PHB) and Multi-Processor Interrupt Controller (MPIC). It is* connected to the single VMEbus interrupt from the Hawk and examines the* Universe to chip to determine the interrupt level and vector of the* interrupt source. Having obtained the vector number, this routine then* vectors into the system vector table to the specified interrupt handling* routine.** RETURNS: N/A*/void sysUnivVmeIntr (void) { int pendingIntr; int highestIntr; int prevIntLvl; int univIntLvl; int vec_num = 0; INT_HANDLER_DESC * currHandler; /* get pending interrupt level(s) */ UNIV_IN_LONG(UNIVERSE_LINT_STAT, &pendingIntr); pendingIntr &= LINT_STAT_INT_MASK; pendingIntr &= sysUnivIntsEnabled; /* * Handle pending interrupts in order of highest priority. * * For each interrupt, determine the level, get vector associated * with the interrupt, set the appropriate interrupt level, clear the * interrupt in the Universe, and dispatch to all associated ISRs. */ if (pendingIntr != 0) { /* Determine highest interrupt priority level and vector */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -