/*********************************************************************
 *
 *  Copyright (C) 2004  Freescale Semiconductors, Inc.
 *
 ********************************************************************/
/*********************************************************************
 *  FILE: rio_tests.c
 *
 *  DESCRIPTION :
 *    Two routines to execute reads and writes to an agent's memory
 *    testa : execute 100 32-bit writes, read back and compare
 *    testb : execute a 64k byte DMA transfer to agent, DMA back and
 *     compare
 *
 * NOTES :
 *
 *
 * HISTORY
 * Version    Date     Auth.,Loc.     Comments
 *   0.1    27-Jul-04  LM, EKB       First released version
 *   0.2    14-Apr-05  LM, EKB       Updated for MPC8548 SRIO 
 ********************************************************************/

#include <common.h>
#include <syscall.h>
#include <asm-ppc/immap_85xx.h>
#include <asm-ppc/mmu.h>
#include <asm-ppc/processor.h>

//#define DEBUG
#ifdef DEBUG
	#define debug(arg...) printf(arg)
#else
	#define debug(arg...)
#endif
//#include "rio_regs.h"
#include "rio_bringup.h"
#include "srio_msgs.h"

long long tbget_start (void);
long long tbget_end (void);

extern volatile immap_t *local_imm;
extern volatile ccsr_srio_t *local_srio; 
extern volatile ccsr_local_ecm_t *local_ecm;
extern volatile srio_device_t *srio_device;

/******************************************************************
int testa(int device_id)
TestA executes 100 32-bit writes to the agent, and then 100 32-bit reads.
*******************************************************************/
int
testa (int deviceid)
{
  printf ("Running demo A for deviceid %d \n", deviceid);
   int i, failed = 0;
  u32 readback;
  volatile u32 *memptr;

 
  /*************************************************************************
  Use the srio_device[device_id].mem_block pointer to confirm that remote access to this processors
  memory has been enhabled
  *************************************************************************/
  if (srio_device[deviceid].mem_block == NULL) {
    printf ("Remote access to memory on device %d has not been enabled \n",
            deviceid);
    return 1;
  }
  else {
    printf ("Executing 100 32-bit writes into agent memory \n");
    
/*     printf ("rowbar3 = 0x%08x, rowar3 = 0x%08x, rowtar3 = 0x%08x\n",
          local_srio->rowbar3, local_srio->rowar3, local_srio->rowtar3);
	  	printf("local_srio->rows1r3 = 0x%08x @ address 0x%08x \n",local_srio->rows1r3, &local_srio->rows1r3); 
	printf("local_srio->rows2r3 = 0x%08x @ address 0x%08x \n",local_srio->rows2r3, &local_srio->rows2r3); 
	printf("local_srio->rows3r3 = 0x%08x @ address 0x%08x \n",local_srio->rows3r3, &local_srio->rows3r3); 

	printf ("Agent riwbar1=0x%08x, riwtar1=0x%08x, riwar1=0x%08x\n",
          srio_device[deviceid].srio->riwbar1, srio_device[deviceid].srio->riwtar1,
          srio_device[deviceid].srio->riwar1);
	
	printf("About to attempt to read from location 0x%08x \n",srio_device[deviceid].mem_block); 
  */  

    memptr = srio_device[deviceid].mem_block;
    /*************************************************************************
    fill 100 32-bit locations with a known data pattern
    *************************************************************************/
    for (i = 0; i < 50; i++) {
      *memptr++ = 0x55555555;
      *memptr++ = 0xaaaaaaaa;
    }

    printf ("Executing 100 32-bit reads, and comparing \n");

    /*************************************************************************
    reset the pointer back to the first location
    *************************************************************************/
    memptr = srio_device[deviceid].mem_block;

    /*************************************************************************
    read back the same 100 locations and compare with known data
    *************************************************************************/
    for (i = 0; i < 50; i++) {
      readback = *memptr++;
      if (readback != 0x55555555) {
        printf
          ("Failed at i=%d, memptr = 0x%08x. Expected 0x55555555, read back 0x%08x \n",
           i, memptr - 1, readback);
        failed = 1;
      }

      readback = *memptr++;
      if (readback != 0xaaaaaaaa) {
        printf
          ("Failed at i=%d, memptr = 0x%08x. Expectd 0xaaaaaaaa, read back 0x%08x \n",
           i, memptr - 1, readback);
        failed = 1;
      }
    }

    if (failed == 0)
      return SUCCESS;
    else
      return TEST_FAILED;
  }
}

