/**
 * ============================================================================
 * = COPYRIGHT
 *              INTEL CORPORATION PROPRIETARY INFORMATION
 *   This software is supplied under the terms of a licence agreement or
 *   nondisclosure agreement with Intel Corporation and may not be copied
 *   or disclosed except in accordance with the terms in that agreement.
 *      Copyright (C) 2003 Intel Corporation. All rights reserved.
 *
 * = PRODUCT
 *      Intel(r) IXA SDK for the IXP2X00 Network Processor
 *
 * = FILENAME
 *      quad_gbeth_2401_init.c
 *
 * = DESCRIPTION
 *      This file contains scripts to initialize the quad_gbeth_2401
 *      application on an IXPD2401 platform.
 *
 * = AUTHOR
 *      Tomasz Madajczak
 *      tomasz.madajczak@intel.com
 *
 * = CHANGE HISTORY
 *      01/22/2003      Created by Tomasz Madajczak
 * ============================================================================
 */

#include "../quad_gbeth_memory.h"
#include "xscale_init.h"

#ifdef USE_BB_DRV_CONFIG
#include "baseboard_media_drv.h"
#endif /* USE_BB_DRV_CONFIG */

/* Macro to write and read one longword from memory
   the macro assumes that the memory being read or written to
   is mapped
 */

/* Defines for MCCR register */
#define PLL_25MHZ	0x0
#define PLL_50MHZ	0x5
#define PLL_104MHZ	0xA
#define PLL_125MHZ	0xF

#define MSF_CLKCFG_MEDIA	PLL_125MHZ
#define MSF_CLKCFG_SF		PLL_125MHZ

#define MSF_CLKCFG_IN		(MSF_CLKCFG_MEDIA | (MSF_CLKCFG_SF << 4))
#define MSF_CLKCFG_EG		(MSF_CLKCFG_SF | (MSF_CLKCFG_MEDIA << 4))

#define MCCR_MASK1	0x0000F0F0 /* bypass and powerdown */
#define MCCR_MASK2	0x000000F0 /* powerdown */
#define MCCR_MASK3	0x00000000

/* Utility defines */

#ifndef NULL
#define NULL 		0
#endif

/* define for control block */
#define _CONTROL_BLOCK_SRAM_BASE (SRAM_BASE_CH0 + CONTROL_BLOCK_SRAM_BASE)

/* define for L2 MAC addresses table */
#define _L2_TABLE_SRAM_BASE (SRAM_BASE_CH0 + L2_TABLE_SRAM_BASE)

#define L2_TABLE_NUM_OF_ENTRIES	(L2_TABLE_SRAM_SIZE/32)



/* define for rtmInit */

#define	_SRAM_LOOKUP_BASE   (SRAM_BASE_CH0 + TRIE_TABLE_SRAM_BASE)
#define	_DRAM_NEXTHOP_BASE	(SDRAM_BASE + NEXTHOP_TABLE_SDRAM_BASE)
#define	_SRAM_NEXTHOP_BASE	(SRAM_BASE_CH0 + NEXTHOP_TABLE_SRAM_BASE)
#define	SIZE_OF_TRIE_SET	16
#define	NUM_TRIE_SETS		1024
#define	NUM_NEXTHOPS		512
#define	SIZE_OF_NEXTHOP		4

/* define for ipv4clear counters */
#ifndef IPV4_COUNTERS_SCRATCH
#define IPV4_COUNTERS_SCRATCH
#endif

#define	_SRAM_COUNTER_BASE	(SRAM_BASE_CH0 + STATS_TABLE_SRAM_BASE)
#define	_IPV4_COUNTER_SIZE	IPV4_STATS_TABLE_SIZE
#define _SCR_COUNTER_BASE	(SCRATCH_BASE + IPV4_STATS_TABLE_BASE)

/* define for directed broadcast dbcast_init */

