/** * @file IxNpeMhConfig.c * * @author Intel Corporation * @date 18 Jan 2002 * * @brief This file contains the implementation of the private API for the * Configuration module. * * * @par * IXP400 SW Release version 2.0 * * -- Copyright Notice -- * * @par * Copyright 2001-2005, Intel Corporation. * All rights reserved. * * @par * SPDX-License-Identifier: BSD-3-Clause * @par * -- End of Copyright Notice -- */ /* * Put the system defined include files required. */ /* * Put the user defined include files required. */ #include "IxOsal.h" #include "IxNpeMhMacros_p.h" #include "IxNpeMhConfig_p.h" /* * #defines and macros used in this file. */ #define IX_NPE_MH_MAX_NUM_OF_RETRIES 1000000 /**< Maximum number of * retries before * timeout */ /* * Typedefs whose scope is limited to this file. */ /** * @struct IxNpeMhConfigStats * * @brief This structure is used to maintain statistics for the * Configuration module. */ typedef struct { UINT32 outFifoReads; /**< outFifo reads */ UINT32 inFifoWrites; /**< inFifo writes */ UINT32 maxInFifoFullRetries; /**< max retries if inFIFO full */ UINT32 maxOutFifoEmptyRetries; /**< max retries if outFIFO empty */ } IxNpeMhConfigStats; /* * Variable declarations global to this file only. Externs are followed by * static variables. */ IxNpeMhConfigNpeInfo ixNpeMhConfigNpeInfo[IX_NPEMH_NUM_NPES] = { { 0, IX_NPEMH_NPEA_INT, 0, 0, 0, 0, 0, NULL, false }, { 0, IX_NPEMH_NPEB_INT, 0, 0, 0, 0, 0, NULL, false }, { 0, IX_NPEMH_NPEC_INT, 0, 0, 0, 0, 0, NULL, false } }; PRIVATE IxNpeMhConfigStats ixNpeMhConfigStats[IX_NPEMH_NUM_NPES]; /* * Extern function prototypes. */ /* * Static function prototypes. */ PRIVATE void ixNpeMhConfigIsr (void *parameter); /* * Function definition: ixNpeMhConfigIsr */ PRIVATE void ixNpeMhConfigIsr (void *parameter) { IxNpeMhNpeId npeId = (IxNpeMhNpeId)parameter; UINT32 ofint; volatile UINT32 *statusReg = (UINT32 *)ixNpeMhConfigNpeInfo[npeId].statusRegister; IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigIsr\n"); /* get the OFINT (OutFifo interrupt) bit of the status register */ IX_NPEMH_REGISTER_READ_BITS (statusReg, &ofint, IX_NPEMH_NPE_STAT_OFINT); /* if the OFINT status bit is set */ if (ofint) { /* if there is an ISR registered for this NPE */ if (ixNpeMhConfigNpeInfo[npeId].isr != NULL) { /* invoke the ISR routine */ ixNpeMhConfigNpeInfo[npeId].isr (npeId); } else { /* if we don't service the interrupt the NPE will continue */ /* to trigger the interrupt indefinitely */ IX_NPEMH_ERROR_REPORT ("No ISR registered to service " "interrupt\n"); } } IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigIsr\n"); } /* * Function definition: ixNpeMhConfigInitialize */ void ixNpeMhConfigInitialize ( IxNpeMhNpeInterrupts npeInterrupts) { IxNpeMhNpeId npeId; UINT32 virtualAddr[IX_NPEMH_NUM_NPES]; IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigInitialize\n"); /* Request a mapping for the NPE-A config register address space */ virtualAddr[IX_NPEMH_NPEID_NPEA] = (UINT32) IX_OSAL_MEM_MAP (IX_NPEMH_NPEA_BASE, IX_OSAL_IXP400_NPEA_MAP_SIZE); IX_OSAL_ASSERT (virtualAddr[IX_NPEMH_NPEID_NPEA]); /* Request a mapping for the NPE-B config register address space */ virtualAddr[IX_NPEMH_NPEID_NPEB] = (UINT32) IX_OSAL_MEM_MAP (IX_NPEMH_NPEB_BASE, IX_OSAL_IXP400_NPEB_MAP_SIZE); IX_OSAL_ASSERT (virtualAddr[IX_NPEMH_NPEID_NPEB]); /* Request a mapping for the NPE-C config register address space */ virtualAddr[IX_NPEMH_NPEID_NPEC] = (UINT32) IX_OSAL_MEM_MAP (IX_NPEMH_NPEC_BASE, IX_OSAL_IXP400_NPEC_MAP_SIZE); IX_OSAL_ASSERT (virtualAddr[IX_NPEMH_NPEID_NPEC]); /* for each NPE ... */ for (npeId = 0; npeId < IX_NPEMH_NUM_NPES; npeId++) { /* declare a convenience pointer */ IxNpeMhConfigNpeInfo *npeInfo = &ixNpeMhConfigNpeInfo[npeId]; /* store the virtual addresses of the NPE registers for later use */ npeInfo->virtualRegisterBase = virtualAddr[npeId]; npeInfo->statusRegister = virtualAddr[npeId] + IX_NPEMH_NPESTAT_OFFSET; npeInfo->controlRegister = virtualAddr[npeId] + IX_NPEMH_NPECTL_OFFSET; npeInfo->inFifoRegister = virtualAddr[npeId] + IX_NPEMH_NPEFIFO_OFFSET; npeInfo->outFifoRegister = virtualAddr[npeId] + IX_NPEMH_NPEFIFO_OFFSET; /* for test purposes - to verify the register addresses */ IX_NPEMH_TRACE2 (IX_NPEMH_DEBUG, "NPE %d status register = " "0x%08X\n", npeId, npeInfo->statusRegister); IX_NPEMH_TRACE2 (IX_NPEMH_DEBUG, "NPE %d control register = " "0x%08X\n", npeId, npeInfo->controlRegister); IX_NPEMH_TRACE2 (IX_NPEMH_DEBUG, "NPE %d inFifo register = " "0x%08X\n", npeId, npeInfo->inFifoRegister); IX_NPEMH_TRACE2 (IX_NPEMH_DEBUG, "NPE %d outFifo register = " "0x%08X\n", npeId, npeInfo->outFifoRegister); /* connect our ISR to the NPE interrupt */ (void) ixOsalIrqBind ( npeInfo->interruptId, ixNpeMhConfigIsr, (void *)npeId); /* initialise a mutex for this NPE */ (void) ixOsalMutexInit (&npeInfo->mutex); /* if we should service the NPE's "outFIFO not empty" interrupt */ if (npeInterrupts == IX_NPEMH_NPEINTERRUPTS_YES) { /* enable the NPE's "outFIFO not empty" interrupt */ ixNpeMhConfigNpeInterruptEnable (npeId); } else { /* disable the NPE's "outFIFO not empty" interrupt */ ixNpeMhConfigNpeInterruptDisable (npeId); } } IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigInitialize\n"); } /* * Function definition: ixNpeMhConfigUninit */ void ixNpeMhConfigUninit (void) { IxNpeMhNpeId npeId; IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigUninit\n"); /* for each NPE ... */ for (npeId = 0; npeId < IX_NPEMH_NUM_NPES; npeId++) { /* declare a convenience pointer */ IxNpeMhConfigNpeInfo *npeInfo = &ixNpeMhConfigNpeInfo[npeId]; /* disconnect ISR */ ixOsalIrqUnbind(npeInfo->interruptId); /* destroy mutex associated with this NPE */ ixOsalMutexDestroy(&npeInfo->mutex); IX_OSAL_MEM_UNMAP (npeInfo->virtualRegisterBase); npeInfo->virtualRegisterBase = 0; npeInfo->statusRegister = 0; npeInfo->controlRegister = 0; npeInfo->inFifoRegister = 0; npeInfo->outFifoRegister = 0; } IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigUninit\n"); } /* * Function definition: ixNpeMhConfigIsrRegister */ void ixNpeMhConfigIsrRegister ( IxNpeMhNpeId npeId, IxNpeMhConfigIsr isr) { IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigIsrRegister\n"); /* check if there is already an ISR registered for this NPE */ if (ixNpeMhConfigNpeInfo[npeId].isr != NULL) { IX_NPEMH_TRACE0 (IX_NPEMH_DEBUG, "Over-writing registered NPE ISR\n"); } /* save the ISR routine with the NPE info */ ixNpeMhConfigNpeInfo[npeId].isr = isr; IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigIsrRegister\n"); } /* * Function definition: ixNpeMhConfigNpeInterruptEnable */ BOOL ixNpeMhConfigNpeInterruptEnable ( IxNpeMhNpeId npeId) { UINT32 ofe; volatile UINT32 *controlReg = (UINT32 *)ixNpeMhConfigNpeInfo[npeId].controlRegister; /* get the OFE (OutFifoEnable) bit of the control register */ IX_NPEMH_REGISTER_READ_BITS (controlReg, &ofe, IX_NPEMH_NPE_CTL_OFE); /* if the interrupt is disabled then we must enable it */ if (!ofe) { /* set the OFE (OutFifoEnable) bit of the control register */ /* we must set the OFEWE (OutFifoEnableWriteEnable) at the same */ /* time for the write to have effect */ IX_NPEMH_REGISTER_WRITE_BITS (controlReg, (IX_NPEMH_NPE_CTL_OFE | IX_NPEMH_NPE_CTL_OFEWE), (IX_NPEMH_NPE_CTL_OFE | IX_NPEMH_NPE_CTL_OFEWE)); } /* return the previous state of the interrupt */ return (ofe != 0); } /* * Function definition: ixNpeMhConfigNpeInterruptDisable */ BOOL ixNpeMhConfigNpeInterruptDisable ( IxNpeMhNpeId npeId) { UINT32 ofe; volatile UINT32 *controlReg = (UINT32 *)ixNpeMhConfigNpeInfo[npeId].controlRegister; /* get the OFE (OutFifoEnable) bit of the control register */ IX_NPEMH_REGISTER_READ_BITS (controlReg, &ofe, IX_NPEMH_NPE_CTL_OFE); /* if the interrupt is enabled then we must disable it */ if (ofe) { /* unset the OFE (OutFifoEnable) bit of the control register */ /* we must set the OFEWE (OutFifoEnableWriteEnable) at the same */ /* time for the write to have effect */ IX_NPEMH_REGISTER_WRITE_BITS (controlReg, (0 | IX_NPEMH_NPE_CTL_OFEWE), (IX_NPEMH_NPE_CTL_OFE | IX_NPEMH_NPE_CTL_OFEWE)); } /* return the previous state of the interrupt */ return (ofe != 0); } /* * Function definition: ixNpeMhConfigMessageIdGet */ IxNpeMhMessageId ixNpeMhConfigMessageIdGet ( IxNpeMhMessage message) { /* return the most-significant byte of the first word of the */ /* message */ return ((IxNpeMhMessageId) ((message.data[0] >> 24) & 0xFF)); } /* * Function definition: ixNpeMhConfigNpeIdIsValid */ BOOL ixNpeMhConfigNpeIdIsValid ( IxNpeMhNpeId npeId) { /* check that the npeId parameter is within the range of valid IDs */ return (npeId >= 0 && npeId < IX_NPEMH_NUM_NPES); } /* * Function definition: ixNpeMhConfigLockGet */ void ixNpeMhConfigLockGet ( IxNpeMhNpeId npeId) { IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigLockGet\n"); /* lock the mutex for this NPE */ (void) ixOsalMutexLock (&ixNpeMhConfigNpeInfo[npeId].mutex, IX_OSAL_WAIT_FOREVER); /* disable the NPE's "outFIFO not empty" interrupt */ ixNpeMhConfigNpeInfo[npeId].oldInterruptState = ixNpeMhConfigNpeInterruptDisable (npeId); IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigLockGet\n"); } /* * Function definition: ixNpeMhConfigLockRelease */ void ixNpeMhConfigLockRelease ( IxNpeMhNpeId npeId) { IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Entering " "ixNpeMhConfigLockRelease\n"); /* if the interrupt was previously enabled */ if (ixNpeMhConfigNpeInfo[npeId].oldInterruptState) { /* enable the NPE's "outFIFO not empty" interrupt */ ixNpeMhConfigNpeInfo[npeId].oldInterruptState = ixNpeMhConfigNpeInterruptEnable (npeId); } /* unlock the mutex for this NPE */ (void) ixOsalMutexUnlock (&ixNpeMhConfigNpeInfo[npeId].mutex); IX_NPEMH_TRACE0 (IX_NPEMH_FN_ENTRY_EXIT, "Exiting " "ixNpeMhConfigLockRelease\n"); } /* * Function definition: ixNpeMhConfigInFifoWrite */ IX_STATUS ixNpeMhConfigInFifoWrite ( IxNpeMhNpeId npeId, IxNpeMhMessage message) { volatile UINT32 *npeInFifo = (UINT32 *)ixNpeMhConfigNpeInfo[npeId].inFifoRegister; UINT32 retriesCount = 0; /* write the first word of the message to the NPE's inFIFO */ IX_NPEMH_REGISTER_WRITE (npeInFifo, message.data[0]); /* need to wait for room to write second word - see SCR #493, poll for maximum number of retries, if exceed maximum retries, exit from while loop */ while ((IX_NPE_MH_MAX_NUM_OF_RETRIES > retriesCount) && ixNpeMhConfigInFifoIsFull (npeId)) { retriesCount++; } /* Return TIMEOUT status to caller, indicate that NPE Hang / Halt */ if (IX_NPE_MH_MAX_NUM_OF_RETRIES == retriesCount) { return IX_NPEMH_CRITICAL_NPE_ERR; } /* write the second word of the message to the NPE's inFIFO */ IX_NPEMH_REGISTER_WRITE (npeInFifo, message.data[1]); /* record in the stats the maximum number of retries needed */ if (ixNpeMhConfigStats[npeId].maxInFifoFullRetries < retriesCount) { ixNpeMhConfigStats[npeId].maxInFifoFullRetries = retriesCount; } /* update statistical info */ ixNpeMhConfigStats[npeId].inFifoWrites++; return IX_SUCCESS; } /* * Function definition: ixNpeMhConfigOutFifoRead */ IX_STATUS ixNpeMhConfigOutFifoRead ( IxNpeMhNpeId npeId, IxNpeMhMessage *message) { volatile UINT32 *npeOutFifo = (UINT32 *)ixNpeMhConfigNpeInfo[npeId].outFifoRegister; UINT32 retriesCount = 0; /* read the first word of the message from the NPE's outFIFO */ IX_NPEMH_REGISTER_READ (npeOutFifo, &message->data[0]); /* need to wait for NPE to write second word - see SCR #493 poll for maximum number of retries, if exceed maximum retries, exit from while loop */ while ((IX_NPE_MH_MAX_NUM_OF_RETRIES > retriesCount) && ixNpeMhConfigOutFifoIsEmpty (npeId)) { retriesCount++; } /* Return TIMEOUT status to caller, indicate that NPE Hang / Halt */ if (IX_NPE_MH_MAX_NUM_OF_RETRIES == retriesCount) { return IX_NPEMH_CRITICAL_NPE_ERR; } /* read the second word of the message from the NPE's outFIFO */ IX_NPEMH_REGISTER_READ (npeOutFifo, &message->data[1]); /* record in the stats the maximum number of retries needed */ if (ixNpeMhConfigStats[npeId].maxOutFifoEmptyRetries < retriesCount) { ixNpeMhConfigStats[npeId].maxOutFifoEmptyRetries = retriesCount; } /* update statistical info */ ixNpeMhConfigStats[npeId].outFifoReads++; return IX_SUCCESS; } /* * Function definition: ixNpeMhConfigShow */ void ixNpeMhConfigShow ( IxNpeMhNpeId npeId) { /* show the message fifo read counter */ IX_NPEMH_SHOW ("Message FIFO reads", ixNpeMhConfigStats[npeId].outFifoReads); /* show the message fifo write counter */ IX_NPEMH_SHOW ("Message FIFO writes", ixNpeMhConfigStats[npeId].inFifoWrites); /* show the max retries performed when inFIFO full */ IX_NPEMH_SHOW ("Max inFIFO Full retries", ixNpeMhConfigStats[npeId].maxInFifoFullRetries); /* show the max retries performed when outFIFO empty */ IX_NPEMH_SHOW ("Max outFIFO Empty retries", ixNpeMhConfigStats[npeId].maxOutFifoEmptyRetries); /* show the current status of the inFifo */ ixOsalLog (IX_OSAL_LOG_LVL_USER, IX_OSAL_LOG_DEV_STDOUT, "InFifo is %s and %s\n", (ixNpeMhConfigInFifoIsEmpty (npeId) ? (int) "EMPTY" : (int) "NOT EMPTY"), (ixNpeMhConfigInFifoIsFull (npeId) ? (int) "FULL" : (int) "NOT FULL"), 0, 0, 0, 0); /* show the current status of the outFifo */ ixOsalLog (IX_OSAL_LOG_LVL_USER, IX_OSAL_LOG_DEV_STDOUT, "OutFifo is %s and %s\n", (ixNpeMhConfigOutFifoIsEmpty (npeId) ? (int) "EMPTY" : (int) "NOT EMPTY"), (ixNpeMhConfigOutFifoIsFull (npeId) ? (int) "FULL" : (int) "NOT FULL"), 0, 0, 0, 0); } /* * Function definition: ixNpeMhConfigShowReset */ void ixNpeMhConfigShowReset ( IxNpeMhNpeId npeId) { /* reset the message fifo read counter */ ixNpeMhConfigStats[npeId].outFifoReads = 0; /* reset the message fifo write counter */ ixNpeMhConfigStats[npeId].inFifoWrites = 0; /* reset the max inFIFO Full retries counter */ ixNpeMhConfigStats[npeId].maxInFifoFullRetries = 0; /* reset the max outFIFO empty retries counter */ ixNpeMhConfigStats[npeId].maxOutFifoEmptyRetries = 0; }