////////////////////////////////////////////////////////////////////////////////////////////
//                                                                      
//                  I N T E L   P R O P R I E T A R Y                   
//                                                                      
//     COPYRIGHT (c)  2001 BY  INTEL  CORPORATION.  ALL RIGHTS          
//     RESERVED.   NO  PART  OF THIS PROGRAM  OR  PUBLICATION  MAY      
//     BE  REPRODUCED,   TRANSMITTED,   TRANSCRIBED,   STORED  IN  A    
//     RETRIEVAL SYSTEM, OR TRANSLATED INTO ANY LANGUAGE OR COMPUTER    
//     LANGUAGE IN ANY FORM OR BY ANY MEANS, ELECTRONIC, MECHANICAL,    
//     MAGNETIC,  OPTICAL,  CHEMICAL, MANUAL, OR OTHERWISE,  WITHOUT    
//     THE PRIOR WRITTEN PERMISSION OF :                                
//                                                                      
//                        INTEL  CORPORATION                            
//                                                                     
//                     2200 MISSION COLLEGE BLVD                        
//                                                                      
//               SANTA  CLARA,  CALIFORNIA  95052-8119                  
//                                                                 
//
// Change History
// --------------
//
// Date			Description											Whom
// ------------------------------------------------------------------------------------
//
// 11/11/01    	Created for IXP2400								Uday Naik
//
//
////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Flow Control Handling Routines
//
//
////////////////////////////////////////////////////////////////////////////////////////////

#include <ixp.h>

// header file with constants for algorithm

#include "scheduler.h"

////////////////////////////////////////////////////////////////////////////////////////////

// Offset of the flow control fifo

#define FCIFIFO 0x100

////////////////////////////////////////////////////////////////////////////////////////////
//
//
// HandleFlowControl:
//
//	  Handle Flow Control Messages from the Fabric
//
//    This runs in one single thread and handles flow control 
//	  messages coming in from the Fabric
//
//    Each frame has atleast n messages of 1 word each. Additional there is 
//    a payload length (16 bits) and vertical parity (16 bits)
//
//
//  Flow Control Word 1
// 
//  |----------------------------------------------------------------------|
//  |	xxxxxxxx | PayloadLength | xxxx	    | Class   | xxxxxxx | On/Off   |
//  |	(31..24) | (16..23)	     | (15..12)	| (8..11) | (7..1)  | (0)      |
//  |----------------------------------------------------------------------|
//
//
//  Flow Control Word 2
//
//  |------------------------------------------------------------------|
//  |	xxxxxxxx | Port Number   | Next Message (or vertical parity)   |
//  |	(31..22) | (16..21)	     |    (0..15)				     	   |
//  |------------------------------------------------------------------|
//
//
//  Flow Control Word 3..n (last word has vertical parity)
//
//  |------------------------------------------------------------------|
//  |	xxxxxxxx | Port Number   | Next Message (or vertical parity)   |
//  |	(31..22) | (16..21)	     |    (0..15)				     	   |
//  |------------------------------------------------------------------|
//
//  
// 
//
////////////////////////////////////////////////////////////////////////////////////////////
//
// handle a single flow control message
//
////////////////////////////////////////////////////////////////////////////////////////////


INLINE static void SchedulerHandleMessage(uint32_t msg1, uint32_t msg2)
{	
	
	uint32_t 	queueGroupNumber;
	uint32_t		queueNumber;
	
	// declare a pointer to the queue group structure 

	__declspec(local_mem shared aligned(16)) queue_group_t* pQueueGroup;

	// find the queue group from 0..31 

	queueGroupNumber = (msg2 >> 17) & 0x1f;

	// find the queue number from 0..31 within a group 

	queueNumber = ((msg1 >> 8) & 0xf) | ((msg2 & 0x10000) >> 12);

	// find the byte position in local memory  with bit vector for queue id
	// read the local memory word
		
	// get a pointer to the queue group structure 

	pQueueGroup = &globalQueueGroups[queueGroupNumber];
	
	// check if flow control is on or off. If bit is 
	// is set then flow control is off else on

	if (msg1 & 0x1)
	{
		// flow control is off. So turn it off within the queuegroup

		pQueueGroup->flowControlVector |= ( 1 << queueNumber);

		// Set the bit in the parent vector. Actually we only need
		// to do this if it is zero. Rather than check for it, we 
		// we just set it
	
		globalRootFlowControlVector |= (1 << queueGroupNumber);
	}
	else
	{
		// flow control is off. So turn if off within group
		
		pQueueGroup->flowControlVector &= ~(1 << queueNumber);

		// If flow control vector is 0, clear the bit in parent

		if (!pQueueGroup->flowControlVector)
			globalRootFlowControlVector &= ~(1 << queueGroupNumber);
	}
		
}

///////////////////////////////////////////////////////////////////////////////////////////
// 
// flow control thread
//
///////////////////////////////////////////////////////////////////////////////////////////

INLINE void SchedulerHandleFlowControl(void)
{

	int									numberOfMessages;
	SIGNAL								sig_flowControl;
	volatile void*						address = (volatile void*) FCIFIFO;
	uint32_t								msg1;
	__declspec(sram_read_reg)			uint32_t	msg[2];

	// swap out waiting for a signal from the scheduler thread to finish
	// initialization

	wait_for_all(&sig_initDone);

	// In an infinite loop process flow control messages 

	while (1)
	{
	
		// Read the flow control message (2 words) from the FIFO

		msf_read(msg, address, 2, ctx_swap, &sig_flowControl);

		// Extract the number of messages in this aggregated message

		numberOfMessages = (msg[0] >> 16) / 4;

		msg1 = msg[0];

		// Handle one aggregated message consisting of one or more messages

		while (1)
		{

			// handle a message 

			SchedulerHandleMessage(msg1, msg[1]);

			numberOfMessages--;
		
			// The second word becomes the start of the message 

			msg1 = msg[1];
			
			// if there are more messages left then read one more word into the second xfer
			// register

			if (numberOfMessages == 0)
				break;
			else
				msf_read(&msg[1], address, 1, ctx_swap, &sig_flowControl);

		} 
	}
}

////////////////////////////////////////////////////////////////////////////////////////////














