Files
netbsd/sys/dev/pci/n8/QMgr/RNQueue.c
2013-04-06 16:48:33 +02:00

939 lines
36 KiB
C

/*-
* 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
* <tech-crypto@netbsd.org>.
*
* 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 <string.h> 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 <BR>
* @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 <BR>
* @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 */