/**************************************************************************** * 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; channelChannelError[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 */