www.pudn.com > vxworks0108.rar > sysMcp.c


/*---------------------------------------------------------------- +includes+-*/
#include "type.h"
#include "asm.h"
#include "reg.h"
#include "esf.h"
#include "pciConfigLib.h"
#include "config.h"
#include "vg4.h"
#include "mpc107.h"
#include "syslib.h"
#include "string.h"
#include "universe.h"
/*-----------------------------------------------------------------(includes)-*/


/*------------------------------------------------------------------+defines+-*/
#define _PPC_SRR1_MCPIN_U       0x0008  /* set by assertion of MCP */
#define EXC_MCP_LOCK            /* lock MCP pin during exception handling */
/*------------------------------------------------------------------(defines)-*/


/*-----------------------------------------------------------------+typedefs+-*/
/*-----------------------------------------------------------------(typedefs)-*/


/*------------------------------------------------------------------+globals+-*/
/* Counter for machine check exceptions caused by assertion of MCP. */
UINT32 mcpExcCnt = 0;

/* ECC single-bit error counter */
UINT32 eccSingleBitErrorCnt = 0;

/* ECC multi-bit error counter */
UINT32 eccMultiBitErrorCnt = 0;

/* User ECC Single-Bit error routines */
LOCAL FUNCPTR eccSingleBitErrorRoutine = NULL;
LOCAL int eccSingleBitArg = 0;

/* User ECC Multi-Bit error routines */
LOCAL FUNCPTR eccMultiBitErrorRoutine = NULL;
LOCAL int eccMultiBitArg = 0;
/*------------------------------------------------------------------(globals)-*/


/*-------------------------------------------------------------+declarations+-*/
IMPORT void printf();
/*-------------------------------------------------------------(declarations)-*/

#if defined (EXC_MCP_LOCK)
/*********************************************************************
*
* mcpLock - Locks out further machine check exceptions from MCP
*
* This routine clears HID0[EMCP]. This masks out further machine check 
* exceptions caused by assertion of MCP.
*
* RETURNS: content of HID0 before masking MCP exceptions
*
* ULONG mcpLock
*     (
*     void
*     )
*
*/

LOCAL ULONG mcpLock (void)
{
   UINT     hid0;

   __asm__ volatile ("mfspr     %0, 1008 
                      rlwinm    4, %0, 0, 1, 31
                      mtspr     1008, 4
                      isync"
                     : "=r" (hid0)  /* output operand, %0 */
                     :              /* no input operand */
                     : "r4"         /* side effects: r4 altered */
                     );

    return (hid0);
}

/*********************************************************************
*
* mcpUnlock - Unlocks machine check exceptions from MCP
*
* This routine sets HID0[EMCP]. This re-enables machine check 
* exceptions caused by assertion of MCP.
*
* RETURNS: N/A
*
* ULONG mcpLock
*     (
*     void
*     )
*
*/

LOCAL __inline__ void mcpUnlock 
        (
        ULONG oldHid0   /* value returned by mcpLock() */
        )
{
   __asm__ volatile ("rlwinm    3, %0, 0, 0, 0
                      mfspr     4, 1008 
                      or        4, 3, 4
                      mtspr     1008, 4
                      isync"
                     :                  /* no output operand */
                     : "r" (oldHid0)    /* input operand, %0 = input */
                     : "r4"             /* side effects: r4 altered */
                     );

    return;
}
#endif /* defined (EXC_MCP_LOCK) */


/***************************************************************************
*
* sysMcpExcHandler - machine check exception handler
*
* This function is invoked in response to a PPC Machine Check Exception.
*
* This exception may be due to an ECC error, in which case the user installed 
* routine for single-bit or multi-bit errors is called if it has been 
* connected. Otherwise the VxWorks generic exception handler is then called.
*
* The machine check exception may also occur due to the VG4 MCP timer.
* The MCP timer can trigger IOCHCK at the ISA bus periodically, if enabled. 
* This will trigger the MCP input of the processor via the NMI input of 
* the MPC107. 
*
* RETURNS:  N/A
*
* SEE ALSO: sysMcpInit()
*
*/

