mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-10 06:29:51 -04:00
918 lines
34 KiB
C
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);
|
|
}
|
|
}
|
|
|