/* $Revision: 2 $ */
/* $Date: 10/29/07 8:15a $ */
/*
*	Implement various Receiver related services.
*/
/* $Log: /NEW SOURCESAFE DATABASE/SDK/PLX/gsc/hpdi32/sbtest/rx.c $
 * 
 * 2     10/29/07 8:15a Dnewbold
 * Updated for Linux port.
 * 
 * 1     8/22/05 4:14p Dnewbold
 * 
 * 5     12/27/04 4:28p Dnewbold
 * Moved some items to the utils directory.
 * 
 * 4     7/08/04 8:34a Dnewbold
 * Cross platform porting.
 * 
 * 3     10/22/03 4:40p Dnewbold
 * Account for the absence of Tx or Rx FIFOs.
 * 
 * 2     8/25/03 2:18p Dnewbold
 * Updated test procedures.
 * 
 * 1     6/18/03 9:29a Dnewbold
*/

#include <stdio.h>
#include <string.h>

#include "hpdi32_api.h"
#include "main.h"
#include "util_label.h"
#include "util_sleep.h"



/* typedefs	*****************************************************************/

typedef struct
{
	U32	set;
	U32	get;
} set_get_t;

typedef struct
{
	const char*			name;
	U32					parm;
	const set_get_t*	list;
	size_t				size;
} set_get_list_t;



/*****************************************************************************
*
*	Function:	_parm_list_test
*
*	Purpose:
*
*		Perform a series of tests per the given data and list.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		set		The data set to act on.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _parm_list_test(void* handle, const set_get_list_t* set)
{
	int				errs	= 0;
	int				form;
	unsigned long	get;
	int				i;
	U32				status	= GSC_SUCCESS;

	if (set->name)
		label_text(set->name);

	for (form = 0; form <= 2; form++)
	{
		printf(".");

		for (i = 0; i < (int) set->size; i++)
		{
			status	= hpdi32_config(handle,
									set->parm,
									0,
									set->list[i].set,
									&get);

			if ((status == GSC_SUCCESS) && (get != set->list[i].get))
			{
				printf(	"(%d. %ld->%ld) ",
						i,
						(long) set->list[i].get,
						(long) get);
				status	= GSC_FAILED;
			}

			if (status != GSC_SUCCESS)
				break;
		}

		if (status != GSC_SUCCESS)
			break;
	}

	if (set->name)
		hpdi32_reset(handle);

	errs	= (status == GSC_SUCCESS) ? 0 : 1;

	if (set->name == NULL)
		;
	else if (errs)
		printf("FAIL <---\n");
	else
		printf("PASS\n");

	return(errs);
}



/*****************************************************************************
*
*	Function:	_rx_enable_tests
*
*	Purpose:
*
*		Perform Receiver Enable tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_enable_tests(void* handle)
{
	static const set_get_t	list[]	=
	{
		/* set						get							*/
		{ HPDI32_RX_ENABLE_YES,		HPDI32_RX_ENABLE_YES		},
		{ GSC_NO_CHANGE,			HPDI32_RX_ENABLE_YES		},
		{ GSC_DEFAULT,				HPDI32_RX_ENABLE_DEFAULT	},
		{ HPDI32_RX_ENABLE_NO,		HPDI32_RX_ENABLE_NO			},
		{ GSC_NO_CHANGE,			HPDI32_RX_ENABLE_NO			},
		{ GSC_DEFAULT,				HPDI32_RX_ENABLE_DEFAULT	},
		{ HPDI32_RX_ENABLE_DEFAULT,	HPDI32_RX_ENABLE_DEFAULT	},
		{ GSC_NO_CHANGE,			HPDI32_RX_ENABLE_DEFAULT	},
		{ GSC_DEFAULT,				HPDI32_RX_ENABLE_DEFAULT	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_ENABLE,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	U32				bcr		= 0;
	int				errs;
	unsigned long	get;
	U32				status;

	label_text("Rx Enable");
	errs	= _parm_list_test(handle, &set);

	if (errs == 0)
	{
		// Enable the received and verify the results via BCR

		status	= hpdi32_config(handle,
								HPDI32_RX_ENABLE,
								0,
								HPDI32_RX_ENABLE_YES,
								&get);

		if ((status == GSC_SUCCESS) && (get != HPDI32_RX_ENABLE_YES))
			status	= GSC_FAILED;

		if (status == GSC_SUCCESS)
			status	= hpdi32_reg_read(handle, HPDI32_BCR, &bcr);

		if ((status == GSC_SUCCESS) && ((bcr & HPDI32_BCR_RX_ENABLED) == 0))
			status	= GSC_FAILED;

		// Disable the received and verify the results via BCR

		if (status == GSC_SUCCESS)
		{
			status	= hpdi32_config(handle,
									HPDI32_RX_ENABLE,
									0,
									HPDI32_RX_ENABLE_NO,
									&get);
		}

		if ((status == GSC_SUCCESS) && (get != HPDI32_RX_ENABLE_NO))
			status	= GSC_FAILED;

		if (status == GSC_SUCCESS)
			status	= hpdi32_reg_read(handle, HPDI32_BCR, &bcr);

		if ((status == GSC_SUCCESS) && ((bcr & HPDI32_BCR_RX_ENABLED) != 0))
			status	= GSC_FAILED;

		errs	= (status == GSC_SUCCESS) ? 0 : 1;
	}

	if (errs)
		printf("FAIL <---\n");
	else
		printf("PASS\n");

	return(errs);
}