LOCAL void sysMcpExcHandler 
    (
    void * pEsf
    )
{
#if defined (INCLUDE_ECC) || defined (INCLUDE_MCP_TIMER) || defined (INCLUDE_VME)

#if defined (EXC_MCP_LOCK)
    ULONG   lockVal;
#endif /* defined (EXC_MCP_LOCK) */
    int fatal=0;    /* set when error is assumed fatal and
                       default exception handler shall be called */
    volatile ULONG dummy;

#if defined (INCLUDE_ECC)
    UINT8   eccRegVal,
            eccRegVal2;
#endif /* defined (INCLUDE_ECC) */


#if 0
    _PPC_SRR1_MCPIN_U might not been set although, for instance, an VMEbus
    error occurred. This happens for example when using the dump command
    on the console (e.g. d 0xd0001234).
    Better check I/O status bits first.
    /* 
     * Call VxWorks default exception handler, if source for the machine check 
     * exception is not the MCP.
     */
    if ((vxSrr1Get() & (_PPC_SRR1_MCPIN_U << 16)) != (_PPC_SRR1_MCPIN_U << 16))
    {
        excExcHandle (pEsf);
    }
#endif

#if defined (EXC_MCP_LOCK)
/* Disable further machine check exception from the MCP. */
    lockVal = mcpLock ();
#endif /* defined (EXC_MCP_LOCK) */

    /* Increment counter for number of MCP exceptions. */
    mcpExcCnt++;

#if defined (INCLUDE_VME)
	{
	UINT32 pciCsr;
	UINT32 laerr, amerr;
	IMPORT UINT32 univBaseAdrs;

	/* Get current UNIVERSE status */
	sysPciRead32 ((UINT32)(UNIVERSE_PCI_CSR), &pciCsr);
	sysPciRead32 ((UINT32)UNIVERSE_V_AMERR, &amerr);
	if ((pciCsr & 0xf8000000) || (amerr & V_AMERR_V_STAT)) {
		/* VME error occurred */
		printf("\nVMEbus ERROR\nUNIVERSE PCI_CSR 0x%x\n", pciCsr, 0, 0, 0, 0);
		sysPciWrite32 ((UINT32)(UNIVERSE_PCI_CSR), pciCsr);
		sysPciRead32 ((UINT32)UNIVERSE_VAERR, &laerr);
		printf("UNIVERSE VAERR 0x%x\n", laerr, 0, 0, 0, 0);
		printf("UNIVERSE AMERR 0x%x\n", amerr, 0, 0, 0, 0);
		/* Clear any VME address error */
		sysPciWrite32 ((UINT32)UNIVERSE_V_AMERR, V_AMERR_V_STAT);
		/* Force write due to Write-Posting and get updated status */
		sysPciRead32 ((UINT32)(UNIVERSE_PCI_CSR), &pciCsr);

        /* Dummy read from 0x0200 to cause the negation of MCP. */
        dummy = *((volatile ULONG*)_EXC_OFF_MACH);

        fatal = 1;
	}
	}
#endif /* defined (INCLUDE_VME) */

#if defined (INCLUDE_ECC)
    /* Read Error Detection Register 1 and check for ECC trigger exceeded error. */
    if (OK == pciConfigInByte (0, 0, 0, MPC107_EDR1, &eccRegVal))
    {

        if (eccRegVal & MPC107_EDR1_MRPE)
        {
            /* Increment counter for single-bit errors. */
            eccSingleBitErrorCnt++;

            /* ECC Single-Bit Error Trigger exceeded */
            if ( eccSingleBitErrorRoutine != NULL )
            {
                (*(FUNCPTR)eccSingleBitErrorRoutine)(eccSingleBitArg);
            }
            else
            {
                eccRegVal = 0;
                if (OK == pciConfigInByte (0, 0, 0, MPC107_ECCSBETR, &eccRegVal))
                {
                    printf ("ECC Single-Bit Errors occurred (trigger value is %d)!\n",
                             (UINT)eccRegVal,0,0,0,0);
                }
                else
                {
                    printf ("ECC Single-Bit Errors occurred!\n",0,0,0,0,0);
                }
            }

            /* reset ECC single-bit error counter */
            (void)pciConfigOutByte (0, 0, 0, MPC107_ECCSBEC, 0x00);

            /* Clear ECC single-bit error trigger exceeded bit */
            (void)pciConfigOutByte (0, 0, 0, MPC107_EDR1, MPC107_EDR1_MRPE);

            /* Dummy read from 0x0200 to cause the negation of MCP. */
            dummy = *((volatile ULONG*)_EXC_OFF_MACH);
        }
    }    

    /* Read Error Detection Register 2 and check for ECC multi-bit error. */
    if (OK == pciConfigInByte (0, 0, 0, MPC107_EDR2, &eccRegVal2))
    {
        if (eccRegVal2 & MPC107_EDR2_EMBE)
        {
            /* Increment counter for multi-bit errors. */
            eccMultiBitErrorCnt++;

            /* ECC Multi-Bit Error occurred */
            if ( eccMultiBitErrorRoutine != NULL )
            {
                (*(FUNCPTR)eccMultiBitErrorRoutine)(eccMultiBitArg);
            }
            else
            {
                printf ("ECC Multi-Bit Error occurred!\n",0,0,0,0,0);
            }

            /* Clear ECC multi-bit error bit */
            (void)pciConfigOutByte (0, 0, 0, MPC107_EDR2, MPC107_EDR2_EMBE);

            /* Dummy read from 0x0200 to cause the negation of MCP. */
            dummy = *((volatile ULONG*)_EXC_OFF_MACH);
        }   
    }
#endif /* defined (INCLUDE_ECC) */

	/*
	 * not needed for ECC errors, since they are not reported in the cnf
	 * status reg, but for VMEbus errors (Target Abort Error).
	 */
    /* Clear Cnfg Hdr Status Reg of Chaparral (MPC107) */
    pciConfigOutWord (0, 0, 0, MPC107_PCI_STAT, MPC107_PCI_STAT_CLR);

#if defined (EXC_MCP_LOCK)
    /* Enable machine check exception from the MCP again. */
    mcpUnlock (lockVal);
#endif /* defined (EXC_MCP_LOCK) */

    if (fatal) {
        /* Call VxWorks default exception handler. */
/*        excExcHandle (pEsf); */
    }

    return;
#else       

    /* Call VxWorks default exception handler. */
/*    excExcHandle (pEsf); */

    return;
#endif /* defined (INCLUDE_ECC) || defined (INCLUDE_MCP_TIMER) */
}