#define	SRAM_READ_BLOCK_COUNT	8	/* in number of long words */
#define	SRAM_READ_SHIFT		3	/* block count is pow of 2 */
#define	DBCAST_SRAM_BASE	(SRAM_BASE_CH0 + DBCAST_TABLE_SRAM_BASE)
#define	DBCAST_NUM_BLOCKS	256
#define	DBCAST_BLOCK_SIZE	SRAM_READ_BLOCK_COUNT


/* defines for QM */

#define	_QD_SRAM_BASE		(SRAM_BASE_CH0 + QD_SRAM_BASE)
#define NUM_OF_Q		    QD_TOTAL

#define _SRAM_ZERO_BLOCK    (SRAM_BASE_CH0 + SRAM_ZERO_BLOCK)


extern int l2_encap_init_addresses(void); /* l2 addresses init routine */
extern void vinit(char mode); /* vallejo init routine */
void t_hw_init(void);
void media_reset(void);


/**
 * NAME: init_sram
 *
 * DESCRIPTION: This function initializes SRAM memory to a value
 *              in a given range
 */
void init_scratch(int data, int start_addr, int end_addr)
{
	int i;

	for(i = (start_addr ); i < (end_addr); i+=4)
		PUT32(i, data);


}

/**
 * NAME: init_sram
 *
 * DESCRIPTION: This function initializes SRAM memory to a value
 *              in a given range
 */
void init_sram(int data, int start_addr, int end_addr)
{
	int i;

	for(i = (start_addr ); i < (end_addr); i+=4)
		PUT32(i, data);


}


/**
 * NAME: init_dram
 *
 * DESCRIPTION: This function initializes DRAM memory to a value
 *              in a given range
 */
void init_dram(int data, int start_addr, int end_addr)
{
	int i;

	for(i = (start_addr ); i < (end_addr); i+=4)
		PUT32(i, data);


}


/**
 * NAME: l2_encap_init
 *
 * DESCRIPTION: This function initializes memory for L2 table
 */
int l2_encap_init(void) {

	int finaladdr;

	printf("l2_encap_init()	: Initializing L2 Table SRAM memory :=..\n");

	finaladdr = _L2_TABLE_SRAM_BASE + L2_TABLE_SRAM_SIZE;

	printf("Clearing SRAM ...");
	init_sram(0x0,_L2_TABLE_SRAM_BASE,finaladdr);

	printf("L2 table memory initialization COMPLETE.\n\n");

	return 1;

}


/**
 * NAME: rtmInit
 *
 * DESCRIPTION: This function initializes memory for RTM table
 */
int rtmInit(void) {

	int cnt, index,addr;
	int baseaddr;

	printf("rtmInit()	: Initializing RTM memory :=..\n");

	baseaddr = _SRAM_LOOKUP_BASE;
	cnt = 64 * 1024 + 256 + SIZE_OF_TRIE_SET * NUM_TRIE_SETS;
	addr = baseaddr + (cnt * 4);/* this gives 324704 bytes of memory */

	printf("Clearing SRAM ...");
	init_sram(0x0,baseaddr,addr);

	baseaddr = _DRAM_NEXTHOP_BASE;
	cnt = NUM_NEXTHOPS * SIZE_OF_NEXTHOP * 4;
	addr = baseaddr + cnt;

	printf("Clearing DRAM nexthop info...");
	init_dram(0x0,baseaddr,addr);

	printf("RTM memory initialization COMPLETE.\n\n");

	return 1;
}

/**
 * NAME: ipv4ClearCounters
 *
 * DESCRIPTION: This function initializes  memory for IPV4 counters
 */
int ipv4ClearCounters(void){

	int addr_lo,addr_hi;

#ifdef IPV4_COUNTERS_SCRATCH

	addr_lo = _SCR_COUNTER_BASE;
	addr_hi = _SCR_COUNTER_BASE + _IPV4_COUNTER_SIZE;

    init_scratch(0x0,addr_lo,addr_hi);

#else
	addr_lo = _SRAM_COUNTER_BASE;
	addr_hi = _SRAM_COUNTER_BASE + _IPV4_COUNTER_SIZE;

	init_sram(0x0,addr_lo,addr_hi);
#endif

	return 1;
}