/*****************************************************************************
*
*	Function:	_rx_overrun_tests
*
*	Purpose:
*
*		Perform Receiver Overrun tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_overrun_tests(void* handle)
{
	static set_get_t	list[]	=
	{
		/* set	get	*/
		{ 0,	0	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_OVERRUN,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	U32			bsr		= 0;
	int			errs;
	const char*	msg		= NULL;
	fifo_info_t	rx_info;
	U32			rx_size;
	U32			status	= GSC_SUCCESS;
	fifo_info_t	tx_info;
	U32			tx_size;

	label_text("Rx Overrun");
	hpdi32_reset(handle);
	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if (tx_info == FIFO_NONE)
		msg	= "no Tx FIFOs installed";
	else if (tx_size < RX_WRITE_SAMPLES)
		msg	= "Tx FIFO is too small";
	else if (rx_info == FIFO_NONE)
		msg	= "no Rx FIFOs installed";
	else if (rx_size < RX_WRITE_SAMPLES)
		msg	= "Rx FIFO is too small";

	// Force an Rx Overrun and verify that it is so.
	if (msg	== NULL)
		status	= rx_write(handle, 129L * 1024);

	if (status == GSC_SUCCESS)
		status	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);

	if ((status == GSC_SUCCESS) && ((bsr & HPDI32_BSR_RX_OVERRUN) == 0))
		status	= GSC_FAILED;

	if (status == GSC_SUCCESS)
	{
		list[0].set	= HPDI32_RX_OVERRUN_IGNORE;
		list[0].get	= HPDI32_RX_OVERRUN_YES;
		errs	= _parm_list_test(handle, &set);
	}
	else
	{
		errs	= 1;
	}

	status	= errs ? GSC_FAILED : status;

	if (status == GSC_SUCCESS)
		status	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);

	if ((status == GSC_SUCCESS) && ((bsr & HPDI32_BSR_RX_OVERRUN) == 0))
		status	= GSC_FAILED;

	// Clear the Rx Overrun and verify that it is so.

	if (msg)
	{
	}
	else if (status == GSC_SUCCESS)
	{
		list[0].set	= HPDI32_RX_OVERRUN_CLEAR;
		list[0].get	= HPDI32_RX_OVERRUN_NO;
		errs	= _parm_list_test(handle, &set);
	}
	else
	{
		errs	= 1;
	}

	status	= errs ? GSC_FAILED : status;

	if (status == GSC_SUCCESS)
	{
		sleep_ms(100);
		status	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);
	}

	if ((status == GSC_SUCCESS) && (bsr & HPDI32_BSR_RX_OVERRUN))
		status	= GSC_FAILED;

	errs	= (status == GSC_SUCCESS) ? errs : 1;
	hpdi32_reset(handle);

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_rx_row_count_tests
*
*	Purpose:
*
*		Perform Receiver Row Count tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_row_count_tests(void* handle)
{
	#define	TEST_SIZE	256

	static set_get_t	list[]	=
	{
		/* set	get	*/
		{ 0,	0	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_ROW_COUNT,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	int			errs;
	const char*	msg		= NULL;
	fifo_info_t	rx_info;
	U32			rx_size;
	U32			status	= GSC_SUCCESS;
	fifo_info_t	tx_info;
	U32			tx_size;

	label_text("Rx Row Count");
	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if (tx_info == FIFO_NONE)
		msg	= "no Tx FIFOs installed";
	else if (tx_size < TEST_SIZE)
		msg	= "Tx FIFO is too small";
	else if (rx_info == FIFO_NONE)
		msg	= "no Rx FIFOs installed";
	else if (rx_size < TEST_SIZE)
		msg	= "Rx FIFO is too small";

	// Reset the board then check the count.
	if (msg == NULL)
		status	= hpdi32_reset(handle);

	if ((msg == NULL) && (status == GSC_SUCCESS))
	{
		list[0].get	= 0;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	// Write data to the Rx FIFO then check the count.

	if ((msg == NULL) && (status == GSC_SUCCESS))
		status	= rx_write(handle, TEST_SIZE);

	if ((msg == NULL) && (status == GSC_SUCCESS))
	{
		list[0].get	= TEST_SIZE;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	errs	= (status == GSC_SUCCESS) ? 0 : 1;
	hpdi32_reset(handle);

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
	#undef	TEST_SIZE
}



/*****************************************************************************
*
*	Function:	_rx_state_tests
*
*	Purpose:
*
*		Perform Receiver State tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_state_tests(void* handle)
{
	static set_get_t	list[]	=
	{
		/* set	get	*/
		{ 0,	0	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_STATE,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	int	errs;
	U32	status;

	label_text("Rx State");
	hpdi32_reset(handle);

	// Enable the transciever and verify the results.
	status	= hpdi32_reg_write(handle, HPDI32_BCR, HPDI32_BCR_RX_ENABLED);

	if (status == GSC_SUCCESS)
	{
		list[0].get	= HPDI32_RX_STATE_ACTIVE;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	// Disable the transciever and verify the results.

	if (status == GSC_SUCCESS)
		status	= hpdi32_reg_write(handle, HPDI32_BCR, 0);

	if (status == GSC_SUCCESS)
	{
		list[0].get	= HPDI32_RX_STATE_INACTIVE;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	errs	= (status == GSC_SUCCESS) ? 0 : 1;
	hpdi32_reset(handle);

	if (errs)
		printf("FAIL <---\n");
	else
		printf("PASS\n");

	return(errs);
}



/*****************************************************************************
*
*	Function:	_rx_status_count_tests
*
*	Purpose:
*
*		Perform Receiver Status Count tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_status_count_tests(void* handle)
{
	static set_get_t	list[]	=
	{
		/* set	get	*/
		{ 0,	0	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_STATUS_COUNT,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	int			errs	= 0;
	const char*	msg		= NULL;
	fifo_info_t	rx_info;
	U32			rx_size;
	U32			status	= GSC_SUCCESS;
	fifo_info_t	tx_info;
	U32			tx_size;

	label_text("Rx Status Count");
	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if (tx_info == FIFO_NONE)
		msg	= "no Tx FIFOs installed";
	else if (tx_size < RX_WRITE_SAMPLES)
		msg	= "Tx FIFO is too small";
	else if (rx_info == FIFO_NONE)
		msg	= "no Rx FIFOs installed";
	else if (rx_size < RX_WRITE_SAMPLES)
		msg	= "Rx FIFO is too small";

	// Reset the board then check the count.

	if (msg	== NULL)
		status	= hpdi32_reset(handle);

	if ((msg	== NULL) && (status == GSC_SUCCESS))
	{
		list[0].get	= 0;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	// Write data to the Rx FIFO then check the count.

	if ((msg	== NULL) && (status == GSC_SUCCESS))
		status	= hpdi32_reg_write(handle, HPDI32_TLVLCR, 10240);

	if ((msg	== NULL) && (status == GSC_SUCCESS))
		status	= hpdi32_reg_write(handle, HPDI32_TLILCR, 16);

	if ((msg	== NULL) && (status == GSC_SUCCESS))
		status	= hpdi32_reg_write(handle, HPDI32_TSVLCR, 256);

	if ((msg	== NULL) && (status == GSC_SUCCESS))
		status	= rx_write(handle, 1024);

	if ((msg	== NULL) && (status == GSC_SUCCESS))
	{
		list[0].get	= 256;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	errs	= (status == GSC_SUCCESS) ? errs : 1;
	hpdi32_reset(handle);

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		// This is aknown issue on some boards.
		errs	= 0;
		printf("SKIPPED\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_rx_under_run_tests
*
*	Purpose:
*
*		Perform Receiver Under Run tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _rx_under_run_tests(void* handle)
{
	static set_get_t	list[]	=
	{
		/* set	get	*/
		{ 0,	0	}
	};

	static const set_get_list_t	set	=
	{
		/* name	*/	NULL,
		/* parm	*/	HPDI32_RX_UNDER_RUN,
		/* list	*/	list,
		/* size	*/	ARRAY_ELEMENTS(list)
	};

	U32	bsr;
	int	errs;
	U32	status;

	label_text("Rx Under Run");
	hpdi32_reset(handle);

	// Cause an under run and verify there there it is so.
	status	= hpdi32_reg_read(handle, HPDI32_FDR, &bsr);

	if (status == GSC_SUCCESS)
	{
		list[0].set	= HPDI32_RX_UNDER_RUN_IGNORE;
		list[0].get	= HPDI32_RX_UNDER_RUN_YES;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	// Clear the Under Run c\and verify that it is so.

	if (status == GSC_SUCCESS)
	{
		list[0].set	= HPDI32_RX_UNDER_RUN_CLEAR;
		list[0].get	= HPDI32_RX_UNDER_RUN_NO;
		errs	= _parm_list_test(handle, &set);
		status	= errs ? GSC_FAILED : GSC_SUCCESS;
	}

	errs	= (status == GSC_SUCCESS) ? 0 : 1;
	hpdi32_reset(handle);

	if (errs)
		printf("FAIL <---\n");
	else
		printf("PASS\n");

	return(errs);
}



/*****************************************************************************
*
*	Function:	rx_config_tests
*
*	Purpose:
*
*		Perform Receiver configuration tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

int rx_config_tests(void* handle)
{
	int	errs	= 0;

	label_text("Receiver Configuration");
	printf("\n");
	label_level_inc();

	errs	+= _rx_enable_tests(handle);
	errs	+= _rx_overrun_tests(handle);
	errs	+= _rx_row_count_tests(handle);
	errs	+= _rx_state_tests(handle);
	errs	+= _rx_status_count_tests(handle);
	errs	+= _rx_under_run_tests(handle);

	label_level_dec();
	return(errs);
}



/*****************************************************************************
*
*	Function:	rx_write
*
*	Purpose:
*
*		Write data so that it appears in the Rx FIFO
*
*	Arguments:
*
*		handle		The handle used to access the device under test.
*
*		samples		The number of samples to write.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

U32 rx_write(void* handle, U32 samples)
{
	U32	bsr		= 0;
	U32	send;	/*lint !e578 */
	U32	status	= GSC_SUCCESS;

	for (;samples;)
	{
		send	= (samples > RX_WRITE_SAMPLES) ? RX_WRITE_SAMPLES : samples;
		samples	-= send;

		for (; send--;)
		{
			status	= hpdi32_reg_write(handle, HPDI32_FDR, 0);

			if (status != GSC_SUCCESS)
				break;
		}

		if (status == GSC_SUCCESS)
		{
			status	= hpdi32_reg_mod(	handle,
										HPDI32_BCR,
										HPDI32_BCR_TX_ENABLED,
										HPDI32_BCR_TX_ENABLED);
		}

		if (status == GSC_SUCCESS)
		{
			status	= hpdi32_reg_mod(	handle,
										HPDI32_BCR,
										HPDI32_BCR_RX_ENABLED,
										HPDI32_BCR_RX_ENABLED);
		}

		if (status == GSC_SUCCESS)
		{
			status	= hpdi32_reg_mod(	handle,
										HPDI32_BCR,
										HPDI32_BCR_TX_START,
										HPDI32_BCR_TX_START);
		}

		if (status != GSC_SUCCESS)
			break;

		for (;;)
		{
			if (status == GSC_SUCCESS)
				status	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);

			if (status != GSC_SUCCESS)
				break;

			if (bsr & HPDI32_BSR_TX_NOT_EMPTY)
				continue;

			sleep_ms(100);
			break;
		}

		if (status != GSC_SUCCESS)
			break;
	}

	return(status);
}