/***************************************************************************
*
* sysMcpInit - machine check pin initialization
*
* This function is initializes possible MCP sources like memory ECC or 
* MCP timer.
*
* First error reporting is disabled for all kind of ECC errors. 
* If ECC error handling is included, a machine check exception handler is
* connected, all error counters are reset and error reporting is enabled.
* ECC error reporting for single-bit errors is not enabled by default. It
* must be included in config.h if desired. 
*
* PCI Received Target Abort Error is enabled to generate MCP interrupts for
* VMEbus Bus Errors.
* Finally Machine Check Exception are enabled in the MPC107.
*
* RETURNS:  N/A
*
* SEE ALSO: sysMcpExcHandler()
*
*/
#if 0
void sysMcpInit (void)
{
#if defined (INCLUDE_ECC)
    UINT32  regVal;
#endif /* defined (INCLUDE_ECC) */
    int     lockVal;

    /* Disable single-bit ECC error reporting for SDRAM. */
    (void)pciConfigModifyByte (0, 0, 0, MPC107_EER1, MPC107_EER1_MPECCEE, 0);

    /* Disable multi-bit ECC error reporting for SDRAM. */
    (void)pciConfigModifyByte (0, 0, 0, MPC107_EER2, MPC107_EER2_ECCMEE, 0);

	/* Disable PCI Received Target Abort Error in ErrEnR2 - 0xc4 */
	(void)pciConfigModifyByte(0, 0, 0, MPC107_EER2, MPC107_EER2_PCIRTAEE, 0);


#if defined (INCLUDE_ECC)

    /* Reset error counter. */
    eccSingleBitErrorCnt = 0;
    eccMultiBitErrorCnt = 0;
    mcpExcCnt = 0;

    /* Enable ECC error reporting if ECC is enabled. */
    if ( OK == pciConfigInLong (0, 0, 0, MPC107_MCCR2, ®Val) )
    {
        if ( 0 == (regVal & MPC107_MCCR2_INLPARNOTECC) )              /* ECC enabled */
        {
            /* Clear ECC single-bit error trigger exceeded bit. */
            (void)pciConfigOutByte (0, 0, 0, MPC107_EDR1, MPC107_EDR1_MRPE);

            /* Clear ECC multi-bit error bit */
            (void)pciConfigOutByte (0, 0, 0, MPC107_EDR2, MPC107_EDR2_EMBE);

            /* Reset ECC single-bit error counter. */
            (void)pciConfigOutByte (0, 0, 0, MPC107_ECCSBEC, 0x00);

            /* Set ECC single-bit error trigger to pre-defined value. */
            (void)pciConfigOutByte (0, 0, 0, MPC107_ECCSBETR, ECC_SINGLE_BIT_TRIG_VAL);


#if defined (INCLUDE_ECC_SINGLE_BIT)
             /* Enable single-bit ECC erorrs for SDRAM */
            (void)pciConfigModifyByte (0, 0, 0, MPC107_EER1, MPC107_EER1_MPECCEE, MPC107_EER1_MPECCEE);
#endif /* defined (INCLUDE_ECC_SINGLE_BIT) */

            /* Enable multibit ECC erorrs for SDRAM */
            (void)pciConfigModifyByte (0, 0, 0, MPC107_EER2, MPC107_EER2_ECCMEE, MPC107_EER2_ECCMEE);
        }
    }
#endif /* defined (INCLUDE_ECC) */
	
    /* Connect handler for Machine Check exception. */
    excConnect ((VOIDFUNCPTR *) _EXC_OFF_MACH, sysMcpExcHandler);

    /* Enable Machine Check exception */
    lockVal=intLock();
    vxMsrSet(vxMsrGet() | _PPC_MSR_ME);
    intUnlock(lockVal);
    EIEIO_SYNC;

    /* Enable Machine Check Pin (EMCP) */
    lockVal=intLock();
    vxHid0Set(vxHid0Get() | _PPC_HID0_EMCP);
    intUnlock(lockVal);
    EIEIO_SYNC;

	/*
	 * Enable MCP interrupts in MPC107
	 * Processor Interface Configuration Register (PRC1/PICR1 - 0xA8)
	 */
	(void) pciConfigModifyLong(0, 0, 0,
			MPC107_PRC1, MPC107_PRC1_MCP_EN, MPC107_PRC1_MCP_EN);
    EIEIO_SYNC;

	/*
	 * enable PCI Received Target Abort Error in ErrEnR2 - 0xc4 
	 * this will cause an machine check exception upon VMEbus BERR
	 * if MCP interrupts are enabled in MPC107 (PICR1 |= MCP_EN)
	 */
	(void)pciConfigModifyByte(0, 0, 0,
					MPC107_EER2, MPC107_EER2_PCIRTAEE, MPC107_EER2_PCIRTAEE);
}
#endif

