////////////////////////////////////////////////////////////////////////////////////////
//
//
//                  I N T E L   P R O P R I E T A R Y
//
//     COPYRIGHT [c]  2002 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
//
////////////////////////////////////////////////////////////////////////////////////////
//
//
//      File Name: qm_internal.c
//
//      Purpose: utility functions for queue manager 
//
//		
////////////////////////////////////////////////////////////////////////////////////////

#include "qm_packet.h"

////////////////////////////////////////////////////////////////////////////////////////
//
// QmReadEnqueueRequest()
//
// Description:
//
//		Read the Enqueue Request 
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmReadEnqueueRequest(__declspec(sram_read_reg) qm_enq_msg_t  *enqueueMessage)			
{

	// Read enqueue scratch requeust
							 
	scratch_get_ring(
						(void *) enqueueMessage, 
						(volatile __declspec(scratch) int *) ENQ_RING_NUMBER, 
						sizeof(*enqueueMessage)/sizeof(uint32_t), 
						sig_done, 
						&sig_enqReadDone
					);
}

////////////////////////////////////////////////////////////////////////////////////////
//
// QmReadDequeueRequest()
//
// Description:
//
//		Read the Dequeue Request 
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmReadDequeueRequest(__declspec(sram_read_reg) uint32_t  *dequeueMessage)			
{

	// Read enqueue scratch requeust
							 
	scratch_get_ring(
						(void *) dequeueMessage, 
						(volatile __declspec(scratch) int *) DEQ_RING_NUMBER, 
						1, 
						sig_done, 
						&sig_deqReadDone
					);
}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmNextNeighborRingInit()
//
//	 	Description: 
//
//		Initialize the next neighbour ring
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmNextNeighborRingInit(void)
{

	// initialization
	// bit 20 in CTX_ENABLE - NN_MODE = 0 : next neighbor register are written
	//                                      by previous ME 
	// bits [19:18] in CTX_ENABLE - NN_RING_EMPTY = 0 : NN_EMPTY asserts when
	//                                                  NN_PUT == NN_GET
	// bits [15:8] CTX enables for contexts 0 to 7
	// initialize local csr CTX_ENABLES to 0xFF00, local csr NN_PUT and NN_GET
	// to 0

	local_csr_write(local_csr_ctx_enables, 0xFF00);  
	local_csr_write(local_csr_nn_put, 0);			
    local_csr_write(local_csr_nn_get, 0);			
		
}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmReadQueueDescriptor()
//
//	 	Description: 
//
//		This routine reads from the queue descriptor from SRAM into
//		the Q_Array
//
//	 	Outputs:
//					
//			pQueueCount					Returns the queue count  
//
//		Inputs
//
//	    	queueNumber					Queue Number for queue 
//			queueArrayEntryNumber		QArray entry number where this queue is cached
//			sig_readQueueDescriptor 	signal 
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmReadQueueDescriptor
(
	uint32_t							queueNumber,
	uint32_t 							queueArrayEntryNumber,  
	SIGNAL 								*sig_readQueueDescriptor,
	__declspec(sram_read_reg) uint32_t  *pQueueCount
)
{

	qm_q_desc_t	readQueueDescriptor = {0};

	// Set up the channel number, queue array entry and base address of queue descriptor 

	readQueueDescriptor.channel 			= CHANNEL_NUMBER;
	readQueueDescriptor.qArrayEntryNumber 	= queueArrayEntryNumber;
	readQueueDescriptor.address				= (QD_SRAM_BASE >> 2) + (queueNumber << 2);


	// read the head of the  queue descriptor from the sram.

	sram_read_qdesc_head( pQueueCount, (void*) readQueueDescriptor.value, 2, sig_done, 
						  sig_readQueueDescriptor );

	__implicit_read(pQueueCount);

	// read the tail 

	sram_read_qdesc_other((void*) readQueueDescriptor.value);

}
 