/******************************************************************
int testb(int device_id, int size_bytes)
TestB uses the DMA to transfer a block of data between the host and agent.
*******************************************************************/
int
testb (int device_id, int size_bytes, int count, int detail)
{
   volatile ccsr_dma_t *local_dma;
   	volatile u32 *memptr;
	int i, failed = 0, c1, c2;
   	unsigned long long	timer_start = 0;		// 64-bit timer holding TBU and TBL
	long tb_time = 0;
    long * plocal_a; 
    long * plocal_b;
	u32 min=0x10000000;
	u32 max =0;
	u32 total =0;
	u32 timeout =0; 
	u32 not_valid = 0;
	u32 dot_time = 100000;


  printf ("Running demo B for deviceid %d \n", device_id);

  /******************************************************************
  set up a pointer to the dma on the host processor
  ******************************************************************/
  local_dma = &(local_imm->im_dma);
	plocal_a = (long *) MEM_LOCAL_A;   
   	plocal_b = (long *) MEM_LOCAL_B;    

  
  /*************************************************************************
  Use the srio_device[device_id].mem_block pointer to confirm that remote access to this processors
  memory has been enhabled
  *************************************************************************/
  if (srio_device[device_id].mem_block == NULL) {
    printf ("Remote access to memory on device %d has not been enabled \n",
            device_id);
    return 1;
  }
  else {
    memptr = srio_device[device_id].mem_block;

    /************************************************************************
    fill the data array with recognisable data
    ************************************************************************/
    for (i = 0; i < size_bytes >> 2; i++) {
      plocal_a[i] = (i << 16) | i;
    }

    /************************************************************************
    zero fill the array which will hold the data read back
    ************************************************************************/
    for (i = 0; i < size_bytes >> 2; i++) {
      plocal_b[i] = 0;
    }
    for (i=0; i<count;i++)
    {
		// reset DMA channel 0
		local_dma->mr0 = 0x00000008;
		local_dma->sr0 = 0x0000009B;
    	asm ("sync");
		local_dma->mr0 = 0x00000000;
	
    	if ((local_dma->sr0 & DMA_CHANNEL_BUSY) != 0)
      		printf ("Channel was busy, did not run demo \n");

    	memptr = srio_device[device_id].mem_block;

    	local_dma->satr0 = DMA_SATR_SNOOP;
    	local_dma->sar0 = plocal_a;
    	local_dma->datr0 = DMA_DATR_NWRITER;
    	local_dma->dar0 = (u32) memptr;
    	local_dma->bcr0 = size_bytes;

//    printf ("About to DMA write %d bytes to the agent \n", size_bytes);

    /*************************************************************************
    twiddle the bits in the dma registers to start the transcation
    *************************************************************************/
    	local_dma->mr0 |= DMA_CHANNEL_TRANSFER_MODE; /*direct mode */
    	asm ("sync");

    	local_dma->mr0 &= (~DMA_CHANNEL_START);
    	asm ("sync");
	
		timer_start = tbget_start();   

    	local_dma->mr0 |= DMA_CHANNEL_START;
    	asm ("sync");

    /************************************************************************
    wait for the DMA transfer to complete
    ************************************************************************/

    	while ((local_dma->sr0 & DMA_CHANNEL_BUSY) != 0) 
    	{
    		dot_time--;
    		if (dot_time == 0)
    		{	
    			debug(".");
    			dot_time = 10000;
    		}

    		;
    	}
   		tb_time = (unsigned long) (tbget_end() - timer_start);	// write time duration to array
		debug("\n");
		if (local_dma->sr0 != 0)
			printf ("local_dma->sr0 = 0x%8x\n",local_dma->sr0);
    	if (tb_time<10000000)
    		printf ("DMA write of %d bytes to the agent has completed in %d tb_clk\n",size_bytes,tb_time);

		if (tb_time>3000000)
			timeout++;
		else if (tb_time<100)
			not_valid++;
		else
		{
	   		if (tb_time<min)
	   			min=tb_time;
	   		if (tb_time>max)
				max=tb_time;
			total = total + tb_time;
		}
	}
	printf ("*******************************************************\n");
	if (detail)
	{
		printf ("timeout = %d\n",timeout);
 		printf ("not_valid = %d\n",not_valid);
    }
	printf ("DMA write of %d bytes to the agent %d times completed\n",size_bytes,count);
    printf ("min time base clocks taken = %d \n", min);
    printf ("max time base clocks taken = %d \n", max);
    debug ("total 64KB DMA NWRITE_R access time = %d tb_clk\n", total);
    printf ("average time base clocks taken = %d \n", (total/(count-timeout))+1);
	printf ("*******************************************************\n");

#if 0
	//reset DMA channel 0
	local_dma->mr0 = 0x00000008;
	local_dma->sr0 = 0x0000009B;
    asm ("sync");
	local_dma->mr0 = 0x00000000;

    /************************************************************************
    read the data back onto local_b 2
    ************************************************************************/
    local_dma->satr0 = DMA_SATR_NREAD;
    local_dma->sar0 = (u32) memptr;
    local_dma->datr0 = DMA_DATR_SNOOP;
    local_dma->dar0 = plocal_b;
    local_dma->bcr0 = size_bytes;

    /************************************************************************
    twiddle the bits in the dma registers to start the transcation
    ************************************************************************/
    local_dma->mr0 |= DMA_CHANNEL_TRANSFER_MODE; /*direct mode */

    asm ("sync");

    local_dma->mr0 &= (~DMA_CHANNEL_START);
    asm ("sync");

    timer_start = tbget_start();   
	local_dma->mr0 |= DMA_CHANNEL_START;
    asm ("sync");

    /***********************************************************************
    wait for the DMA transfer to complete
    ***********************************************************************/
    while ((local_dma->sr0 & DMA_CHANNEL_BUSY) != 0) {;
    }
   	tb_time = (unsigned long) (tbget() - timer_start);	// write time duration to array
	printf ("local_dma->sr0 = 0x%8x\n",local_dma->sr0);

    printf ("DMA transfer (read) back from host has completed in in %d tb_clk\n",tb_time);
    printf ("Comparing data sent with data received \n");

    for (i = 0; i < size_bytes >> 2; i++,plocal_b++,memptr++) {
      *plocal_b = *memptr;
    }
    for (i = 0; i < size_bytes >> 2; i++) {
      if (plocal_a[i] != plocal_b[i]) {
        if (failed!=1)	
        	printf ("\nFAILED!! when i=0x%x. Expected 0x%08x, got 0x%08x \n", i,
                plocal_a[i], plocal_b[i]);
        failed = 1;
      }
    }
#endif

      return SUCCESS;
  }
}

