/*- * 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 * . * * 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: RNQueue.c,v 1.1 2008/10/30 12:02:14 darran Exp $"; /*****************************************************************************/ /** @file RNQueue.c * @brief Random Number Queue Manager * * This file handles the queue of command blocks sent by the API * to the DeviceDriver/BehavioralModel for the Random Number Generator * hardware (or the model thereof) * *****************************************************************************/ /***************************************************************************** * Revision history: * 05/15/03 brr Enable RNH interrupts. * 05/13/03 brr Correctly compute number of elements in RN Queue to determine * when to update the RN write index. (Bug 914) * 03/26/03 brr Modified RNG not to perform PCI accesses with each reqeust * for random bytes. * 03/21/03 jpw Use correct delay time for RNG_WaitForHardwareStart n8_delay * 03/12/03 jpw N8_usleep may use a wait queue which is not safe when holding * a spin lock. Use N8_delay_ms instead. * 12/12/02 jpw Make sure TOD counter Flag is enabled - Make sure n8_usleep() u* value is specified in microseconds not milliseconds * 12/10/02 brr Removed obsolete function RNH_WaitWhileBusy. * 12/10/02 jpw Change Queue_RN_Request to properly initialize RNG one time * by using the RNG only first in seed mode to extract seeds * to be used as DES keys for the X9.17 expander. Also change * TOD prescale to correct chip freq and properly set up the TOD * 12/09/02 brr Modified RN_GetParameters to not shut down the RNH. * 11/25/02 brr Removed use of the updateAll semaphore. Use the define from * n8_driver_parms.h to determine which RNG core to use. * 10/25/02 brr Clean up function prototypes & include files. * 05/30/02 brr Use common struct for statistics. * 05/15/02 brr Reworked RNG requests such that the random bytes are returned * by the ioctl. Removed KMALLOC requirements. * 05/01/02 brr Removed references to qr.queue_p. * 04/02/02 msz Need to index into queue by sample size, not straight index. * (Or else random numbers aren't so random) * 03/27/02 brr Update bufferState when requests are queued/dequeued. * 03/20/02 msz Don't do consecutive 32 bit writes. Workaround for queue * full and wraparound on disable problem. Replaced most * macros. (BUG 650) * 03/20/02 mmd Incrementing requestsCompleted stat counter in RN_CheckQueue. * 03/19/02 msz Added a couple statistics counters. * 03/18/02 msz Don't loop forever on a hardware error. * 03/08/02 msz If we have a direct physical address, we don't need the * extra copy of random bytes to a temporary area. * 03/06/02 brr Removed SAPI include files. * 02/22/02 spm Converted n8_udelay to n8_usleep. * 02/22/02 spm Converted printk's to DBG's. * 02/18/02 msz More general QMgrRequest, RNG parameter initialization now * done in this code (with a call out to SAPI), no longer need * some routines (RN_InitParameters, RNG_ValidateRequest) * 01/16/02 brr Removed queue intialization now performed by driver. * 12/06/01 msz Disable/enable rnh around updating read_pointer. * Fix for NSP2000 BUG 2. * 12/05/01 brr Removed obsoleted queue allocation. * 12/05/01 brr Move queue initialization to the driver. * 12/04/01 msz Changes to allow chaining of requests. * 11/27/01 msz Don't get process lock and setup queue if we don't have * to - BUG 379 * 11/14/01 msz Moved callbacks out of locked area. * 11/13/01 brr Removed all refernces to shared_resource. * 11/12/01 msz Some small fixes, code review items 43,44,45,46,48,49,50, * 51,52. * 11/11/01 mmd Modified RNSetParameters to attach to existing command queue * if using real hardware. * 11/10/01 brr Modified to support static allocations of persistant data * by the driver. * 10/30/01 hml Changed NSP_2000 to NSP_2000_HW. * 10/23/01 dkm Mod to use enum for seed source from set params. * 10/15/01 brr Removed warnings exposed when optimization turned up. * 10/15/01 msz Protect Behavioral Model with hardwareAccessSem. Needed * for running in a multithreaded environment. * 10/05/01 msz Added support for mulitple RNG execution units. * 10/04/01 msz Added RN_InitParameters * 09/24/01 msz Shared memory changes. * 09/17/01 msz Wait a bit to let some random numbers be generated. This * prevents a hardware hang in waiting for lack of busy bit. * 09/14/01 bac Set the bitfields in the command block before allocation to * the default set for unshared kernel memory. This will need to * be addressed for the multi-process case. * 09/14/01 bac Use new value of seed_source which requires no shifting. * 09/06/01 bac Added include of to silence warning. * 09/06/01 msz Set queue to inititialized after it is first initialized. * Changes for host seed. * 08/31/01 msz Some minor changes in init_rng_q found in investigation of * hang waiting for RNH not busy. * 08/21/01 msz Replaced COPY_OUT with QMCopy * 08/15/01 brr Release process semaphore upon exit of init_rng_q. * 08/09/01 msz Added locking. * 08/06/01 msz All macros now take queue_p rather than simon_p, and are * capitalized, and combined sizeOfRNG_Q with sizeOfQueue * 07/27/01 bac Fixed a bug computing the number of elements between the * read pointer and the end of the queue. * 07/27/01 bac Changed use of COPY_OUT to hard-code NSP2000 as the hardware * type to avoid byte swapping. * 07/19/01 bac Retrieve queue_p from request rather than making a call to * QMgr_get_control_struct. * 07/06/01 msz Check request pointer against being null before using it * to return error. BUG #114 * 07/03/01 msz Moved n8_common.h first as a workaround for not being * able to compile because of multiple uint8_t's in BSDi * 06/28/01 hml Use the rnh_wait_while_busy macro instead of a usleep. * 06/28/01 hml Added some debugging statements. Make sure to disable the * rnh before writing the rng. * 06/27/01 hml Used the physical address instead of virtual address and * write the seed values immediately before re-enabling the * rnh. * 06/25/01 bac Fixed a bug in GetRandomBytes so that it acquires the queue * pointer. * 06/21/01 hml Removed chip parameter from init_rng_q routine. * 06/21/01 msz Added some more documentation, re-arranged some checking * of requests. * 06/19/01 hml Converted to Queue Control Architecture. * 06/08/01 msz Added call to open driver * 05/07/01 bac Shifted the seed source to the correct location for the * control status register. * 05/03/01 jke fixed a bug with the allocation and free-ing of requests * 04/27/01 dkm Fixed return bug in Queue_RN_request and changed * seed use to External. * 04/11/01 bac Standardization changes to compile with changes to * header files. This file has not been brought up to * standard otherwise. * 04/10/01 jke Added request queue preliminary to making multithreaded. * 03/19/01 jke Original version. ****************************************************************************/ /** @defgroup subsystem_name Subsystem Title (not used for a header file) */ #include "n8_pub_types.h" #include "n8_common.h" #include "RN_Queue.h" #include "n8_enqueue_common.h" #include "n8_rn_common.h" #include "QMUtil.h" #include "n8_semaphore.h" #include "n8_malloc_common.h" #include "n8_OS_intf.h" #include "helper.h" #include "QMQueue.h" #include "n8_driver_api.h" #include "n8_key_works.h" /* Globals */ N8_RNG_Parameter_t RngParametersShadow; N8_Status_t RN_SetChipParameters(N8_RNG_Parameter_t *parms_p, QueueControl_t *queue_p); /***************************************************************************** * function RNG_WaitForHardwareStart *****************************************************************************/ /** @ingroup QMgr * @brief Waits a short bit for the hardware to generate some random numbers. * * Waits for random numbers to start. Called after any enable. * The main reason for this wait is to prevent problems from back to back * set parameters, which shouldn't occur in a normal case anyhow. * * Note: * Not done for host seed or external seed mode, as we don't want to * loop forever if we don't have seed. We don't provide random numbers * if they aren't available anyhow. * * @param queue_p RO: Pointer to the control structure * for this queue. * * @par Externals: * none. * * @return * None * * @par Errors: * * @par Locks: * This routine requires the queueControlSem be already held. * * @par Assumptions: * *****************************************************************************/ static void RNG_WaitForHardwareStart(QueueControl_t *queue_p) { uint32_t read; uint32_t write; uint32_t counter; /* Don't use the wait below for host seed, because it could be we */ /* don't have a valid host seed. The code elsewhere will not */ /* provide any random numbers if none are available. The main */ /* reason for this wait is to prevent problems from back to back */ /* set parameters, which shouldn't occur in a normal case anyhow. */ if (RngParametersShadow.seed_source != N8_RNG_SEED_INTERNAL) { DBG(("RNH_WaitForHardwareStart - seed not internal.\n")); return; } counter = 0; RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&read,&write); while ( (read == write) && ( queue_p->hardwareFailed == 0 ) ) { /* If we don't have random numbers in the queue, wait 1ms */ /* This should be plenty of time to generate X9.17 samples */ /* If after the START_COUNT is exceeded, the RNG may be */ /* offline - Print a console Warning - This may NOT be a */ /* fatal error - but it should be investigated. */ n8_delay_ms(1); RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&read,&write); counter++; if (counter > RNH_BUSY_WAIT_HARDWARE_START_COUNT) { N8_PRINT("NSP2000: Warning: RNG_WaitForHardwareStart > 100ms \n"); counter = 0; /* Let's not wait forever for the RNG hardware. */ queue_p->hardwareFailed++; break; } } } /* RNG_WaitForHardwareStart */ /***************************************************************************** * function getContentsOfRNGQ *****************************************************************************/ /** @ingroup QMgr * * @brief reads data from the queue of random bytes maintained by NSP. * * @param queue_p RO: Pointer to the control structure * for this queue. * @param numBytesRequested RO: The number of bytes being requested * to be read from the RNG queue. * @param buf_p RO: A pointer into where we are copying the * elements read. * @param numBytesReturned_p WO: The number of bytes being returned * (actually read from the queue.) * * @par Externals: * none. * * @return * The number bytes elements actually read from the queue in * numBytesReturned_p, and see Errors. * * @par Errors: * enum-ed error types. * N8_STATUS_OK Bytes are being returned. * N8_RNG_QUEUE_EMPTY No bytes returned, queue is empty. * * @par Locks: * This routine requires the caller to obtain the queueControlSem. * * @par Assumptions: *****************************************************************************/ static N8_Status_t getContentsOfRNGQ(QueueControl_t *queue_p, int numBytesRequested, unsigned char *buf_p, uint32_t *numBytesReturned_p, int userReq) { int numFromReadIndex; int numFromHead; int numElementsInQ; int numBytesInQ; int samplesRead; N8_Status_t ret = N8_STATUS_OK; const int sampleSize = sizeof( RNG_Sample_t ); /* Calculate the number of bytes available in the queue given the */ /* number of samples available in the queue using our soft copy of */ /* the queue pointers. */ numElementsInQ = (queue_p->writeIndex - queue_p->readIndex) & queue_p->sizeMask; numBytesInQ = numElementsInQ * sampleSize; /* are there enough elements in the queue */ if (numBytesInQ < numBytesRequested) { /* Our soft copies of the read and write pointers indicate there are */ /* not enough bytes. Read the queue pointers from the NSP2000, update */ /* our soft copy of the pointers, and retry. */ RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&queue_p->readIndex,&queue_p->writeIndex); numElementsInQ = (queue_p->writeIndex - queue_p->readIndex) & queue_p->sizeMask; /* Calculate the number of bytes available in the queue given the */ /* number of samples available in the queue. */ numBytesInQ = numElementsInQ * sampleSize; /* are there enough elements in the queue */ if (numBytesInQ < numBytesRequested) { /* if not, return the error */ queue_p->stats.hardwareErrorCount++; return (N8_RNG_QUEUE_EMPTY); } } /* tell calling fcn how many elements were copied */ *numBytesReturned_p = numBytesRequested; /* are there enough bytes before queue wrap? */ /* note: this calc works even if the write_index */ /* is between the read_index and the end of queue */ /* because the *numBytesReturned_p has already been */ /* size limited to the min of numElementsInQ and */ /* numBytesRequested */ numFromReadIndex = (queue_p->sizeOfQueue - queue_p->readIndex) * sampleSize; if (numFromReadIndex >= *numBytesReturned_p) { /* this next calc obtains the num elements returned */ /* from between the read_index and the eoq */ numFromReadIndex = *numBytesReturned_p; /* return only elements from tail of queue */ numFromHead = 0; } else { /* else return some elements from head */ numFromHead = *numBytesReturned_p - numFromReadIndex; } if (numFromHead != 0) { /* copy source will be the head of the Q */ /* copy dest will be target bfr plus elements from Q tail */ /* Copy into temporary buffer at the end of the */ /* request. The callback routine will copy the bytes */ /* back out to the proper place. */ if (userReq == N8_TRUE) { N8_TO_USER((char *)buf_p + numFromReadIndex, (char *)queue_p->cmdQueVirtPtr, numFromHead); } else { memcpy((char *)buf_p + numFromReadIndex, (char *)queue_p->cmdQueVirtPtr, numFromHead); } } /* copy source elements from read_index to tail of queue */ /* copy dest the beginning of the target bfr */ if (userReq == N8_TRUE) { N8_TO_USER((char*)buf_p, (char*)(queue_p->cmdQueVirtPtr + queue_p->readIndex * sampleSize), numFromReadIndex); } else { memcpy((char*)buf_p, (char*)(queue_p->cmdQueVirtPtr + queue_p->readIndex * sampleSize), numFromReadIndex); } /* Increment the read queue pointer by the number of samples read */ samplesRead = (*numBytesReturned_p/sampleSize); if ( ( *numBytesReturned_p % sampleSize ) != 0 ) { ++samplesRead; } queue_p->readIndex = (queue_p->readIndex + samplesRead) & (queue_p->sizeMask); /* Determine if the read pointer should be written to the NSP2000 */ numElementsInQ -= samplesRead; /* If we have read half the number of samples out of the queue, */ /* update the read pointer. */ if (numElementsInQ < (queue_p->sizeOfQueue>>1)) { queue_p->rngReg_p->rnh_q_ptr = queue_p->readIndex; } return ret; } /* getContentsOfRNGQ */ /***************************************************************************** * function Queue_RN_request *****************************************************************************/ /** @ingroup QMgr * @brief add new request for entropy to linked-list of such requests. * * add new request for entropy to linked-list of such requests. * * @param rn_req_p RW: request to be enqueued. * * @par Externals: * None. * * @return * returns an enum-ed error type * return RNG_REQUEST_ERROR There was a problem with the request * values from RNG_GetRandomBytes * * @par Errors: * * @par Locks: * This routine gets the queueControlSem. * * @par Assumptions: * the structure handed in by the pointer argument must not be * freed by the calling function until after the request has been * satisfied. A request has been satisfied only after a RN_CheckQueue * says that it is finished - (N8_QUEUE_REQUEST_FINISHED.) * * It is assumed that the user is not modifying requests that are on the * queue. * *****************************************************************************/ N8_Status_t Queue_RN_request(RN_Request_t *rn_req_p ) { N8_Status_t ret = N8_STATUS_OK; QueueControl_t *queue_p; uint32_t numBytesReturned; uint32_t rng_control_status; n8_timeval_t n8currenttime; /* Verify that the rn_req_p is valid. */ if ((rn_req_p == NULL) || (rn_req_p->userBuffer_p == NULL)) { return N8_INVALID_OBJECT; } /* Always use chip 0 */ queue_p = &(queueTable_g.controlSets_p[N8_RNG_UNIT][N8_RNG]); /* Grab the queueControlSem to ensure exclusive access */ N8_AtomicLock(queue_p->queueControlSem); /* Make sure queue initialization has already been done. If it has */ /* not been done, then do it. */ if (queue_p->rngInitialized != N8_TRUE) { N8_RNG_Parameter_t n8_rng_param; /* random number N */ /* The RNG has not been called before so we must properly initialize * the RNG core and X9.17 seed expander. First we will use the * internal seed generator to generate random seeds to be used as * DES keys for the X9.17 PRBS. The RNG will be reset from seed * mode to X9.17 mode once the keys have been generated and the * RNH will be enabled to automatically transfer X9.17 RNG output * to the RNG output queue. * Note that the host system must have asserted PCI Reset 5 seconds * before this code runs for the LFSRs to have the appropriate * level of uncertainty. */ #ifdef N8_RNG_TEST_MODE /* The N8_RNG_TEST_MODE code was the default init prior to 2.3 */ /* Normally want this running. */ n8_rng_param.todEnable = N8_TRUE; /* Use internal clock */ n8_rng_param.use_external_clock = N8_FALSE; /* Use internal seed */ n8_rng_param.seed_source = N8_RNG_SEED_INTERNAL; /* Number or randoms before reseed, 255 max */ n8_rng_param.iteration_count = 255; /* Clock frequency of N8 HW */ n8_rng_param.TOD_prescale = 0x0bebc200; n8_rng_param.set_TOD_counter = N8_TRUE; /* TODO: Need to randomize this a bit with a call to get time */ /* of day or something like that. n8_gettime */ n8_rng_param.key1[0] = 0x2a; n8_rng_param.key1[1] = 0xd3; n8_rng_param.key1[2] = 0x38; n8_rng_param.key1[3] = 0x4f; n8_rng_param.key1[4] = 0x2c; n8_rng_param.key1[5] = 0xda; n8_rng_param.key1[6] = 0x67; n8_rng_param.key1[7] = 0xab; n8_rng_param.key2[0] = 0xf2; n8_rng_param.key2[1] = 0x15; n8_rng_param.key2[2] = 0x7a; n8_rng_param.key2[3] = 0x97; n8_rng_param.key2[4] = 0x54; n8_rng_param.key2[5] = 0x8c; n8_rng_param.key2[6] = 0x46; n8_rng_param.key2[7] = 0xc7; n8_rng_param.hostSeed[0] = 0x34; n8_rng_param.hostSeed[1] = 0x56; n8_rng_param.hostSeed[2] = 0xab; n8_rng_param.hostSeed[3] = 0xcd; n8_rng_param.hostSeed[4] = 0x09; n8_rng_param.hostSeed[5] = 0x87; n8_rng_param.hostSeed[6] = 0xf2; n8_rng_param.hostSeed[7] = 0x5a; n8_rng_param.initial_TOD_seconds = 0x001029c5; n8_rng_param.externalClockScaler = 0; /* Ignored from values above */ /* Perform initial set-up for RNG */ ret = RN_SetChipParameters(&n8_rng_param, queue_p); /* TODO: Ultimately we should check the return status. */ /* The check of return status is more critical once we put in */ /* code above to randomize the keys, etc. above. */ #else /* Enable the RNG to get SEEDs for DES keys - we need 2 64 bit samples to use as the 64bit DES keys. */ do { /* clear any errors and set up to enable the RNG */ rng_control_status = RNG_Status_RNG_Enable | RNG_Status_Buffer_Use_Seed_Generator | RNG_Status_Seed_Use_Internal | RNG_Status_Any_Condition_Mask | (RNG_Status_Iteration_Count_Mask & 255); /* Start generating Internally Seeded Samples to the RNG Buffer */ queue_p->rngReg_p->rng_control_status = rng_control_status; /* spin while waiting for for RNG SEEDs to be created */ n8_delay_ms(30); /* Wait 30 milliseconds for seed data to be valid */ /* Stop the RNG Core */ queue_p->rngReg_p->rng_control_status = 0; { /* Extract the seeds from the RNG buffer and copy them * into the n8_rng_param structure. */ unsigned char key[16]; int i; for ( i = 0; i < 4; i++ ) { key[i*4] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[0]; key[i*4+1] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[1]; key[i*4+2] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[2]; key[i*4+3] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[3]; } for ( i = 0; i < N8_DES_KEY_LENGTH ; i++) { n8_rng_param.key1[i] = key[i]; n8_rng_param.key2[i] = key[i+8]; } } /* check key1 and key2 for parity and force parity if needed*/ if (checkKeyParity(&n8_rng_param.key1) == N8_FALSE) { forceParity(&n8_rng_param.key1); } if(checkKeyParity(&n8_rng_param.key2) == N8_FALSE) { forceParity(&n8_rng_param.key2); } /* check key1 and key2 for weakness */ if (checkKeyForWeakness(&n8_rng_param.key1) == N8_TRUE || checkKeyForWeakness(&n8_rng_param.key2) == N8_TRUE) { DBG(("Weak key\nRNG Startup INIT - return Error\n")); ret = N8_WEAK_KEY; /* get another seed to generate another key ! */ } /* If the seed passed all the tests - break out of the do/while loop */ if (ret != N8_WEAK_KEY) { break; } } while (TRUE); /* Make sure Time of Day counter is running */ n8_rng_param.todEnable = N8_TRUE; /* Use internal clock */ n8_rng_param.use_external_clock = N8_FALSE; /* Use internal seed */ n8_rng_param.seed_source = N8_RNG_SEED_INTERNAL; /* Number or randoms before reseed, 255 max */ n8_rng_param.iteration_count = 255; /* Clock frequency of N8 HW - Set here to ~167Mhz */ n8_rng_param.TOD_prescale = 0x09f437C0; n8_rng_param.set_TOD_counter = N8_TRUE; /* Get the time of day */ n8_gettime(&n8currenttime); n8_rng_param.initial_TOD_seconds = n8currenttime.tv_sec; n8_rng_param.externalClockScaler = 0; /* Ignored from values above */ /* Perform initial set-up for RNG */ ret = RN_SetChipParameters(&n8_rng_param, queue_p); #endif } /* Copy the bytes out of the RNG queue */ ret = getContentsOfRNGQ( queue_p, rn_req_p->numBytesRequested, rn_req_p->userBuffer_p, &numBytesReturned, rn_req_p->userRequest ); /* Increment our count of requests queued. */ queue_p->stats.requestsQueued++; N8_AtomicUnlock(queue_p->queueControlSem); return ret; } /* Queue_RN_request */ /***************************************************************************** * function RN_GetParameters *****************************************************************************/ /** @ingroup QMgr * @brief Fill in values in a N8_RNG_Parameter_t structure that require * looking at hardware. * * A note on the strategy for RNG_ALL_UNITS: * The use of the RNG core has been simplified to use only one RNG * execution unit. The obsoletes the system level updateAllSem lock. * All references to RNG_ALL_UNITS have been modified to simply use * the first execution unit. * * @param parms_p WO: a pointer to a parameter-holding structure * @param chip RO: The chipset which is being read. * * @par Externals: * queueTable_g RO: The pointer to the global control set table. * * @return * enum-ed error types. * N8_STATUS_OK Success * * @par Errors: * * @par Locks: * This routine requires no locks. * * @par Assumptions: * Only the RN execution unit for chip 0 is used. Given the implementation * of the RNG, using more than one just complicates the implementation and * requires additional resources with no performance gain. * *****************************************************************************/ N8_Status_t RN_GetParameters(N8_RNG_Parameter_t *parms_p, int chip) { QueueControl_t *queue_p; N8_Status_t ret = N8_STATUS_OK; if (parms_p == NULL ) { return(N8_INVALID_OBJECT); } ret = QMgr_get_control_struct(&queue_p, N8_RNG, chip); if (ret != N8_STATUS_OK) { return(ret); } /* Make sure the hardware has been initialized before we can return */ /* initialization parameters. */ if ( queue_p->rngInitialized != N8_TRUE ) { ret = N8_NOT_INITIALIZED; } else { /* Copy in the current parameters. */ memcpy(parms_p, &RngParametersShadow, sizeof(N8_RNG_Parameter_t)); } return ret; } /* RN_GetParameters */ /***************************************************************************** * function RN_SetChipParameters *****************************************************************************/ /** @ingroup QMgr * @brief initialize the RN hardware * * This is called only when we want to actually initialize hardware. * * * IMPORTANT note on register access: * The north bridge is optimizing consecutive 32-bit writes into burst * transfers. SIMON handles the 32-bit bursts correctly but has problems * with the 64-bit bursts. Therefore we do NOT want to do any consecutive * 32-bit writes. See the structure N8RNGRegs_t for order of the registers. * * @param parms_p RO: a pointer to a parameter-holding structure
* @param queue_p RO: Pointer to the queue control structure * associated with hardware we are configuring. * * @return * enum-ed error types. * * @par Errors: * * @par Locks: * This routine requires that the caller has obtained the queueControlSem. * *****************************************************************************/ N8_Status_t RN_SetChipParameters(N8_RNG_Parameter_t *parms_p, QueueControl_t *queue_p) { N8_Status_t ret = N8_STATUS_OK; uint32_t rng_control_status; uint32_t key1_ms; uint32_t key1_ls; uint32_t key2_ms; uint32_t key2_ls; uint32_t hostSeed_ms; uint32_t hostSeed_ls; uint32_t rng_seed_source; /* Only set the chip parameters if it has not already been initialized */ if (queue_p->rngInitialized != N8_TRUE) { /* Set up the keys and seed and time of day */ key1_ms = BE_to_uint32(&parms_p->key1[N8_MS_BYTE]); key1_ls = BE_to_uint32(&parms_p->key1[N8_LS_BYTE]); key2_ms = BE_to_uint32(&parms_p->key2[N8_MS_BYTE]); key2_ls = BE_to_uint32(&parms_p->key2[N8_LS_BYTE]); queue_p->rngReg_p->rng_key1_msw = key1_ms; queue_p->rngReg_p->rng_key2_msw = key2_ms; queue_p->rngReg_p->rng_tod_prescale = parms_p->TOD_prescale; queue_p->rngReg_p->rng_key2_lsw = key2_ls; queue_p->rngReg_p->rng_key1_lsw = key1_ls; /* Set up the time of day */ if (parms_p->set_TOD_counter == N8_TRUE) { queue_p->rngReg_p->rng_tod_seconds = parms_p->initial_TOD_seconds; } DBG(("rnh config: %x\n", queue_p->rngReg_p->rnh_control_status)); /* * Set seed source values. * These values are keyed to the expected values set by the hardware * spec. See [RNG] Control Status Register for the Seed Source * specification. */ switch (parms_p->seed_source) { case N8_RNG_SEED_EXTERNAL: rng_seed_source = RNG_Status_Seed_Use_External; break; case N8_RNG_SEED_HOST: rng_seed_source = RNG_Status_Seed_Use_Host3; break; case N8_RNG_SEED_INTERNAL: default: rng_seed_source = RNG_Status_Seed_Use_Internal; break; } /* clear any errors and set up to enable the RNH/RNG */ rng_control_status = RNG_Status_RNG_Enable | RNG_Status_Buffer_Use_X917 | rng_seed_source | RNG_Status_Any_Condition_Mask | (RNG_Status_Iteration_Count_Mask & parms_p->iteration_count); /* Set TOD enable if needed. */ if ( parms_p->todEnable == N8_TRUE ) { rng_control_status |= RNG_Status_TOD_Enable; } else { rng_control_status &= ~RNG_Status_TOD_Enable; } /* Set External clock and external clock scaler register if needed. */ if (parms_p->use_external_clock == N8_TRUE) { rng_control_status |= RNG_Status_Ext_Clock_Enable; queue_p->rngReg_p->rng_external_clock_scalar = parms_p->externalClockScaler; } else { rng_control_status &= ~RNG_Status_Ext_Clock_Enable; } hostSeed_ms = BE_to_uint32(&parms_p->hostSeed[N8_MS_BYTE]); hostSeed_ls = BE_to_uint32(&parms_p->hostSeed[N8_LS_BYTE]); queue_p->rngReg_p->rng_hostseed_msw = hostSeed_ms; queue_p->rngReg_p->rng_control_status = rng_control_status; queue_p->rngReg_p->rng_hostseed_lsw = hostSeed_ls; DBG(("rnh config: %x\n", queue_p->rngReg_p->rnh_control_status)); queue_p->rngReg_p->rnh_control_status = RNH_Status_Transfer_Enable | RNH_Status_All_Enable_Mask; /* Save off the parameters. */ /* This assumes the parameters are the same on all RNG units. */ memcpy(&RngParametersShadow, parms_p, sizeof(N8_RNG_Parameter_t)); /* Wait for a bit to let some random numbers be generated. */ RNG_WaitForHardwareStart(queue_p); /* Set that the queue has been initialized. */ queue_p->rngInitialized = N8_TRUE; } return ret; } /* RN_SetChipParameters */ /***************************************************************************** * function RN_SetParameters *****************************************************************************/ /** @ingroup QMgr * @brief initialize the RN Hardware * * This is called only when we want to actually initialize hardware. * * A note on the strategy for RNG_ALL_UNITS: * The use of the RNG core has been simplified to use only one RNG * execution unit. The obsoletes the system level updateAllSem lock. * All references to RNG_ALL_UNITS have been modified to simply use * the first execution unit. * * @param parms_p RO: a pointer to a parameter-holding structure
* @param chip RO: The chipset which is being initialized. * * @par Externals: * queueTable_g RO: The pointer to the global control set table. * * @return * enum-ed error types. * * @par Errors: * * @par Locks: * This routine gets the queueControlSem for each execution unit as it * set its individual parameters. * * @par Assumptions: * Only the RN execution unit for chip 0 is used. Given the implementation * of the RNG, using more than one just complicates the implementation and * requires additional resources with no performance gain. * *****************************************************************************/ N8_Status_t RN_SetParameters(N8_RNG_Parameter_t *parms_p, int chip) { QueueControl_t *queue_p; N8_Status_t ret = N8_STATUS_OK; if (parms_p == NULL ) { ret = N8_INVALID_OBJECT; goto RN_SetParametersReturn; } ret = QMgr_get_control_struct(&queue_p, N8_RNG, chip); if (ret != N8_STATUS_OK) { goto RN_SetParametersReturn; } /* Get the queue control semaphore to protect queue initialization */ N8_AtomicLock(queue_p->queueControlSem); ret = RN_SetChipParameters( parms_p, queue_p ); /* Release aquired semaphore */ N8_AtomicUnlock(queue_p->queueControlSem); RN_SetParametersReturn: return ret; } /* RN_SetParameters */