171 lines
6.6 KiB
C
171 lines
6.6 KiB
C
/****************************************************************************
|
|
* sec2isr.c -- The Interrupt Service code for SEC2 Driver
|
|
****************************************************************************
|
|
* Copyright (c) Certicom Corp. 1996-2002. All rights reserved
|
|
* Copyright (c) 2003, 2004 Freescale Semiconductor
|
|
* All Rights Reserved. Proprietary and Confidential.
|
|
*
|
|
* NOTICE: The information contained in this file is proprietary
|
|
* to Freescale Semiconductor, and is being made available to
|
|
* Freescale's customers under strict license agreements.
|
|
* Use or disclosure of this information is permissible only
|
|
* under the terms of the existing license agreement.
|
|
****************************************************************************/
|
|
|
|
/*
|
|
* Revision History:
|
|
* 1.0 Aug 24,2003 dgs - adapted from the final version of mpc18x
|
|
* May 12,2004 sec - turned on some windview events for debug
|
|
* Jun 06,2004 sec - corrected channel reset logic
|
|
* Jun 10,2004 sec - remove superfluous I/O calls
|
|
* Jul 22,2004 sec - added double CHA reset to handle errata
|
|
* 1.1.0 Nov 16,2004 sec - updated for linux change merge from prior revs
|
|
* 1.1.1 Dec 16,2004 sec - cleanup, remove unused diagnostics
|
|
* 1.2 Jan 27,2005
|
|
*/
|
|
|
|
|
|
#include "Sec2Driver.h"
|
|
|
|
/* Interpeak begin */
|
|
#undef NUM_CHANNELS
|
|
#define NUM_CHANNELS (num_channels)
|
|
extern int num_channels;
|
|
/* Interpeak end */
|
|
|
|
/**************************************************************************
|
|
* Function Name: InterruptServiceRoutine
|
|
* Purpose: To handle all interrupt generated by Channel or CHA (Done or Error)
|
|
* indicated by the Interrupt Status Register
|
|
* If Error, clean the InterruptStatusRegister by writing InterruptClearRegister
|
|
* If Done, call ProcessRequestDone routine
|
|
* Input: Interrupt - PKINTERRUPT
|
|
* Context - PVOID the request Context
|
|
*
|
|
|
|
*************************************************************************/
|
|
#ifdef __KERNEL__
|
|
DEVICE_REGS pRegs_queue[PREGS_QUEUE_DEPTH];
|
|
unsigned PQ_head = 0;
|
|
unsigned PQ_tail = 0;
|
|
unsigned PQ_entries = 0;
|
|
|
|
extern void ProcessingComplete(unsigned long not_used);
|
|
DECLARE_TASKLET(isr_tasklet,ProcessingComplete,0);
|
|
|
|
void InterruptServiceRoutine(int irq, void *dev_id, struct pt_regs *pt_regs)
|
|
#else
|
|
void InterruptServiceRoutine(void)
|
|
#endif
|
|
{
|
|
register int cha, cha_res;
|
|
register int channel;
|
|
unsigned long temp[2];
|
|
unsigned long intStatus0, intStatus1;
|
|
DEVICE_REGS *pRegs;
|
|
static DEVICE_REGS regs;
|
|
|
|
|
|
|
|
/* save interrupt status register for the ProcessingComplete */
|
|
intStatus0 = *(InterruptStatusRegister);
|
|
intStatus1 = *(InterruptStatusRegister + 1);
|
|
|
|
pRegs = ®s;
|
|
pRegs->IntStatus[0] = intStatus0;
|
|
pRegs->IntStatus[1] = intStatus1;
|
|
|
|
/* check for error interrupts, was there any error? */
|
|
if ((intStatus0 & ALL_INT_ERRORS_MASK_LOW) ||
|
|
(intStatus1 & ALL_INT_ERRORS_MASK_HIGH))
|
|
{
|
|
/* save assigment statii for background servicing to use */
|
|
pRegs->ChaAssignmentStatus[0] = *(ChaAssignmentStatusRegister);
|
|
pRegs->ChaAssignmentStatus[1] = *(ChaAssignmentStatusRegister + 1);
|
|
|
|
/* service CHA error interrupts first */
|
|
for (cha_res = 0; cha_res < NUM_CHAS; cha_res++)
|
|
{
|
|
/* save the channel this CHA is assigned to if any */
|
|
if (cha_res < 4)
|
|
channel = (pRegs->ChaAssignmentStatus[0] >> (cha_res * 8)) & 0xF;
|
|
else
|
|
channel = (pRegs->ChaAssignmentStatus[1] >> ((cha_res - 4) * 8)) & 0xF;
|
|
|
|
cha = cha_idx[cha_res];
|
|
if ((intStatus1 & ChaErrorInterruptMasks[cha]) ||
|
|
(channel > 0 && channel < (NUM_CHANNELS+1) &&
|
|
(intStatus0 & ChannelErrorInterruptMasks[channel-1])))
|
|
{
|
|
/* found a CHA error interrupt, read the CHA status register */
|
|
pRegs->ChaError[cha][0] = *(unsigned long *)(ChaInterruptStatusRegister[cha]);
|
|
pRegs->ChaError[cha][1] = *(unsigned long *)(ChaInterruptStatusRegister[cha] + 1);
|
|
|
|
/* ensure that the associated channel is reset */
|
|
if (channel > 0 && channel < (NUM_CHANNELS+1))
|
|
intStatus0 |= ChannelErrorInterruptMasks[channel-1];
|
|
|
|
pRegs->ChannelError[channel][0] = *(unsigned long *)(ChannelPointerStatusRegister[channel-1]);
|
|
pRegs->ChannelError[channel][1] = *(unsigned long *)(ChannelPointerStatusRegister[channel-1] + 1);
|
|
|
|
|
|
|
|
/* Done extracting info, reset the CHA */
|
|
/* This will be done twice to work around an errata that has to do with CHA */
|
|
/* reset hold time */
|
|
|
|
*(ChaResetControlRegister[cha]) = CHA_SOFTWARE_RESET;
|
|
*(ChaResetControlRegister[cha] + 1) = 0;
|
|
|
|
*(ChaResetControlRegister[cha]) = CHA_SOFTWARE_RESET;
|
|
*(ChaResetControlRegister[cha] + 1) = 0;
|
|
|
|
if (cha == CHA_DES) /* is this cha des? */
|
|
{
|
|
*(ChaInterruptControlRegister[cha]) = CHA_DESA_KEY_PARITY_ERROR_DISABLE;
|
|
*(ChaInterruptControlRegister[cha] + 1) = 0;
|
|
}
|
|
if (cha == CHA_PKHA) /* is this cha the pkha? */
|
|
{
|
|
*(ChaInterruptControlRegister[cha]) = CHA_PKHA_ILLEGAL_ADDR_ERROR_DISABLE;
|
|
*(ChaInterruptControlRegister[cha] + 1) = 0;
|
|
}
|
|
} /* if (cha causes error) */
|
|
} /* for (all chas) */
|
|
|
|
|
|
/* look at the channel error interrupts next */
|
|
for (channel=0; channel<NUM_CHANNELS; channel++)
|
|
{
|
|
if (intStatus0 & ChannelErrorInterruptMasks[channel])
|
|
{
|
|
/* fetch a copy of the CPSR for out-of-ISR processing */
|
|
pRegs->ChannelError[channel][0] = *(unsigned long *)(ChannelPointerStatusRegister[channel]);
|
|
pRegs->ChannelError[channel][1] = *(unsigned long *)(ChannelPointerStatusRegister[channel] + 1);
|
|
|
|
/* reset the channel */
|
|
*(ChannelConfigRegister[channel]) = (unsigned long)CHANNEL_RESET;
|
|
*(ChannelConfigRegister[channel] + 1) = (unsigned long)0;
|
|
|
|
/* give the hardware a chance to clock... */
|
|
temp[0] = *(unsigned long *)(ChannelConfigRegister[channel]);
|
|
|
|
/* re-enable channel interrupts */
|
|
*(ChannelConfigRegister[channel]) = (unsigned long)0;
|
|
*(ChannelConfigRegister[channel] + 1) = (unsigned long)CHANNEL_INTEN | CHANNEL_BURST128;
|
|
} /* if (channel error) */
|
|
} /* for (all channels) */
|
|
} /* if (any error interrupt) */
|
|
|
|
/* clear latched interrupts at the control register level */
|
|
*(InterruptClearRegister) = intStatus0;
|
|
*(InterruptClearRegister + 1) = intStatus1;
|
|
|
|
/* schedule process complete function */
|
|
#ifdef __KERNEL__
|
|
(void)QmsgSend();
|
|
#else
|
|
(void)msgQSend(IsrMsgQId, (char*)pRegs, sizeof(DEVICE_REGS), NO_WAIT, MSG_PRI_NORMAL);
|
|
#endif
|
|
} /* end of SEC2InterruptService */
|