/**
 * NAME: dbcast_init
 *
 * DESCRIPTION: This function initializes  memory for directed broadcast
 */
int dbcast_init(void){

	int size, low, high;

	size = DBCAST_NUM_BLOCKS * SRAM_READ_BLOCK_COUNT * 4; /* = 0x2000 */

	low = DBCAST_SRAM_BASE;
	high = low+size;

	init_sram(0x0,low,high);

	return 1;
}

/**
 * NAME: dbcast_add
 *
 * DESCRIPTION: This function adds entries for directed broadcast
 */
int	dbcast_add(int ipAddr){

	int hash_result, base, index, value;


	hash_result = (ipAddr) ^ (ipAddr >> 8) ^ (ipAddr >> 16) ^ (ipAddr>>24);

	hash_result = hash_result & 0xff;


	base = DBCAST_SRAM_BASE + (hash_result << SRAM_READ_SHIFT) * 4;

	for (index=0;index<SRAM_READ_BLOCK_COUNT-1;index++)
	{
		value = GET32(base+(index*4));
		if (value)
			continue;
		else
		{
			PUT32(base+(index*4),ipAddr);
			printf("Added 0x%x to DBCAST table at 0x%x\n",
				ipAddr,base+(index*4));
			break;
		}

	}

	if (index == (SRAM_READ_BLOCK_COUNT-1))
		printf("DBCAST table is full. Can't add 0x%x\n",ipAddr);

	return 1;
}


/**
 * NAME: qmInit
 *
 * DESCRIPTION: This function initializes  memory for QM
 */
int qmInit(void) {

	int finaladdr;
	int baseaddr;

	printf("qmInit()	: Initializing QM SRAM memory :=..\n");

	baseaddr = _QD_SRAM_BASE;
	finaladdr = baseaddr + NUM_OF_Q*16 ;

	printf("Clearing SRAM ...");
	init_sram(0x0,_QD_SRAM_BASE,finaladdr);

	printf("QM memory initialization COMPLETE.\n\n");

	printf("Clearing SRAM for scheduller ...");
	finaladdr = _SRAM_ZERO_BLOCK + SRAM_ZERO_BLOCK_SIZE;
	init_sram(0x0,_SRAM_ZERO_BLOCK,finaladdr);

	printf("Scheduller memory initialization COMPLETE.\n\n");

	return 1;
}


/**
 * NAME: ixdp2401_system_setup
 *
 * DESCRIPTION: This function sets up the memory for an ixdp2401 system
 * processor for the quad_gbeth_2401 application
 */
int ixdp2401_system_setup(void)
{

    printf("\n**********************************************\n");
    printf("\n        IXDP2401 System setup begin ...       \n");
    printf("\n**********************************************\n");

    /*media_reset();*/

    printf("Clearing scratch ...\n");
    init_scratch(0x0, SCRATCH_BASE, SCRATCH_BASE + SCRATCH_SIZE);

    /* Initializing the route tables */

    printf("Clearing route table ...\n");

    rtmInit();

    printf("Initializing with some routes ...\n");

    rtm_routes();

    /*  clearing counters  */

    printf("Clearing IPv4 counters  ...\n");

    ipv4ClearCounters();

    printf("Initializing the directed broadcast table ...\n");

    dbcast_init();

    PUT32(_CONTROL_BLOCK_SRAM_BASE,0xffffffff);

    /* qm initialization */

    qmInit();

    dbcast_add(0x1affffff);

    dbcast_add(0x1a86ffff);

    dbcast_add(0x1a877fff);

    dbcast_add(0x1887ffff);

    dbcast_add(0x18870aff);

    dbcast_add(0x18870a00);

    /* L2 table initialization */

    l2_encap_init();

    l2_encap_init_addresses();


    printf("\n**********************************************\n");
    printf("\n       IXDP2401 System setup COMPLETE.        \n");
    printf("\n**********************************************\n");

    return 0 ;

}