#if defined (INCLUDE_ECC)
#if defined (INCLUDE_ECC_SINGLE_BIT)
/*****************************************************************************
*
* sysEccSingleBitErrorConnect - connect user routine for ECC single-bit error
*
* This function installs the specified user routine that is to be invoked upon
* an ECC single-bit error. Single-bit errors can be corrected by the ECC 
* hardware logic. Therefore single-bit error handling is not included by 
* default. To include single-bit error support the following define must be set 
* in config.h in addition to INCLUDE_ECC:
* #define INCLUDE_ECC_SINGLE_BIT
* 
* The number of single-bit errors at which a mchine check exception is asserted
* may be specified with the following define:
* #define ECC_SINGLE_BIT_TRIG_VAL  0xff  (0xff is the default value)
*
* RETURNS: OK, always
*
* SEE ALSO: sysEccMultiBitErrorConnect()
*
*/

STATUS sysEccSingleBitErrorConnect 
    (
    FUNCPTR routine,    /* routine called for ECC single-bit error */
    int arg             /* argument to single-bit error routine */
    )
{
    eccSingleBitErrorRoutine = routine;
    eccSingleBitArg = arg;
    return OK;
}
#endif /* defined (INCLUDE_ECC_SINGLE_BIT) */


/*****************************************************************************
*
* sysEccMultiBitErrorConnect - connect user routine for ECC multi-bit error
*
* This function installs the specified user routine that is to be invoked upon
* an ECC multi-bit error. Usually multi-bit errors are not correctable, 
* therefore multi-bit ECC error handling is included, if INCLUDE_ECC is defined 
* in config.h.
*
* RETURNS: OK, always
*
* SEE ALSO: sysEccSingleBitErrorConnect()
*
*/