/******************************
latency test. single read
***************************/
int
testc (int deviceid, int count, int detail)
{
  printf ("Running demo C for deviceid %d \n", deviceid);
   int i, failed = 0;
  u32 readback;
  volatile u32 *memptr;
	u32 rmin=0x10000000, wmin=0x10000000;
	u32 rmax =0,wmax=0;
	u32 rtotal =0,wtotal=0;
	u32 rtimeout =0,wtimeout=0; 
	u32 rnot_valid = 0,wnot_valid=0;
	u32 tb_time = 0;
	u32 timer_start, timer_end; 
  /*************************************************************************
  Use the srio_device[device_id].mem_block pointer to confirm that remote access to this processors
  memory has been enhabled
  *************************************************************************/
  if (srio_device[deviceid].mem_block == NULL) {
    printf ("Remote access to memory on device %d has not been enabled \n",
            deviceid);
    return 1;
  }
  else {
#if 1
/*	printf ("*******************************************************\n");
    printf ("Executing %d single 32-bit NWRITE_R into agent memory \n", count);
*/
    memptr = srio_device[deviceid].mem_block;

    /*************************************************************************
    single write
    *************************************************************************/
    for (i = 0; i < count; i++) {
		timer_start = mfspr(SPRN_TBRL);   
      	*memptr++ = 0x55aa55aa;
		asm("msync");
		timer_end = mfspr(SPRN_TBRL);
	    printf("timer_start = %d\n", timer_start);
	    printf("timer_end = %d\n", timer_end);
	   	tb_time = timer_end - timer_start;
    	printf("tb_clk = %d \n",tb_time);
//    	printf(".");
		if (tb_time>1000)
			wtimeout++;
		else if (tb_time<1)
			wnot_valid++;
		else 
		{
	   		if (tb_time<wmin)
	   			wmin=tb_time;
	   		if (tb_time>wmax)
				wmax=tb_time;
			wtotal = wtotal + tb_time;
    	}
    }
    printf("\n");
/*
	if (detail==1)
	{
		printf ("timeout = %d\n",wtimeout);
   		printf ("not_valid = %d\n",wnot_valid);
    }
    printf ("min single NWRITE_R access time = %d time base clk\n", wmin);
    printf ("max single NWRITE_R access time = %d time base clk\n", wmax);
    printf ("total single NWRITE_R access time = %d time base clk\n", wtotal);
    printf ("average single NWRITE_R access time = %d time base clk\n", (wtotal/(count-wtimeout-wnot_valid))+1);
*/
#endif
    /*************************************************************************
    single read
    *************************************************************************/
	printf ("*******************************************************\n");
    printf ("Executing %d single 32-bit NREAD into agent memory \n", count/4);
    for (i = 0; i < count/4; i++) {
		timer_start = mfspr(SPRN_TBRL);   
      	readback = *memptr++;
		asm("msync");
		timer_end = mfspr(SPRN_TBRL);
	    printf("timer_start = %d\n", timer_start);
	    printf("timer_end = %d\n", timer_end);
	   	tb_time = timer_end - timer_start;
    	printf("tb_clk = %d \n",tb_time);
    	printf(".");
		if (tb_time>1000)
			rtimeout++;
		else if (tb_time<2)
			rnot_valid++;
		else 
		{
	   		if (tb_time<rmin)
	   			rmin=tb_time;
	   		if (tb_time>rmax)
				rmax=tb_time;
			rtotal = rtotal + tb_time;
    	}
    }
#if 1
	printf ("*******************************************************\n");
	if (detail==1)
	{
		printf ("timeout = %d\n",wtimeout);
   		printf ("not_valid = %d\n",wnot_valid);
    }
    printf ("min single NWRITE_R access time = %d time base clk\n", wmin);
    printf ("max single NWRITE_R access time = %d time base clk\n", wmax);
    printf ("total single NWRITE_R access time = %d time base clk\n", wtotal);
    printf ("average single NWRITE_R access time = %d time base clk\n", (wtotal/(count-wtimeout-wnot_valid))+1);
	printf ("*******************************************************\n");
#endif
    printf("\n");
	if (detail==1)
	{
		printf ("timeout = %d\n",rtimeout);
   		printf ("not_valid = %d\n",rnot_valid);
    }
    printf ("min single NREAD access time = %d tb_clk\n", rmin);
    printf ("max single NREAD access time = %d tb_clk\n", rmax);
    printf ("total single NREAD access time = %d tb_clk\n", rtotal);
    printf ("average single NREAD access time = %d tb_clk\n", (rtotal/(count/4-rtimeout-rnot_valid))+1);

	printf ("*******************************************************\n");
    return SUCCESS;
  }
}
  
  