/**
 * NAME: system_setup
 *
 * DESCRIPTION: This function sets up the all necessary setting for an ixdp2401
 * system
 */
int system_setup(char mode)
{
    /* Resetting the media everytime the app is restarted */

    /*t_hw_init();
      msf_pll();*/
#if ((defined IX_PLATFORM_2401) || (defined IX_PLATFORM_2801))
#ifdef USE_BB_DRV_CONFIG
#if (_IX_OS_TYPE_ == _IX_OS_VXWORKS_)
	Bb_DriverStart("", "", "spi0;spi1;spi2;spi3;sphy;125mhz");
#endif /* _IX_OS_TYPE_ == _IX_OS_VXWORKS_ */
#endif /* USE_BB_DRV_CONFIG */
#endif /* IX_PLATFORM_2x01 */

    printf("Resetting MSF.\n");
    media_reset();

    ixdp2401_system_setup();

    /* Initialize the vallejo PHY */
    vinit(mode);

    /* Then initialze the memory of the IXP */
    /*ixdp2401_system_setup();*/
#if ((defined IX_PLATFORM_2401) || (defined IX_PLATFORM_2801))
#ifdef USE_BB_DRV_CONFIG
#if (_IX_OS_TYPE_ == _IX_OS_VXWORKS_)
	Bb_DriverStop();
#endif /* _IX_OS_TYPE_ == _IX_OS_VXWORKS_ */
#endif /* USE_BB_DRV_CONFIG */
#endif /* IX_PLATFORM_2x01 */

    return 0;
}


/**
 * NAME: msf_init
 *
 * DESCRIPTION: This function will initialize the the MSF RBUF and enable it
 */
void msf_init(void)
{

	/* Setting RESET_0 CAP CSR. */
	PUT32(0xc0004a0c,0x208080);
	PUT32(0xc0004a0c,0x208000);

    /* This is a Vxworks delay routine
       and is OS dependent */

    taskDelay(10);
}

/**
 * NAME: media_reset
 *
 * DESCRIPTION: This routine resets media settings and MSF on the ingress
 */
void media_reset(void)
{
	int tries, i;
	int a ;

	/* Initialize MSF */
	msf_init();

	/* MSF PLL 125MHz */
	if(msf_pll() != 0)
    	printf("Setting PLL CLK Error\n");


	/* Flush RBUF elements that might contain packets from media card buffer */
	/* Repeat 100 times for now */
	for(tries = 0; tries < 100; tries++ )
	{
		for(i =0; i < 64; i++ )
			PUT32(0xc8000000 + 0x44, i);
	}
}


/**
 * NAME: media_egress__reset
 *
 * DESCRIPTION: This routine resets  MSF on the egress processor
 */
void media_egress_reset(void)
{

	int a ;

	/* Setting RESET_0 CAP CSR. */
	PUT32(0xc0004a0c,0x208080) ;
	PUT32(0xc0004a0c,0x208000) ;

	/* MSF PLL 125MHz */
	a = msf_pll_egress() ;


        /* This is a Vxworks delay routine
        and is OS dependent */

        taskDelay(1) ;

}


/**
 * NAME: l_sleep
 *
 * DESCRIPTION: Obsolete function.
 */
void l_sleep(void)
{
	int i ;
	for(i=0; i<10000; i++) ;
}


/**
 * NAME: media_workaround
 *
 * DESCRIPTION: Obsolete function. This routine is the media workaround for getting rid of spurious packets.
 */
