/*******************************************************************************
  INTEL CONFIDENTIAL

  Copyright 2003 Intel Corporation All Rights Reserved.

  The source code contained or described herein and all documents related to
  the source code ("Material") are owned by Intel Corporation or its
  suppliers or licensors.

  Title to the Material remains with Intel Corporation or its suppliers and
  licensors. The Material contains trade secrets and proprietary and
  confidential information of Intel or its suppliers and licensors.
  The Material is protected by worldwide copyright and trade secret laws and
  treaty provisions. No part of the Material may be used, copied, reproduced,
  modified, published, uploaded, posted, transmitted, distributed,
  or disclosed in any way without Intel's prior express written permission.

  No license under any patent, copyright, trade secret or other intellectual
  property right is granted to or conferred upon you by disclosure
  or delivery of the Materials, either expressly, by implication, inducement,
  estoppel or otherwise. Any license under such intellectual property rights
  must be express and approved by Intel in writing.

*******************************************************************************/

/**
 * ============================================================================
 *
 * = PRODUCT
 *      Intel(r) IXA SDK for the IXP2400 Network Processor
 *
 * = FILENAME
 *      quad_gbeth_2401_linux_init.c
 *
 * = DESCRIPTION
 *
 * ============================================================================
 */

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

int rtm_routes(void);
int l2_encap_init_addresses(void);

/* 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)

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

	int cnt, 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 = get_sram(base+(index*4));
		if (value)
			continue;
		else
		{
			set_sram(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: 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;
    
}

void quad_gbeth_2401_setup(void)
{
    printf("Clearing scratch ...\n");
    init_scratch(0x0, SCRATCH_BASE, SCRATCH_BASE + SCRATCH_SIZE); //TBD tego nie ma w ind

    //-----------------------------------------------------
    //	IPV4 Forwarder stuff
    //-----------------------------------------------------
    printf("Clearing route table ...\n");
    
    rtmInit();

    
    printf("Initializing with some routes ...\n");
    
    rtm_routes(); 
    
    printf("Clearing counters in SRAM ...\n");
    
    ipv4ClearCounters();
    
    printf("Initializing the directed broadcast table ...\n");
    
    dbcast_init();

    // here, set up the control block to enable only 0-31 ports
    // for forwarding
    set_sram(_CONTROL_BLOCK_SRAM_BASE,0xffffffff);

    //-----------------------------------------------------
    //	QM Forwarder stuff
    //-----------------------------------------------------
    
    qmInit();
        
    //
    //	here add dbast entries using addresses from rtm_routes.ind
    //  file (take the destination IP address for which the 'LOCAL'
    //	flag is set, and then add corresponding network broadcast 
    //	address	for that network in the table).
    //

    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();

    //-----------------------------------------------------
    //	Done
    //------------------------------------------------------
    
    printf("\n**********************************************\n");
    printf("\n         Ethernet IPv4 System setup COMPLETE. \n");
    printf("\n**********************************************\n");

    return;
}


int main(int argc, char **argv)
{

    printf("Quad Gbeth system Linux Setup\n");

    printf("Initializing IND library.\n");
    ind_lib_start();

    printf("Initializing hardware.\n");
    printf("Resetting hardware...\n");

    printf("Initializing system.\n");

    quad_gbeth_2401_setup();    

    printf("Finishing IND library.\n");
    
    ind_lib_end();

    return 0;
}
