/* $Revision: 4 $ */
/* $Date: 3/18/08 8:24a $ */
/*
*	Implement special tests.
*/
/* $Log: /NEW SOURCESAFE DATABASE/SDK/hpdi32/sbtest/special.c $
 * 
 * 4     3/18/08 8:24a Dnewbold
 * Changed to Clock Divider value for a test.
 * 
 * 3     10/29/07 8:15a Dnewbold
 * Updated for Linux port.
 * 
 * 2     3/28/06 11:13a Dnewbold
 * 
 * 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     1/30/04 11:40a Dnewbold
 * Added a Tx Single Cycle Disable test.
 * 
 * 2     10/22/03 4:40p Dnewbold
 * Account for the absence of Tx or Rx FIFOs.
 * 
 * 1     8/25/03 2:24p Dnewbold
*/

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

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



// #defines	*******************************************************************

#define	_1G		(1024L * 1024L * 1024L)



/* variables	*************************************************************/

static	U8	_big_buf[4L * 1024 * 1024];



/*****************************************************************************
*
*	Function:	_fifo_write_read_tdwodtr_test
*
*	Purpose:
*
*		Verify that a TdwodTr for a FIFO read in the middle of FIFO writes
*		doesn't produce data loss.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

#if TDWODTR

static int _fifo_write_read_tdwodtr_test(void* handle)
{
	#define	SAMPLES	16

	int			errs;
	U32*		fdr;
	U32			gsc		= 0;
	int			i;
	int			j;
	int			ok;
	int			qty;
	fifo_info_t	rx_info;
	U32			rx_size;
	U32			status;
	fifo_info_t	tx_info;
	U32			tx_size;
	U32			u32;

	label_text("FIFO Read w/TdwodTr");
	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if ((tx_info == FIFO_NONE) || (rx_info == FIFO_NONE))
		ok	= FALSE;
	else
		ok	= TRUE;

	status	= hpdi32_init(handle);

	if ((ok) && (status == GSC_SUCCESS))
		status	= HPDI32_TX_ENABLE__YES(handle);

	if ((ok) && (status == GSC_SUCCESS))
		status	= HPDI32_RX_ENABLE__YES(handle);

	if ((ok) && (status == GSC_SUCCESS))
	{
		status	= HPDI32_MISC_MAP_GSC_REGS_PTR__GET(handle, &gsc);

		if ((status != GSC_SUCCESS) || (gsc == 0))
		{
			status	= GSC_FAILED;
			printf("(register mapping failed) ");
		}
	}

	if ((ok) && (status == GSC_SUCCESS))
		fdr	= (U32*) (gsc + GSC_REG_OFFSET(HPDI32_FDR));
	else
		fdr	= NULL;

	/*
	*	Verify that the data can be read successfully when all is quiet.
	*/

	for (i = 0; (fdr) && (i < SAMPLES); i++)
		fdr[0]	= (U32) i;

	if (status == GSC_SUCCESS)
		status	= HPDI32_TX_FLOW_CONTROL__START(handle);

	sleep_ms(100);	// Wait for the data to get to the receive FIFO.

	if (status == GSC_SUCCESS)
		status	= HPDI32_TX_FLOW_CONTROL__STOP(handle);

	for (i = 0; (ok) && (fdr) && (i < SAMPLES); i++)
	{
		u32	= fdr[0];

		if (u32 != (U32) i)
		{
			status	= GSC_FAILED;
			printf("(pre-read: %d = 0x%lX, %ld) ", i, (long) u32, (long) u32);
			break;
		}
	}

	/*
	*	Verify that the data can be read successfully during writes.
	*/

	for (qty = 1; (ok) && (qty < 256); qty++)
	{
		if (status == GSC_SUCCESS)
			status	= HPDI32_FIFO_RESET__TX_YES(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_FIFO_RESET__RX_YES(handle);

		for (i = 0; (fdr) && (i < SAMPLES); i++)
			fdr[0]	= (U32) i;

		if (status == GSC_SUCCESS)
			status	= HPDI32_TX_FLOW_CONTROL__START(handle);

		sleep_ms(10);	// Wait for the data to get to the receive FIFO.

		if (status == GSC_SUCCESS)
			status	= HPDI32_TX_FLOW_CONTROL__STOP(handle);

		if (status != GSC_SUCCESS)
			break;

		// Perform the read during writes.

		for (i = 0; (fdr) && (i < (SAMPLES / 2)); i++)
		{
			for (j = 0; j < qty; j++)
				fdr[0]	= 0xFFFFFFFF;	// MemWr FDR

			u32	= fdr[0];		// MemRd FDR

			if (u32 != (U32) i)
			{
				status	= GSC_FAILED;
				break;
			}
		}

		if (status != GSC_SUCCESS)
		{
			printf("(%d writes) ", qty);
			break;
		}
	}

	// Trigger the PCI bus analyzer.
	hpdi32_reg_write(handle, HPDI32_FRR, 0xdeadbeef);

	if (tx_info == FIFO_NONE)
	{
		errs	= 0;
		printf("SKIPPED (no Tx FIFOs)\n");
	}
	else if (rx_info == FIFO_NONE)
	{
		errs	= 0;
		printf("SKIPPED (no Rx FIFOs)\n");
	}
	else if (status != GSC_SUCCESS)
	{
		errs	= 1;
		printf("FAIL <---\n");
	}
	else if (fdr == NULL)
	{
		errs	= 0;
		printf("SKIPPED (can't map GSC register)\n");
	}
	else
	{
		errs	= 0;
		printf("PASS\n");
	}

	hpdi32_init(handle);
	return(errs);
}

