Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / n8 / QMgr / RNQueue.c
blob3c6b355c0ecd1d6dde2a09d785458592e266aa9d
1 /*-
2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
3 * All rights reserved.
5 * NBMK Encryption Technologies provides no support of any kind for
6 * this software. Questions or concerns about it may be addressed to
7 * the members of the relevant open-source community at
8 * <tech-crypto@netbsd.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
12 * met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 static char const n8_id[] = "$Id: RNQueue.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
36 /*****************************************************************************/
37 /** @file RNQueue.c
38 * @brief Random Number Queue Manager
40 * This file handles the queue of command blocks sent by the API
41 * to the DeviceDriver/BehavioralModel for the Random Number Generator
42 * hardware (or the model thereof)
44 *****************************************************************************/
46 /*****************************************************************************
47 * Revision history:
48 * 05/15/03 brr Enable RNH interrupts.
49 * 05/13/03 brr Correctly compute number of elements in RN Queue to determine
50 * when to update the RN write index. (Bug 914)
51 * 03/26/03 brr Modified RNG not to perform PCI accesses with each reqeust
52 * for random bytes.
53 * 03/21/03 jpw Use correct delay time for RNG_WaitForHardwareStart n8_delay
54 * 03/12/03 jpw N8_usleep may use a wait queue which is not safe when holding
55 * a spin lock. Use N8_delay_ms instead.
56 * 12/12/02 jpw Make sure TOD counter Flag is enabled - Make sure n8_usleep()
57 u* value is specified in microseconds not milliseconds
58 * 12/10/02 brr Removed obsolete function RNH_WaitWhileBusy.
59 * 12/10/02 jpw Change Queue_RN_Request to properly initialize RNG one time
60 * by using the RNG only first in seed mode to extract seeds
61 * to be used as DES keys for the X9.17 expander. Also change
62 * TOD prescale to correct chip freq and properly set up the TOD
63 * 12/09/02 brr Modified RN_GetParameters to not shut down the RNH.
64 * 11/25/02 brr Removed use of the updateAll semaphore. Use the define from
65 * n8_driver_parms.h to determine which RNG core to use.
66 * 10/25/02 brr Clean up function prototypes & include files.
67 * 05/30/02 brr Use common struct for statistics.
68 * 05/15/02 brr Reworked RNG requests such that the random bytes are returned
69 * by the ioctl. Removed KMALLOC requirements.
70 * 05/01/02 brr Removed references to qr.queue_p.
71 * 04/02/02 msz Need to index into queue by sample size, not straight index.
72 * (Or else random numbers aren't so random)
73 * 03/27/02 brr Update bufferState when requests are queued/dequeued.
74 * 03/20/02 msz Don't do consecutive 32 bit writes. Workaround for queue
75 * full and wraparound on disable problem. Replaced most
76 * macros. (BUG 650)
77 * 03/20/02 mmd Incrementing requestsCompleted stat counter in RN_CheckQueue.
78 * 03/19/02 msz Added a couple statistics counters.
79 * 03/18/02 msz Don't loop forever on a hardware error.
80 * 03/08/02 msz If we have a direct physical address, we don't need the
81 * extra copy of random bytes to a temporary area.
82 * 03/06/02 brr Removed SAPI include files.
83 * 02/22/02 spm Converted n8_udelay to n8_usleep.
84 * 02/22/02 spm Converted printk's to DBG's.
85 * 02/18/02 msz More general QMgrRequest, RNG parameter initialization now
86 * done in this code (with a call out to SAPI), no longer need
87 * some routines (RN_InitParameters, RNG_ValidateRequest)
88 * 01/16/02 brr Removed queue intialization now performed by driver.
89 * 12/06/01 msz Disable/enable rnh around updating read_pointer.
90 * Fix for NSP2000 BUG 2.
91 * 12/05/01 brr Removed obsoleted queue allocation.
92 * 12/05/01 brr Move queue initialization to the driver.
93 * 12/04/01 msz Changes to allow chaining of requests.
94 * 11/27/01 msz Don't get process lock and setup queue if we don't have
95 * to - BUG 379
96 * 11/14/01 msz Moved callbacks out of locked area.
97 * 11/13/01 brr Removed all refernces to shared_resource.
98 * 11/12/01 msz Some small fixes, code review items 43,44,45,46,48,49,50,
99 * 51,52.
100 * 11/11/01 mmd Modified RNSetParameters to attach to existing command queue
101 * if using real hardware.
102 * 11/10/01 brr Modified to support static allocations of persistant data
103 * by the driver.
104 * 10/30/01 hml Changed NSP_2000 to NSP_2000_HW.
105 * 10/23/01 dkm Mod to use enum for seed source from set params.
106 * 10/15/01 brr Removed warnings exposed when optimization turned up.
107 * 10/15/01 msz Protect Behavioral Model with hardwareAccessSem. Needed
108 * for running in a multithreaded environment.
109 * 10/05/01 msz Added support for mulitple RNG execution units.
110 * 10/04/01 msz Added RN_InitParameters
111 * 09/24/01 msz Shared memory changes.
112 * 09/17/01 msz Wait a bit to let some random numbers be generated. This
113 * prevents a hardware hang in waiting for lack of busy bit.
114 * 09/14/01 bac Set the bitfields in the command block before allocation to
115 * the default set for unshared kernel memory. This will need to
116 * be addressed for the multi-process case.
117 * 09/14/01 bac Use new value of seed_source which requires no shifting.
118 * 09/06/01 bac Added include of <string.h> to silence warning.
119 * 09/06/01 msz Set queue to inititialized after it is first initialized.
120 * Changes for host seed.
121 * 08/31/01 msz Some minor changes in init_rng_q found in investigation of
122 * hang waiting for RNH not busy.
123 * 08/21/01 msz Replaced COPY_OUT with QMCopy
124 * 08/15/01 brr Release process semaphore upon exit of init_rng_q.
125 * 08/09/01 msz Added locking.
126 * 08/06/01 msz All macros now take queue_p rather than simon_p, and are
127 * capitalized, and combined sizeOfRNG_Q with sizeOfQueue
128 * 07/27/01 bac Fixed a bug computing the number of elements between the
129 * read pointer and the end of the queue.
130 * 07/27/01 bac Changed use of COPY_OUT to hard-code NSP2000 as the hardware
131 * type to avoid byte swapping.
132 * 07/19/01 bac Retrieve queue_p from request rather than making a call to
133 * QMgr_get_control_struct.
134 * 07/06/01 msz Check request pointer against being null before using it
135 * to return error. BUG #114
136 * 07/03/01 msz Moved n8_common.h first as a workaround for not being
137 * able to compile because of multiple uint8_t's in BSDi
138 * 06/28/01 hml Use the rnh_wait_while_busy macro instead of a usleep.
139 * 06/28/01 hml Added some debugging statements. Make sure to disable the
140 * rnh before writing the rng.
141 * 06/27/01 hml Used the physical address instead of virtual address and
142 * write the seed values immediately before re-enabling the
143 * rnh.
144 * 06/25/01 bac Fixed a bug in GetRandomBytes so that it acquires the queue
145 * pointer.
146 * 06/21/01 hml Removed chip parameter from init_rng_q routine.
147 * 06/21/01 msz Added some more documentation, re-arranged some checking
148 * of requests.
149 * 06/19/01 hml Converted to Queue Control Architecture.
150 * 06/08/01 msz Added call to open driver
151 * 05/07/01 bac Shifted the seed source to the correct location for the
152 * control status register.
153 * 05/03/01 jke fixed a bug with the allocation and free-ing of requests
154 * 04/27/01 dkm Fixed return bug in Queue_RN_request and changed
155 * seed use to External.
156 * 04/11/01 bac Standardization changes to compile with changes to
157 * header files. This file has not been brought up to
158 * standard otherwise.
159 * 04/10/01 jke Added request queue preliminary to making multithreaded.
160 * 03/19/01 jke Original version.
161 ****************************************************************************/
162 /** @defgroup subsystem_name Subsystem Title (not used for a header file)
165 #include "n8_pub_types.h"
166 #include "n8_common.h"
167 #include "RN_Queue.h"
168 #include "n8_enqueue_common.h"
169 #include "n8_rn_common.h"
170 #include "QMUtil.h"
171 #include "n8_semaphore.h"
172 #include "n8_malloc_common.h"
173 #include "n8_OS_intf.h"
174 #include "helper.h"
175 #include "QMQueue.h"
176 #include "n8_driver_api.h"
177 #include "n8_key_works.h"
180 /* Globals */
181 N8_RNG_Parameter_t RngParametersShadow;
183 N8_Status_t
184 RN_SetChipParameters(N8_RNG_Parameter_t *parms_p, QueueControl_t *queue_p);
185 /*****************************************************************************
186 * function RNG_WaitForHardwareStart
187 *****************************************************************************/
188 /** @ingroup QMgr
189 * @brief Waits a short bit for the hardware to generate some random numbers.
191 * Waits for random numbers to start. Called after any enable.
192 * The main reason for this wait is to prevent problems from back to back
193 * set parameters, which shouldn't occur in a normal case anyhow.
195 * Note:
196 * Not done for host seed or external seed mode, as we don't want to
197 * loop forever if we don't have seed. We don't provide random numbers
198 * if they aren't available anyhow.
200 * @param queue_p RO: Pointer to the control structure
201 * for this queue.
203 * @par Externals:
204 * none.
206 * @return
207 * None
209 * @par Errors:
211 * @par Locks:
212 * This routine requires the queueControlSem be already held.
214 * @par Assumptions:
216 *****************************************************************************/
218 static void
219 RNG_WaitForHardwareStart(QueueControl_t *queue_p)
222 uint32_t read;
223 uint32_t write;
224 uint32_t counter;
226 /* Don't use the wait below for host seed, because it could be we */
227 /* don't have a valid host seed. The code elsewhere will not */
228 /* provide any random numbers if none are available. The main */
229 /* reason for this wait is to prevent problems from back to back */
230 /* set parameters, which shouldn't occur in a normal case anyhow. */
231 if (RngParametersShadow.seed_source != N8_RNG_SEED_INTERNAL)
233 DBG(("RNH_WaitForHardwareStart - seed not internal.\n"));
234 return;
237 counter = 0;
238 RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&read,&write);
239 while ( (read == write) && ( queue_p->hardwareFailed == 0 ) )
241 /* If we don't have random numbers in the queue, wait 1ms */
242 /* This should be plenty of time to generate X9.17 samples */
243 /* If after the START_COUNT is exceeded, the RNG may be */
244 /* offline - Print a console Warning - This may NOT be a */
245 /* fatal error - but it should be investigated. */
247 n8_delay_ms(1);
248 RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&read,&write);
249 counter++;
250 if (counter > RNH_BUSY_WAIT_HARDWARE_START_COUNT)
252 N8_PRINT("NSP2000: Warning: RNG_WaitForHardwareStart > 100ms \n");
253 counter = 0;
254 /* Let's not wait forever for the RNG hardware. */
255 queue_p->hardwareFailed++;
256 break;
260 } /* RNG_WaitForHardwareStart */
264 /*****************************************************************************
265 * function getContentsOfRNGQ
266 *****************************************************************************/
267 /** @ingroup QMgr
269 * @brief reads data from the queue of random bytes maintained by NSP.
271 * @param queue_p RO: Pointer to the control structure
272 * for this queue.
273 * @param numBytesRequested RO: The number of bytes being requested
274 * to be read from the RNG queue.
275 * @param buf_p RO: A pointer into where we are copying the
276 * elements read.
277 * @param numBytesReturned_p WO: The number of bytes being returned
278 * (actually read from the queue.)
280 * @par Externals:
281 * none.
283 * @return
284 * The number bytes elements actually read from the queue in
285 * numBytesReturned_p, and see Errors.
287 * @par Errors:
288 * enum-ed error types.
289 * N8_STATUS_OK Bytes are being returned.
290 * N8_RNG_QUEUE_EMPTY No bytes returned, queue is empty.
292 * @par Locks:
293 * This routine requires the caller to obtain the queueControlSem.
295 * @par Assumptions:
296 *****************************************************************************/
298 static N8_Status_t
299 getContentsOfRNGQ(QueueControl_t *queue_p,
300 int numBytesRequested,
301 unsigned char *buf_p,
302 uint32_t *numBytesReturned_p,
303 int userReq)
305 int numFromReadIndex;
306 int numFromHead;
307 int numElementsInQ;
308 int numBytesInQ;
309 int samplesRead;
310 N8_Status_t ret = N8_STATUS_OK;
311 const int sampleSize = sizeof( RNG_Sample_t );
313 /* Calculate the number of bytes available in the queue given the */
314 /* number of samples available in the queue using our soft copy of */
315 /* the queue pointers. */
316 numElementsInQ = (queue_p->writeIndex - queue_p->readIndex) & queue_p->sizeMask;
317 numBytesInQ = numElementsInQ * sampleSize;
320 /* are there enough elements in the queue */
321 if (numBytesInQ < numBytesRequested)
323 /* Our soft copies of the read and write pointers indicate there are */
324 /* not enough bytes. Read the queue pointers from the NSP2000, update */
325 /* our soft copy of the pointers, and retry. */
326 RNG_CMD_Q_GET_READ_WRITE_PTR(queue_p,&queue_p->readIndex,&queue_p->writeIndex);
328 numElementsInQ = (queue_p->writeIndex - queue_p->readIndex) & queue_p->sizeMask;
330 /* Calculate the number of bytes available in the queue given the */
331 /* number of samples available in the queue. */
332 numBytesInQ = numElementsInQ * sampleSize;
335 /* are there enough elements in the queue */
336 if (numBytesInQ < numBytesRequested)
338 /* if not, return the error */
339 queue_p->stats.hardwareErrorCount++;
340 return (N8_RNG_QUEUE_EMPTY);
344 /* tell calling fcn how many elements were copied */
345 *numBytesReturned_p = numBytesRequested;
347 /* are there enough bytes before queue wrap? */
348 /* note: this calc works even if the write_index */
349 /* is between the read_index and the end of queue */
350 /* because the *numBytesReturned_p has already been */
351 /* size limited to the min of numElementsInQ and */
352 /* numBytesRequested */
353 numFromReadIndex = (queue_p->sizeOfQueue - queue_p->readIndex) * sampleSize;
355 if (numFromReadIndex >= *numBytesReturned_p)
357 /* this next calc obtains the num elements returned */
358 /* from between the read_index and the eoq */
359 numFromReadIndex = *numBytesReturned_p;
361 /* return only elements from tail of queue */
362 numFromHead = 0;
364 else
366 /* else return some elements from head */
367 numFromHead = *numBytesReturned_p - numFromReadIndex;
370 if (numFromHead != 0)
372 /* copy source will be the head of the Q */
373 /* copy dest will be target bfr plus elements from Q tail */
375 /* Copy into temporary buffer at the end of the */
376 /* request. The callback routine will copy the bytes */
377 /* back out to the proper place. */
378 if (userReq == N8_TRUE)
380 N8_TO_USER((char *)buf_p + numFromReadIndex,
381 (char *)queue_p->cmdQueVirtPtr,
382 numFromHead);
384 else
386 memcpy((char *)buf_p + numFromReadIndex,
387 (char *)queue_p->cmdQueVirtPtr,
388 numFromHead);
392 /* copy source elements from read_index to tail of queue */
393 /* copy dest the beginning of the target bfr */
394 if (userReq == N8_TRUE)
396 N8_TO_USER((char*)buf_p,
397 (char*)(queue_p->cmdQueVirtPtr + queue_p->readIndex * sampleSize),
398 numFromReadIndex);
400 else
402 memcpy((char*)buf_p,
403 (char*)(queue_p->cmdQueVirtPtr + queue_p->readIndex * sampleSize),
404 numFromReadIndex);
408 /* Increment the read queue pointer by the number of samples read */
409 samplesRead = (*numBytesReturned_p/sampleSize);
410 if ( ( *numBytesReturned_p % sampleSize ) != 0 )
412 ++samplesRead;
414 queue_p->readIndex = (queue_p->readIndex + samplesRead) & (queue_p->sizeMask);
416 /* Determine if the read pointer should be written to the NSP2000 */
417 numElementsInQ -= samplesRead;
419 /* If we have read half the number of samples out of the queue, */
420 /* update the read pointer. */
421 if (numElementsInQ < (queue_p->sizeOfQueue>>1))
423 queue_p->rngReg_p->rnh_q_ptr = queue_p->readIndex;
426 return ret;
428 } /* getContentsOfRNGQ */
431 /*****************************************************************************
432 * function Queue_RN_request
433 *****************************************************************************/
434 /** @ingroup QMgr
435 * @brief add new request for entropy to linked-list of such requests.
437 * add new request for entropy to linked-list of such requests.
439 * @param rn_req_p RW: request to be enqueued.
441 * @par Externals:
442 * None.
444 * @return
445 * returns an enum-ed error type
446 * return RNG_REQUEST_ERROR There was a problem with the request
447 * values from RNG_GetRandomBytes
449 * @par Errors:
451 * @par Locks:
452 * This routine gets the queueControlSem.
454 * @par Assumptions:
455 * the structure handed in by the pointer argument must not be
456 * freed by the calling function until after the request has been
457 * satisfied. A request has been satisfied only after a RN_CheckQueue
458 * says that it is finished - (N8_QUEUE_REQUEST_FINISHED.)
460 * It is assumed that the user is not modifying requests that are on the
461 * queue.
463 *****************************************************************************/
465 N8_Status_t
466 Queue_RN_request(RN_Request_t *rn_req_p )
468 N8_Status_t ret = N8_STATUS_OK;
469 QueueControl_t *queue_p;
470 uint32_t numBytesReturned;
471 uint32_t rng_control_status;
472 n8_timeval_t n8currenttime;
474 /* Verify that the rn_req_p is valid. */
475 if ((rn_req_p == NULL) || (rn_req_p->userBuffer_p == NULL))
477 return N8_INVALID_OBJECT;
480 /* Always use chip 0 */
481 queue_p = &(queueTable_g.controlSets_p[N8_RNG_UNIT][N8_RNG]);
483 /* Grab the queueControlSem to ensure exclusive access */
484 N8_AtomicLock(queue_p->queueControlSem);
486 /* Make sure queue initialization has already been done. If it has */
487 /* not been done, then do it. */
488 if (queue_p->rngInitialized != N8_TRUE)
490 N8_RNG_Parameter_t n8_rng_param; /* random number N */
492 /* The RNG has not been called before so we must properly initialize
493 * the RNG core and X9.17 seed expander. First we will use the
494 * internal seed generator to generate random seeds to be used as
495 * DES keys for the X9.17 PRBS. The RNG will be reset from seed
496 * mode to X9.17 mode once the keys have been generated and the
497 * RNH will be enabled to automatically transfer X9.17 RNG output
498 * to the RNG output queue.
499 * Note that the host system must have asserted PCI Reset 5 seconds
500 * before this code runs for the LFSRs to have the appropriate
501 * level of uncertainty.
505 #ifdef N8_RNG_TEST_MODE
506 /* The N8_RNG_TEST_MODE code was the default init prior to 2.3 */
507 /* Normally want this running. */
508 n8_rng_param.todEnable = N8_TRUE;
509 /* Use internal clock */
510 n8_rng_param.use_external_clock = N8_FALSE;
511 /* Use internal seed */
512 n8_rng_param.seed_source = N8_RNG_SEED_INTERNAL;
513 /* Number or randoms before reseed, 255 max */
514 n8_rng_param.iteration_count = 255;
515 /* Clock frequency of N8 HW */
516 n8_rng_param.TOD_prescale = 0x0bebc200;
517 n8_rng_param.set_TOD_counter = N8_TRUE;
519 /* TODO: Need to randomize this a bit with a call to get time */
520 /* of day or something like that. n8_gettime */
521 n8_rng_param.key1[0] = 0x2a; n8_rng_param.key1[1] = 0xd3;
522 n8_rng_param.key1[2] = 0x38; n8_rng_param.key1[3] = 0x4f;
523 n8_rng_param.key1[4] = 0x2c; n8_rng_param.key1[5] = 0xda;
524 n8_rng_param.key1[6] = 0x67; n8_rng_param.key1[7] = 0xab;
526 n8_rng_param.key2[0] = 0xf2; n8_rng_param.key2[1] = 0x15;
527 n8_rng_param.key2[2] = 0x7a; n8_rng_param.key2[3] = 0x97;
528 n8_rng_param.key2[4] = 0x54; n8_rng_param.key2[5] = 0x8c;
529 n8_rng_param.key2[6] = 0x46; n8_rng_param.key2[7] = 0xc7;
531 n8_rng_param.hostSeed[0] = 0x34; n8_rng_param.hostSeed[1] = 0x56;
532 n8_rng_param.hostSeed[2] = 0xab; n8_rng_param.hostSeed[3] = 0xcd;
533 n8_rng_param.hostSeed[4] = 0x09; n8_rng_param.hostSeed[5] = 0x87;
534 n8_rng_param.hostSeed[6] = 0xf2; n8_rng_param.hostSeed[7] = 0x5a;
536 n8_rng_param.initial_TOD_seconds = 0x001029c5;
537 n8_rng_param.externalClockScaler = 0; /* Ignored from values above */
539 /* Perform initial set-up for RNG */
540 ret = RN_SetChipParameters(&n8_rng_param, queue_p);
541 /* TODO: Ultimately we should check the return status. */
542 /* The check of return status is more critical once we put in */
543 /* code above to randomize the keys, etc. above. */
544 #else
545 /* Enable the RNG to get SEEDs for DES keys - we need 2 64 bit
546 samples to use as the 64bit DES keys.
551 /* clear any errors and set up to enable the RNG */
552 rng_control_status = RNG_Status_RNG_Enable |
553 RNG_Status_Buffer_Use_Seed_Generator |
554 RNG_Status_Seed_Use_Internal |
555 RNG_Status_Any_Condition_Mask |
556 (RNG_Status_Iteration_Count_Mask &
557 255);
559 /* Start generating Internally Seeded Samples to the RNG Buffer */
560 queue_p->rngReg_p->rng_control_status = rng_control_status;
562 /* spin while waiting for for RNG SEEDs to be created */
563 n8_delay_ms(30); /* Wait 30 milliseconds for seed data to be valid */
565 /* Stop the RNG Core */
566 queue_p->rngReg_p->rng_control_status = 0;
569 /* Extract the seeds from the RNG buffer and copy them
570 * into the n8_rng_param structure.
572 unsigned char key[16];
573 int i;
574 for ( i = 0; i < 4; i++ )
576 key[i*4] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[0];
577 key[i*4+1] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[1];
578 key[i*4+2] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[2];
579 key[i*4+3] = ((volatile char *)&queue_p->rngReg_p->rng_buffer[i])[3];
581 for ( i = 0; i < N8_DES_KEY_LENGTH ; i++) {
582 n8_rng_param.key1[i] = key[i];
583 n8_rng_param.key2[i] = key[i+8];
587 /* check key1 and key2 for parity and force parity if needed*/
588 if (checkKeyParity(&n8_rng_param.key1) == N8_FALSE)
590 forceParity(&n8_rng_param.key1);
593 if(checkKeyParity(&n8_rng_param.key2) == N8_FALSE)
595 forceParity(&n8_rng_param.key2);
598 /* check key1 and key2 for weakness */
599 if (checkKeyForWeakness(&n8_rng_param.key1) == N8_TRUE ||
600 checkKeyForWeakness(&n8_rng_param.key2) == N8_TRUE)
602 DBG(("Weak key\nRNG Startup INIT - return Error\n"));
603 ret = N8_WEAK_KEY;
604 /* get another seed to generate another key ! */
606 /* If the seed passed all the tests - break out of the do/while loop */
607 if (ret != N8_WEAK_KEY) {
608 break;
610 } while (TRUE);
612 /* Make sure Time of Day counter is running */
613 n8_rng_param.todEnable = N8_TRUE;
614 /* Use internal clock */
615 n8_rng_param.use_external_clock = N8_FALSE;
616 /* Use internal seed */
617 n8_rng_param.seed_source = N8_RNG_SEED_INTERNAL;
618 /* Number or randoms before reseed, 255 max */
619 n8_rng_param.iteration_count = 255;
620 /* Clock frequency of N8 HW - Set here to ~167Mhz */
621 n8_rng_param.TOD_prescale = 0x09f437C0;
622 n8_rng_param.set_TOD_counter = N8_TRUE;
624 /* Get the time of day */
625 n8_gettime(&n8currenttime);
626 n8_rng_param.initial_TOD_seconds = n8currenttime.tv_sec;
627 n8_rng_param.externalClockScaler = 0; /* Ignored from values above */
629 /* Perform initial set-up for RNG */
630 ret = RN_SetChipParameters(&n8_rng_param, queue_p);
633 #endif
637 /* Copy the bytes out of the RNG queue */
638 ret = getContentsOfRNGQ( queue_p,
639 rn_req_p->numBytesRequested,
640 rn_req_p->userBuffer_p,
641 &numBytesReturned,
642 rn_req_p->userRequest );
644 /* Increment our count of requests queued. */
645 queue_p->stats.requestsQueued++;
647 N8_AtomicUnlock(queue_p->queueControlSem);
649 return ret;
651 } /* Queue_RN_request */
654 /*****************************************************************************
655 * function RN_GetParameters
656 *****************************************************************************/
657 /** @ingroup QMgr
658 * @brief Fill in values in a N8_RNG_Parameter_t structure that require
659 * looking at hardware.
661 * A note on the strategy for RNG_ALL_UNITS:
662 * The use of the RNG core has been simplified to use only one RNG
663 * execution unit. The obsoletes the system level updateAllSem lock.
664 * All references to RNG_ALL_UNITS have been modified to simply use
665 * the first execution unit.
667 * @param parms_p WO: a pointer to a parameter-holding structure
668 * @param chip RO: The chipset which is being read.
670 * @par Externals:
671 * queueTable_g RO: The pointer to the global control set table.
673 * @return
674 * enum-ed error types.
675 * N8_STATUS_OK Success
677 * @par Errors:
679 * @par Locks:
680 * This routine requires no locks.
682 * @par Assumptions:
683 * Only the RN execution unit for chip 0 is used. Given the implementation
684 * of the RNG, using more than one just complicates the implementation and
685 * requires additional resources with no performance gain.
687 *****************************************************************************/
689 N8_Status_t
690 RN_GetParameters(N8_RNG_Parameter_t *parms_p, int chip)
692 QueueControl_t *queue_p;
693 N8_Status_t ret = N8_STATUS_OK;
695 if (parms_p == NULL )
697 return(N8_INVALID_OBJECT);
700 ret = QMgr_get_control_struct(&queue_p, N8_RNG, chip);
701 if (ret != N8_STATUS_OK)
703 return(ret);
706 /* Make sure the hardware has been initialized before we can return */
707 /* initialization parameters. */
708 if ( queue_p->rngInitialized != N8_TRUE )
710 ret = N8_NOT_INITIALIZED;
712 else
714 /* Copy in the current parameters. */
715 memcpy(parms_p, &RngParametersShadow, sizeof(N8_RNG_Parameter_t));
718 return ret;
720 } /* RN_GetParameters */
723 /*****************************************************************************
724 * function RN_SetChipParameters
725 *****************************************************************************/
726 /** @ingroup QMgr
727 * @brief initialize the RN hardware
729 * This is called only when we want to actually initialize hardware.
732 * IMPORTANT note on register access:
733 * The north bridge is optimizing consecutive 32-bit writes into burst
734 * transfers. SIMON handles the 32-bit bursts correctly but has problems
735 * with the 64-bit bursts. Therefore we do NOT want to do any consecutive
736 * 32-bit writes. See the structure N8RNGRegs_t for order of the registers.
738 * @param parms_p RO: a pointer to a parameter-holding structure <BR>
739 * @param queue_p RO: Pointer to the queue control structure
740 * associated with hardware we are configuring.
742 * @return
743 * enum-ed error types.
745 * @par Errors:
747 * @par Locks:
748 * This routine requires that the caller has obtained the queueControlSem.
750 *****************************************************************************/
752 N8_Status_t
753 RN_SetChipParameters(N8_RNG_Parameter_t *parms_p, QueueControl_t *queue_p)
755 N8_Status_t ret = N8_STATUS_OK;
756 uint32_t rng_control_status;
757 uint32_t key1_ms;
758 uint32_t key1_ls;
759 uint32_t key2_ms;
760 uint32_t key2_ls;
761 uint32_t hostSeed_ms;
762 uint32_t hostSeed_ls;
763 uint32_t rng_seed_source;
766 /* Only set the chip parameters if it has not already been initialized */
767 if (queue_p->rngInitialized != N8_TRUE)
770 /* Set up the keys and seed and time of day */
771 key1_ms = BE_to_uint32(&parms_p->key1[N8_MS_BYTE]);
772 key1_ls = BE_to_uint32(&parms_p->key1[N8_LS_BYTE]);
773 key2_ms = BE_to_uint32(&parms_p->key2[N8_MS_BYTE]);
774 key2_ls = BE_to_uint32(&parms_p->key2[N8_LS_BYTE]);
776 queue_p->rngReg_p->rng_key1_msw = key1_ms;
777 queue_p->rngReg_p->rng_key2_msw = key2_ms;
779 queue_p->rngReg_p->rng_tod_prescale = parms_p->TOD_prescale;
781 queue_p->rngReg_p->rng_key2_lsw = key2_ls;
782 queue_p->rngReg_p->rng_key1_lsw = key1_ls;
784 /* Set up the time of day */
785 if (parms_p->set_TOD_counter == N8_TRUE)
787 queue_p->rngReg_p->rng_tod_seconds = parms_p->initial_TOD_seconds;
789 DBG(("rnh config: %x\n", queue_p->rngReg_p->rnh_control_status));
792 * Set seed source values.
793 * These values are keyed to the expected values set by the hardware
794 * spec. See [RNG] Control Status Register for the Seed Source
795 * specification.
797 switch (parms_p->seed_source)
799 case N8_RNG_SEED_EXTERNAL:
800 rng_seed_source = RNG_Status_Seed_Use_External;
801 break;
803 case N8_RNG_SEED_HOST:
804 rng_seed_source = RNG_Status_Seed_Use_Host3;
805 break;
807 case N8_RNG_SEED_INTERNAL:
808 default:
809 rng_seed_source = RNG_Status_Seed_Use_Internal;
810 break;
813 /* clear any errors and set up to enable the RNH/RNG */
814 rng_control_status = RNG_Status_RNG_Enable |
815 RNG_Status_Buffer_Use_X917 |
816 rng_seed_source |
817 RNG_Status_Any_Condition_Mask |
818 (RNG_Status_Iteration_Count_Mask &
819 parms_p->iteration_count);
821 /* Set TOD enable if needed. */
822 if ( parms_p->todEnable == N8_TRUE )
824 rng_control_status |= RNG_Status_TOD_Enable;
826 else
828 rng_control_status &= ~RNG_Status_TOD_Enable;
831 /* Set External clock and external clock scaler register if needed. */
832 if (parms_p->use_external_clock == N8_TRUE)
834 rng_control_status |= RNG_Status_Ext_Clock_Enable;
835 queue_p->rngReg_p->rng_external_clock_scalar =
836 parms_p->externalClockScaler;
838 else
840 rng_control_status &= ~RNG_Status_Ext_Clock_Enable;
843 hostSeed_ms = BE_to_uint32(&parms_p->hostSeed[N8_MS_BYTE]);
844 hostSeed_ls = BE_to_uint32(&parms_p->hostSeed[N8_LS_BYTE]);
846 queue_p->rngReg_p->rng_hostseed_msw = hostSeed_ms;
847 queue_p->rngReg_p->rng_control_status = rng_control_status;
848 queue_p->rngReg_p->rng_hostseed_lsw = hostSeed_ls;
850 DBG(("rnh config: %x\n", queue_p->rngReg_p->rnh_control_status));
852 queue_p->rngReg_p->rnh_control_status =
853 RNH_Status_Transfer_Enable |
854 RNH_Status_All_Enable_Mask;
857 /* Save off the parameters. */
858 /* This assumes the parameters are the same on all RNG units. */
859 memcpy(&RngParametersShadow, parms_p, sizeof(N8_RNG_Parameter_t));
861 /* Wait for a bit to let some random numbers be generated. */
862 RNG_WaitForHardwareStart(queue_p);
864 /* Set that the queue has been initialized. */
865 queue_p->rngInitialized = N8_TRUE;
868 return ret;
870 } /* RN_SetChipParameters */
872 /*****************************************************************************
873 * function RN_SetParameters
874 *****************************************************************************/
875 /** @ingroup QMgr
876 * @brief initialize the RN Hardware
878 * This is called only when we want to actually initialize hardware.
880 * A note on the strategy for RNG_ALL_UNITS:
881 * The use of the RNG core has been simplified to use only one RNG
882 * execution unit. The obsoletes the system level updateAllSem lock.
883 * All references to RNG_ALL_UNITS have been modified to simply use
884 * the first execution unit.
886 * @param parms_p RO: a pointer to a parameter-holding structure <BR>
887 * @param chip RO: The chipset which is being initialized.
889 * @par Externals:
890 * queueTable_g RO: The pointer to the global control set table.
892 * @return
893 * enum-ed error types.
895 * @par Errors:
897 * @par Locks:
898 * This routine gets the queueControlSem for each execution unit as it
899 * set its individual parameters.
901 * @par Assumptions:
902 * Only the RN execution unit for chip 0 is used. Given the implementation
903 * of the RNG, using more than one just complicates the implementation and
904 * requires additional resources with no performance gain.
906 *****************************************************************************/
908 N8_Status_t
909 RN_SetParameters(N8_RNG_Parameter_t *parms_p, int chip)
911 QueueControl_t *queue_p;
912 N8_Status_t ret = N8_STATUS_OK;
914 if (parms_p == NULL )
916 ret = N8_INVALID_OBJECT;
917 goto RN_SetParametersReturn;
920 ret = QMgr_get_control_struct(&queue_p, N8_RNG, chip);
921 if (ret != N8_STATUS_OK)
923 goto RN_SetParametersReturn;
926 /* Get the queue control semaphore to protect queue initialization */
927 N8_AtomicLock(queue_p->queueControlSem);
929 ret = RN_SetChipParameters( parms_p, queue_p );
931 /* Release aquired semaphore */
932 N8_AtomicUnlock(queue_p->queueControlSem);
934 RN_SetParametersReturn:
935 return ret;
937 } /* RN_SetParameters */