NetBSD/sys/dev/pci/n8/QMgr/RNQueue.c
darran 0e11c6bfd5 NetOctave NSP2000 driver, ported from FreeBSD and integrated with
opencrypto by CoyotePoint Systems.  The FreeBSD driver source was recently
made available by NBMK Encryption Technologies.

The port includes some currently unused code which implements kernel and
user space interfaces for the driver in FreeBSD.  These are left in at this
time to facilitate the port of these interface to NetBSD if they are of
interest.
2008-10-30 12:02:14 +00: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 */