meta-digi/meta-digi-dey/recipes-digi/dey-examples/files/sahara_test/callback.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 */