/////////////////////////////////////////////////////////////////////////////////////////
//
// QmWriteQueueDescriptor()
//
// Description: 
//
//		This routine writes the QD from the Q_Array to SRAM.
//
//	Inputs
//
//		queueNumber			queue number	
//		channel				sram channel
//		qArrayEntry			queue Array Entry 
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmWriteQueueDescriptor
(
	uint32_t	queueNumber,
	uint32_t	qArrayEntryNumber
)
{
	qm_q_desc_t	queueDescriptor = {0};

	// Set up the channel number, queue array entry and base address of queue descriptor 

	queueDescriptor.channel 			= CHANNEL_NUMBER;
	queueDescriptor.qArrayEntryNumber 	= qArrayEntryNumber;
	queueDescriptor.address				= (QD_SRAM_BASE >> 2) + (queueNumber << 2);

	// write the complete queue descriptor to sram.

	sram_write_qdesc((void*) queueDescriptor.value) ;

}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmCellEnqueue()
//
// Description: 
//
//		This is the enqueue routine used to enqueue an address. This routine is
// 		for cell based enqueuing in which we might have to link the EOP handle of
// 		the chained buffer.
//
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmCellEnqueue
(
	dl_buf_handle_t 	sopHandle, 
	dl_buf_handle_t 	eopHandle,
	uint32_t			qArrayEntryNumber
)
{

#ifndef PACKET_MODE

	qm_q_desc_t			queueDescriptor = {0};
	sram_enqueue_ind_t  enqueueOp = {0};

	// Set up the channel number, queue array entry and base address of 
	// queue descriptor 

	queueDescriptor.channel 			= CHANNEL_NUMBER;
	queueDescriptor.qArrayEntryNumber 	= qArrayEntryNumber;
	queueDescriptor.address				= sopHandle.lw_offset;

	// check if SOP and EOP bits are set and cell count is 0 - min packet case 

	if ((sopHandle.value >> 24) == 0xC0)
	{

		// simply use the sram enqueue instruction, by default the SOP, EOP
		// and cell counts are set to 0

		sram_enqueue((void*) queueDescriptor.value);

	}
	else
	{

		// Set the indirect reference structure with the override bit set.

		enqueueOp.ov_eop_sop_seg_count   = 1 ;
		enqueueOp.eop					 = sopHandle.eop;
		enqueueOp.sop				 	 = sopHandle.sop;
		enqueueOp.seg_count				 = sopHandle.seg_count; 

		// Issue an enqueue of the given address.

		sram_enqueue_ind((void*) queueDescriptor.value, enqueueOp);

		// check if there is a chained buffer. If not then its a chained buffer
		// and we need to link the tail pointer correctly.

		if (sopHandle.eop == 0)
		{
			queueDescriptor.address = eopHandle.lw_offset;
			sram_enqueue_tail((void*) queueDescriptor.value);
		}

	}

#endif

} 

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmPacketEnqueue()
//
// Description: 
//
//		This is the enqueue routine used to enqueue an address. This routine is
// 		for packet based enqueuing in which eop handle is not linked.
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmPacketEnqueue
(
	dl_buf_handle_t 	sopHandle,
	uint32_t			qArrayEntryNumber
)
{

	qm_q_desc_t			queueDescriptor = {0};
	sram_enqueue_ind_t  enqueueOp = {0};

	// Set up the channel number, queue array entry and base address of 
	// queue descriptor 

	queueDescriptor.channel 			= CHANNEL_NUMBER;
	queueDescriptor.qArrayEntryNumber 	= qArrayEntryNumber;
	queueDescriptor.address				= sopHandle.lw_offset + META_PACKET_NEXT_LW_PTR;

	// check if SOP and EOP bits are set and cell count is 0 - min packet case 

	if ((sopHandle.value >> 24) == 0xC0)
	{

		// simply use the sram enqueue instruction, by default the SOP, EOP
		// and cell counts are set to 0

		sram_enqueue((void*) queueDescriptor.value);

	}
	else
	{

		// Set the indirect reference structure with the override bit set.

		enqueueOp.ov_eop_sop_seg_count   = 1 ;
		enqueueOp.eop					 = 1;
		enqueueOp.sop				 	 = sopHandle.sop;
		enqueueOp.seg_count				 = sopHandle.seg_count; 

		// Issue an enqueue of the given address.

		sram_enqueue_ind((void*) queueDescriptor.value, enqueueOp);
		
	}

}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmQArrayInit()
//
// Description: 
//
//		Initialize the qarray.
//
////////////////////////////////////////////////////////////////////////////////////////