#endif



/*****************************************************************************
*
*	Function:	_rx_dmdma_single_cycle
*
*	Purpose:
*
*		Verify that the Single Cycle Disable feature is handled properly by
*		the driver for read requests.
*
*	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_dmdma_single_cycle(void* handle)
{
	U8				buf[4];
	int				errs;
	long long		mem;
	fifo_info_t		rx_info;
	U32				rx_size;
	unsigned long	scd		= 0;
	U32				status	= GSC_SUCCESS;
	fifo_info_t		tx_info;
	U32				tx_size;
	U32				xfer;

	for (;;)
	{
		label_text("Rx DMDMA Single Cycle");
		fifo_info_tx(&tx_info, &tx_size);
		fifo_info_rx(&rx_info, &rx_size);

		if ((tx_info == FIFO_NONE) || (rx_info == FIFO_NONE))
			break;

		mem	= id_total_mem_silent();

		if ((mem / _1G) >= 4)
			break;

		status	= hpdi32_init(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_MISC_FEATURES__1_CYCLE_DISABLE(handle, &scd);

		if ((status == GSC_SUCCESS) && (scd != HPDI32_MISC_FEATURES_PRESENT))
			break;

		if (status == GSC_SUCCESS)
			status	= HPDI32_TX_ENABLE__YES(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_RX_ENABLE__YES(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_DATA_SIZE__RX_8(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_TIMEOUT__TX_SET(handle, 1);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_PIO_THRESHOLD__RX_SET(handle, 0);

		// Write a single data value as we'll be asking for four.

		if (status == GSC_SUCCESS)
			status	= hpdi32_reg_write(handle, HPDI32_FDR, 0xDEADBEEF);

		// Let the data flow.

		if (status == GSC_SUCCESS)
			status	= hpdi32_reg_mod(handle, HPDI32_FDR, 0xFFFFFFFF, HPDI32_BCR_TX_START);

		sleep_ms(20);

		if (status == GSC_SUCCESS)
		{
			status	= hpdi32_read(handle, buf, 4, &xfer);

			if (status == GSC_WAIT_TIMEOUT)
			{
				status	= GSC_SUCCESS;
				break;
			}

			if (status == GSC_SUCCESS)
			{
				printf("(unexpected success) ");
				status	= GSC_FAILED;
				break;
			}

			if (status == GSC_INVALID_DATA)
			{
				// This is expected when Single Cycle Disable fails.
				status	= GSC_FAILED;
				break;
			}

			printf("(unexpected failure status: 0x%lX) ", (long) status);
			status	= GSC_FAILED;
		}

		break;
	}

	if (tx_info == FIFO_NONE)
	{
		errs	= 0;
		printf("SKIPPED (no Tx FIFOs)\n");
	}
	else if (rx_info == FIFO_NONE)
	{
		errs	= 0;
		printf("SKIPPED (no Rx FIFOs)\n");
	}
	else if ((mem / _1G) >= 4)
	{
		errs	= 0;
		printf("SKIPPED (Test not supported on systems with 4G or more of memory.)\n");
	}
	else if (status != GSC_SUCCESS)
	{
		errs	= 1;
		printf("FAIL <---\n");
	}
	else if (scd != HPDI32_MISC_FEATURES_PRESENT)
	{
		errs	= 0;
		printf("SKIPPED (feature not present)\n");
	}
	else
	{
		errs	= 0;
		printf("PASS\n");
	}

	hpdi32_init(handle);
	return(errs);
}



/*****************************************************************************
*
*	Function:	_tx_dmdma_single_cycle
*
*	Purpose:
*
*		Verify that the Single Cycle Disable feature is handled properly by
*		the driver for write requests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _tx_dmdma_single_cycle(void* handle)
{
	int				errs;
	long long		mem;
	unsigned long	scd		= 0;
	U32				status	= GSC_SUCCESS;
	fifo_info_t		tx_info;
	U32				tx_size;
	U32				xfer;

	for (;;)
	{
		label_text("Tx DMDMA Single Cycle");
		fifo_info_tx(&tx_info, &tx_size);

		if (tx_info == FIFO_NONE)
			break;

		mem	= id_total_mem_silent();

		if ((mem / _1G) >= 4)
			break;

		status	= hpdi32_init(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_MISC_FEATURES__1_CYCLE_DISABLE(handle, &scd);

//		if ((status == GSC_SUCCESS) && (scd != HPDI32_MISC_FEATURES_PRESENT))
//			break;

		if (status == GSC_SUCCESS)
			status	= HPDI32_TX_ENABLE__YES(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_DATA_SIZE__TX_8(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_MODE__TX_DMDMA(handle);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_TIMEOUT__TX_SET(handle, 2);

		if (status == GSC_SUCCESS)
			status	= HPDI32_IO_PIO_THRESHOLD__TX_SET(handle, 0);

		if (status == GSC_SUCCESS)
			status	= HPDI32_TX_CLOCK_DIVIDER__SET(handle, 0xFFFF);

		if (status == GSC_SUCCESS)
		{
			memset(_big_buf, 0, sizeof(_big_buf));
			status	= hpdi32_write(handle, _big_buf, sizeof(_big_buf), &xfer);

			if (status == GSC_WAIT_TIMEOUT)
			{
				status	= GSC_SUCCESS;
				break;
			}

			if (status == GSC_SUCCESS)
			{
				printf("(unexpected success) ");
				status	= GSC_FAILED;
				break;
			}

			if (status == GSC_INVALID_DATA)
			{
				// This is expected when Single Cycle Disable fails.
				status	= GSC_FAILED;
				break;
			}

			printf("(unexpected failure status: 0x%lX) ", (long) status);
			status	= GSC_FAILED;
		}

		break;
	}

	if (tx_info == FIFO_NONE)
	{
		errs	= 0;
		printf("SKIPPED (no Tx FIFOs)\n");
	}
	else if ((mem / _1G) >= 4)
	{
		errs	= 0;
		printf("SKIPPED (Test not supported on systems with 4G or more of memory.)\n");
	}
	else if (status != GSC_SUCCESS)
	{
		errs	= 1;
		printf("FAIL <---\n");
	}
	else if (scd != HPDI32_MISC_FEATURES_PRESENT)
	{
		errs	= 0;
		printf("SKIPPED (feature not present)\n");
	}
	else
	{
		errs	= 0;
		printf("PASS\n");
	}

	hpdi32_init(handle);
	return(errs);
}



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

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

	label_text("Special Tests");
	printf("\n");
	label_level_inc();

#if TDWODTR
// This test is skipped as we don't have sufficient information to identify
// when it should be performed (because it should pass) or skipped (because
// it is expected to fail). Plus, it doesn't occur on all systems.
//	errs	+= _fifo_write_read_tdwodtr_test(handle);
#endif

	errs	+= _rx_dmdma_single_cycle(handle);
	errs	+= _tx_dmdma_single_cycle(handle);

	label_level_dec();
	return(errs);
}