/******************************
Doorbell test. Switch version only. Looped back to self 
***************************/

int doorbelltest()
{
	int txd=0, rxd=0, dest=0, data=0;
	int doorbells_to_send = 10000;
	int loopcount = 0; 
	int result; 
	u32 target_data, source_data; 
	int i; 
	
	/*while there are still doobells to be sent*/ 
	while(txd < doorbells_to_send)
	{
		loopcount++;
		result = send_db(dest, data);
		if(result == SUCCESS)
		{
				txd++;
			data++;
			loopcount=0;
		}
		
		/*check for any incoming doorbells */ 
		while(get_ib_db(&target_data, &source_data) == DOORBELL_RECEIVED)
		{
			rxd++;
		}	
		
		/*need to put some limit on this loop, so that we are 
		not stuck here forever if something goes wrong*/
		if(loopcount >  0xFFFFFF)
		{
			printf("TIMEOUT : waiting too long to send doorbell \n"); 
			return DB_TIMEOUT;
		}
		
	}
	
	printf("received %d so far, waiting for others \n", rxd); 
	for(i=0;i<0xFFFFFF;i++)
	{
		/*check for any additional incoming doobells */ 
		while(get_ib_db(&target_data, &source_data) == DOORBELL_RECEIVED)
		{
			rxd++;
		}	
		
	}
	
	
	if(txd != rxd)
	{
		printf("MISMATCH - didn't receive as many doorbells as I expected \n");
		printf("sent %d doorbells, receive %d doorbells \n", txd, rxd);  
		return DB_MISMATCH;
	}
	else
	{	printf("sent %d doorbells to myself, received %d doorbells \n", txd, rxd); 
		return SUCCESS; 
	}

	
}