void QmQArrayInit(void)
{
	
	uint32_t							i;
	uint32_t							qArrayEntry;
	SIGNAL								sig_readQueueDescriptor;
	__declspec(sram_read_reg) uint32_t	qSize;
	uint32_t							queueNumber; 
	
	// Set queue number to 0 (MSB is always set since CAM cannot handle 0)

	queueNumber = 0x80000000 ;

	// Initialize 16 queue array entries and their local memory queue counts

	for (i = 0; i < 16; i++ )
	{

		// get the entry in the Queue Array 

		qArrayEntry = i + QM_QARRAY_BASE;

		// Read the Queue Descriptor 

		QmReadQueueDescriptor(queueNumber, qArrayEntry, &sig_readQueueDescriptor, 
							  &qSize);

		// Wait for read to complete

		wait_for_all( &sig_readQueueDescriptor);

		// update CAM with new tag entry

		cam_write(i, queueNumber, STATUS_VALID) ;

		// increment queue number 

		queueNumber++;

		// initialize the local memory

		qCount[i] = 0;

	}

	// initialize packet count for drop queue 

	dropQueueCount = 0;

}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmHandleEnqueue()
//
// Description: 
//
//		This routine handles the enqueue and setting of the transition message
//
/// 
////////////////////////////////////////////////////////////////////////////////////////

