2013-04-06 16:48:33 +02:00

918 lines
34 KiB
C

/*-
* Copyright (C) 2001-2003 by NBMK Encryption Technologies.
* All rights reserved.
*
* NBMK Encryption Technologies provides no support of any kind for
* this software. Questions or concerns about it may be addressed to
* the members of the relevant open-source community at
* <tech-crypto@netbsd.org>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static char const n8_id[] = "$Id: irq.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
/*****************************************************************************/
/** @file irq.c
* @brief NSP2000 Device Driver interrupt handling functions
*
* This file contains all secondary interrupt handling routines for the
* NSP2000 Device Driver.
*
*****************************************************************************/
/*****************************************************************************
* Revision history:
* 01/06/04 brr Clear the PKH & CCH status register prior to reading queue
* pointer register to ensure write completes before exiting the
* interrupt handler. Only write AMBA status register on AMBA
* timer interrupts. (Bug 995)
* 07/15/03 brr Moved CCH processing to a Linux tasklet.
* 07/01/03 brr Clear CCH interrupts before reenabling the core.
* 05/15/03 brr Enable RNG interrupt, remove references to duplicate register
* definitions in irq.h
* 04/08/03 brr Bypass AMBA mirror registers.
* 04/03/03 brr Minor modifications to improve performance.
* 04/01/03 brr Reverted N8_WaitOnRequest to accept timeout parameter.
* 03/31/03 brr Do not rely on atomic_inc_and_test.
* 03/24/03 brr Fix race condition when conditionally resetting AMBA timer.
* 03/21/03 brr Only check for completed EA commands on AMBA timer interrupt.
* 03/19/03 brr Added Interrupt statistics and display function, eliminating
* IRQ prints. Added reload_AMBA_timer function in order support
* running AMBA timer only when there are requests queued.
* Modified and moved N8_WaitOnRequest to QMGR.
* 03/18/03 brr Do not read PKH/CCH status register if no errors are reported
* in the AMBA status registers, assume command complete.
* 02/02/03 brr Updated command completion determination to use the number
* of commands completed instead of queue position. This
* elimated the need for forceCheck & relying on the request
* state to avoid prematurely marking a command complete.
* 12/09/02 brr Remove duplicate read in of read index in CCHInterrupt.
* 11/01/02 brr Reinstate forceCheck.
* 10/23/02 brr Remove forceCheck since interrupts are now disabled during
* the queue operation.
* 10/25/02 brr Clean up function prototypes & include files.
* 10/11/02 brr Added timeout parameter to N8_WaitOnRequest.
* 09/18/02 brr Added N8_WaitOnRequest & modified ISR to keep track of the
* number of requests completed.
* 09/10/02 brr Modified PKH & CCH interrupt service routines to handle the
* command completion interrupt.
* 06/10/02 brr Call QMgrCheckQueue if forceCheck is set.
* 06/05/02 mmd Eliminated unused debug messages, and ensured that when
* waitOnInterrupt is called with interruptible == FALSE,
* that AMBAbitmask is updated with the specified bitmask.
* 05/30/02 brr Enable interrupts for error conditions and handle them in the
* ISR.
* 05/20/02 brr Revert to a single AMBA wait queue.
* 04/30/02 brr Minor revisions to improve performance & incorporate comments
* from code review.
* 04/17/02 msz Don't call QMgr if there is nothing new done.
* 04/15/02 hml Added a call to N8_DOWN_KERNELSEM when we get an AMBA
* interrupt in kernel mode.
* 04/11/02 brr Pass parameter to waitOnInterrupt to indicate whether
* sleep should be interruptable.
* 04/03/02 brr Fix spurious interrupt by clearing the interrupt before
* reading the amba_pci_control.
* 03/19/02 msz Shadow memory is now called shared memory.
* 02/26/02 brr Modified the timer interrupt to update the queue pointers
* and complete the API requests.
* 02/27/02 msz Fixes for N8_WaitOnInterrupt support.
* 02/22/02 spm Converted printk's to DBG's. Added #include of n8_OS_intf.h
* 02/22/02 brr Removed references to qmgrData.
* 02/22/02 msz Fix for BUG 620, CCH should be using the EAshadow_p
* 02/15/02 brr Removed FPGA references.
* 02/06/02 msz Moved where we set shadow hw status.
* 01/31/02 brr On error, save status to shared memory.
* 01/15/02 msz Support for array of AMBA wait blocks. Also we now always
* do the wakeup call for AMBA interrupts once something has
* waited on an AMBA interrupt.
* 01/03/02 brr Reset bridge timer upon expiration.
* 01/16/02 brr Removed FPGA support.
* 12/03/01 mmd Accidentally always performing 11-12 PCI accesses when using
* ASIC, regardless of whether or not we have an IRQ.
* 11/30/01 mmd Forgot to wrap LCR manipulation with check for FPGA.
* 11/27/01 mmd Eliminated N8_EnableInterrupts. Modified
* n8_MainInterruptHandler to only bother with PLX if FPGA.
* Beyond that, everything is and should be treated identically.
* Renamed from simon_irq.c.
* 11/10/01 brr Modified to support static allocations of persistant data
* by the driver.
* 10/17/01 mmd Revised all debug messages to use N8_IRQprint/N8_IRQPRINT
* except for N8_EnableInterrupts and n8_WaitOnInterrupt,
* neither of which are called from Interrupt time.
* 10/12/01 mmd In n8_WaitOnInterrupt, corrected handling of return values
* from N8_BlockWithTimeout.
* 09/24/01 mmd Added support in n8_WaitOnInterrupt and
* N8_MainInterruptHandler for AMBA interrupts, and adjusted
* return values for n8_WaitOnInterrupt. Corrected bug where
* the return code from N8_BlockWithTimeout was being
* misinterpreted. Updated call to N8_BlockWithTimeout, when
* passing a wait_queue_head_t* type.
* 09/20/01 mmd Implemented N8_MainInterruptHandler.
* 09/07/01 mmd Cleanup and revision of WaitOnInterrupt routine.
* 08/16/01 mmd No longer includes n8_types.h.
* 08/16/01 mmd Now includes nsp2000_regs.h instead of simon.h..
* 08/08/01 brr Moved all OS kernel specific macros to helper.h.
* 08/02/01 brr Fixed debug statements in WaitOn functions.
* 07/31/01 mmd Added SIMON_EnableInterrupts call.
* 06/27/01 jke added to debug print statements. Changed logic of if state-
* ments in IRQs to handle non-debug-execution
* 06/21/01 jke added use of BSDIDRIVER and WakeUp macro, altered N8_dbgPrt
* macro to encorporate "if (N8_IRQ_Debug_g)", making the
* resulting source more readable and compact.
* 06/12/01 jke altered to run under BSDi
* 05/29/01 mmd Incorporated suggestions from code review.
* 05/17/01 mmd Original version.
****************************************************************************/
/** @defgroup NSP2000Driver NSP2000 Device Driver
*/
#include "helper.h"
#include "n8_driver_main.h"
#include "n8_driver_api.h"
#include "irq.h"
#include "nsp2000_regs.h"
#include "nsp_ioctl.h"
#include "n8_OS_intf.h"
#include "QMUtil.h"
#include "n8_ea_common.h"
#include "n8_pk_common.h"
#include <sys/proc.h>
/* FORWARD PROTOTYPES */
void N8_PKHInterruptHandler ( NspInstance_t *NSPinstance_p,
uint32_t reg_amba );
void N8_RNHInterruptHandler ( NspInstance_t *NSPinstance_p );
void N8_CCHInterruptHandler ( NspInstance_t *NSPinstance_p,
uint32_t reg_amba );
/* INSTANCE, INDEXED BY MINOR NUMBER */
extern NspInstance_t NSPDeviceTable_g [DEF_MAX_SIMON_INSTANCES];
/* NSPcount_g MAINTAINS THE NUMBER OF DETECTED HARDWARE INSTANCES */
extern int NSPcount_g;
extern wait_queue_head_t requestBlock;
/* IRQ statistics */
static int n8_IRQs_g = 0;
static int n8_AMBA_IRQs_g = 0;
static int n8_CCH_IRQs_g = 0;
static int n8_PKH_IRQs_g = 0;
int ambaTimerActive = FALSE;
#define N8_RELOAD_AMBA_MASK (AMBAIRQ_PKP | AMBAIRQ_CCH | AMBAIRQ_RNG | \
AMBAIRQ_Timer | AMBA_Timer_Reload)
void cch_do_tasklet (unsigned long unused);
#ifdef __linux
DECLARE_TASKLET(cch_tasklet, cch_do_tasklet, 0);
#endif
void cch_do_tasklet (unsigned long unused)
{
int nspIdx;
NSP2000REGS_t *nspRegPtr;
NspInstance_t *localNSPinstance_p;
int eaReqsComplete = 0;
uint32_t cch_read;
uint16_t newReadIndex;
uint16_t cmdsComplete;
/* The bridge timer interrupt is only enabled for the first */
/* NSP, so when it fires, update the read pointer for each */
/* device installed in the system. */
for (nspIdx = 0; nspIdx < NSPcount_g; nspIdx++)
{
localNSPinstance_p = &NSPDeviceTable_g[nspIdx];
nspRegPtr = (NSP2000REGS_t *)localNSPinstance_p->NSPregs_p;
/* Read & store the read pointers on each timer interrupt. */
cch_read = (nspRegPtr->cch_q_ptr>>16);
/* Check for completed EA command blocks on */
/* the AMBA timer interrupt */
newReadIndex = cch_read;
if (newReadIndex != localNSPinstance_p->EAreadIndex)
{
cmdsComplete = (newReadIndex - localNSPinstance_p->EAreadIndex) &
(localNSPinstance_p->EAqueue_size-1);
localNSPinstance_p->EAreadIndex = newReadIndex;
eaReqsComplete += QMgrCheckQueue(N8_EA, nspIdx, cmdsComplete);
}
}
/* Reload the AMBA timer only if there were */
/* outstanding EA requests */
if ((eaReqsComplete) || QMgrCount(N8_EA))
{
ambaTimerActive = TRUE;
localNSPinstance_p = &NSPDeviceTable_g[N8_AMBA_TIMER_CHIP];
nspRegPtr = (NSP2000REGS_t *)localNSPinstance_p->NSPregs_p;
nspRegPtr->amba_pci_control = N8_RELOAD_AMBA_MASK;
}
if (eaReqsComplete)
{
WakeUp(&requestBlock);
}
}
/*****************************************************************************
* N8_MainInterruptHandler
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief Main NSP2000 interrupt handler.
*
* This routine performs the main interrupt handling of the NSP2000.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
* @param debug RO: Specifies whether debug messages are enabled.
*
* @return
* N/A
*
* @par Errors:
* See return section for error information.
*
* @par Assumptions:
* We are assuming that AMBA interrupts are used the same way in
* each user process that might use them.
*
*****************************************************************************/
#define DEF_NSP_IRQ_ACTIVE (AMBAIRQ_PKP | AMBAIRQ_CCH | AMBAIRQ_RNG | \
AMBAIRQ_Bridge | AMBAIRQ_Timer)
void n8_MainInterruptHandler(NspInstance_t *NSPinstance_p)
{
NSP2000REGS_t *nsp = (NSP2000REGS_t *)NSPinstance_p->NSPregs_p;
uint32_t reg_amba = nsp->amba_pci_status;
#ifdef __linux
uint32_t temp;
#endif
/* CHECK FOR ACTIVE NSP2000 INTERRUPT */
if (reg_amba & DEF_NSP_IRQ_ACTIVE)
{
/* Count the receipt of interrupt */
#ifdef N8_IRQ_COUNT
n8_IRQs_g++;
#endif
/* If this interrupt is from the Bridge Timer, reload it */
if (reg_amba & AMBAIRQ_Timer)
{
/* Clear the AMBA timer interrupt */
nsp->amba_pci_status = reg_amba;
#ifdef N8_IRQ_COUNT
n8_AMBA_IRQs_g++;
#endif
ambaTimerActive = FALSE;
#ifdef __linux
tasklet_schedule(&cch_tasklet);
/* Ensure PCI write completes by reading register */
/* before exiting the ISR. */
temp = nsp->amba_pci_status;
#else
cch_do_tasklet(n8_IRQs_g);
#endif
}
/* IF APPROPRIATE, RELEASE ANYONE BLOCKED ON AMBA INTERRUPTS */
/* Note that usage of a single AMBAbitmask doesn't allow for */
/* different processes to wait on different masks. However, */
/* we only use the AMBA timer, and all processes that wait on */
/* AMBA interrupts are just waiting on the timer. */
if (NSPinstance_p->AMBAbitmask & reg_amba)
{
/* RELEASE BLOCKED CALL */
/* We are using the timer of the AMBA to generate a */
/* periodic interrupt. */
WakeUp( &NSPinstance_p->AMBAblock );
}
/* HANDLE ANY RNG/PKE/EA INTERRUPTS */
if (reg_amba & AMBAIRQ_PKP)
{
#ifdef N8_IRQ_COUNT
n8_PKH_IRQs_g++;
#endif
N8_PKHInterruptHandler(NSPinstance_p, reg_amba);
}
if (reg_amba & AMBAIRQ_CCH)
{
#ifdef N8_IRQ_COUNT
n8_CCH_IRQs_g++;
#endif
N8_CCHInterruptHandler(NSPinstance_p, reg_amba);
}
if (reg_amba & AMBAIRQ_RNG)
{
N8_RNHInterruptHandler(NSPinstance_p);
}
}
return;
}
/*****************************************************************************
* N8_PKHInterruptHandler
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief PKH interrupt handler.
*
* This routine is called by the main interrupt handler to handle PKH
* interrupts. It first samples the PKH control/status register for future
* reference. It then clears all active bits, to handle all active interrupts.
* If debug messages are enabled, it also translates the meaning of each
* active bit.
*
* Bits 0-17 indicate PKH interrupts. An active bit is cleared by writing 1
* to it.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
* @param reg_amba RO: Value reported in the AMBA Bridge Status Register
*
* @par Externals:
* PKHIRQ_* RO: #define - Constants that identify each bit of the <BR>
* PKH Control/Status register.
*
* @return
* N/A
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
void N8_PKHInterruptHandler(NspInstance_t *NSPinstance_p,
uint32_t reg_amba)
{
NSP2000REGS_t *nsp;
unsigned long reg, newreg;
uint16_t readIndx;
uint16_t cmdsComplete;
int reqsComplete = 0;
nsp = (NSP2000REGS_t *)NSPinstance_p->NSPregs_p;
/* Check for an error */
if (reg_amba & AMBAPKH_Error)
{
/* An error has been detected, read and save PKH status register */
reg = (unsigned long)nsp->pkh_control_status;
NSPinstance_p->PKHirqstatus = reg;
if (reg & PK_Status_Any_Error_Mask)
{
/* CLEAR PKH ENABLE TO ALLOW PKE TO STOP */
nsp->pkh_control_status = 0;
while (nsp->pkh_control_status & PK_Status_PKH_Busy)
{
/* WAITING FOR PKE_BUSY TO CLEAR */
}
/* CLEAR ALL SIGNALLING IRQS AND DISABLE PKH */
newreg = reg & PK_Enable_All_Enable_Mask;
/* If it is a problem with the command, call the QMgr to noop command blocks */
if (reg & PK_Status_Cmd_Error_Mask)
{
NSPinstance_p->PKHcmderrors++;
/* Read & store the current read pointer. */
readIndx = nsp->pkh_q_ptr>>16;
/* Check for completed PK command blocks */
if (readIndx != NSPinstance_p->PKreadIndex)
{
cmdsComplete = (readIndx - NSPinstance_p->PKreadIndex) &
(NSPinstance_p->PKqueue_size-1);
NSPinstance_p->PKreadIndex = readIndx;
/* Process any completed commands */
reqsComplete = QMgrCheckQueue(N8_PKP, NSPinstance_p->chip,
cmdsComplete);
}
/* Process the errored command */
QMgrCmdError(N8_PKP, NSPinstance_p->chip, readIndx, reg);
}
/* Bus errors require no QMgr action, just update counter */
else if (reg & PK_Status_Bus_Error_Mask)
{
NSPinstance_p->PKHbuserrors++;
}
/* update register & reenable the PKH */
nsp->pkh_control_status = newreg | PK_Status_PKH_Enable;
/* IF APPROPRIATE, RELEASE ANYONE BLOCKED ON PKH INTERRUPTS */
if (NSPinstance_p->PKHbitmask & reg)
{
/* RELEASE BLOCKED CALL */
WakeUp(&(NSPinstance_p->PKHblock));
/* PREVENT REENTRY OF THE BLOCKING FUNCTIONALITY */
NSPinstance_p->PKHbitmask = 0;
}
}
}
else /* No Errors, this is a command complete interrupt */
{
/* Clear the command complete bit */
nsp->pkh_control_status = PK_Enable_PKH_Enable |
PK_Enable_Cmd_Complete_Enable;
/* Read & store the current read pointer. */
readIndx = nsp->pkh_q_ptr>>16;
/* Process the completed PK command blocks */
cmdsComplete = (readIndx - NSPinstance_p->PKreadIndex) &
(NSPinstance_p->PKqueue_size-1);
NSPinstance_p->PKreadIndex = readIndx;
reqsComplete = QMgrCheckQueue(N8_PKP, NSPinstance_p->chip, cmdsComplete);
}
if (reqsComplete)
{
WakeUp(&requestBlock);
}
}
/*****************************************************************************
* N8_RNHInterruptHandler
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief RNH interrupt handler.
*
* This routine is called by the main interrupt handler to handle RNH
* interrupts. It first samples the RNH control/status register for future
* reference. It then clears all active bits, to handle all active interrupts.
* If debug messages are enabled, it also translates the meaning of each
* active bit.
*
* Bits 20-23 indicate RNH interrupts. An active bit is cleared by writing 1
* to it.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
*
* @par Externals:
* RNHIRQ_* RO: #define - Constants that identify each bit of the <BR>
* RNH Control/Status register.
*
* @return
* N/A
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
void N8_RNHInterruptHandler(NspInstance_t *NSPinstance_p)
{
NSP2000REGS_t *nsp;
unsigned long reg, newreg;
unsigned char reenable = 1;
/* READ AND SAVE RNH STATUS REGISTER */
nsp = (NSP2000REGS_t *)NSPinstance_p->NSPregs_p;
reg = (unsigned long)nsp->rnh_control_status;
NSPinstance_p->RNHirqstatus = reg;
/* CLEAR RNH ENABLE TO ALLOW RNG TO STOP */
nsp->rnh_control_status = 0;
while (nsp->rnh_control_status & RNH_Status_Transfer_Busy)
{
/* WAITING FOR XFER_BUSY TO CLEAR */
}
/* CLEAR ALL SIGNALLING IRQS AND RE-ENABLE RNH */
newreg = reg & RNH_Status_Any_Condition_Mask;
/* DISABLE RNH IF BIG ERROR */
if (reg & DEF_RNH_BIGERROR_IRQ_BITS)
{
/* IRQPRINT(("NSP2000: Serious error - RNG execution halted.\n")); */
reenable = 0;
}
/* Record the bus error */
else if (reg & RNH_Status_Bus_Error)
{
NSPinstance_p->RNHbuserrors++;
}
/* UPDATE REGISTER */
nsp->rnh_control_status = newreg;
if (reenable)
{
nsp->rnh_control_status = RNH_Status_Transfer_Enable;
}
/* IF APPROPRIATE, RELEASE ANYONE BLOCKED ON RNH INTERRUPTS */
if (NSPinstance_p->RNHbitmask & reg)
{
/* RELEASE BLOCKED CALL */
WakeUp(&(NSPinstance_p->RNHblock));
/* PREVENT REENTRY OF THE BLOCKING FUNCTIONALITY */
NSPinstance_p->RNHbitmask = 0;
}
return;
}
/*****************************************************************************
* N8_CCHInterruptHandler
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief CCH interrupt handler.
*
* This routine is called by the main interrupt handler to handle CCH
* interrupts. It first samples the CCH control/status register for future
* reference. It then clears all active bits, to handle all active interrupts.
* If debug messages are enabled, it also translates the meaning of each
* active bit.
*
* Bits 0-15 indicate CCH interrupts. An active bit is cleared by writing 1
* to it.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
* @param reg_amba RO: Value reported in the AMBA Bridge Status Register
*
* @par Externals:
* CCHIRQ_* RO: #define - Constants that identify each bit of the <BR>
* CCH Control/Status register.
*
* @return
* N/A
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
void N8_CCHInterruptHandler(NspInstance_t *NSPinstance_p,
uint32_t reg_amba)
{
NSP2000REGS_t *nsp;
unsigned long reg;
uint16_t readIndx;
uint16_t cmdsComplete;
nsp = (NSP2000REGS_t *)NSPinstance_p->NSPregs_p;
/* Check for an error */
if (reg_amba & AMBACCH_Error)
{
/* An error has been detected, read and save CCH status register */
reg = (unsigned long)nsp->cch_control_status;
NSPinstance_p->CCHirqstatus = reg;
if (reg & EA_Status_Any_Error_Mask)
{
/* CLEAR CCH ENABLE TO ALLOW CC TO STOP */
nsp->cch_control_status = 0;
while (nsp->cch_control_status & EA_Status_Module_Busy)
{
/* WAITING FOR CCH_BUSY TO CLEAR */
}
/* Clear all outstanding IRQS */
nsp->cch_control_status = reg & EA_Status_Any_Condition_Mask;
/* If it is a problem with the command, call the QMgr to noop command blocks */
if (reg & EA_Status_Cmd_Error_Mask)
{
NSPinstance_p->CCHcmderrors++;
/* Read & store the current read pointer. */
readIndx = nsp->cch_q_ptr >> 16;
/* Check for completed EA command blocks */
if (readIndx != NSPinstance_p->EAreadIndex)
{
cmdsComplete = (readIndx - NSPinstance_p->EAreadIndex) &
(NSPinstance_p->EAqueue_size-1);
NSPinstance_p->EAreadIndex = readIndx;
/* Process any completed commands */
QMgrCheckQueue(N8_EA, NSPinstance_p->chip, cmdsComplete);
}
/* Process the errored command */
QMgrCmdError(N8_EA, NSPinstance_p->chip, readIndx, reg);
}
/* Bus errors require no QMgr action, just update counter */
else if (reg & EA_Status_Bus_Error_Mask)
{
NSPinstance_p->CCHbuserrors++;
}
/* Reenable the CCH */
nsp->cch_control_status = EA_Enable_Module_Enable;
/* IF APPROPRIATE, RELEASE ANYONE BLOCKED ON CCH INTERRUPTS */
if (NSPinstance_p->CCHbitmask & reg)
{
/* RELEASE BLOCKED CALL */
WakeUp(&(NSPinstance_p->CCHblock));
/* PREVENT REENTRY OF THE BLOCKING FUNCTIONALITY */
NSPinstance_p->CCHbitmask = 0;
}
}
}
else /* No Errors, this is a command complete interrupt */
{
/* Clear the command complete bit */
nsp->cch_control_status = EA_Enable_Module_Enable |
EA_Enable_Cmd_Complete_Enable;
/* Read & store the current read pointer. */
readIndx = nsp->cch_q_ptr >> 16;
/* Process the completed EA command blocks */
cmdsComplete = (readIndx - NSPinstance_p->EAreadIndex) &
(NSPinstance_p->EAqueue_size-1);
NSPinstance_p->EAreadIndex = readIndx;
QMgrCheckQueue(N8_EA, NSPinstance_p->chip, cmdsComplete);
}
return;
}
/*****************************************************************************
* waitOnInterrupt
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief Interrupt notification routine.
*
* This routine allows a process to block for interrupt notification for the
* PKE, EA, RNG, or AMBA. This routine initializes a wait queue and blocks on
* it with a timeout value. If the specified execution core signals an IRQ that
* matches one of the set bits in the bitmask, the IRQ handler will release
* this blocked process for completion. Otherwise, if no satisfactory IRQ is
* received, this routine will time out and return with appropriate error code.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
* @param bitmask RO: Bitmask to filter received interrupts.
* @param coretype RO: Specifies which execution core to monitor.
* @param timeout RO: Timeout value for blocking, in seconds.
* @param debug RO: Specifies whether debug messages are enabled.
* @param interruptable RO: Specifies whether the wait should be interruptable
*
* @par Externals:
* N8_DAPI_* RO: #define - Constants to specify an execution core.
*
* @return
* -EINVAL Invalid core specified.
* 0 Timeout - interrupt not received.
* 1 Success - interrupt received.
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
int waitOnInterrupt ( N8_Unit_t chip,
unsigned char coretype,
unsigned long bitmask,
unsigned long timeout,
int interruptable )
{
unsigned char rc;
unsigned char debug = 0; /* was passed from DEBUG_IRQ in nsp_ioctl.c */
NspInstance_t *NSPinstance_p = &NSPDeviceTable_g[chip];
if (interruptable == FALSE)
{
if (coretype == N8_DAPI_AMBA)
{
NSPinstance_p->AMBAbitmask = bitmask;
return 1;
}
else
{
return -EINVAL;
}
}
if (coretype == N8_DAPI_PKE)
{
NSPinstance_p->PKHbitmask = bitmask;
rc = N8_BlockWithTimeout(&(NSPinstance_p->PKHblock),
timeout, debug);
}
else if (coretype == N8_DAPI_RNG)
{
NSPinstance_p->RNHbitmask = bitmask;
rc = N8_BlockWithTimeout(&(NSPinstance_p->RNHblock),
timeout, debug);
}
else if (coretype == N8_DAPI_EA)
{
NSPinstance_p->CCHbitmask = bitmask;
rc = N8_BlockWithTimeout(&(NSPinstance_p->CCHblock),
timeout, debug);
}
else if (coretype == N8_DAPI_AMBA)
{
NSPinstance_p->AMBAbitmask = bitmask;
/* We are using the timer of the AMBA to generate a */
/* periodic interrupt. */
rc = N8_BlockWithTimeout(
&(NSPinstance_p->AMBAblock),
timeout,
debug);
/* Note that the AMBAbitmask will not be cleared. */
/* There is no hard (other than some amount of overhead) */
/* of doing extra wake-ups. If we do clear the bitmask */
/* then it would need to be on a per process basis, */
/* because otherwise, one process could starting to do a */
/* block, while the other is doing a clear. Then the */
/* wake up will never occur, as the bitmask is 0. */
/* NSPinstance_p->AMBAbitmask = 0; */
/* The advance to the next wait block occurs in the isr. */
}
else
{
return -EINVAL;
}
return rc;
}
/*****************************************************************************
* n8_WaitOnInterrupt
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief Interrupt notification routine.
*
* This routine allows a process to block for interrupt notification for the
* PKE, EA, RNG, or AMBA. This routine initializes a wait queue and blocks on
* it with a timeout value. If the specified execution core signals an IRQ that
* matches one of the set bits in the bitmask, the IRQ handler will release
* this blocked process for completion. Otherwise, if no satisfactory IRQ is
* received, this routine will time out and return with appropriate error code.
*
* @param NSPinstance_p RO: Pointer to the information structure for an
* NSP2000 hardware instance, containing a
* pointer to its control register set.
* @param bitmask RO: Bitmask to filter received interrupts.
* @param coretype RO: Specifies which execution core to monitor.
* @param timeout RO: Timeout value for blocking, in seconds.
* @param debug RO: Specifies whether debug messages are enabled.
*
* @par Externals:
* N8_DAPI_* RO: #define - Constants to specify an execution core.
*
* @return
* -EINVAL Invalid core specified.
* 0 Timeout - interrupt not received.
* 1 Success - interrupt received.
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
N8_Status_t N8_WaitOnInterrupt ( N8_Unit_t chip,
unsigned char coretype,
unsigned long bitmask,
unsigned long timeout )
{
return waitOnInterrupt(chip, coretype, bitmask, timeout, FALSE);
}
N8_Status_t N8_WaitOnRequest ( int timeout )
{
if (N8_BlockWithTimeout(&requestBlock, timeout, 0))
{
return (N8_STATUS_OK);
}
return (N8_TIMEOUT);
}
/*****************************************************************************
* reload_AMBA_timer
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief This function reloads the AMBA timer.
*
* @return
* N/A
*
* @par Errors:
* N/A
*****************************************************************************/
void reload_AMBA_timer(void)
{
NspInstance_t *NSPinstance_p;
NSP2000REGS_t *nspRegPtr;
if (ambaTimerActive == FALSE)
{
NSPinstance_p = &NSPDeviceTable_g[N8_AMBA_TIMER_CHIP];
nspRegPtr = (NSP2000REGS_t *)NSPinstance_p->NSPregs_p;
ambaTimerActive = TRUE;
nspRegPtr->amba_pci_control = N8_RELOAD_AMBA_MASK;
}
}
/*****************************************************************************
* n8_DisplayIRQ
*****************************************************************************/
/** @ingroup NSP2000Driver
* @brief Displays the IRQ statistics
*
* This routine displays the NSP2000's IRQ statistics to the
* kernel log. This routine is intended for debugging purposes.
*
* @return
* N/A
*
* @par Errors:
* See return section for error information.
*****************************************************************************/
void n8_DisplayIRQ(void)
{
int nspIdx;
NspInstance_t *NSPinstance_p;
N8_PRINT(KERN_CRIT "\n");
N8_PRINT(KERN_CRIT "NSP2000: Displaying IRQ statistics:\n\n");
N8_PRINT(KERN_CRIT " AMBA IRQ's = %d\n", n8_AMBA_IRQs_g);
N8_PRINT(KERN_CRIT " CCH IRQ's = %d\n", n8_CCH_IRQs_g);
N8_PRINT(KERN_CRIT " PKH IRQ's = %d\n", n8_PKH_IRQs_g);
N8_PRINT(KERN_CRIT " Total IRQ's = %d\n", n8_IRQs_g);
for (nspIdx = 0; nspIdx < NSPcount_g; nspIdx++)
{
NSPinstance_p = &NSPDeviceTable_g[nspIdx];
N8_PRINT(KERN_CRIT "\n");
N8_PRINT(KERN_CRIT "NSP2000: Displaying IRQ statistics for chip %d:\n",
NSPinstance_p->chip);
N8_PRINT(KERN_CRIT " CCH Bus errors = %d\n", NSPinstance_p->CCHbuserrors);
N8_PRINT(KERN_CRIT " PKH Bus errors = %d\n", NSPinstance_p->PKHbuserrors);
N8_PRINT(KERN_CRIT " CCH Cmd errors = %d\n", NSPinstance_p->CCHcmderrors);
N8_PRINT(KERN_CRIT " PKH Cmd errors = %d\n", NSPinstance_p->PKHcmderrors);
}
}