#define MAX_MESSAGE_SIZE 4096

int datamessagetest(data_msg_cntrllr *local_msg_unit)
{
	int txd=0, rxd=0, i;
	u32 mcgroup, mclist;
	int messages_to_send = 10000;
	int loopcount=0; 
	int message_size = 1024; 
	int result; 
	u32 *message_in; 
	
	static u32 message_array[MAX_MESSAGE_SIZE>> 2] __attribute__ ((aligned (64))); 
	
	
			
	/*Fill the array to send with recognisable data.  */
	for(i=0;i<(MAX_MESSAGE_SIZE>>2);i++)
	{
		message_array[i] = (i);
	}
	
	mcgroup = 0;
	mclist = 0;


	/*while there are still messages to be sent*/ 
	while(txd < messages_to_send)
	{
		loopcount++;
		
		/*send a message */
		result = send_msg_ch(local_msg_unit, 0,0,message_size,0x00, (&message_array[0]), mcgroup, mclist);
	
		/* if the message was actually sent, increment the counter*/
		if(result == SUCCESS)
		{
			txd++;
			loopcount=0;
			//printf("sent messagr \n"); 
		}
		
		/*check for any incoming, release them, and increment counter*/
		while(get_ib_msg(local_msg_unit, &message_in) == MESSAGE_READ)
		{
		//	printf("received a msg\n"); 
			rxd++;
			release_ib_msg(local_msg_unit);
		//	printf("released a message\n"); 
			asm("sync");
		}

			
		/*need to put some limit on this loop, so that we are 
		not stuck here forever if something goes wrong*/
		if(loopcount >  0xFFFFFFF)
		{
			printf("Timed out after sending %d, and receiving %d \n", txd, rxd); 
			return MSG_TIMEOUT;
		}
		
			
	}
	
	printf("received %d so far, waiting for others \n", rxd); 
	for(i=0;i<0xFFFFFF;i++)
	{
		/*check for any additional incoming messages */ 
		while(get_ib_msg(local_msg_unit, &message_in) == MESSAGE_READ)
		{
			rxd++;
			release_ib_msg(local_msg_unit);
		}

	}
		for(i=0;i<0xFFFFFF;i++)
	{
		/*check for any additional incoming messages */ 
		while(get_ib_msg(local_msg_unit, &message_in) == MESSAGE_READ)
		{
			rxd++;
			release_ib_msg(local_msg_unit);
		}

	}

	
	
	if(rxd != txd)
	{
		printf("MISMATCH : Send %d, received %d \n", txd, rxd); 
		return MSG_MISMATCH;
	}
	else
	{
		printf("Sent %d messages to myself, received %d \n", txd, rxd); 
		return SUCCESS; 
	}
	

}

long long tbget_start (void)
{		
   	unsigned long	timer_H = 0;
   	unsigned long	timer_L = 0;
   	unsigned long long	ticks = 0;		// 64-bit timer holding TBU and TBL
	timer_H = mfspr(SPRN_TBRU);

    printf("timer_H = %x\t", timer_H);
   
   	ticks = (unsigned long long)(timer_H);
   	ticks <<= 32;
	timer_L = mfspr(SPRN_TBRL);

    printf("timer_L = %x\n", timer_L);
   	ticks = ticks | (unsigned long long)(timer_L);	
	return ticks;
}

long long tbget_end (void)
{		
   	unsigned long	timer_H = 0;
   	unsigned long	timer_L = 0;
   	unsigned long long	ticks = 0;		// 64-bit timer holding TBU and TBL
	timer_L = mfspr(SPRN_TBRL);
	timer_H = mfspr(SPRN_TBRU);

    printf("timer_H = %x\t", timer_H);
   
   	ticks = (unsigned long long)(timer_H);
   	ticks <<= 32;
    printf("timer_L = %x\n", timer_L);
   	ticks = ticks | (unsigned long long)(timer_L);	
	return ticks;
}