INLINE qm_enq_response_t QmHandleEnqueue (qm_enq_msg_t enqueueMessage)
{

	cam_lookup_t 											camResult;
	uint32_t	 											camTag; 
	uint32_t	 											camEntry;
	__declspec(sram_read_reg)  uint32_t  					qSize;
	qm_enq_response_t										enqueueResponse = {0};
	volatile __declspec(local_mem  aligned(4)) uint32_t 	*pCurrentQueueCount;


	// signal the next thread and swap out waiting for IO to finish

	QmSignalNextThread();

	// Do the CAM lookup. The queue number has the MSB bit set, so a check
	// for zero which is not allowed by the CAM will never happen 

	camResult = cam_lookup(enqueueMessage.camValue);
	camEntry  = camResult.entry_num;
	camTag	  = cam_read_tag(camEntry);

	// For optimization we get a pointer to the queue count and use it
	// Eventually the compiler should do this

	pCurrentQueueCount 	  = &qCount[camEntry];
	
	// check the result of the CAM operation 

	if (camResult.hit == 0)
	{

		// Its a miss. Write back the queue information 

		QmWriteQueueDescriptor(camTag, camEntry); 

		// Read the new queue into Q_Array

		QmReadQueueDescriptor(enqueueMessage.qNumber, camEntry, &sig_readQueueDescriptor, &qSize);
	
		// update CAM with new tag entry

		cam_write(camEntry, enqueueMessage.camValue, STATUS_VALID );

		#ifdef PACKET_MODE

			// do the actual enqueue
			QmPacketEnqueue(enqueueMessage.sopHandle, camEntry); 
	
		#else

			// do the actual enqueue 
			QmCellEnqueue(enqueueMessage.sopHandle, enqueueMessage.eopHandle, camEntry); 
		
		#endif
		
		// wait for the signals 

		wait_for_all(&sig_readQueueDescriptor, &sig_deqReadDone, &sig_prevThread);
	
		// Since this is a miss update the local memory with the new packet count
		// Add 1 to account for new enqueue 
		
		*pCurrentQueueCount = qSize + 1;

		// if the queue count is 1 - which means it went from 0 to 1, then send 
		// a transition message 

		if (*pCurrentQueueCount == 1) 
		{
			enqueueResponse.queueNumber = enqueueMessage.qNumber;
			enqueueResponse.transition = 1;
		}

	}
	else
	{
		// If we are here it implies that there is a CAM hit.

		#ifdef PACKET_MODE

			// do the actual enqueue
			QmPacketEnqueue(enqueueMessage.sopHandle, camEntry); 
	
		#else

			// do the actual enqueue 
			QmCellEnqueue(enqueueMessage.sopHandle, enqueueMessage.eopHandle, camEntry) ; 
		
		#endif

		wait_for_all( &sig_deqReadDone, &sig_prevThread);
	
		// increment the queue count

		*pCurrentQueueCount = *pCurrentQueueCount + 1;

		if (*pCurrentQueueCount == 1) 
		{
			enqueueResponse.queueNumber = enqueueMessage.qNumber;
			enqueueResponse.transition = 1;
		}
	}

	return enqueueResponse;

}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmHandleDequeue()
//
// Description: 
//
//	This routine handles the dequeue and setting of the transition message
//
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE dl_buf_handle_t QmHandleDequeue 
(
	uint32_t			dequeueRequest,		// queue number with the MSB (bit 31) set 
	qm_deq_response_t*	dequeueResponse		// Dequeue Response is returned in this 
)
{
	
	cam_lookup_t 											camResult;
	uint32_t												camTag; 
	uint32_t												camEntry;
	uint32_t												queueNumber;
	qm_q_desc_t												queue = {0};
	__declspec(sram_read_reg) dl_buf_handle_t 				bufHandle;
	__declspec(sram_read_reg) uint32_t 						qSize;
	volatile __declspec(local_mem  aligned(4)) uint32_t 	*pCurrentQueueCount;
	uint32_t												qCountCurrent;

	// Signal the next thread

	QmSignalNextThread();
	
	// Get rid of the MSB bit in the dequeue request 

	queueNumber = dequeueRequest & ~(1 << 31);		
	
	// Do the CAM lookup 

	camResult = cam_lookup(dequeueRequest);
	camEntry  = camResult.entry_num;
	camTag 	  = cam_read_tag(camEntry) ;

	// For optimization we get a pointer to the qCount. Eventually
	// the compiler should do this directly 

	pCurrentQueueCount = &qCount[camEntry];
	
	// Check if result shows hit or miss

	if (camResult.hit == 0)
	{
		// Its a miss
	
		// Write back the queue information 

		QmWriteQueueDescriptor(camTag, camEntry);

		// Read in the new queue 

		QmReadQueueDescriptor(queueNumber, camEntry, &sig_readQueueDescriptor, &qSize);
		
		// Update CAM with new tag entry
		
		cam_write(camEntry, dequeueRequest, STATUS_VALID);
		
		// Set up the structure for a dequeue operation 

		queue.qArrayEntryNumber   = camEntry;
		queue.channel			  = CHANNEL_NUMBER;

		// Do the Dequeue 

		sram_dequeue((void*) &bufHandle, (void*) queue.value, sig_done, &sig_deqDone);
	
		// Wait for the signals

		wait_for_all(&sig_readQueueDescriptor, &sig_enqReadDone, &sig_deqDone, &sig_prevThread);

		// store the new packet count in the local memory

		*pCurrentQueueCount = qSize;
	}
	else
	{
		// This is the hit case. Simply issue a dequeue

		queue.qArrayEntryNumber   = camEntry;
		queue.channel			  = CHANNEL_NUMBER;

		sram_dequeue((void*) &bufHandle, (void*) queue.value, sig_done, &sig_deqDone);

		// Wait for all the signals 

		wait_for_all(&sig_enqReadDone, &sig_deqDone, &sig_prevThread) ;

	}

	// Make a copy of the queue count for use. Since the queue count is stored
	// in local memory, this helps with optimization. May be removed once compiler
	// has this optimization

    qCountCurrent 		= *pCurrentQueueCount;
	
	// Initialize all fields of the dequeue response to 0
	 
	dequeueResponse->value 	= 0;
	
	// Check if the current queue count is 0. 

	if (qCountCurrent != 0)
	{

		#ifdef PACKET_MODE

			// decrement the queue count 

			qCountCurrent = qCountCurrent - 1;

		#else

			// check if the eop bit is set and the cell count went to zero 
			// If so then decrement the packet count for this queue 

			if ((bufHandle.eop) && (bufHandle.seg_count == 0))
				qCountCurrent = qCountCurrent - 1;

		#endif

		// check if the queue count has gone to 0

		if (qCountCurrent == 0)
		{
			// Set the queue number and valid bit in the dequeue response 

			dequeueResponse->queueNumber = queueNumber;
			dequeueResponse->valid 		 = 1;
			dequeueResponse->transition  = 1;
		}
	}
	else
	{
		// If not return invalid dequeue 

		dequeueResponse->queueNumber 	= queueNumber;
		dequeueResponse->valid 			= 1;
		dequeueResponse->invalidDequeue = 1;
	}

	// copy back the current queue count 

	*pCurrentQueueCount = qCountCurrent;

	// return the buffer handle dequeued

	return bufHandle;

}

