410 lines
13 KiB
C
410 lines
13 KiB
C
|
|
|
|
/****************************************************************************
|
|
* sec2_init.c -- The Initialization code for SEC2 Driver
|
|
****************************************************************************
|
|
* Copyright (c) Certicom Corp. 1996-2002. All rights reserved
|
|
* Copyright (c) 2003-2005 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
|
|
* 1.1.0 Nov 16,2004 sec - incorporate linux changes from prior versions
|
|
* 1.1.1 Dec 16,2004 sec - remove old unused diagnostics
|
|
* 1.2 Jan 27,2005 sec - fix comments associated with global inhibit
|
|
*/
|
|
|
|
#define SEC2_GLOBAL
|
|
#define INIT_C
|
|
|
|
#include "Sec2Driver.h"
|
|
|
|
/* Interpeak begin */
|
|
#undef NUM_CHANNELS
|
|
#define NUM_CHANNELS (num_channels)
|
|
int num_channels;
|
|
extern int ipfreescale_sec_num_channels(void);
|
|
/* Interpeak end */
|
|
|
|
#if defined(DBG)
|
|
/* unsigned long SEC2DebugLevel = (DBGTXT_SETRQ | DBGTXT_SVCRQ | DBGTXT_INITDEV | DBGTXT_DPDSHOW | DBGTXT_INFO); */
|
|
unsigned long SEC2DebugLevel = (DBGTXT_INFO);
|
|
#else
|
|
unsigned long SEC2DebugLevel = 0x0;
|
|
#endif
|
|
|
|
#ifdef __KERNEL
|
|
EXPORT_SYMBOL(SEC2DebugLevel);
|
|
#endif
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* Function Name: SEC2DriverInit
|
|
* Purpose:
|
|
* Step1: Build base address by requesting peripheral base
|
|
* Step2: Init ChannelRegister & Cha Register
|
|
* Step3: Allocate Channel Assignments
|
|
* Step4: Init ChannelAssignments & ChaAssignments
|
|
* Step5: Init ProcessQueueTop & ProcessQueueBottom
|
|
* Step6: Init Semaphores
|
|
* Step7: Reset all Chas and Channels
|
|
* Step8: Config all Channels
|
|
* Step9: Connect Interrupt
|
|
* Step10: Enable Interrupt
|
|
* Step11: Return Success
|
|
*
|
|
* Input: None
|
|
*
|
|
* Return: SEC2_SUCCESS if everything passed, otherwise the error code
|
|
*************************************************************************/
|
|
/* static unsigned long CurrentCHAStatus[2]; */
|
|
|
|
int SEC2DriverInit(void)
|
|
{
|
|
static int status, i;
|
|
static int cha;
|
|
static int channel;
|
|
static unsigned long address;
|
|
static unsigned int idx[] = {0,2,4,3,5,1};
|
|
static char *coreID;
|
|
#ifdef __KERNEL__
|
|
bd_t *binfo = (bd_t *) __res;
|
|
#endif
|
|
|
|
/* Interpeak begin */
|
|
num_channels = ipfreescale_sec_num_channels();
|
|
/* Interpeak end */
|
|
|
|
|
|
/* Check prior initialization, and initialize driver per OS convention */
|
|
#ifdef VXWORKS
|
|
if (taskIdVerify (taskNameToId ("tSEC2_pc")) == OK) {
|
|
printf ("\nSecurity Processor already initialized\n");
|
|
return (OK);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
/* Anything not done in the module init hook? */
|
|
|
|
#endif
|
|
|
|
|
|
/* sysGetPeripheralBase() gets the PQ3 CCSBAR from the OS */
|
|
#ifdef VXWORKS
|
|
IOBaseAddress = (sysGetPeripheralBase() + TALITOS2X_BASE_ADDRESS);
|
|
#endif
|
|
|
|
/* get base from the kernel, and map it into an accessible region */
|
|
#ifdef __KERNEL__
|
|
IOBaseAddress = (unsigned long) ioremap((phys_addr_t)(binfo->bi_immr_base + TALITOS2X_BASE_ADDRESS), SEC2_BASE_SIZE);
|
|
#endif
|
|
|
|
|
|
/* Identify the running hardware */
|
|
SEC2Dump(DBGTXT_INFO, ("SEC 2.x Security Processor Core\n"));
|
|
SEC2Dump(DBGTXT_INFO, ("Driver Version %s %s %s\n", VERSION, __DATE__,__TIME__));
|
|
|
|
coremask = *((volatile unsigned long *)(IOBaseAddress + IDENTIFICATION_OFFSET) + 1);
|
|
|
|
switch(coremask)
|
|
{
|
|
case SEC_COREID_2_0_0:
|
|
coreID = "2.0.0";
|
|
break;
|
|
|
|
case SEC_COREID_2_1_0:
|
|
coreID = "2.1.0";
|
|
break;
|
|
|
|
default:
|
|
coreID = "unknown";
|
|
break;
|
|
}
|
|
|
|
SEC2Dump(DBGTXT_INFO, ("Security Core Version Mask: %s (0x%08lx)\n\n", coreID, coremask));
|
|
|
|
|
|
/* set up rebound cha index table */
|
|
memcpy ((char *)cha_idx, (char *)idx, sizeof (idx));
|
|
|
|
/* set up SEC2 register addresses */
|
|
/* controller registers */
|
|
ChaAssignmentStatusRegister = (volatile unsigned long*)
|
|
(IOBaseAddress + CHA_ASSIGNMENT_STATUS_OFFSET);
|
|
InterruptControlRegister = (volatile unsigned long*)
|
|
(IOBaseAddress + INTERRUPT_CONTROL_OFFSET);
|
|
InterruptStatusRegister = (volatile unsigned long*)
|
|
(IOBaseAddress + INTERRUPT_STATUS_OFFSET);
|
|
InterruptClearRegister = (volatile unsigned long*)
|
|
(IOBaseAddress + INTERRUPT_CLEAR_OFFSET);
|
|
IdRegister = (volatile unsigned long*)
|
|
(IOBaseAddress + IDENTIFICATION_OFFSET);
|
|
MasterControlRegister = (volatile unsigned long *)
|
|
(IOBaseAddress + SEC2_MASTER_CONTROL_REGISTER);
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->IOBaseAddress=0x%08lx\n", IOBaseAddress));
|
|
|
|
|
|
|
|
/* Reset the SEC2 */
|
|
/* Note that we turn on global inhibit for all processors. At the time */
|
|
/* of coding, GI only exists in the 8349; it's irrelevant to PQ3 devices. */
|
|
/* So, it's just turned on for all processors, which is OK for now. */
|
|
/* In time, this may be need to become an option in build configuration. */
|
|
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->reset Master Control Register\n"));
|
|
*(MasterControlRegister) = SEC2_RESET | SEC2_GLOBAL_INHIBIT;
|
|
*(MasterControlRegister + 1) = 0;
|
|
|
|
|
|
SEC2Dump(DBGTXT_INITDEV,
|
|
("SEC2DriverInit->IdRegister=0x%08lx 0x%08lx\n",
|
|
*(IdRegister),
|
|
*(IdRegister + 1)));
|
|
|
|
|
|
|
|
/* channel registers */
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->channel registers\n"));
|
|
for (channel=0, address=CHANNEL_CONFIG_BASE; channel<NUM_CHANNELS;
|
|
channel++,address+=CHANNEL_DISTANCE)
|
|
{
|
|
ChannelConfigRegister[channel] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (channel=0,address=CHANNEL_POINTER_STATUS_BASE; channel<NUM_CHANNELS;
|
|
channel++,address+=CHANNEL_DISTANCE)
|
|
{
|
|
ChannelPointerStatusRegister[channel] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (channel=0,address=CHANNEL_NEXT_DESCRIPTOR_BASE; channel<NUM_CHANNELS;
|
|
channel++,address+=CHANNEL_DISTANCE)
|
|
{
|
|
ChannelNextDescriptorRegister[channel] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (channel=0,address=CHANNEL_DBR_BASE; channel<NUM_CHANNELS;
|
|
channel++,address+=CHANNEL_DISTANCE)
|
|
{
|
|
ChannelDataBufferDescriptorRegister[channel] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (channel=0,address=CHANNEL_CDPR_BASE; channel<NUM_CHANNELS;
|
|
channel++,address+=CHANNEL_DISTANCE)
|
|
{
|
|
ChannelCurrentDescriptorPointerRegister[channel] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
|
|
/* cha registers */
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->cha registers\n"));
|
|
for (cha=0,address=CHA_RESET_CONTROL_BASE; cha<NUM_CHAS;
|
|
cha++,address+=CHA_DISTANCE)
|
|
{
|
|
ChaResetControlRegister[cha] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (cha=0,address=CHA_INTERRUPT_STATUS_BASE; cha<NUM_CHAS;
|
|
cha++,address+=CHA_DISTANCE)
|
|
{
|
|
ChaInterruptStatusRegister[cha_idx[cha]] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
for (cha=0,address=CHA_INTERRUPT_CONTROL_BASE; cha<NUM_CHAS;
|
|
cha++,address+=CHA_DISTANCE)
|
|
{
|
|
ChaInterruptControlRegister[cha] =
|
|
(volatile unsigned long*)(IOBaseAddress + address);
|
|
}
|
|
|
|
/* allocate other driver variables */
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->allocating other driver variables\n"));
|
|
|
|
/* variable init */
|
|
FreeChannels = NUM_CHANNELS;
|
|
FreeRngas = NUM_RNGAS;
|
|
FreeAfhas = NUM_AFHAS;
|
|
FreeDesas = NUM_DESAS;
|
|
FreeMdhas = NUM_MDHAS;
|
|
FreePkhas = NUM_PKHAS;
|
|
FreeAesas = NUM_AESAS;
|
|
|
|
/* Init ChannelAssignments */
|
|
for (channel=0; channel<NUM_CHANNELS; channel++)
|
|
{
|
|
if ((status = InitChannelAssignment(channel)) != SEC2_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* Init ChaAssignments */
|
|
for (cha=0; cha<16; cha++)
|
|
{
|
|
ChaAssignments[cha] = CHA_DYNAMIC;
|
|
}
|
|
|
|
/* initialize process queue */
|
|
for (i=0; i<QUEUE_ENTRY_DEPTH-1;i++)
|
|
Queue[i].next = &Queue[i+1];
|
|
Queue[QUEUE_ENTRY_DEPTH-1].next = &Queue[0];
|
|
for (i=1; i<QUEUE_ENTRY_DEPTH;i++)
|
|
Queue[i].previous = &Queue[i-1];
|
|
Queue[0].previous = &Queue[QUEUE_ENTRY_DEPTH-1];
|
|
|
|
ProcessQueueTop = &Queue[0];
|
|
ProcessQueueBottom = &Queue[0];
|
|
|
|
IOInitSemaphores();
|
|
|
|
#ifdef VXWORKS
|
|
if ((status = IOInitQs()) != SEC2_SUCCESS)
|
|
return status;
|
|
|
|
if ((status = IORegisterDriver()) != SEC2_SUCCESS)
|
|
return status;
|
|
#endif
|
|
|
|
/* reset all the CHA's */
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->reset Reset Control Register %d\n", NUM_CHAS));
|
|
for (cha=0; cha<NUM_CHAS; cha++)
|
|
{
|
|
|
|
*(ChaResetControlRegister[cha]) = 0;
|
|
*(ChaResetControlRegister[cha] + 1) = CHA_SOFTWARE_RESET;
|
|
|
|
if (cha == CHA_DES) /* is this cha des? */
|
|
{
|
|
*(ChaInterruptControlRegister[cha]) = 0;
|
|
*(ChaInterruptControlRegister[cha] + 1) = CHA_DESA_KEY_PARITY_ERROR_DISABLE;
|
|
}
|
|
|
|
if (cha == CHA_PKHA) /* is this cha the pkha? */
|
|
{
|
|
*(ChaInterruptControlRegister[cha]) = 0;
|
|
*(ChaInterruptControlRegister[cha] + 1) = CHA_PKHA_ILLEGAL_ADDR_ERROR_DISABLE;
|
|
}
|
|
}
|
|
|
|
/* reset all the channels */
|
|
SEC2Dump(DBGTXT_INITDEV,
|
|
("SEC2DriverInit->reset Crypto-Channel Configuration Registers %d\n",
|
|
NUM_CHANNELS));
|
|
for (channel=0; channel<NUM_CHANNELS; channel++)
|
|
{
|
|
/* reset the channel & configure the channels */
|
|
*(ChannelConfigRegister[channel]) = CHANNEL_RESET;
|
|
*(ChannelConfigRegister[channel] + 1) = 0;
|
|
|
|
*(ChannelConfigRegister[channel]) = 0;
|
|
*(ChannelConfigRegister[channel] + 1) = CHANNEL_INTEN | CHANNEL_BURST128;
|
|
}
|
|
|
|
/* Enable the main interrupt from SEC core at the controller/OS level */
|
|
if ((status = IOConnectInterrupt()) != SEC2_SUCCESS)
|
|
return status;
|
|
|
|
/* enable interrupts at the core level -- channels done and all errors */
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->enable interrupts\n"));
|
|
|
|
|
|
|
|
/* Unmask all "done" bits from all channels and accelerators */
|
|
*(InterruptControlRegister) = ALL_CHANNEL_INT_DONE_MASK | ALL_CHANNEL_INT_ERROR_MASK;
|
|
*(InterruptControlRegister + 1) = ALL_CHA_INT_ERROR_MASK;
|
|
|
|
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->return SEC2_SUCCESS!\n"));
|
|
|
|
return SEC2_SUCCESS;
|
|
} /* end of DriverEntry */
|
|
|
|
|
|
|
|
|
|
|
|
IO_STATUS InitChannelAssignment(int channel)
|
|
{
|
|
size_t count;
|
|
|
|
SEC2Dump(DBGTXT_INITDEV, ("InitChannelAssignment channel=%d\n", channel+1));
|
|
|
|
ChannelAssignments[channel].assignment = CHANNEL_FREE;
|
|
ChannelAssignments[channel].ownerTaskId = 0;
|
|
ChannelAssignments[channel].pReq = NULL;
|
|
ChannelAssignments[channel].pCurrReq = NULL;
|
|
ChannelAssignments[channel].Dpds = &dpd[channel][0];
|
|
|
|
for (count=0; count<MAX_DPDS; count++)
|
|
{
|
|
ChannelAssignments[channel].Dpds[count] = &Descriptors[channel][count];
|
|
if (ChannelAssignments[channel].Dpds[count] == NULL)
|
|
return SEC2_IO_MEMORY_ALLOCATE_ERROR;
|
|
}
|
|
|
|
SEC2Dump(DBGTXT_INITDEV, ("InitChannelAssignment channel=%d done\n", channel+1));
|
|
|
|
return (SEC2_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
/* Module initialization stuff for Linux */
|
|
#ifdef __KERNEL__
|
|
|
|
/* fopts struct from device registration */
|
|
SEC2_GLOBAL struct file_operations sec2_fopts = {
|
|
open: SEC2Open,
|
|
release: SEC2Close,
|
|
ioctl: SEC2_ioctl,
|
|
};
|
|
|
|
static int __init sec2_init(void)
|
|
{
|
|
int rtstat;
|
|
|
|
/* Assume that this is going to be a chrdev */
|
|
/* If a major number isn't specified, default to dynamic assignment */
|
|
rtstat = register_chrdev(SEC2_DEVMAJOR, SEC2_DEVNAME, &sec2_fopts);
|
|
if (rtstat < 0) {
|
|
printk(KERN_WARNING "sec2drv: can't register driver, fatal\n");
|
|
return rtstat;
|
|
}
|
|
|
|
if (SEC2_DEVMAJOR == 0) /* if no specific major requested, and there was no error above */
|
|
sec2_devmajor = rtstat; /* set the dynamic number */
|
|
|
|
/* Now go call the standard driver initialization */
|
|
return SEC2DriverInit();
|
|
}
|
|
|
|
|
|
static void __exit sec2_exit(void)
|
|
{
|
|
int rtstat;
|
|
|
|
rtstat = unregister_chrdev(sec2_devmajor, SEC2_DEVNAME);
|
|
free_irq(MPC85xx_IRQ_SEC, NULL);
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL (SEC2_ioctl);
|
|
EXPORT_SYMBOL (MarkScatterBuffer);
|
|
/* EXPORT_SYMTAB */
|
|
|
|
module_init(sec2_init);
|
|
module_exit(sec2_exit);
|
|
|
|
MODULE_LICENSE("Freescale Restricted");
|
|
MODULE_DESCRIPTION("SEC 2.x Security Core Device Driver");
|
|
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
|
#endif
|