void media_workaround(void)
{
	int tries, i ;

	t_hw_init() ;

	msf_init() ;


	for(tries =0 ; tries < 10 ; tries++ )
	{

		t_hw_init() ;

		msf_init() ;

		l_sleep() ;
		for(  i =0; i <64 ; i++ )
			PUT32(0xc8000000 + 0x44, i);

	}
}


/**
 * NAME: t_hw_init
 *
 * DESCRIPTION: Obsolete function.
 */
void t_hw_init(void)
{
	int a ;

	/* Bring MSF out of Reset */
	PUT32(0xc0004a0c,0x208080) ;
	PUT32(0xc0004a0c,0x208000) ;

	/* MSF PLL 105MHz */
	/*	a = msf_pll() ; */


	/* RCOMP OVERRIDE */
	/* PUT32(0xc8000000 + 0xfc,0x15291e) ; */
	/* PUT32(0xc8000000 + 0xf8,0x15291e) ; */


}


/**
 * NAME: t_hw_egress_init
 *
 * DESCRIPTION: Obsolete function.
 */
void t_hw_egress_init(void)
{
	int a ;

	/* Bring MSF out of Reset */
	PUT32(0xc0004a0c,0x208080) ;
	PUT32(0xc0004a0c,0x208000) ;

	/* MSF PLL 105MHz */
	/* a = msf_pll_egress() ; */


	/* RCOMP OVERRIDE */
	/* PUT32(0xc8000000 + 0xfc,0x15291e) ; */
	/* PUT32(0xc8000000 + 0xf8,0x15291e) ; */


}

int msf_pll(void)
{
	 unsigned int temp_val;
	unsigned int freq;


#if ((defined IX_PLATFORM_2401) || (defined IX_PLATFORM_2801))

#ifdef USE_BB_DRV_CONFIG
	int	bb_handle;
	bb_handle = Bb_Open();

	if(((freq = Bb_GetSpiClk(bb_handle, BB_DB0)) == BB_FAILURE) || (freq == BB_CLK_UNKNOWN))
		if(((freq = Bb_GetSpiClk(bb_handle, BB_DB1)) == BB_FAILURE) || (freq == BB_CLK_UNKNOWN))
			if(((freq = Bb_GetSpiClk(bb_handle, BB_VAL)) == BB_FAILURE) || (freq == BB_CLK_UNKNOWN))
			{
        	 	printf("Freqency for DB0, DB1 or VAL doesn't set!!!\n");
				return -1;
			}

   switch(freq)
   {
		case	BB_CLK_50MHz	:	freq = (PLL_50MHZ | (PLL_50MHZ << 4));
									printf("Setting PLL CLK 50MHz\n");
									break;
		case	BB_CLK_104MHz	:	freq = (PLL_104MHZ | (PLL_104MHZ << 4));
									printf("Setting PLL CLK 104MHz\n");
									break;
		case	BB_CLK_125MHz	:	freq = (PLL_125MHZ | (PLL_125MHZ << 4));
									printf("Setting PLL CLK 125MHz\n");
									break;
		case	BB_CLK_133MHz	:	/*freq = (PLL_133MHZ | (PLL_133MHZ << 4));*/
									printf("PLL CLK 133MHz doesn't known!!!\n");
									return -1;
									break;
		default					:	printf("Unknown freqency for DB0, DB1 or VAL!!!\n");
									return -1;
   }

   Bb_Close(bb_handle);

#else /* USE_BB_DRV_CONFIG */
    freq = MSF_CLKCFG_IN;
#endif /* USE_BB_DRV_CONFIG */

#else /*IX_PLATFORM_2x01 */
	/* Orginal code */
	freq = MSF_CLKCFG_IN;
#endif /*IX_PLATFORM_2x01 */

	temp_val = ((unsigned int) MCCR_MASK1 | (freq << 16));
	/*printf("Writing 0xC0004A08 with 0x%X\n", temp_val);*/
	PUT32(0xC0004A08, temp_val);

	temp_val = ((unsigned int)MCCR_MASK2 | (freq << 16));
	/*printf("Writing 0xC0004A08 with 0x%X\n", temp_val);*/
	PUT32(0xC0004A08, temp_val);

	temp_val = ((unsigned int)MCCR_MASK3 | (freq << 16));
	/*printf("Writing 0xC0004A08 with 0x%X\n", temp_val);*/
	PUT32(0xC0004A08, temp_val);

	return 0 ;
}