STATUS sysEccMultiBitErrorConnect 
    (
    FUNCPTR routine,    /* routine called for ECC multi-bit error */
    int arg             /* argument to multi-bit error routine */
    )
{
    eccMultiBitErrorRoutine = routine;
    eccMultiBitArg = arg;
    return OK;
}
#endif /* defined (INCLUDE_ECC) */


#if defined (INCLUDE_SHOW_ROUTINES) && (defined (INCLUDE_ECC) || defined (INCLUDE_MCP_TIMER))
/******************************************************************************
*
* sysMcpExcShow - display MCP debug information
*
* This function displays the number of exceptions handled by the MCP handler
* sysMcpExcHandler(). The number of single-bit and multi-bit ECC errors are
* displayed too.
*
* RETURNS: none
*/

void sysMcpExcShow (void)
{
#if defined (INCLUDE_ECC_SINGLE_BIT)
    UINT8   eccRegVal;
#endif /* defined (INCLUDE_ECC_SINGLE_BIT) */

    printf ("\nMCP Exception Count Summary:\n");
    printf (" # of total MCP exceptions:        %8d\n", mcpExcCnt);
#if defined (INCLUDE_ECC_SINGLE_BIT)
    printf (" # of single-bit ECC exceptions:   %8d\n", eccSingleBitErrorCnt);
    if (OK == pciConfigInByte (0, 0, 0, MPC107_ECCSBEC, &eccRegVal))
    {
        printf (" # of current single-bit ECC errors:    %3d\n", eccRegVal);
    }
    if (OK == pciConfigInByte (0, 0, 0, MPC107_ECCSBETR, &eccRegVal))
    {
        printf (" single-bit ECC trigger value:          %3d\n", eccRegVal);
    }
#endif /* defined (INCLUDE_ECC_SINGLE_BIT) */
    printf (" # of multi-bit ECC exceptions:    %8d\n", eccMultiBitErrorCnt);

}
#endif /* defined (INCLUDE_SHOW_ROUTINES) && (defined (INCLUDE_ECC) || defined (INCLUDE_MCP_TIMER))*/