/**************************************************************************** * Sec2Driver.h - Private/local include file for SEC2 security driver **************************************************************************** * 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 - moved interrupt assign for MPC8555 * May 26,2004 sec - add support for scatter buffers * Aug 27,2004 sec - fixed channel interrupt masks * 1.1.0 Nov 05,2004 sec - integrate/merge linux changes from prior revs * 1.2 Jan 27,2005 sec - move global inhibit bit */ #ifndef SEC2DRIVER_H #define SEC2DRIVER_H #ifdef __KERNEL__ #include /* Interpeak begin */ #include /* Interpeak end */ #include #include #include #include #include #include #include #include #include #include #include #include #include #undef malloc #undef free #define free kfree #define malloc(a) kmalloc(a, GFP_KERNEL) #undef semGive #undef semTake #define semDelete(x) #define semGive(a) up(&a) #define semTake(a, b) down_interruptible_timeout(&a, b) extern long __down_interruptible_timeout(struct semaphore *sem, long timeout); extern inline int down_interruptible_timeout(struct semaphore *sem, long timeout) { int ret = 0; #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif if (atomic_dec_return(&sem->count) < 0) ret = __down_interruptible_timeout(sem, timeout); smp_wmb(); return ret; } #define taskIdSelf() current->pid #define __vpa(va) ((pte_val(*pte_offset(pmd_offset(pgd_offset_k(va), (va)), (va))) & PAGE_MASK) + (va & ~PAGE_MASK)) #define SEC2_DEVMAJOR 0 #else /* assume VXWORKS */ #include "vxWorks.h" #include "iosLib.h" #include "msgQLib.h" #include "stdlib.h" #include "semLib.h" #include "time.h" #include "string.h" #include "taskLib.h" #include "cacheLib.h" #include "signal.h" #define IVEC_TO_INUM(intVec) ((int) (intVec)) #define INUM_TO_IVEC(intNum) ((VOIDFUNCPTR *) (intNum)) #define __vpa(pa) (pa) #endif #include "Sec2.h" #define VERSION "1.2" #define SEC2_DEVNAME "sec2" /* This might move out to a board-specfic header somewhere, */ /* not a core-specific header such as this */ #define INUM_SEC2 0x29 /* SEC core is wired to #29 within the MPC8555 */ /* Define an offset from the peripheral base register where the core */ /* should be located relative to */ #define TALITOS2X_BASE_ADDRESS (0x00030000) /* Define the size of the register region */ #define SEC2_BASE_SIZE (0x10000) /* When static scatter pool fully functional, define here */ /* Else, use dynamic pool */ #define DYNAMIC_SCATTER_POOL /* Do right-justifies output shift for PKHA results due to errata */ #define PKHA_OUTPUT_SHIFT /* Interpeak begin */ #ifdef __KERNEL__ typedef struct Ctx_queue_element_struct { struct Ctx_queue_element_struct *next; int pid; void *ctx; } Ctx_queue_element; typedef struct Ctx_queue_header_struct { Ctx_queue_element *head; Ctx_queue_element *tail; } Ctx_queue_header; extern Ctx_queue_header ctx_done_queue; extern Ctx_queue_header ctx_error_queue; #endif /* Interpeak end */ /* * Debug message type enabler switches for SEC2DebugLevel: * DBGTXT_SETRQ - all messages from request setups * DBGTXT_SVCRQ - all messages from request servicing * DBGTXT_INITDEV - all messages from initialization * DBGTXT_DPDSHOW - content of each DPD before it's queued * DBGTXT_INFO - general driver information messages */ #ifdef DBG #define DBGTXT_SETRQ ((unsigned long)0x00000001) #define DBGTXT_SVCRQ ((unsigned long)0x00000002) #define DBGTXT_INITDEV ((unsigned long)0x00000004) #define DBGTXT_DPDSHOW ((unsigned long)0x00000008) #define DBGTXT_INFO ((unsigned long)0x00000010) /* Interpeak begin */ #define DBGTXT_INTERPEAK ((unsigned long)0x00000020) /* Interpeak end */ extern unsigned long SEC2DebugLevel; #ifdef VXWORKS #define SEC2Dump(LEVEL,STRING) \ do { \ unsigned long _level = (LEVEL); \ if ((_level == 0)||(SEC2DebugLevel & _level)) { \ printf STRING; \ } \ } while (0) #else #define SEC2Dump(LEVEL,STRING) \ do { \ unsigned long _level = (LEVEL); \ if ((_level == 0)||(SEC2DebugLevel & _level)) { \ printk STRING; \ } \ } while (0) #endif #else /* ndef DBG */ #define SEC2Dump(LEVEL,STRING) #endif /* DBG */ #ifdef VXWORKS #define IOLockChannelAssignment() (void) semTake(ChannelAssignSemId, WAIT_FOREVER) #define IOUnLockChannelAssignment() (void) semGive(ChannelAssignSemId) #endif #ifdef __KERNEL__ extern unsigned long irq_flag; #define IOLockChannelAssignment() spin_lock_irqsave(&ChannelAssignLock,irq_flag) #define IOUnLockChannelAssignment() spin_unlock_irqrestore(&ChannelAssignLock,irq_flag) #define M_ioLib (12 << 16) #define S_ioLib_UNKNOWN_REQUEST (M_ioLib | 2) typedef long DEV_HDR; #endif #define IO_STATUS int #define MAX_DPDS (24) /* Interpeak begin */ /* #define QUEUE_ENTRY_DEPTH (16) */ #define QUEUE_ENTRY_DEPTH (32) /* Interpeak end */ /* internal flag for pointer register - indirect pointer */ #define PTRTYPE_JBIT (0x00008000) /* SEC2_MASTER_CONTROL_REGISTER - Master Control Register offset */ #define SEC2_MASTER_CONTROL_REGISTER ((unsigned long)0x00001030) /* SEC2_RESET - software-controller reset of the SEC2 core */ #define SEC2_RESET ((unsigned long)0x00000001) /* SEC2_GLOBAL_INHIBIT - */ #define SEC2_GLOBAL_INHIBIT ((unsigned long)0x00000002) /*! \def MAX_MESSAGES \brief (VxWorks Only) Queue Length for Isr queue represented by global variale #IsrMsgQId */ #define MAX_MESSAGES (40) /*! \def PROCESSING_COMPLETE_PRIORITY \brief (VxWorks Only) #ProcessingComplete() Task priority */ #define PROCESSING_COMPLETE_PRIORITY (3) /*! \def PROCESSING_COMPLETE_STACKSIZE \brief (VxWorks Only) #ProcessingComplete() Task stack size */ /* Interpeak begin */ /* #define PROCESSING_COMPLETE_STACKSIZE (2048) */ #define PROCESSING_COMPLETE_STACKSIZE (4096) /* Interpeak end */ /*! \def CHANNEL_FREE \brief Channel is available Indicates that the channel assignment is FREE or available. */ #define CHANNEL_FREE (unsigned char) (0) /*! \def CHANNEL_DYNAMIC \brief Channel is assigned as dynamic Indicates that the channel assignment is dynamic. A process is in the middle of performing a dynamic operation. */ #define CHANNEL_DYNAMIC (unsigned char) (1) /*! \def CHA_DYNAMIC \brief The CHA is available for dynamic acquisition This applies to the #ChaAssignments array. Any element in this array that is set to CHA_DYNAMIC means that the CHA represented by the array index is available */ #define CHA_DYNAMIC (0) #define CHA_DES (0) #define CHA_AESA (1) #define CHA_MDHA (2) #define CHA_AFHA (3) #define CHA_RNG (4) #define CHA_PKHA (5) #define CHA_MDHA_DES (106) #define CHA_MDHA_AES (105) /*! \def CHA_AFHA_BITMASK \brief An internal bitmask representation for an ARC4 CHA */ #define CHA_AFHA_BITMASK (0x1) /*! \def CHA_DESA_BITMASK \brief An internal bitmask representation for a DES CHA */ #define CHA_DESA_BITMASK (0x2) /*! \def CHA_MDHA_BITMASK \brief An internal bitmask representation for an MD CHA */ #define CHA_MDHA_BITMASK (0x4) /*! \def CHA_RNGA_BITMASK \brief An internal bitmask representation for an RNG CHA */ #define CHA_RNGA_BITMASK (0x8) /*! \def CHA_PKHA_BITMASK \brief An internal bitmask representation for a PK CHA */ #define CHA_PKHA_BITMASK (0x10) /*! \def CHA_AESA_BITMASK \brief An internal bitmask representation for a AESA CHA */ #define CHA_AESA_BITMASK (0x20) /*! \def CHA_KEA_BITMASK \brief An internal bitmask representation for a KEA CHA */ #define CHA_KEA_BITMASK (0x40) /*! \def DES_BLOCK \brief Size of DES block */ #define DES_BLOCK (8) /*! \def ARC4_MIN_KEYBYTES \brief Minimum ARC4 key length */ #define ARC4_MIN_KEYBYTES (1) /*! \def ARC4_MAX_KEYBYTES \brief Maximum ARC4 key length */ #define ARC4_MAX_KEYBYTES (16) /*! \def ARC4_CONTEXTBYTES \brief Context length for ARC4 */ #define ARC4_CONTEXTBYTES (259) /*! \def DOUBLE_WORD_ALIGNMENT \brief Mask to be applied to address in order to determine if it is double word aligned or not */ #ifdef NO_DOUBLE_WORD_ALIGNMENT #define DOUBLE_WORD_ALIGNMENT ((unsigned long)0x00000000) #else #define DOUBLE_WORD_ALIGNMENT ((unsigned long)0x00000007) #endif /*! \def IO_BASE_ADDRESS_MASK \brief Mask to be applied to base address value return from IO bus */ #define IO_BASE_ADDRESS_MASK ((unsigned long)0xFFFE0000) /*! \def INTERRUPT_CONTROL_OFFSET \brief Offset for the Interrupt Control Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #InterruptControlRegister variable during Driver Startup */ #define INTERRUPT_CONTROL_OFFSET ((unsigned long)0x00001008) /*! \def INTERRUPT_STATUS_OFFSET \brief Offset for the Interrupt Status Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #InterruptStatusRegister variable during Driver Startup */ #define INTERRUPT_STATUS_OFFSET ((unsigned long)0x00001010) /*! \def INTERRUPT_CLEAR_OFFSET \brief Offset for the Interrupt Clear Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #InterruptClearRegister variable during Driver Startup */ #define INTERRUPT_CLEAR_OFFSET ((unsigned long)0x00001018) /*! \def IDENTIFICATION_OFFSET \brief Offset for the ID Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #IDRegister variable during Driver Startup */ #define IDENTIFICATION_OFFSET ((unsigned long)0x00001020) /* Possible core ID mask values */ /* Least-significant 4 bits may end up as sub-version mask */ #define SEC_COREID_2_0_0 (0x00000040) #define SEC_COREID_2_1_0 (0x00000080) /*! \def CHA_ASSIGNMENT_STATUS_OFFSET \brief Offset for the CHA Assignment Control Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChaAssignmentStatusRegister variable during Driver Startup */ #define CHA_ASSIGNMENT_STATUS_OFFSET ((unsigned long)0x00001028) /*! \def CHANNEL_CONFIG_BASE \brief Base address for the Channel # 1's Channel Configuration Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChannelConfigRegister variable array during Driver Startup Each channel has a Channel Configuration Register that is offset #CHANNEL_DISTANCE from the previous. */ #define CHANNEL_CONFIG_BASE ((unsigned long)0x00001108) /*! \def CHANNEL_POINTER_STATUS_BASE \brief Base address for the Channel # 1's Channel Pointer Status Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChannelPointerStatusRegister variable array during Driver Startup Each channel has a Channel Pointer Status Register that is offset #CHANNEL_DISTANCE from the previous. */ #define CHANNEL_POINTER_STATUS_BASE ((unsigned long)0x00001110) /*! \def CHANNEL_NEXT_DESCRIPTOR_BASE \brief Base address for the Channel # 1's Channel Next Descriptor Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChannelNextDescriptorRegister variable array during Driver Startup Each channel has a Channel Next Descriptor Register that is offset #CHANNEL_DISTANCE from the previous. */ #define CHANNEL_NEXT_DESCRIPTOR_BASE ((unsigned long)0x00001148) /* Debugging Only definition */ #define CHANNEL_DBR_BASE ((unsigned long)0x00001180) #define CHANNEL_CDPR_BASE ((unsigned long)0x00002040) /*! \def CHANNEL_DISTANCE \brief Number of bytes to the next channel register */ #define CHANNEL_DISTANCE ((unsigned long)0x00000100) /*! \def CHA_RESET_CONTROL_BASE \brief Base address for the CHA # 1 (DES) CHA Reset Control Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChaResetControlRegister variable array during Driver Startup Each CHA has a CHA Reset Control Register that is offset #CHA_DISTANCE from the previous. */ #define CHA_RESET_CONTROL_BASE ((unsigned long)0x00002018) /*! \def CHA_INTERRUPT_STATUS_BASE \brief Base address for the CHA # 1 (DES) CHA Interrupt Status Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChaInterruptStatusRegister variable array during Driver Startup Each CHA has a CHA Interrupt Status Register that is offset #CHA_DISTANCE from the previous. */ #define CHA_INTERRUPT_STATUS_BASE ((unsigned long)0x00002030) /*! \def CHA_INTERRUPT_CONTROL_BASE \brief Base address for the CHA # 1 (DES) CHA Interrupt Control Register. This is relative to the base address register for the SEC2 coprocessor. It is used to setup the #ChaInterruptControlRegister variable array during Driver Startup Each CHA has a CHA Interrupt Control Register that is offset #CHA_DISTANCE from the previous. */ #define CHA_INTERRUPT_CONTROL_BASE ((unsigned long)0x00002038) /*! \def AFHA_STATUS_OFFSET \brief Debugging Only definition. */ #define AFHA_STATUS_OFFSET ((unsigned long)0x0008028) /*! \def PKHA_STATUS_BASE \brief Debugging Only definition. */ #define PKHA_STATUS_BASE ((unsigned long)0x0000C028) /* CHA_DISTANCE Number of bytes to the next CHA register */ #define CHA_DISTANCE ((unsigned long)0x00002000) /* CHANNEL_INTEN Channel Interrupt Enable */ #define CHANNEL_INTEN ((unsigned long)0x00000002) /* Force channel burst size to 128 bytes (normal default is 64) */ #define CHANNEL_BURST128 ((unsigned long)0x00000100) /* CHANNEL_RESET Bit field setting to write to the #ChannelConfigRegister in order to reset the channel. First Word The bit setting indicates that we are resetting the channel */ #define CHANNEL_RESET ((unsigned long)0x00000001) /* Bit field mask for reading from the #ChannelPointerStatusRegister in order to determine if a CHA assigned to the channel generated an error or not. First Word */ #define CHANNEL_CHA_ERROR_DOF ((unsigned long)0x80000000) #define CHANNEL_CHA_ERROR_SOF ((unsigned long)0x40000000) #define CHANNEL_CHA_ERROR_GER ((unsigned long)0x00100000) #define CHANNEL_CHA_ERROR_SES ((unsigned long)0x00001000) /* Bit field mask for reading from the #ChannelPointerStatusRegister in order to determine if there is an illegal descriptor or not Second Word */ #define CHANNEL_SCATTER_LENGTH_ERROR ((unsigned long) 0x00000010) #define CHANNEL_SCATTER_BOUND_ERROR ((unsigned long) 0x00000020) #define CHANNEL_GATHER_LENGTH_ERROR ((unsigned long) 0x00000040) #define CHANNEL_GATHER_BOUND_ERROR ((unsigned long) 0x00000080) #define CHANNEL_CHA_ERROR ((unsigned long) 0x00000100) #define CHANNEL_CHA_ASSIGN_ERROR ((unsigned long) 0x00000200) #define CHANNEL_UNRECOGNIZED_HEADER_ERROR ((unsigned long) 0x00000400) #define CHA_PARITY_SYSTEM_ERROR ((unsigned long) 0x00000800) /* compatibility */ #define CHANNEL_NULL_FETCH_POINTER ((unsigned long) 0x00000800) #define CHANNEL_ZERO_SCATTER_LEN_ERROR ((unsigned long) 0x00001000) #define CHANNEL_BUS_MASTER_ERROR ((unsigned long) 0x00002000) #define CHANNEL_FETCH_FIFO_NEARMISS_ERROR ((unsigned long) 0x00004000) #define CHANNEL_FETCH_FIFO_OVERFLOW_ERROR ((unsigned long) 0x00008000) /*! \def SET_ALL_CHA_INT_DONE_MASK \brief Bit field setting to write to the #InterruptControlRegister in order to disable interrupts when any of the CHAs have completed an operation */ /*! \def SET_ALL_CHA_INT_DONE_MASK \brief Bit field setting to write to the #InterruptControlRegister in order to disable interrupts when any of the CHAs have completed an operation */ /*! \def CHA_SOFTWARE_RESET \brief Bit field setting to write to any of the #ChaResetControlRegister"s" in order to software reset the CHA */ /*! \def CHA_MODULE_INIT \brief Bit field setting to write to any of the #ChaResetControlRegister"s" in order to initialize the CHA */ /*! \def CHA_RESET_INT \brief Bit field setting to write to any of the #ChaResetControlRegister"s" in order to reset the CHA */ /*! \def CHA_RESET_INT \brief Bit field setting to write to any of the #ChaResetControlRegister"s" in order to reset the CHA */ /*! \def CHA_DESA_KEY_PARITY_ERROR_DISABLE \brief Bit field setting to write to any of the #ChaInterruptControlRegister"s" in order to disable parity errors for the CHA. This is only good for DES specific CHAs. */ /*! \def CHA_PKHA_ILLEGAL_ADDR_ERROR_DISABLE \brief Bit field setting to write to any of the #ChaInterruptControlRegister"s" in order to disable illegal address errors for the CHA. This is only good for PK specific CHAs. */ #define SET_ALL_CHA_INT_DONE_MASK ((unsigned long)0x00111111) #define CHA_SOFTWARE_RESET ((unsigned long)0x00000001) #define CHA_DESA_KEY_PARITY_ERROR_DISABLE ((unsigned long)0x00002000) #define CHA_PKHA_ILLEGAL_ADDR_ERROR_DISABLE ((unsigned long)0x00000040) /* NUM_DPD_FLDS Number of fields in a ::dpd */ #define NUM_DPD_FLDS 7 /* This is the physical representation of a DPD. It is how the SEC2 sees a DPD. */ typedef struct dpd { unsigned long header; unsigned long dpd_reserved; /* Each field in a DPD. They are length and pointer pairs. */ struct dpd_fld { unsigned long len; unsigned long ptr; } fld[NUM_DPD_FLDS]; } DPD; /* CHANNEL_ASSIGNMENT Controls the assignment of channels */ typedef struct channel_assignment { unsigned char assignment; /* The current state of the channel. It can be one of the following values: #CHANNEL_FREE, or #CHANNEL_BUSY */ int ownerTaskId; /* Task Id that currently owns the channel. */ GENERIC_REQ *pReq; /* Pointer to the start of a linked list describing the request */ GENERIC_REQ *pCurrReq; /* Pointer to the current linked list member. Used when the list is chunked */ DPD **Dpds; /* Array of pointers to DPDs that can used when generating DPD requests #MAX_DPDS identifies how many DPDs are allocated during startup. */ } CHANNEL_ASSIGNMENT; /* A double linked list to pending dynamic requests */ typedef struct queue_entry { int requestingTaskId; /* Requesting task's Id. This becomes channel_assignment::ownerTaskId when a channel can be assigned. */ int chan; /* channel if static be free before the entry can be assigned to a channel */ GENERIC_REQ *pReq; /* Pointer to the start of a linked list describing the request This becomes channel_assignment::pReq when a channel can be assigned. */ struct queue_entry *next; /* pointer to next entry */ struct queue_entry *previous; /* pointer to previous entry */ } QUEUE_ENTRY; /* (!sec) these may be obsolete */ #define ALL_INT_ERRORS_MASK_LOW ((unsigned long)0x000000ff) #define ALL_INT_ERRORS_MASK_HIGH ((unsigned long)0x00333333) /* All possible channel done interrupts from high interrupt status word */ #define ALL_CHANNEL_INT_DONE_MASK ((unsigned long)0x00000055) #define CHANNEL_INT_DONE_1 ((unsigned long)0x00000001) #define CHANNEL_INT_DONE_2 ((unsigned long)0x00000004) #define CHANNEL_INT_DONE_3 ((unsigned long)0x00000010) #define CHANNEL_INT_DONE_4 ((unsigned long)0x00000040) /* All possible CHA done interrupts from low interrupt status word */ #define ALL_CHA_INT_DONE_MASK ((unsigned long)0x00111111) #define CHA_INT_DONE_DEU ((unsigned long)0x00000001) #define CHA_INT_DONE_AESU ((unsigned long)0x00000010) #define CHA_INT_DONE_MDEU ((unsigned long)0x00000100) #define CHA_INT_DONE_AFEU ((unsigned long)0x00001000) #define CHA_INT_DONE_RNG ((unsigned long)0x00010000) #define CHA_INT_DONE_PKEU ((unsigned long)0x00100000) /* All possible channel error interrupts from high interrupt status word */ #define ALL_CHANNEL_INT_ERROR_MASK ((unsigned long)0x000000aa) #define CHANNEL_INT_ERROR_1 ((unsigned long)0x00000002) #define CHANNEL_INT_ERROR_2 ((unsigned long)0x00000008) #define CHANNEL_INT_ERROR_3 ((unsigned long)0x00000020) #define CHANNEL_INT_ERROR_4 ((unsigned long)0x00000080) /* All possible CHA done interrupts from low interrupt status word */ #define ALL_CHA_INT_ERROR_MASK ((unsigned long)0x00222222) #define CHA_INT_ERROR_DEU ((unsigned long)0x00000002) #define CHA_INT_ERROR_AESU ((unsigned long)0x00000020) #define CHA_INT_ERROR_MDEU ((unsigned long)0x00000200) #define CHA_INT_ERROR_AFEU ((unsigned long)0x00002000) #define CHA_INT_ERROR_RNG ((unsigned long)0x00020000) #define CHA_INT_ERROR_PKEU ((unsigned long)0x00200000) /*! \struct device_regs \brief A grouping of status and error indication registers */ typedef struct device_regs { unsigned long IntStatus[2]; /*!< The Interrupt Status Register (#InterruptStatusRegister)*/ unsigned long IntStatusDbg[2]; /*!< The Interrupt Status Register (#InterruptStatusRegister)*/ unsigned long ChaAssignmentStatus[2]; /*!< The CHA Assignment Status Register (#ChaAssignmentStatusRegister) */ unsigned long ChannelError[NUM_CHANNELS][2]; /*!< An array of Channel Pointer Status Registers. One per channel (#ChannelPointerStatusRegister) */ unsigned long ChaError[NUM_CHAS][2]; /*!< an array of CHA Interrupt Status Registers. One per CHA (#ChaInterruptStatusRegister) */ } DEVICE_REGS; /* Queueing */ #ifdef __KERNEL__ #define PREGS_QUEUE_DEPTH 16 extern DEVICE_REGS pRegs_queue[PREGS_QUEUE_DEPTH]; extern unsigned PQ_head, PQ_tail, PQ_entries; #define QmsgSend() \ if (PQ_entries == PREGS_QUEUE_DEPTH) { \ panic("SEC driver's pRegs queue overflow!"); \ } \ pRegs_queue[PQ_tail] = *pRegs; \ PQ_tail = (PQ_tail + 1) % PREGS_QUEUE_DEPTH; \ PQ_entries ++; \ tasklet_schedule(&isr_tasklet) #define QmsgWait() \ disable_irq(MPC85xx_IRQ_SEC); \ if (!PQ_entries) { \ enable_irq(MPC85xx_IRQ_SEC); break;} \ *pRegs = pRegs_queue[PQ_head]; \ PQ_head = (PQ_head + 1) % PREGS_QUEUE_DEPTH; \ PQ_entries --; \ enable_irq(MPC85xx_IRQ_SEC) #endif /* Components of a SEC2 scatter/gather list element. This is the native format */ /* that the channel processor expects to see so as to translate a scattered */ /* buffer in the course of processing */ #define MAX_SCATTER_FRAGS 1024 /* limit of static fragment descriptor pool */ /* used in "linkStat" below */ #define SEGLIST_RETURN 0x0200 #define SEGLIST_NEXT 0x0100 typedef struct _sec2scatterListElement { unsigned short segLen; unsigned short linkStat; void *segAddr; } SCATTER_ELEMENT; #if defined(SEC2_GLOBAL) || defined(__cplusplus) /* unsigned long ChaDoneInterruptMasks[NUM_CHAS] An array of CHA done completion bit masks. The index of the array represents the CHA. This bit mask is applied against #InterruptStatusRegister in order to determine if an interrupt is due to a CHA completion or not. */ const unsigned long ChaDoneInterruptMasks[NUM_CHAS] = { 0x00000001, 0x00000010, 0x00000100, 0x00001000, 0x00010000, 0x00100000 }; /* unsigned long ChannelDoneInterruptMasks[NUM_CHANNELS] An array of channel done completion bit masks. The index of the array represents the channel. This bit mask is applied against #InterruptStatusRegister in order to determine if an interrupt is due to a channel completion or not. */ const unsigned long ChannelDoneInterruptMasks[NUM_CHANNELS] = { 0x00000001, 0x00000004, 0x00000010, 0x00000040 }; /*! \var unsigned long ChannelErrorInterruptMasks[NUM_CHANNELS] \brief An array of channel error bit masks. The index of the array represents the channel. This bit mask is applied against #InterruptStatusRegister in order to determine if an interrupt is due to a channel error or not. */ const unsigned long ChannelErrorInterruptMasks[NUM_CHANNELS] = { 0x00000002, 0x00000008, 0x00000020, 0x00000080 }; /*! \var unsigned long ChaErrorInterruptMasks[NUM_CHAS] \brief An array of CHA error bit masks. The index of the array represents the CHA. This bit mask is applied against #InterruptStatusRegister in order to determine if an interrupt is due to a CHA error or not. */ const unsigned long ChaErrorInterruptMasks[NUM_CHAS] = { 0x00000002, 0x00000020, 0x00000200, 0x00002000, 0x00020000, 0x00200000 }; #else extern const unsigned long ChaDoneInterruptMasks[]; extern const unsigned long ChannelDoneInterruptMasks[]; extern const unsigned long ChannelErrorInterruptMasks[]; extern const unsigned long ChaErrorInterruptMasks[]; #endif #ifndef SEC2_GLOBAL #define SEC2_GLOBAL extern #endif /* SEC2_GLOBAL A definition used to control allocation and referencing of global variables. When the definition is not set it is considered to be used as a reference (extern is prepended). When the definition is set (to nothing) it is considered to be allocating the global variable. This is done in one place only. In init.c */ /* CHANNEL_ASSIGNMENT ChannelAssignments A global variable which is a array of channel assignment structures. Each channel is reqresented by its own channel assignment structure. */ SEC2_GLOBAL DPD Descriptors[NUM_CHANNELS][MAX_DPDS] ; SEC2_GLOBAL CHANNEL_ASSIGNMENT ChannelAssignments[NUM_CHANNELS]; SEC2_GLOBAL DPD *dpd[NUM_CHANNELS][MAX_DPDS]; SEC2_GLOBAL QUEUE_ENTRY Queue[QUEUE_ENTRY_DEPTH]; /* A global variable which is an array of CHAs that are assigned to channels. The value in each element is either #CHA_BUSY which is unassigned or the channel that is assigned (1-4) to the CHA represented by the array index. */ SEC2_GLOBAL unsigned char ChaAssignments[16]; /* A global variable which is the address of the base address register for the SEC2 coprocessor All registers accessed are offsets from this register. This variable is initialized during startup. */ SEC2_GLOBAL unsigned long IOBaseAddress; /* A global variable which is a pointer to the CHA Assignment Status Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChaAssignmentStatusRegister; /* A global variable which is a pointer to the CHA Assignment Control Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChaAssignmentControlRegister; /* A global variable which is a pointer to the Interrupt Control Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *InterruptControlRegister; /* A global variable which is a pointer to the Interrupt Status Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *InterruptStatusRegister; /* A global variable which is a pointer to the Interrupt Clear Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *InterruptClearRegister; /* A global variable which is a pointer to the ID Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *IdRegister; /* A global variable which is a array of pointers to the Channel Config Registers. There is one per channel. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChannelConfigRegister[NUM_CHANNELS]; /* A global variable which is a array of pointers to the Channel Pointer Status Registers. There is one per channel. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChannelPointerStatusRegister[NUM_CHANNELS]; /* A global variable which is a array of pointers to the Channel Next Descriptor Registers. There is one per channel. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChannelNextDescriptorRegister[NUM_CHANNELS]; /* A global variable which is a array of pointers to the CHA Reset Control Registers. There is one per CHA. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChaResetControlRegister[NUM_CHAS]; /* A global variable which is a array of pointers to the CHA Interrupt Status Registers. There is one per CHA. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChaInterruptStatusRegister[NUM_CHAS]; /* A global variable which is a array of pointers to the CHA Interrupt Control Registers. There is one per CHA. This pointers are initialized during startup. They are determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *ChaInterruptControlRegister[NUM_CHAS]; /* Debugging Only variables. */ SEC2_GLOBAL volatile unsigned long *ChannelDataBufferDescriptorRegister[NUM_CHANNELS]; SEC2_GLOBAL volatile unsigned long *ChannelCurrentDescriptorPointerRegister[NUM_CHANNELS]; /* long *MasterControlRegister A global variable which is a pointer to the Master Control Register This variable is initialized during startup. It is determined to be a fixed offset from the #IOBaseAddress register. See the SEC2 manual for details. */ SEC2_GLOBAL volatile unsigned long *MasterControlRegister; /* FreeChannels A global variable which keeps track of the number of free channels */ SEC2_GLOBAL int FreeChannels; /*! \var int FreeRngas \brief A global variable which keeps track of the number of free RNG CHAs */ SEC2_GLOBAL int FreeRngas; /*! \var int FreeAfhas \brief A global variable which keeps track of the number of free ARC4 CHAs */ SEC2_GLOBAL int FreeAfhas; /*! \var int FreeDesas \brief A global variable which keeps track of the number of free DES CHAs */ SEC2_GLOBAL int FreeDesas; /*! \var int FreeMdhas \brief A global variable which keeps track of the number of free MD CHAs */ SEC2_GLOBAL int FreeMdhas; /*! \var int FreePkhas \brief A global variable which keeps track of the number of free PK CHAs */ SEC2_GLOBAL int FreePkhas; /*! \var int FreeAesas \brief A global variable which keeps track of the number of free AESA CHAs */ SEC2_GLOBAL int FreeAesas; /*! \var int FreeKeas \brief A global variable which keeps track of the number of free KEA CHAs */ SEC2_GLOBAL int FreeKeas; /*! \var unsigned long BlockSize \brief A global variable which indicates what the current block size is */ SEC2_GLOBAL unsigned long BlockSize; /*! \var ProcessQueueTop \brief A global variable which is a pointer to the top of the Pending dynamic request list (list of ::queue_entry"s"). */ SEC2_GLOBAL QUEUE_ENTRY *ProcessQueueTop; /*! \var ProcessQueueBottom \brief A global variable which is a pointer to the bottom of the Pending dynamic request list (list of ::queue_entry"s"). */ SEC2_GLOBAL QUEUE_ENTRY *ProcessQueueBottom; /*! \var unsigned long QueueEntryDepth \brief A global variable which keeps track of the number of entries in the Pending dynamic request list pointed to by #ProcessQueueTop */ SEC2_GLOBAL unsigned long QueueEntryDepth; /*! \var SEM_ID ChannelAssignSemId \brief (VxWorks Only) A global variable which is used as a mutual exclusion semaphore for the #ChannelAssignments array. The variable is not used directly. It used by calling #IOLockChannelAssignment() to lock and #IOUnLockChannelAssignment() to unlock. */ #if defined(VXWORKS) SEC2_GLOBAL SEM_ID ChannelAssignSemId; #else #ifdef __KERNEL__ extern spinlock_t ChannelAssignLock; #else #ifdef INIT_C DECLARE_MUTEX(ChannelAssignSemId); #else extern struct semaphore ChannelAssignSemId; #endif #endif #endif /*! \var SEM_ID QueueSemId \brief (VxWorks Only) A global variable which is used as a mutual exclusion semaphore for the Queue The variable is not used directly. It used by calling #IOLockBlockSize() to lock and #IOUnLockBlockSize() to unlock. */ #if defined(VXWORKS) SEC2_GLOBAL SEM_ID QueueSemId; #else #ifdef INIT_C DECLARE_MUTEX(QueueSemId); #else extern struct semaphore QueueSemId; #endif #endif #ifdef VXWORKS /* The queue identifier is used to queue register values read by the ISR (#InterruptServiceRoutine()) to the deferred interrupt process routine (#ProcessingComplete()) */ SEC2_GLOBAL MSG_Q_ID IsrMsgQId; /* OS's identification of the device*/ SEC2_GLOBAL int driverNum; #endif #ifdef __KERNEL__ /* Device major number registered at device initialization */ SEC2_GLOBAL int sec2_devmajor; #endif SEC2_GLOBAL unsigned int cha_idx[6]; /*! \var DEV_HDR vxworksDrvDev \brief (VxWorks Only) Used in driver startup. */ #ifdef VXWORKS SEC2_GLOBAL DEV_HDR vxworksDrvDev; #endif /* coremask holds the core ID register for version/feature control */ SEC2_GLOBAL unsigned long coremask; /* Forward declarations for internal driver functions not meant for "public use" */ int ReleaseChannel(unsigned long, int, BOOLEAN); int MapScatterFragments(unsigned long , unsigned long *); void UnmapScatterFragments(unsigned long *); /* Read/write a block of data from hardware registers (obsolete) */ void IORead(unsigned long *, int, volatile unsigned long *); void IOWrite(unsigned long *, int, volatile unsigned long *); /* Register driver and it's handlers with the OS */ IO_STATUS IORegisterDriver(void); /* Set up internal driver semaphores */ void IOInitSemaphores(void); /* Initialize drive queues */ IO_STATUS IOInitQs(void); /* Enable/Disable the hardware interrupt */ IO_STATUS IOConnectInterrupt(void); void IODisconnectInterrupt(void); /* Allocate/free a dynamic queue entry (obsolete) */ QUEUE_ENTRY *IOAllocateQEntry(void); void IOFreeQEntry(QUEUE_ENTRY *); /* Initialize/Allocate/Release channel assignment table */ IO_STATUS InitChannelAssignment(int); void FreeChannelAssignment(int); /* Translate CHA index to type */ int ChaNumToType(int); /* Check to see if the CHA type is available */ extern int CheckChas(unsigned long); /* Open a new connection to this driver */ #ifdef __KERNEL__ int SEC2Open(struct inode *, struct file *); #else int SEC2Open(DEV_HDR *, int, int); #endif /* Close a connection to this driver */ #ifdef __KERNEL__ int SEC2Close(struct inode *, struct file *); #else int SEC2Close(int); #endif /* Request a driver operation*/ #ifdef __KERNEL__ int SEC2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); #else int SEC2_ioctl(int, register int, register void *); #endif /* Driver's top level ISR handler */ #ifdef __KERNEL__ void InterruptServiceRoutine(int irq, void *dev_id, struct pt_regs *pt_regs); #else void InterruptServiceRoutine(void); #endif /* ISR's Deferred processing (bottom half) handler */ #if defined(VXWORKS) || defined(_MSC_VER) extern void ProcessingComplete(void); #else extern void ProcessingComplete(unsigned long not_used); #endif /* External function to mark scatter buffers for kernel-state usage */ #ifdef __KERNEL__ int MarkScatterBuffer(void *, void *); #endif /* Take a user request, build a DPD, and submit it for processing */ int ProcessRequest(GENERIC_REQ *, int); /* Start any pending requests */ void ScheduleNext(void); /*! \fn BOOLEAN StartDescriptor(int channel, unsigned long addr) \brief Start a DPD request to the SEC2 Write \a addr to the #ChannelNextDescriptorRegister register for this \a channel Timers are launched if USE_TIMERS are defined \param channel \param addr address to be saved in #ChannelNextDescriptorRegister \retval TRUE if successful */ extern BOOLEAN StartDescriptor(int channel, unsigned long addr); /*! \fn int CompleteRequest(int channel, int status, BOOLEAN bDoNotify, DEVICE_REGS *pRegs) \brief Complete a request Call FinishIoRequest() Cleanup the ::req_list associated with this request by calling CleanupRequestList() Make the #ChannelAssignment entry for the \a channel available If \a bDoNotify is set, call a notify routine \param channel Channel request was issued on \param status Status of the request \param bDoNotify Notify requester? \param pRegs Pointer to register snapshot \retval status */ extern int CompleteRequest(int channel, int status, BOOLEAN bDoNotify, DEVICE_REGS *pRegs); /*! \fn void RemoveQueueEntry(QUEUE_ENTRY *entry) \brief Remove entry from pending dynamic request list \param entry ::queue_entry to be deleted */ extern void RemoveQueueEntry(QUEUE_ENTRY *entry); /*! \fn int RequestToDpd(int channel) \brief Transform the current request into a chain of DPDs This routine will traverse a ::req_list populating CHANNEL_ASSIGNMENT::Dpds for the given \a channel. The ::req_list will have been built by BuildRequestList(). After successful completion, the caller will be able to get the hardware to process the request by calling StartDescriptor(). StartDescriptor() expects a Hardware specific address, i.e. use CHANNEL_ASSIGNMENT::addrHwDpds for the given \a channel. \param channel Channel that DPD(s) will be launched on \retval #SEC2_SUCCESS if successful */ extern int RequestToDpd(GENERIC_REQ *pReq, int channel); /*! \fn void CopyRegsToStatus(STATUS_REQ *pStatus, DEVICE_REGS *pRegs) \brief A helper function to copy a register snapshot into a status request \param pStatus Pointer to status request \param pRegs Pointer to register snapshot */ extern void CopyRegsToStatus(STATUS_REQ *pStatus, DEVICE_REGS *pRegs); /*! \fn int SetBlockSize(unsigned long* newBlockSize) \brief Set the Block Size for DPD requests \param newBlockSize Size to set #BlockSize to. \retval #SEC2_SUCCESS if successful */ extern int SetBlockSize(unsigned long* newBlockSize); /*! \fn int GetStatus(STATUS_REQ *pStatus, int callingTaskId) \brief Get Current Status of the Driver \param pStatus Pointer to status request. \param callingTaskId Id of Task that is making the request \retval #SEC2_SUCCESS */ extern int GetStatus(STATUS_REQ *pStatus, int callingTaskId); #endif /* SEC2DRIVER_H */