int msf_pll_egress(void)
{
	 unsigned int temp_val;
	unsigned int freq;


	freq = MSF_CLKCFG_EG;
	temp_val = ((unsigned int) MCCR_MASK1 | (freq << 16));
	printf("Writing 0xC0004A08 with 0x%X\n", temp_val);
	PUT32(0xC0004A08, temp_val);

	temp_val = ((unsigned int)MCCR_MASK2 | (freq << 16));
	printf("Writing 0xC0004A08 with 0x%X\n", temp_val);
	PUT32(0xC0004A08, temp_val);

	temp_val = ((unsigned int)MCCR_MASK3 | (freq << 16));
	printf("Writing 0xC0004A08 with 0x%X\n", temp_val);
	PUT32(0xC0004A08, temp_val);

	return 0 ;
}


/*****************************************************
             SOME UTILITIES
*****************************************************/
#ifdef IPV4_COUNTERS_SCRATCH
  #define  IPV4_COUNTERS_BASE           _SCR_COUNTER_BASE
#else
  #define  IPV4_COUNTERS_BASE           0x90200000
#endif

#define BUFFER_SIZE                     2048
#define META_SIZE                       32
#define _BUF_SDRAM_BASE                 SDRAM_BEGIN

/* offsets of counters in big_endian format.*/
/*/	Packets Rxed */
#define	OFFSET_PKTS_RX			0
/*/	Packets Fwd */
#define	OFFSET_PKTS_FWD			4
/*/	Packets dropped */
#define	OFFSET_PKTS_DROP		8
/*	Packets excp */
#define	OFFSET_PKTS_EXCP		12
/*/	pkts bad cksum */
#define	OFFSET_PKTS_BAD_HDR		16
/*/	pkts bad len */
#define	OFFSET_PKTS_BAD_LEN		20
/*/	pkts with bad TTL */
#define	OFFSET_PKTS_BAD_TTL		24
/*/ packets with no route */
#define	OFFSET_PKTS_NO_ROUTE    	28
/*/ packets too small */
#define	OFFSET_PKTS_TOO_SMALL   	32

/**
 * NAME: read_ipv4_counters
 *
 * DESCRIPTION: This function reads IPv4 counters
 */
