392 lines
13 KiB
C
392 lines
13 KiB
C
/*
|
|
* Copyright 2005-2006 Freescale Semiconductor, Inc. All rights reserved.
|
|
*/
|
|
|
|
/*
|
|
* The code contained herein is licensed under the GNU General Public
|
|
* License. You may obtain a copy of the GNU General Public License
|
|
* Version 2 or later at the following locations:
|
|
*
|
|
* http://www.opensource.org/licenses/gpl-license.html
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
/**
|
|
* @file callback.c
|
|
* @brief Test code for non-blocking Callback feature.
|
|
*
|
|
* @ifnot STANDALONE
|
|
* @ingroup MXCSAHARA2_TEST
|
|
* @endif
|
|
*/
|
|
|
|
#include "api_tests.h"
|
|
|
|
/*
|
|
* Note to Maintainers:
|
|
*
|
|
* The use of global variables is inappropriate, as there is only one copy of
|
|
* them when this code is compiled into the kernel. Therefore, the only
|
|
* communication between mainline code and the callback function is through the
|
|
* structure pointed to by the reference.
|
|
*/
|
|
|
|
/** The maximum number of results to request at once */
|
|
#define RESULTS_SIZE 10
|
|
|
|
/** The number of bytes of random data to request. Needs to be greater than
|
|
* five. */
|
|
#define RAND_SIZE 24
|
|
|
|
|
|
/**
|
|
* Values to control and monitor an instance of a fsl_shw_get_random() call.
|
|
* Purpose is to know whether the asynchronous results were returned properly.
|
|
*/
|
|
struct rand_test
|
|
{
|
|
struct rand_test* self; /**< Pointer to this struct, as check. */
|
|
unsigned initiated; /**< Whether fsl_shw_get_random() call
|
|
was kicked off */
|
|
unsigned result_received; /**< Whether fsl_shw_get_results() showed that
|
|
this call finished.*/
|
|
fsl_shw_return_t result; /**< The result code fsl_shw_get_results() */
|
|
int testno; /**< The test number (used as verification */
|
|
unsigned random_ok; /**< Whether data and @c random is OK */
|
|
unsigned unexpected_result; /**< Whether @c result is OK */
|
|
uint8_t cache_buf1[32]; /**< isolate random to cache line */
|
|
uint8_t random[RAND_SIZE]; /**< The buffer for the random data */
|
|
uint8_t cache_buf2[32]; /**< end isolate random to cache line */
|
|
};
|
|
|
|
|
|
static int run_test1(fsl_shw_uco_t* my_ctx, volatile struct rand_test tests[]);
|
|
static int run_test2(fsl_shw_uco_t* my_ctx, volatile struct rand_test tests[]);
|
|
static void test_callback_fn(fsl_shw_uco_t* uco);
|
|
|
|
|
|
/**
|
|
* Check one random number retrieval to see whether random number looks like
|
|
* it was actually retrieved.
|
|
*
|
|
* @param random Location of the bytes of random data to verify. Length
|
|
* is RAND_SIZE.
|
|
*
|
|
* @return 0 if OK, non-zero if number is bad.
|
|
*/
|
|
static int check_one(uint8_t random[RAND_SIZE])
|
|
{
|
|
if ((random[0] == 0) && (random[1] == 0) &&
|
|
(random[2] == 0) && (random[3] == 0) &&
|
|
(random[4] == 0) && (random[5] == 0) &&
|
|
(random[RAND_SIZE/3] == 0) && (random[RAND_SIZE/2] == 0) &&
|
|
(random[RAND_SIZE-1] == 0)) {
|
|
return 1; /* failed */
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Internal function to initialize array of test structures.
|
|
*
|
|
* All values are set to 0 except for 'testno', which is set to the
|
|
* structure's array index.
|
|
*
|
|
* @param tests Pointer to beginning of array
|
|
* @param num_tests Number of elements in array.
|
|
*
|
|
* @return void
|
|
*/
|
|
static void clear_test_data(struct rand_test* tests, uint32_t num_tests)
|
|
{
|
|
uint32_t loop;
|
|
|
|
for (loop = 0; loop < num_tests; loop++) {
|
|
tests[loop].self = &tests[loop];
|
|
tests[loop].initiated = 0;
|
|
tests[loop].result_received = 0;
|
|
tests[loop].testno = loop;
|
|
tests[loop].random_ok = 0;
|
|
tests[loop].unexpected_result = 0;
|
|
memset((void*)tests[loop].random, 0, sizeof(tests[loop].random));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Tests the callback and get results operations using get random function
|
|
*
|
|
* @param my_ctx User context to use
|
|
* @param[pout] total_passed_count Number of tests which passed.
|
|
* @param[pout] total_failed_count Number of tests which failed.
|
|
*
|
|
* @return void
|
|
*/
|
|
void run_callback(
|
|
fsl_shw_uco_t* my_ctx,
|
|
uint32_t* total_passed_count,
|
|
uint32_t* total_failed_count)
|
|
{
|
|
volatile struct rand_test* tests = malloc(RESULTS_SIZE
|
|
* sizeof(struct rand_test));
|
|
|
|
unsigned passed; /* boolean */
|
|
|
|
printf("\nCallback Tests\n");
|
|
|
|
fsl_shw_uco_clear_flags(my_ctx, FSL_UCO_BLOCKING_MODE);
|
|
fsl_shw_uco_clear_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
|
|
clear_test_data((void*)tests, RESULTS_SIZE);
|
|
|
|
printf(" Callback Test 1: Get block of results\n");
|
|
passed = run_test1(my_ctx, tests);
|
|
if (passed) {
|
|
printf("Callback Test 1: Passed\n");
|
|
*total_passed_count += 1;
|
|
} else {
|
|
printf("Callback Test 1: Failed\n");
|
|
*total_failed_count += 1;
|
|
}
|
|
|
|
/* Clean up for second test */
|
|
clear_test_data((void*)tests, RESULTS_SIZE);
|
|
|
|
if (0) {
|
|
printf(" Callback Test 2: Set callback for each request\n");
|
|
passed = run_test2(my_ctx, tests);
|
|
if (passed) {
|
|
printf("Callback Test 2: Passed\n");
|
|
*total_passed_count += 1;
|
|
} else {
|
|
printf("Callback Test 2: Failed\n");
|
|
*total_failed_count += 1;
|
|
}
|
|
}
|
|
|
|
/* set uco back back to its default */
|
|
fsl_shw_uco_set_flags(my_ctx, FSL_UCO_BLOCKING_MODE);
|
|
fsl_shw_uco_clear_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
fsl_shw_uco_set_callback(my_ctx, NULL);
|
|
|
|
|
|
if (tests != NULL) {
|
|
free((void*)tests);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* send multiple requests in non-blocking mode. request a callback
|
|
* only on the last service request. The callback should be able to
|
|
* obtain all of the results in a single "get results" call
|
|
*******************************************************************/
|
|
static int run_test1(fsl_shw_uco_t* my_ctx, volatile struct rand_test tests[])
|
|
{
|
|
uint32_t loop;
|
|
uint32_t loop_count = 0;
|
|
fsl_shw_return_t code;
|
|
uint32_t kicked_off_count = 0;
|
|
int passed = 1; /* boolean */
|
|
|
|
/* This loop will have to be fixed when pool size is enforced. */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
/* on last time through loop, request callback be performed */
|
|
if (loop == (RESULTS_SIZE - 1)) {
|
|
fsl_shw_uco_set_callback(my_ctx, test_callback_fn);
|
|
fsl_shw_uco_set_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
}
|
|
|
|
/* use loop value as user reference */
|
|
fsl_shw_uco_set_reference(my_ctx, (uint32_t)(tests+loop));
|
|
/* mark as being intialized */
|
|
tests[loop].initiated = 1;
|
|
|
|
/* perform a descriptor chain generating function */
|
|
code = fsl_shw_get_random(
|
|
my_ctx, sizeof(tests[loop].random),
|
|
(uint8_t*)tests[loop].random);
|
|
|
|
if (code == FSL_RETURN_OK_S) {
|
|
kicked_off_count++;
|
|
} else {
|
|
/* mark test as failed */
|
|
passed = 0;
|
|
/* un-initialize the entry here (must be initialized before the
|
|
* interrupt goes off, so it is initilzed before the descriptor
|
|
* chain generating function above */
|
|
tests[loop].initiated = 0;
|
|
printf(" fsl_shw_random(), call %d returned %s\n",
|
|
loop, fsl_error_string(code));
|
|
}
|
|
}
|
|
|
|
/* Stay in test until we get pass/fail feedback from callback */
|
|
while (++loop_count < 400000) {
|
|
uint32_t callbacks_received = 0;
|
|
|
|
/* check that every request was serviced successfully */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
if (tests[loop].result_received) {
|
|
callbacks_received++;
|
|
}
|
|
}
|
|
if (callbacks_received >= kicked_off_count) {
|
|
break; /* got everything */
|
|
}
|
|
usleep(5);
|
|
}
|
|
|
|
/* check that every request was serviced successfully */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
if (tests[loop].initiated) {
|
|
if (!tests[loop].result_received) {
|
|
printf("result never received for test %d\n", loop);
|
|
passed = 0;
|
|
} else if (tests[loop].result != FSL_RETURN_OK_S) {
|
|
printf("Bad result for result %d: %s\n", loop,
|
|
fsl_error_string(tests[loop].result));
|
|
} else if (!tests[loop].random_ok) {
|
|
printf("bad random result for test %d\n", loop);
|
|
passed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
fsl_shw_uco_clear_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
return passed;
|
|
}
|
|
|
|
|
|
/***************************************************************
|
|
* send a callback request along with each service request
|
|
**************************************************************/
|
|
static int run_test2(fsl_shw_uco_t* my_ctx, volatile struct rand_test tests[])
|
|
{
|
|
uint32_t loop;
|
|
uint32_t loop_count = 0;
|
|
uint32_t kicked_off_count = 0;
|
|
fsl_shw_return_t code;
|
|
int all_received = 0;
|
|
int passed = 1; /* boolean */
|
|
|
|
fsl_shw_uco_set_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
fsl_shw_uco_set_callback(my_ctx, test_callback_fn);
|
|
|
|
/* This loop will have to be fixed when pool size is enforced. */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
fsl_shw_uco_set_reference(my_ctx, (uint32_t)(tests+loop));
|
|
tests[loop].initiated = 1;
|
|
|
|
code = fsl_shw_get_random(
|
|
my_ctx, sizeof(tests[loop].random),
|
|
(uint8_t*)tests[loop].random);
|
|
|
|
if (code == FSL_RETURN_OK_S) {
|
|
kicked_off_count++;
|
|
} else {
|
|
passed = 0;
|
|
tests[loop].initiated = 0;
|
|
printf(" fsl_shw_random(), call %d returned %s\n",
|
|
loop, fsl_error_string(code));
|
|
}
|
|
}
|
|
|
|
/* Stay in test until we get pass/fail feedback from callback */
|
|
while (++loop_count < 8000000) {
|
|
uint32_t callbacks_received = 0;
|
|
|
|
/* check that every request was serviced successfully */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
if (tests[loop].result_received) {
|
|
callbacks_received++;
|
|
}
|
|
}
|
|
if (callbacks_received >= kicked_off_count) {
|
|
all_received = 1;
|
|
break; /* got everything */
|
|
}
|
|
usleep(50);
|
|
}
|
|
|
|
if (!all_received) {
|
|
printf("Not enough callbacks received\n");
|
|
passed = 0;
|
|
}
|
|
|
|
/* check that every request was serviced successfully */
|
|
for (loop = 0; loop < RESULTS_SIZE; loop++) {
|
|
if (tests[loop].initiated) {
|
|
if (!tests[loop].result_received) {
|
|
printf("result never received for test %d\n", loop);
|
|
passed = 0;
|
|
} else if (!tests[loop].random_ok) {
|
|
printf("bad random result for test %d\n", loop);
|
|
passed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
fsl_shw_uco_clear_flags(my_ctx, FSL_UCO_CALLBACK_MODE);
|
|
|
|
return passed;
|
|
}
|
|
|
|
|
|
static void test_callback_fn(fsl_shw_uco_t* uco)
|
|
{
|
|
fsl_shw_result_t results[RESULTS_SIZE]; /* place to put results */
|
|
fsl_shw_return_t code; /* value returned from API call */
|
|
unsigned int loop; /* number of iterations in verify loop */
|
|
unsigned actual; /* number of results actually received */
|
|
|
|
|
|
/* Request results */
|
|
code = fsl_shw_get_results(uco, RESULTS_SIZE, results, &actual);
|
|
|
|
/* check that results request worked */
|
|
if (code != FSL_RETURN_OK_S) {
|
|
printf(" fsl_shw_get_results() returned %s\n",
|
|
fsl_error_string(code));
|
|
} else {
|
|
/* loop over each result received */
|
|
for (loop = 0; loop < actual; ++loop) {
|
|
/* check user reference value is good */
|
|
struct rand_test* test;
|
|
|
|
test = (void*)fsl_shw_ro_get_reference(results + loop);
|
|
|
|
if (test == NULL) {
|
|
printf("Test may not fail... but reference is NULL\n");
|
|
} else if (test->self != test) {
|
|
printf("Test may not fail... but reference is invalid\n");
|
|
} else {
|
|
if (!test->initiated) {
|
|
|
|
printf(" test case %d never initiated\n", test->testno);
|
|
test->unexpected_result = 1;
|
|
} else if (test->result_received) {
|
|
printf(" results already received for test case %d\n",
|
|
test->testno);
|
|
test->unexpected_result = 1;
|
|
} else {
|
|
/* mark that a test result was received for this ref */
|
|
test->result = fsl_shw_ro_get_status(results + loop);
|
|
|
|
/* check that a random number was likely recevied */
|
|
if ((test->result == FSL_RETURN_OK_S)
|
|
&& (check_one(test->random) == 0)) {
|
|
test->random_ok = 1;
|
|
}
|
|
test->result_received = 1;
|
|
}
|
|
} /* for each result received */
|
|
}
|
|
}
|
|
} /* test_callback1 */
|