/////////////////////////////////////////////////////////////////////////////////////////
//
// QmSendTransmitMessage()
//
//	 	Description: 
//
//		This routine writes to the trasmit scratch ring based on the received 
//		buffer handle from dequeue and queue number.
//
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmSendTransmitMessage(dl_buf_handle_t bufHandle, uint32_t queueNumber)
{

#ifdef PACKET_MODE

	__declspec(sram_write_reg)	tx_request_t 		txRequestXfer;
								tx_request_t		txMessage = {0};

	unsigned int portNumber;

	//	queueNumber has msbit (valid bit) always set. 

	portNumber 				  = (queueNumber & 0x7fffffff) >> (NUMBER_OF_BITS_FOR_CLASS);

	// We did the enqueue on the packet next field, which is the long word 7 in the
	// meta data. So to get to the start of the buffer meta, decrement 7 long words.

	txMessage.sopBufferOffset = bufHandle.lw_offset - META_PACKET_NEXT_LW_PTR;
	txMessage.valid 		  = 1;
	txMessage.portNumber 	  = portNumber;

	txRequestXfer = txMessage;

	// In MPHY16 mode the message can go on either of two scratch rings. The decision is
	// made base on port number. queue 0..7 go on one and 8..15 go on the other.

	if (portNumber > 7)
	{
		// check if the dequeue request scratch ring is full

		while (inp_state_test(TX_1_RING_FULL_CSR));

		// write the data on the scratch ring. We dont wait for it to finish 

		scratch_put_ring( 
						  (void*) &txRequestXfer,
						  (volatile __declspec(scratch) void*) TX_RING_NUMBER_1, 
						  sizeof(txMessage)/sizeof(uint32_t), 
						  sig_done, 
						  &sig_txWriteDone
						);
	}
	else
	{
		// check if the dequeue request scratch ring is full

		while (inp_state_test(TX_0_RING_FULL_CSR));

		// write the data on the scratch ring. We dont wait for it to finish 

		scratch_put_ring( 
						  (void*) &txRequestXfer,
						  (volatile __declspec(scratch) void*) TX_RING_NUMBER_0, 
						  sizeof(txMessage)/sizeof(uint32_t), 
						  sig_done, 
						  &sig_txWriteDone
						);
	}

#else // ingress case.

	// in cell based QM trasmit message is 2LW.

	__declspec(sram_write_reg)	tx_request_t 		txRequestXfer;
								tx_request_t		txMessage = {0};

	txMessage.valid 	   		= 1;
	txMessage.queueNumber  		= queueNumber;

	txRequestXfer.value 		= txMessage.value;
	txRequestXfer.bufHandle     = bufHandle;

	// check if the dequeue request scratch ring is full

	while (inp_state_test(QM_TO_CSIX_TX_SCR_RING_FULL_CSR)); 

	// write the data on the scratch ring. We dont wait for it to finish 

	scratch_put_ring( (void*) &txRequestXfer, (volatile __declspec(scratch) void*) TX_RING_NUMBER_0, \
					  sizeof(txMessage)/sizeof(uint32_t), sig_done, &sig_txWriteDone);
	
#endif

}