int read_ipv4_counters(void)
{

	printf("NUM_PKTS_RX       =%d \n",( unsigned int) *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_RX      ) ) ) ;
	printf("NUM_PKTS_FWD      =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_FWD     ) ) ) ;
	printf("NUM_PKTS_DRO      =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_DROP    ) ) ) ;
	printf("NUM_PKTS_EXCEP    =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_EXCP    ) ) ) ;
	printf("NUM_PKTS_BAD_HDR  =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_HDR ) ) ) ;
	printf("NUM_PKTS_BAD_LE   =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_LEN ) ) ) ;
	printf("NUM_PKTS_BAD_TTL  =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_TTL ) ) ) ;
	printf("NUM_PKTS_NO_ROUTE =%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_NO_ROUTE) ) ) ;
	printf("NUM_PKTS_TOO_SMALL=%d \n",( unsigned int)*(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_TOO_SMALL) ) ) ;

	return 0;
}

/**
 * NAME: read_meta_data
 *
 * DESCRIPTION: This function reads the meta data. The input parameter is the buffer handle or SRAM address in LW.
 */
int read_meta_data( unsigned int *bufhandle )
{
	int *temp ;

	if( bufhandle == NULL )
	{
		printf("Enter buffer handle \n") ;
		return 1 ;
	}

	bufhandle = (unsigned int * )( (( (unsigned int )bufhandle) & ((unsigned int ) 0x00ffffff)) << 2 );
	bufhandle = (unsigned int * ) (  (unsigned int )bufhandle |  (unsigned int ) SRAM_BASE_CH0 ) ;

	printf("The SRAM Address for meta data is = 0x%x\n", (unsigned int) bufhandle) ;

	printf("Buffer_NEXT        =0x%x\n",  *(bufhandle +0)                     ) ;

	printf("Buffer_SIZE        =%d\n",   (*(bufhandle+1) >> 16)               ) ;
	printf("Buffer_Data_Offset =0x%x\n", (*(bufhandle+1) & 0x0000ffff)        ) ;

	printf("Buffer_PKT_SIZE    =%d\n",   (*(bufhandle+2) >> 16 )              ) ;
	printf("Buffer_FREE_LIST_ID=%d\n",   (*(bufhandle+2) & 0x0000f000) >> 12  ) ;
	printf("Buffer_RX_STAT     =%d\n",   (*(bufhandle+2) &0x00000f00) >> 8    ) ;
	printf("Buffer_HEADER_TYPE =%d\n",   (*(bufhandle+2) & 0x000000ff)        ) ;

	printf("Buffer_INPUT_PORT  =%d\n",   (*(bufhandle+3) >> 16)               ) ;
	printf("Buffer_OUTPUT_PORT =%d\n",   (*(bufhandle+3) & 0x0000ffff)        ) ;

	printf("Buffer_NEXTHOP_ID  =%d\n",   (*(bufhandle+4) >> 16)               ) ;
	printf("Buffer_FABRIC_PORT =%d\n",   (*(bufhandle+4) & 0x0000ff00) >> 8   ) ;

	printf("Buffer_FLOW_ID     =%d\n",   *(bufhandle +5 )                     ) ;

	printf("Buffer_CLASS_ID    =%d\n",   *(bufhandle+6) >> 16                 ) ;

	printf("Buffer_PKT_NEXT    =0x%x\n", *(bufhandle+7)                       ) ;

	return 0 ;

}

/**
 * NAME: read_pkt_data
 *
 * DESCRIPTION: This function reads the packet data. The input parameter is the buffer handle or SRAM address in LW.
 *              If the buffer size or meta data size or dram_base change just change the definitions above.
 */
int read_pkt_data( unsigned int *bufhandle )
{

	unsigned int * temp ;
        unsigned int ratio  ;
        unsigned int * dataptr ;
	unsigned int offset = 0 ;
	int i ;

	if( bufhandle == NULL )
	{
		printf("Enter buffer handle \n") ;
		return 1 ;
	}


        /* calculate the data offset from meta data */

	temp = (unsigned int * ) ((( (unsigned int )bufhandle) & ((unsigned int ) 0x00ffffff)) << 2 );
	temp = (unsigned int * ) (  (unsigned int )temp |  (unsigned int ) SRAM_BASE_CH0 ) ;
	offset = (*(temp+1) & 0x0000ffff) ;

	printf("Offset at given dram address is 0x%x \n", offset) ;

        /* calculate the ratio. It is 0x100 in the default configuration */
        ratio = (BUFFER_SIZE/META_SIZE) * 4 ;

        /* calculate the data pointer in DRAM */
        dataptr = bufhandle ;
	dataptr = (unsigned int * ) (( (unsigned int )dataptr) & ((unsigned int ) 0x00ffffff)) ;
	dataptr = (unsigned int * ) ((unsigned int ) dataptr *  (unsigned int ) ratio) ;
	dataptr = (unsigned int * ) ((unsigned int )_BUF_SDRAM_BASE + (unsigned int )dataptr + offset) ;

	printf("Pkt data address in DRAM is 0x%x \n", (unsigned int ) bufhandle ) ;

	printf("Printing the first 64  Bytes......\n");
	for(i=0; i<16; i++ )
	{
		printf("0x%x\n", *(dataptr) );
		bufhandle += 1 ;
	}

	return 0 ;


}

/**
 * NAME: read_pkt
 *
 * DESCRIPTION: This function reads the meta data and also prints the first 64bytes of the packet.
 *              The input parameter is the buffer handle or SRAM address in LW.
 */
int read_pkt( unsigned int *bufhandle)
{
	read_meta_data(bufhandle) ;
	read_pkt_data(bufhandle) ;

	return 0 ;

}

/**
 * NAME: read_scratch_reg
 *
 * DESCRIPTION: This function reads the scratch ring CSR register given the ring number
 */
int read_scratch_reg(unsigned int *ring_number)
{
   unsigned int *scratch_base, *ring_address ;

   if( (unsigned int ) ring_number < 0x10 )
   {
	scratch_base = (unsigned int *) 0xc0004800 ;

	ring_address = (unsigned int *) ((unsigned int ) scratch_base + (( unsigned int ) ring_number * 4) );

	printf(" Scratch Ring %d.....\n", (unsigned int ) ring_number) ;
	printf("    Base Address...0x%x\n", *(ring_address) )  ;
	ring_address += 1 ;
	printf("    Head Pointer...0x%x\n", *(ring_address) ) ;
	ring_address += 1 ;
	printf("    Tail Pointer...0x%x\n", *(ring_address) ) ;


   }


   return 0 ;

}

/**
 * NAME: read_rbuf
 *
 * DESCRIPTION: This function reads rbuf given the element size and the element number
 *              By default it will read element 0
 */
int read_rbuf( unsigned int *element_num, unsigned int rbuf_size)
{

	int i ;

	unsigned int *rbuf_base, *rbuf_add ;

	if( rbuf_size  <= 64  )
	{
		printf("Assuming rbuf_size to be 128\n") ;
		rbuf_size = 128 ;
	}

	rbuf_base = (unsigned int *) 0xc8002000 ;

	rbuf_add = ( unsigned int * ) ( ( unsigned int ) rbuf_base + ( ((unsigned int ) element_num ) * rbuf_size));

	printf("Printing the Rbuf data at address 0x%x......\n", (unsigned int) rbuf_add);

	for(i=0; i<32; i++ )
	{
		printf("0x%x\n", *(rbuf_add) );
		rbuf_add += 1 ;
	}

	return 0 ;
}

/**
 * NAME: read_scratch_full_reg
 *
 * DESCRIPTION: This function reads the scratch full CSR register
 */
int read_scratch_full_reg(void)
{
	int i;

	i = GET32(0xd6000058) ;

	printf("Scratch ring full register value is = 0x%x\n", i) ;

	return 0 ;

}

/**
 * NAME: clear_ipv4_counters
 *
 * DESCRIPTION: This function clears the ipv4 counters
 */
int clear_ipv4_counters(void)
{

        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_RX      ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_FWD     ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_DROP    ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_EXCP    ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_HDR ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_LEN ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_BAD_TTL ) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_NO_ROUTE) )  = 0 ;
        *(( unsigned int *) (IPV4_COUNTERS_BASE + OFFSET_PKTS_TOO_SMALL) ) = 0  ;

        printf("IPV4 Counters Reset \n") ;


        return 0 ;

}

/**
 * NAME: read_all_utils
 *
 * DESCRIPTION: This function prints all the utilities available
 */
int read_all_utils(void)
{
	printf("1. read_ipv4_counters()...........\n");
	printf("2. read_meta_data(buf_handle).....\n");
	printf("3. read_pkt_data(buf_handle)......\n");
	printf("4. read_pkt(buf_handle).....................\n");
	printf("5. read_rbuf(element_num, element_size)..default element size is 128....\n");
	printf("6. read_scratch_reg()... \n");
	printf("7. read_scratch_full_reg()..................\n") ;
	printf("8. clear_ipv4_counters()....................\n");

	return 0 ;
}