/////////////////////////////////////////////////////////////////////////////////////////
//
// QmSendSchedulerMessage()
//
// Description: 
//
// This routine sends the transition messages for enqueue and deuque
// by writing on the NN ring.
//
/// 
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmSendSchedulerMessage
(
	qm_enq_response_t						enqueueMessage,
	qm_deq_response_t						dequeueMessage,
	dl_buf_handle_t							bufHandle
) 
{

#ifdef PACKET_MODE

	uint32_t 	packetLength;

	// check if the message needs to be sent to the scheduler

	if (enqueueMessage.value || dequeueMessage.value)
	{

		// get the packet length from 6 bits of the buffer handle 

		packetLength = (bufHandle.value >> PACKET_SIZE_START_BIT) & PACKET_SIZE_MASK;

		// set the pkt length in dequeue message

		dequeueMessage.packetLength = packetLength;

		// check for ring full condition

		while( inp_state_test(inp_state_nn_full));

		// write message to NN ring

		nn_ring_enqueue_incr(enqueueMessage.value);
		nn_ring_enqueue_incr(dequeueMessage.value);
	}

#else // ingress or cell mode

	// check if the message needs to be sent to the scheduler

	if (enqueueMessage.value || dequeueMessage.value)
	{
			
		// check for ring full condition

		while( inp_state_test(inp_state_nn_full));
				
		// write message to NN ring

		nn_ring_enqueue_incr(enqueueMessage.value) ;
		nn_ring_enqueue_incr(dequeueMessage.value) ;
	}

#endif
	

}

////////////////////////////////////////////////////////////////////////////////////////
//
// QmDropQueueEnqueue()
//
// Description: 
//
// This routine enqueues a packet chain to the drop queue for dropping buffer by buffer
// at a later point
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmDropQueueEnqueue(qm_enq_msg_t	enqMessage)
{

	// increment the number of packets enqueued  in the drop queue 

	dropQueueCount= dropQueueCount + 1;

	// Mask off the cell count from the head of the queue.
	// An optimization because of which only one dequeue is
	// needed to free this buffer

	enqMessage.sopHandle.seg_count = 0;

	// enqueue the packet 

	QmCellEnqueue(enqMessage.sopHandle, enqMessage.eopHandle, QM_DROP_QUEUE_ENTRY);

	// Swap out waiting for scratch read and previous thread to signal.

	wait_for_all( &sig_deqReadDone, &sig_prevThread);


}

////////////////////////////////////////////////////////////////////////////////////////
//
// QmDropQueueDequeue()
//
// Dequeue a buffer from the drop queue and return to the free list 
//
////////////////////////////////////////////////////////////////////////////////////////

INLINE void QmDropQueueDequeue(void)
{
	
	__declspec(sram_read_reg) dl_buf_handle_t	bufHandle;
	qm_q_desc_t			queue;

	// If there is anything in the drop queue 

	if (dropQueueCount)
	{
	
		// Set up the structure for a dequeue operation 

		queue.qArrayEntryNumber   = QM_DROP_QUEUE_ENTRY;
		queue.channel			  = CHANNEL_NUMBER;

		// Do the Dequeue 

		sram_dequeue((void*) &bufHandle, (void*) queue.value, sig_done, &sig_deqDone);

		// Swap out waiting for scratch read and previous thread to signal.

		wait_for_all( &sig_deqReadDone, &sig_prevThread, &sig_deqDone);

		// Check if there is a valid buffer dequeued 
		
		if (bufHandle.value)
		{
	
			#ifdef PACKET_MODE

				// Add the buffer to the free list

				Dl_BufDrop(bufHandle);

				// Check if a complete packet has been received. If so, decrement
				// the packet count  

				if (bufHandle.eop)
					dropQueueCount = dropQueueCount - 1;
		
			#else // cell mode 
		
				// Check if the cell count has gone to 0. If so free the buffer

				if (bufHandle.seg_count == 0)
				{

					Dl_BufDrop(bufHandle);

					// Also check if a complete packet has been received. If so
					// decrement the packet count

					if (bufHandle.eop)
						dropQueueCount = dropQueueCount - 1;

				}

			#endif

		}
	}
	else
	{
	
		// Swap out waiting for scratch read and previous thread to signal.

		wait_for_all( &sig_deqReadDone, &sig_prevThread);	

	}

}

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