/* NETGEAR, Inc. 2000-2001 */

/*****************************************************************************
*h*
*   Name:       hsm.c
*
*   Description:
*               Initialization , Send and Receive routines, ISR,
*               Power management and Miscellaneous routines
*               for the Hardware Specific Module (HSM) .
*
*   History:
*
*h*
******************************************************************************/

#pragma ident "@(#)$RCSfile: hsm.c,v $ $Revision: 1.56 $ $Date: 2001/05/11 10:32:23 $ NETGEAR"

/*
 *	Defines for the features.
 *
 *		1. Intr Hold off  	INTR_HOLD_OFF
 *		2. Pause Frames		PAUSE_FRAMES
 *		3. PHY interrupt	PHY_INTR
 *
 *		These flags should be defined in the Makefile for testing 
 *			these features.
 */

/*** Include files ***/

#include "nsmtypes.h"
#include "nsm.h"
#include "ga621.h"                            
#include "hsm.h"

/*** External Global Vars ***/
/*extern UINT    AutoNegFlg; */

/*** External Global Func ***/

/*** Local Constant Definitions ***/

/*
 * Defines for FreeResources()
 */
#define	PRI_QUE_FAILED          1
#define	DP_ALLOC_FAILED         2
#define	TCB_ALLOC_FAILED        3
#define	RCB_ALLOC_FAILED        4
#define	RXINIT_FAILED           5
#define	UNINITIALIZE            6

#define	RCB_ARRAY_ALLOC_FAILURE 100

/*
 * Defines for TxDp and RxDp arrays.
 */
#define	REG_OFFSET      0       /* Register offset */
#define	MINDESCCNT      1       /* Minimum desc. reqd. for the current prio */
#define	DESCCNT         2       /* Number of desc. for the current prio */
#define	PRIQSEL         3       /* Priority queue selection bit in CR */

/*** Local Typedefs ***/

#define	SET_OWN(Desc, Value)	\
		( (Value) ? ((Desc)->CmdSts |= OWN) : ((Desc)->CmdSts &= ~(OWN)) ) 

/*
 * Increment the current descriptor - used for HsmIsr() and HsmRxPackets().
 */
#define	INC_CURR_DESC(pAdapter, Priority, pDesc,count,base)	\
	((base) +	\
		(((UINT)(pDesc) - (UINT)(base))/sizeof(DevDesc) + (count)) %	\
			(pAdapter)->PriQue[(Priority)].iMaxTxDesc)

/*
 * Defines to Load the TXDP and RXDP registers.
 */

#define	HsmLoadTxDp(pAdapter, priIdx)	\
	NsmRegWrite32((pAdapter)->pNsmContext,	\
		((pAdapter)->RegAddr + pAdapter->TxDp[(priIdx)][REG_OFFSET]),	\
		(UINT) ((HsmTCB *)(pAdapter)->PriQue[(priIdx)].pTcbListHead)->pStartDescPa)

#define	HsmLoadRxDp(pAdapter, priIdx)	\
	NsmRegWrite32((pAdapter)->pNsmContext,	\
		((pAdapter)->RegAddr + pAdapter->RxDp[(priIdx)][REG_OFFSET]),	\
		(UINT)((HsmRCB *)((pAdapter)->PriQue[(priIdx)].pRcbListNext))->pRxDpPa )

/*
 * Defines to enable TXE and RXE .
 */


#ifdef PM_WOL
UCHAR IsPowerPatternExsts(AdapterContext *pAdapter, UCHAR *PowerPattern, UCHAR *pPatternIdx, UINT PatternLen) 
{ 
	UCHAR	ptrnIdx;	
	UCHAR 	status;
	for(ptrnIdx = 0; ptrnIdx < pAdapter->PatternCnt; ptrnIdx++) 
	{ 
		status = NsmCompare(PowerPattern, 
			&pAdapter->PowerPattern[ptrnIdx][0], PatternLen); 
		if (status == SUCCESS) 
		{ 
			*pPatternIdx = ptrnIdx;
			return SUCCESS; 
		} 
	} 
	*pPatternIdx = ptrnIdx;
	return FAILURE;
} 


static int PATTERN[MAX_POWER_PTRN][3] = 
{ 
	{ 0x0006, 	APAT0, WKPAT0}, 
	{ 0x0006,	APAT1, WKPAT1},
	{ 0x0008,	APAT2, WKPAT2},
	{ 0x0008,	APAT3, WKPAT3} 
};

#endif
/*** Local Function Prototypes ***/

VOID getHashValue ( UCHAR *MulticastAddr, USHORT *wordindex, 
						USHORT *bitindex, USHORT *hashbit);

INT  search_mca_tbl ( UCHAR *MulticastAddr, mca_hash_t **prevEntry,
                    	mca_hash_t **hashEntry);

VOID refresh_mca_tbl( AdapterContext *pAdapter);
VOID clear_mca_tbl( AdapterContext *pAdapter);

USHORT AddPattern(AdapterContext *pAdapter, UCHAR PatternIdx, 
                        UCHAR *PowerPattern, UINT PatternLen, UINT MatchLen, 
                        UCHAR *MaskPtrn );


/*** Function Definitions ***/

/******************************************************************************
*f*
*   Name:               
*                       HsmTxStart
*
*   Description:        
*                       Start the transmit engine . 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*                       Priority        - Priority.
*
*   Return Value:   
*                       NONE.
*
*f*
******************************************************************************/
VOID
HsmTxStart(AdapterContext *pAdapter, UINT Priority)
{
        UINT    Cr_val; 
        NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), &Cr_val); 
        Cr_val |= TXE;
        Cr_val |= (pAdapter->TxDp[Priority][PRIQSEL]) ; 
        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);

}       /*      end of HsmTxStart()     */

/******************************************************************************
*f*
*   Name:               
*                       HsmRxStart
*
*   Description:        
*                       Start the Receive Engine . 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*                       Priority        - Priority.
*
*   Return Value:   
*                       NONE.
*
*f*
******************************************************************************/
VOID
HsmRxStart(AdapterContext *pAdapter, UINT Priority)
{
        UINT    Cr_val; 
        NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), &Cr_val); 
        Cr_val |= RXE;
        Cr_val |= (pAdapter->RxDp[Priority][PRIQSEL]) ; 
        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);

}       /*      end of HsmRxStart()     */

/******************************************************************************
*f*
*   Name:               
*                       HsmOpen
*
*   Description:        
*                       Open the adapter. 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS - If device is already opened / Open succeded.
*                       FAILURE - Adapter is in reset. 
*
*f*
******************************************************************************/
UCHAR 
HsmOpen(AdapterContext *pAdapter)
{
		USHORT  TCBidx;    
        UINT    priIdx;
		UINT	HoldDpc = 0;
#ifdef NSCDEBUG
    NsmDbgMsg("HsmOpen : Opening the Device\n");
#endif
/*
 *      If adapter is already opened then return SUCCESS.
 */
    	HsmDisableInterrupts(pAdapter);
		if ( ((pAdapter->AdapterStatus & ADAPTER_RESETTING) && (pAdapter->interruptStatus & SWI_INTR)) )
			HoldDpc = 1;
		if (!HoldDpc)
        NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		else
        NsmAcquireDPCLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

        if (pAdapter->AdapterStatus & ADAPTER_OPEN) { 
		if (!HoldDpc)
                NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		else
        		NsmReleaseDPCLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
                return (SUCCESS);
        } 
/*
 *      Initialize the registers (HsmInitRegs()) 
 *      Enable interrupts from the adapter(setting IE bit in IER ) 
 */
#ifdef NSCDEBUG
    NsmDbgMsg("HsmOpen: Initializing the registers & enabling interrupts \n");
#endif

    	HsmInitRegs(pAdapter);

		
/*		
 *		ReInitialize the Tx list before starting any communication or
 *		loading the descriptor list.
 *		Clear the OWN bits and initialize the Head.
 */

/*
 *      Assign Head , Tail pointers Max number and number of free descriptors 
 *              for each priority queue allocated.
 */

        for( priIdx = 0; priIdx < pAdapter->TxNumPrio; priIdx++) 
		{
/*
 *      	Assign pTcbListHead, pTcbListNext pointers for this priority to the 
 *      	first TCB in the TCB ring of the current priority. 
 */
			pAdapter->PriQue[priIdx].pTcbListHead = 
    			pAdapter->PriQue[priIdx].pTcbListNext = 
					pAdapter->PriQue[priIdx].pTcbArray;

/*
 *      	pStartDesc pointer of the First TCB is made point to the First Txd
 *      	of the priority queue.
 */     
			pAdapter->PriQue[priIdx].pTcbArray[0].pStartDesc = 
				&pAdapter->PriQue[priIdx].pTxdArray[0];

			pAdapter->PriQue[priIdx].pTcbArray[0].pStartDescPa = 
				&pAdapter->PriQue[priIdx].pTxdArrayPa[0];

/*
 *     		Set up the Txd List and clear the OWN bit. 
 */
			for (TCBidx= 0; TCBidx < pAdapter->PriQue[priIdx].iMaxTxDesc; TCBidx++) 
			{
				pAdapter->PriQue[priIdx].pTxdArray[TCBidx].CmdSts = 0;
				SET_OWN(&pAdapter->PriQue[priIdx].pTxdArray[TCBidx], 0);
			}
		
		}    
/*			
 *		End of Tx List Re-Init.
 */



		/*Do not enable interrupts if called from HsmReset*/
		if ( !((pAdapter->AdapterStatus & ADAPTER_RESETTING) || (pAdapter->interruptStatus & SWI_INTR) || (pAdapter->AdapterStatus & ADAPTER_SLEEPING)) )
    	HsmEnableInterrupts(pAdapter);

#ifdef NSCDEBUG
    NsmDbgMsg("HsmOpen: Loading RXDP and starting the receive engine. \n");
#endif
/*
 * 		Load the TXDP 
 */
        for (priIdx = 0; priIdx < pAdapter->TxNumPrio; priIdx++)
                HsmLoadTxDp(pAdapter, priIdx);


/*
 * 		Load the RXDP and enable the receive engine.
 */
        for (priIdx = 0; priIdx < pAdapter->RxNumPrio; priIdx++)
		{
                HsmLoadRxDp(pAdapter, priIdx);
        		HsmRxStart(pAdapter, priIdx);
		}
/*
 *      Wait till Transmit and Receive engines are enabled. 
 */
	    NsmSleep(pAdapter->pNsmContext, 10);    

		if ( !(pAdapter->AdapterStatus & ADAPTER_SLEEPING) )
       	pAdapter->AdapterStatus |= ADAPTER_OPEN;
			
		if (!HoldDpc)
                NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		else
        		NsmReleaseDPCLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
        
#ifdef NSCDEBUG
    NsmDbgMsg("HsmOpen: Adapter opened. \n");
#endif
#ifdef PM_WOL

		/* Check if we have to read the curr power state from somewhere */
		pAdapter->CurrPowerStatus = POWER_STATE_D0;

#endif
        return (SUCCESS);

}       /*      end of Hsmopen()        */


/******************************************************************************
*f*
*   Name:               
*                       HsmClose
*
*   Description:        
*                       Close the adapter. 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*               SUCCESS - On successful close operation.
*               FAILURE - If the Adapter status is not ADAPTER_OPEN / 
*                       Adapter is in reset.
*
*f*
******************************************************************************/
UCHAR
HsmClose(AdapterContext *pAdapter)
{
        UINT    Cr_val;

#ifdef NSCDEBUG
    NsmDbgMsg("HsmClose: closing the Adapter . \n");
#endif
        NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
/*
 *      If adapter is not opened then return FAILURE.
 */
        if (!(pAdapter->AdapterStatus & ADAPTER_OPEN))  { 
                NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
                return FAILURE;
        }       

#ifdef NSCDEBUG
    NsmDbgMsg("HsmClose: waiting for the receive and transmit engine to be disabled. \n");
#endif

/*
 *	Disable interrupts from the adapter(setting 0 to IE bit in IER) & disable 
 *	the	receive engine and transmit engine (setting RXD and TXD bits in CR )
 */
        NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), &Cr_val);
		/* No need of SWI
        Cr_val |= (RXD | TXD | SWI);*/
        Cr_val |= (RXD | TXD );
        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);

        pAdapter->SWIFlag = 0;

/*
 *      Clear the bitmask ADAPTER_OPEN from AdapterStatus field.
 */
        HsmDisableInterrupts(pAdapter);
		/* Clear the multicast hash table*/
		clear_mca_tbl(pAdapter);
        HsmClearStatistics(pAdapter);
		pAdapter->AdapterStatus &= ~(ADAPTER_OPEN);
        NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
        
#ifdef NSCDEBUG
    NsmDbgMsg("HsmClose: Adapter closed. \n");
#endif

        return SUCCESS;

}       /* End of HsmClose() */


/* Setting the Interrupt Mask */
VOID HsmMaskIntr( AdapterContext *pAdapter, UINT Mask)
{
	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr+ IMR), Mask);
}


/******************************************************************************
*f*
*   Name:               
*                       HsmReset
*
*   Description:        
*                       Reset the adapter. 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS - Reset successful.
*                       FAILURE - Adapter is not opened already.
*
*f*
******************************************************************************/
UCHAR
HsmReset(AdapterContext *pAdapter, UINT aSynch)
{
	UINT    Cr_val;
	UINT    Bmcr_val;
	UINT    Imr_val;
	UINT    i = 0;

#ifdef FWARE_DOWNLOAD
	UCHAR   Stat;
#endif

#ifdef NSCDEBUG
	UINT    Physts_val;
#endif

#ifdef NSCDEBUG
	NsmDbgMsg("HsmReset: Resetting the adapter . \n");
#endif

	/* Do not interrupt the Reset */
	HsmDisableInterrupts(pAdapter);  
	
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

	/*
	 *      If adapter is not opened then return FAILURE.
	 */
	if (!(pAdapter->AdapterStatus & ADAPTER_INITIALIZED))  
	{ 
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

	if (pAdapter->AdapterStatus & ADAPTER_RESETTING)
	{
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return RESET_IN_PROGRESS;
	}

	pAdapter->AdapterStatus |= ADAPTER_RESETTING;

	/*
	 *      Clear the bitmask ADAPTER_OPEN from AdapterStatus field.
	 */
	if (pAdapter->AdapterStatus & ADAPTER_OPEN)  
		pAdapter->AdapterStatus &= ~(ADAPTER_OPEN);

	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

	/*Wait for pending packets to be sent */
	if (aSynch)
	{
		/*
		 * DO not wait for packets, we will clear the
		 * descriptor list and reset it, effectively we
		 * will abort packets.
		 * NsmSleep(pAdapter->pNsmContext, 2000);
		 */
		Imr_val = (  PHY | SWI_INTR ); 
	}
	else
		Imr_val = 0; 
	
	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr+ IMR), Imr_val);
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), &Cr_val);
	Cr_val |= (RXD | TXD );
	Cr_val &= ~(RXE | TXE);
	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + IHR), 0);
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);
	pAdapter->CurrHoldOff = 0;
	NsmSleep(pAdapter->pNsmContext, 10);    /* 10 milli seconds */
	
	if (aSynch)
	{
		Cr_val |= (SWI );
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);
	}
	else
	{
		/* Call the HsmIsr() before doing the Reset to accomodate for the 
		 * pending recieve packets for Netware
		 */
		HsmIsr(pAdapter);

		/*
		 *	Reset the Adapter (setting RST bit in CR register) and wait till the reset
		 *	is complete.
		 */
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), RST);

		i = 0;
		do {
			NsmSleep(pAdapter->pNsmContext, 10);    /* 10 milli seconds */
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					&Cr_val);
		}while ( (Cr_val & RST) && ++i<200 );


#ifdef NSCDEBUG
		NsmDbgMsg("HsmReset: resetting the PHY register and waiting for the link to be established. \n");
#endif

#ifdef NSCDEBUG
		Physts_val = ReadMiiReg(pAdapter, PHYSUP);
		NsmDbgMsg1("HsmReset : Physup value 0x%x\n",Physts_val);
#endif

		if(!(pAdapter->tbi))
		{
			/*
			 * Reset the PHY register using BMCR
			 */
#ifdef _DP83815_
			NsmRegWrite16(pAdapter->pNsmContext,
				(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
			WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif
			/*
			 *      Wait for the BMCR_RESET bit to clear, for reset complete.
			 */
			i = 0;
			do {

				NsmSleep(pAdapter->pNsmContext, 10 );
#ifdef _DP83815_
				NsmRegRead16(pAdapter->pNsmContext,
					(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
				Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
			} while ( (Bmcr_val & BMCR_RESET) && ++i<400 );
		}

		/* Clear the statistics MIB counter */
		HsmClearStatistics(pAdapter);

		if (!(pAdapter->tbi))
		{
#ifdef FWARE_DOWNLOAD
			if (pAdapter->FileHandle) {
				
				/* Wait For the Phy to reset properly */
				NsmSleep(pAdapter->pNsmContext, 500 );
				
				HsmDownLoadFirmwareInit(pAdapter);

				Stat = NsmDownLoadFirmwareFromFileX(pAdapter);
				
				if( Stat == FAILURE ) {
				
					/* Event log */
					NsmDownLoadFailed(pAdapter);

					/*
					 * Reset the PHY register using BMCR incase of a DownloadFail
					 */
#ifdef _DP83815_
					NsmRegWrite16(pAdapter->pNsmContext,
						(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
					WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif
					/*
					 *      Wait for the BMCR_RESET bit to clear, for reset complete.
					 */
					i = 0;
					do {

						NsmSleep(pAdapter->pNsmContext, 5 );
#ifdef _DP83815_
						NsmRegRead16(pAdapter->pNsmContext,
							(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
						Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
					} while ( (Bmcr_val & BMCR_RESET) && ++i<800 ); 

				}
				else /* if the download is successful */
				{ 
		
					HsmStartFirmWareCode(pAdapter);
			 
					Stat = HsmVerifyDownLoad(pAdapter);

					if(Stat == FAILURE)
					{
						/* Event log */
						NsmDownLoadFailed(pAdapter);

						/*
						 * Reset the PHY register using BMCR incase of a DownloadFail
						 */
#ifdef _DP83815_
						NsmRegWrite16(pAdapter->pNsmContext,
							(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
						WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif
						/*
						 *      Wait for the BMCR_RESET bit to clear, for reset complete.
						 */
						i = 0;

						do 
						{

							NsmSleep(pAdapter->pNsmContext, 5 );
#ifdef _DP83815_
							NsmRegRead16(pAdapter->pNsmContext,
								(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
							Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
						} while ( (Bmcr_val & BMCR_RESET) && ++i<800 ); 

					}
				}
			}
#endif
		}

		/*Indicate Link Down */
		pAdapter->AdapterStatus &= ~(LINK_UP);
				
		/*
		 *	Set the MAC address stored in pAdapter->CurrMacAddr and load the filter 
		 *	memory with the multicast addresses stored in the Adapter context.
		 *	Add the Pause Multicast address for Rx Pause Control.
		 */
		refresh_mca_tbl(pAdapter);
		HsmSetMacAddress(pAdapter, pAdapter->CurrMacAddr);

		NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		if (!(pAdapter->AdapterStatus & ADAPTER_OPEN))  {
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + IMR), Imr_val);
			NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
			HsmEnableInterrupts(pAdapter);  
		}
		else
			NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

		pAdapter->AdapterStatus &= ~ADAPTER_RESETTING;

	}
				
	return SUCCESS;

}       /* End of HsmReset() */

/******************************************************************************
*f*
*   Name:               
*                       HsmInitialize
*
*   Description:        
*                       Initialize the adapter. 
*                               This is called from NSM initialize routine.
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS - Initialization successful.
*                       FAILURE -   
*                                 Descriptor pool creation failure.
*                                 TCB / RCB array initialization failure.
*                                 NSM lock creation failure.
*                                 Priority Queue creation failure.
*
*f*
******************************************************************************/
UCHAR
HsmInitialize(AdapterContext *pAdapter)
{
        USHORT  priIdx;
        UCHAR   AdapterPQ ;
        UINT    DescSize = 0;
        CHAR    retval;
		UINT	phyRev, dword = 0;

#ifdef NSCDEBUG
    NsmDbgMsg("HsmInitialize: Initializing the adapter . \n");
#endif
/*
 *      Create a Adapter lock and TxLock and PktStruct ListLock.
 */
        pAdapter->AdapterLock = (PVOID) NsmCreateLock();
        if (pAdapter->AdapterLock == NULL) {
                return FAILURE;
        }

		pAdapter->TxLock = (PVOID) NsmCreateLock();
        if (pAdapter->TxLock == NULL) {
                NsmDestroyLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
                return FAILURE;
        }

#ifdef ALLOC_PKTSTRUCT
		pAdapter->ListLock = (PVOID) NsmCreateLock();
        if (pAdapter->ListLock == NULL) {
                NsmDestroyLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
                NsmDestroyLock(pAdapter->pNsmContext, pAdapter->TxLock);
                return FAILURE;
        }


/*		
 *		Allocate the Static PktStruct and Initialize the Stack to hold
 *		the pointers to the PktStruct.
 */
		retval = StackInit(pAdapter);
		if(retval == FAILURE)
		{
				NsmDestroyLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
				NsmDestroyLock(pAdapter->pNsmContext, pAdapter->TxLock);
				NsmDestroyLock(pAdapter->pNsmContext, pAdapter->ListLock);
				return FAILURE;
		}
#endif

/*
 *      Determine the number of priority queues to be created based on Adapter 
 *      supported PQ and operating system supported PQ.
 */
        AdapterPQ = MAXPRI_ADAPTER;

#ifdef _GA621_
/*
 *      In DP83815 priority queues are not supported.
 */
        if (pAdapter->OsPrio < AdapterPQ)
                AdapterPQ = pAdapter->OsPrio;   
#endif

		pAdapter->NumPrio = pAdapter->TxNumPrio = pAdapter->RxNumPrio = AdapterPQ;

/*
 *      Create 'NumPrio' number of priority queues. 
 */
#ifdef NSCDEBUG
    NsmDbgMsg("HsmInitialize: Allocating mem for Priority queues. \n");
#endif
        if (pAdapter->NumPrio)
			pAdapter->PriQue = (PriorityQue *)
				NsmMalloc(sizeof(PriorityQue) * pAdapter->NumPrio);

        if (pAdapter->PriQue == NULL) {
                HsmFreeResources(pAdapter, PRI_QUE_FAILED); 
#ifdef NSCDEBUG
	NsmDbgMsg("HsmInitialize: Memory allocation for Priority queues failed.\n");
#endif
                return FAILURE;
        } 

#ifdef NSCDEBUG
	NsmDbgMsg("HsmInitialize: Allocating contiguous memory for descriptors.\n");
#endif
/*
 *  Allocate Pool of Descriptors
 */
        for(priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++) 
			DescSize += sizeof(DevDesc) * 
						( pAdapter->TxDp[priIdx][DESCCNT] +  pAdapter->RxDp[priIdx][DESCCNT]) ;

        pAdapter->pDescList.BufSize = DescSize;
        pAdapter->pDescList.VirtAddr = NULL;
		/* Add cache flag
        NsmMallocContiguous(pAdapter->pNsmContext, &pAdapter->pDescList , 64);*/
        NsmMallocContiguous(pAdapter->pNsmContext, &pAdapter->pDescList , 64, 0);

/*
 *	Allocation for Contiguous Memory failed.
 */
        if (pAdapter->pDescList.VirtAddr == NULL) {
			HsmFreeResources(pAdapter, DP_ALLOC_FAILED);
#ifdef NSCDEBUG
                NsmDbgMsg("HsmInitialize: Contiguous memory allocation for descriptors failed.\n");
#endif
                return FAILURE;
        } 


/*
 *	Create the TCB array and Setup the TCB and Txd ring. Create RCB array and
 *	setup the RCB and Rxd ring.
 */
        retval = HsmTxInit(pAdapter);
        if (retval != SUCCESS) { 
                HsmFreeResources(pAdapter, TCB_ALLOC_FAILED);
#ifdef NSCDEBUG
                NsmDbgMsg("HsmInitialize: HsmTxInit() failed.\n");
#endif
                return FAILURE;
        } 


        retval = HsmRxInit(pAdapter);
        if (retval == RCB_ARRAY_ALLOC_FAILURE) { 
                HsmFreeResources(pAdapter, RCB_ALLOC_FAILED);
#ifdef NSCDEBUG
                NsmDbgMsg("HsmInitialize: HsmRxInit() failed.\n");
#endif
                return FAILURE;
        } 
/*
		Moving it down
        if (retval < pAdapter->RxNumPrio) 
                pAdapter->RxNumPrio = retval; 
*/	
		if (!retval) {
			/*RCB_ALLOC_FAILED should do
	   		HsmFreeResources(pAdapter, RXINIT_FAILED);*/
	   		HsmFreeResources(pAdapter, RCB_ALLOC_FAILED);
	   		return FAILURE;
		}
        if (retval < pAdapter->RxNumPrio) 
                pAdapter->RxNumPrio = retval; 

#ifdef _GA621_
/*
 *      Calculate the Adapter Mapping quotient value and set the 
 *      ADAPTER_INITIALIZED bitmask in AdapterStatus.
 */
        HsmCreateMapValue(pAdapter);
#endif 
		if (!(pAdapter->tbi))
		{

/*
 * 		Getting the PhyAddress of the DP83891 chip.
 *			Read PHYIDR1 and PHYIDR2 and compare the OUI.
 */
        for(pAdapter->phyAddress=31; pAdapter->phyAddress != 0;
                                                pAdapter->phyAddress--)
        {
            dword = ReadMiiReg ( pAdapter, PHYIDR1 );
            if(dword == 0x2000)
            {
                phyRev = ReadMiiReg ( pAdapter, PHYIDR2 );

/* 
 *	Break, if this is a DP83891 / DP83861 
 */
                if ( (phyRev & ~(0x000f)) == 0x00005c50 || 
                	 (phyRev & ~(0x000f)) == 0x00005c60 )
                {
                    break;
                }
            }
        }
		}


        pAdapter->AdapterStatus |= ADAPTER_INITIALIZED;
#ifdef NSCDEBUG
        NsmDbgMsg("HsmInitialize: Adapter initialization completed.\n");
#endif

        return SUCCESS;
}                     /* End of HsmInitialize() */

/******************************************************************************
*f*
*   Name:               
*                       HsmTxInit
*
*   Description:        
*                       Create TCB ring and setup Txd ring. 
*                               This is called from HsmInitialize()
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS         - TxInit Succeded.
*                       FAILURE         - TCB pool allocation failed. 
*
*f*
******************************************************************************/
UCHAR
HsmTxInit(AdapterContext *pAdapter)
{
	USHORT  priIdx, TxdIdx, TCBidx, idx;
	UINT    TotTCBsz = 0;
	UCHAR   *Start_TCBarray; /* Start of the TCB array for the current pri. */
	UCHAR   *Start_DescArray; /* Start of the physical address for Txd. */
	UCHAR   *Start_DescArrayPa; /* Start of the physical address for Txd. */

#ifdef NSCDEBUG
    NsmDbgMsg("HsmTxInit: Allocating and setting up TCB and Txd Ring.\n");
#endif
/*
 *  Allocate Pool of TCBs.
 */
        for(priIdx = 0; priIdx < pAdapter->TxNumPrio; priIdx++) 
                TotTCBsz += sizeof(HsmTCB) *  pAdapter->TxDp[priIdx][DESCCNT];

        pAdapter->pTcbArray = (PVOID)   NsmMalloc(TotTCBsz);
        if (pAdapter->pTcbArray == NULL) 
                return FAILURE;

        Start_TCBarray = (UCHAR *)pAdapter->pTcbArray;
        Start_DescArray = pAdapter->pDescList.VirtAddr;
        Start_DescArrayPa = pAdapter->pDescList.PhysAddr;


/*
 *      Assign Head , Tail pointers Max number and number of free descriptors 
 *              for each priority queue allocated.
 */

        for( priIdx = 0; priIdx < pAdapter->TxNumPrio; priIdx++) {

                pAdapter->PriQue[priIdx].iMaxTxDesc =
					pAdapter->PriQue[priIdx].iFreeTxDesc =
						(USHORT) pAdapter->TxDp[priIdx][DESCCNT];

                pAdapter->PriQue[priIdx].pTxdArray = (DevDesc *)Start_DescArray;
                pAdapter->PriQue[priIdx].pTxdArrayPa =
										(DevDesc *)Start_DescArrayPa;


/* 
 *	Setup the Txd Ring (linking all the Txds with "link" field in the 
 *	descriptor. The "link" field of the last Txd is made to point the first Txd.
 */
			for (TxdIdx =0; TxdIdx< pAdapter->PriQue[priIdx].iMaxTxDesc; 
					TxdIdx++) {

				idx = (TxdIdx + 1) % pAdapter->PriQue[priIdx].iMaxTxDesc;

				pAdapter->PriQue[priIdx].pTxdArray[TxdIdx].link = 
					(UINT) (Start_DescArrayPa + (idx * sizeof(DevDesc)));

				pAdapter->PriQue[priIdx].pTxdArray[TxdIdx].CmdSts = 0;

				SET_OWN(&pAdapter->PriQue[priIdx].pTxdArray[TxdIdx], 0);

 			}       /*      end of for(TxdIdx =0; ....)     */ 

			Start_DescArray += 
				( sizeof(DevDesc) * pAdapter->PriQue[priIdx].iMaxTxDesc ) ;

			Start_DescArrayPa += 
				( sizeof(DevDesc) * pAdapter->PriQue[priIdx].iMaxTxDesc ) ;

			pAdapter->TotTxdPhySz += sizeof(DevDesc) * TxdIdx;
/*
 *      Assign pTcbListHead, pTcbListNext pointers for this priority to the 
 *      first TCB in the TCB ring of the current priority. 
 */
			pAdapter->PriQue[priIdx].pTcbArray = (HsmTCB *) Start_TCBarray; 
                
			pAdapter->PriQue[priIdx].pTcbListHead = 
    		pAdapter->PriQue[priIdx].pTcbListNext = 
				pAdapter->PriQue[priIdx].pTcbArray;

			Start_TCBarray += (sizeof(HsmTCB) * pAdapter->TxDp[priIdx][DESCCNT]);
/*
 *      pStartDesc pointer of the First TCB is made point to the First Txd
 *      of the priority queue.
 */     
			pAdapter->PriQue[priIdx].pTcbArray[0].pStartDesc = 
				&pAdapter->PriQue[priIdx].pTxdArray[0];

			pAdapter->PriQue[priIdx].pTcbArray[0].pStartDescPa = 
				&pAdapter->PriQue[priIdx].pTxdArrayPa[0];

/*
 * 
			pAdapter->PriQue[priIdx].pTcbArray[0].pEndDesc = NULL;
 */

/*
 *      Setup the TCB Ring (linking all the TCBs with "pNext" field in the TCB. 
 *      The "pNext" field of the last TCB is made to point the first TCB. 
 */
			for ( TCBidx =0; TCBidx< pAdapter->PriQue[priIdx].iMaxTxDesc; 
				TCBidx++){
			
				idx = (TCBidx + 1) % pAdapter->PriQue[priIdx].iMaxTxDesc;

				pAdapter->PriQue[priIdx].pTcbArray[TCBidx].pNext = 
					&pAdapter->PriQue[priIdx].pTcbArray[idx];
#ifdef LINK_AGGR
				/* 
				 * Initializing the Slow Protocol Type for Link Aggregation
				 */
				pAdapter->PriQue[priIdx].pTcbArray[TCBidx].SlowProtocolType = FALSE;
#endif
/*
 * 
				pAdapter->PriQue[priIdx].pTcbArray[TCBidx].pEndDesc = NULL;
 */
			}       
		}       /*      End of for (priIdx = 0; priIdx < NumPrio; priIdx++) */

        return SUCCESS;


}       /*      End of HsmTxInit()      */

/******************************************************************************
*f*
*   Name:               
*                       HsmRxInit
*
*   Description:        
*                       Create RCB list, Rx buffers and set up Rxd list.
*                               This is called from HsmInitialize().
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS - RxInit successful.
*                       RCB_ARRAY_ALLOC_FAILURE - RcbArray allocation failure.
*
*f*
******************************************************************************/
CHAR
HsmRxInit(AdapterContext *pAdapter)
{
	USHORT                  RCBidx, Idx;    
	USHORT                  retval = FAILURE;    
	UINT                    TotRCBsz = 0;
	AddrStruct              Addr;
	UCHAR                   *Start_RCBarray, priIdx;
	UCHAR                   *Start_DescArray, *Start_DescArrayPa; 

#ifdef NSCDEBUG
	NsmDbgMsg("HsmRxInit: Allocating and setting up RCB and Rxd list.\n");
#endif
/*
 *  Allocate Pool of RCBs
 */
	for(priIdx = 0; priIdx < pAdapter->RxNumPrio; priIdx++) 
		TotRCBsz += sizeof(HsmRCB) *  pAdapter->RxDp[priIdx][DESCCNT];

	pAdapter->pRcbArray = (PVOID) NsmMalloc(TotRCBsz);
	if (pAdapter->pRcbArray == NULL) 
		return RCB_ARRAY_ALLOC_FAILURE;

	Start_RCBarray = (UCHAR *)pAdapter->pRcbArray;
	Start_DescArray = pAdapter->pDescList.VirtAddr + pAdapter->TotTxdPhySz;
	Start_DescArrayPa = pAdapter->pDescList.PhysAddr + pAdapter->TotTxdPhySz;

	for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++) {
/* 
 *      Assign Max number and number of free  descriptors for this priority .
 */
		pAdapter->PriQue[priIdx].iMaxRxDesc = 
			pAdapter->PriQue[priIdx].iFreeRxDesc = (USHORT) pAdapter->RxDp[priIdx][DESCCNT];

		pAdapter->PriQue[priIdx].pRxdArray = (DevDesc *)Start_DescArray;
			pAdapter->PriQue[priIdx].pRxdArrayPa = (DevDesc *)Start_DescArrayPa;
/*
 *      Assign RCBHead, RCBNext, RCBTail pointers for this priority.
 */
		pAdapter->PriQue[priIdx].pRcbArray = (HsmRCB *)Start_RCBarray;

		pAdapter->PriQue[priIdx].pRcbListHead = 
		pAdapter->PriQue[priIdx].pRcbListNext =
			pAdapter->PriQue[priIdx].pRcbArray;

/*
 *      Setup the RCB list (linking all the RCBs with "pNext" field in the RCB. 
 *  	NULL is assigned to the "pNext" field of the last RCB .
 *      Set up the Rxd List linking the "link" field in the descriptor and 
 *		set the OWN bit. 
 */
		for (RCBidx= 0; RCBidx < pAdapter->PriQue[priIdx].iMaxRxDesc; 
					RCBidx++) {

			if (RCBidx == (pAdapter->PriQue[priIdx].iMaxRxDesc - 1))  { 
				pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pNext = NULL;
				pAdapter->PriQue[priIdx].pRxdArray[RCBidx].link = 0;
				SET_OWN(&pAdapter->PriQue[priIdx].pRxdArray[RCBidx], 1);
			} 
			else { 
				pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pNext = 
				&pAdapter->PriQue[priIdx].pRcbArray[RCBidx + 1];
				pAdapter->PriQue[priIdx].pRxdArray[RCBidx].link = 
				(UINT) (Start_DescArrayPa + ((RCBidx+1) * sizeof(DevDesc)));
				SET_OWN(&pAdapter->PriQue[priIdx].pRxdArray[RCBidx], 0);
			} 

/*
 *      Set the Descriptor pointer in RCB.      
 */
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pRxDp = 
				&pAdapter->PriQue[priIdx].pRxdArray[RCBidx];
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pRxDpPa = 
				&pAdapter->PriQue[priIdx].pRxdArrayPa[RCBidx];
/* 
 *      Populate the Address structure and create the Rx Buffer. If allocation 
 *      failed then return the Priority index.
 */
			Addr.BufSize = pAdapter->MaxPktSize;
			Addr.VirtAddr = Addr.PhysAddr = NULL;

			retval = NsmAllocatePacket(pAdapter->pNsmContext,
				&pAdapter->PriQue[priIdx].pRcbArray[RCBidx], &Addr);

			if (retval != SUCCESS || Addr.VirtAddr == NULL ) { 
/*
 *      If RxBuffer Allocation failed for the current RCB of the current 
 *  	priority Q and the number of RCBs allocated is below the 
 *		threshold value then free the buffers allocated for the RCBs in 
 *		the current priority Q and break the loop. In this case, the NumPrio 
 *		field in the Adapter context is set to the current priority value.
 */
				if (RCBidx < pAdapter->RxDp[priIdx][MINDESCCNT] ) { 
#ifdef NSCDEBUG
				NsmDbgMsg("HsmRxInit: NsmAllocatePacket() failed and the no. of  RCBs allocated is below the threshold value.\n");
#endif

					for ( Idx = 0; Idx < RCBidx ; Idx++) { 

						Addr.BufSize = pAdapter->MaxPktSize;
						Addr.VirtAddr = 
							pAdapter->PriQue[priIdx].pRcbArray[Idx].pDataBuf;
						Addr.PhysAddr = (UCHAR *)
					      pAdapter->PriQue[priIdx].pRcbArray[Idx].pRxDp->BufPtr;
						Addr.pCookie = pAdapter->PriQue[priIdx].pRcbArray[Idx].pOsCtrlBlk; 

						NsmDeAllocatePacket(pAdapter->pNsmContext, &Addr, 
							&pAdapter->PriQue[priIdx].pRcbArray[Idx]);
					} 
					pAdapter->PriQue[priIdx].iMaxRxDesc = 
					pAdapter->PriQue[priIdx].iFreeRxDesc = 0;
					break;
				}       /*      end of if (RCBidx < RxDp[][]    */
                                
				pAdapter->PriQue[priIdx].iMaxRxDesc = 
				pAdapter->PriQue[priIdx].iFreeRxDesc = RCBidx;
				/*Bug fix*/
				pAdapter->PriQue[priIdx].pRcbArray[RCBidx-1].pNext = NULL;
				pAdapter->PriQue[priIdx].pRxdArray[RCBidx-1].link = 0;
				SET_OWN(&pAdapter->PriQue[priIdx].pRxdArray[RCBidx-1], 1);
				Start_RCBarray += 
					(sizeof(HsmRCB) * (pAdapter->PriQue[priIdx].iMaxRxDesc - 1 ));

				pAdapter->PriQue[priIdx].pRcbListTail = (HsmRCB *)Start_RCBarray;

				Start_RCBarray += sizeof(HsmRCB);
				priIdx++;
				break;

			}       /*      if (retval != SUCCESS)  */ 
/* 
 *      Fill the fields in the RCB.
 */
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pOsCtrlBlk = 
				Addr.pCookie;
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pRxDp->BufPtr = 
				(UINT) Addr.PhysAddr;
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pRxDp->CmdSts |= 
				(Addr.BufSize | INTR);
			pAdapter->PriQue[priIdx].pRcbArray[RCBidx].pDataBuf = 
				Addr.VirtAddr;
		} /* end of for(RCBidx = 0; RCBidx < GA621_MAXRXDESC-1 ; RCBidx++) */
/*
 *      Terminate the RCB and Rxd list.
 */
		if (retval != SUCCESS)
			break;
		/*Bug fix*/
		Start_RCBarray += 
			(sizeof(HsmRCB) * (pAdapter->PriQue[priIdx].iMaxRxDesc - 1 ));

		pAdapter->PriQue[priIdx].pRcbListTail = (HsmRCB *)Start_RCBarray;

		Start_RCBarray += sizeof(HsmRCB);
                
		Start_DescArray += ( sizeof(DevDesc) * 
			pAdapter->PriQue[priIdx].iMaxRxDesc );
		Start_DescArrayPa += ( sizeof(DevDesc) * 
			pAdapter->PriQue[priIdx].iMaxRxDesc );

	}       /* end of for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++) */

	return priIdx;

}       /*      End of HsmRxInit()      */


/******************************************************************************
*f*
*   Name:               
*                       HsmUnInitialize
*
*   Description:        
*                       Un-Initialize the adapter.
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       NONE.
*
*f*
******************************************************************************/
VOID
HsmUnInitialize(AdapterContext *pAdapter)
{
#ifdef NSCDEBUG
	NsmDbgMsg("HsmUnInitialize: UnInitializing the Adapter .\n");
#endif
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
	if (!(pAdapter->AdapterStatus & ADAPTER_INITIALIZED)) {
		/*Release lock before leaving*/
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return ;
	}
	pAdapter->AdapterStatus &= ~(ADAPTER_INITIALIZED);
	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
	HsmFreeResources(pAdapter, UNINITIALIZE);
#ifdef NSCDEBUG
	NsmDbgMsg("HsmUnInitialize: Adapter uninitialized.\n");
#endif
	return ;
}       /*      end of HsmUnInitialize()        */ 

/******************************************************************************
*f*
*   Name:               
*          	HsmFreeResources
*
*   Description:        
*   		Free the resources allocated based on the errcode passed.
*
*   Parameters:     
*          pAdapter        - Pointer to the adapter context.
*
*          errcode         - UNINITIALIZE / RXINIT_FAILED ...
*
*   Return Value:   
*                       NONE.
*
*f*
******************************************************************************/
VOID
HsmFreeResources(AdapterContext *pAdapter, UINT errcode)
{
	AddrStruct      Addr;
	USHORT          Idx, RCBidx;
	UINT            RCBsz = 0, TCBsz; 
/*
 * 	This is a free fall switch case condition that is being used to
 * 	to free the resources depending upon how far we gone into the 
 * 	allocation routine before we encounter a failure and then
 * 	free all the resources that were allocated before it.
 */
	switch(errcode) {
		case UNINITIALIZE :
		case RXINIT_FAILED :
/*
 *      Free the Rx buffers allocated for all the priority queues.
 */
		/*Change NumPrio to RxNumPrio
		for (Idx = 0; Idx < pAdapter->NumPrio; Idx++) {*/
		for (Idx = 0; Idx < pAdapter->RxNumPrio; Idx++) {

			for (RCBidx = 0; RCBidx < pAdapter->PriQue[Idx].iMaxRxDesc; 
					RCBidx++) {
				Addr.VirtAddr = 
					pAdapter->PriQue[Idx].pRcbArray[RCBidx].pDataBuf; 
				Addr.PhysAddr = (UCHAR *)
					pAdapter->PriQue[Idx].pRcbArray[RCBidx].pRxDp->BufPtr;
				Addr.BufSize = pAdapter->MaxPktSize;
				Addr.pCookie = pAdapter->PriQue[Idx].pRcbArray[RCBidx].pOsCtrlBlk; 

				NsmDeAllocatePacket(pAdapter->pNsmContext, &Addr, 
					&pAdapter->PriQue[Idx].pRcbArray[RCBidx]);

			}       /*      end of for(RCBidx....   )       */
                                
		}       /* end of for( Idx = 0; Idx < pAdapter->NumPrio; Idx++) */

		case RCB_ALLOC_FAILED:
/*
 *      Free RCB array
 */
			if (pAdapter->pRcbArray) {
				RCBsz = 0;
				for(Idx = 0; Idx < pAdapter->NumPrio; Idx++) 
					RCBsz += sizeof(HsmRCB) *  pAdapter->RxDp[Idx][DESCCNT];
					NsmFree((PVOID)pAdapter->pRcbArray, RCBsz);
				}

		case TCB_ALLOC_FAILED:
/*
 *      Free TCB array
 */
			if (pAdapter->pTcbArray) {
				/*NumPrio to TxNumPrio*/
				TCBsz = 0;
				for(Idx = 0; Idx < pAdapter->NumPrio; Idx++) 
					TCBsz += (sizeof(HsmTCB) * pAdapter->TxDp[Idx][DESCCNT]);
					NsmFree(pAdapter->pTcbArray, TCBsz);
			}
/*
 *      Free the Descriptor array.
 */
			if (pAdapter->pDescList.VirtAddr != NULL) {
				Addr.pCookie = pAdapter->pDescList.pCookie;
				Addr.VirtAddr = pAdapter->pDescList.VirtAddr;
				/*Free proper size*/
        		Addr.BufSize = pAdapter->pDescList.BufSize;

				Addr.pCookie = pAdapter->pDescList.pCookie;
				/*Add cache flag
				NsmFreeContiguous(pAdapter->pNsmContext,&Addr);*/
				NsmFreeContiguous(pAdapter->pNsmContext,&Addr,0);
			}       

		case DP_ALLOC_FAILED :
/*
 *      Free the priority queue allocated.
 */
			NsmFree(pAdapter->PriQue, sizeof(PriorityQue) * pAdapter->NumPrio );
                
		case PRI_QUE_FAILED :
/*
 *      Destroy the locks and free the Static PktStruct's.
 */
#ifdef ALLOC_PKTSTRUCT
			StackFree(pAdapter);
			NsmDestroyLock(pAdapter->pNsmContext, pAdapter->ListLock);
#endif
			NsmDestroyLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
			NsmDestroyLock(pAdapter->pNsmContext, pAdapter->TxLock);
			break;
	}       /*      end of switch() */
        return ;
}       /*      End of HsmFreeResources()       */

/******************************************************************************
*f*
*   Name:               
*                       HsmInitContext
*
*   Description:        
*  			Initialize the HSM related fields in the adapter context. 
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       SUCCESS			- Success 
*                       FAILURE			- EEPROM failed to load
*
*f*
******************************************************************************/
UCHAR
HsmInitContext(AdapterContext *pAdapter)
{
	UCHAR   AdapterPQ ;
	UINT	Ptscr_val, i;
	UINT Cfg_val;

	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + CFG,
		&Cfg_val);
	if(Cfg_val & TBI_EN)
		pAdapter->tbi = 1;

/*Setting up the descriptors */
#ifdef _GA621_

pAdapter->TxDp[0][0] = TXDP;
pAdapter->TxDp[0][1] = 0;
pAdapter->TxDp[0][2] = 0;
pAdapter->TxDp[0][3] = TXDP0_PRISEL;
pAdapter->TxDp[1][0] = TXDP1;
pAdapter->TxDp[1][1] = 0;
pAdapter->TxDp[1][2] = 0;
pAdapter->TxDp[1][3] = TXDP1_PRISEL;
pAdapter->TxDp[2][0] = TXDP2;
pAdapter->TxDp[2][1] = 0;
pAdapter->TxDp[2][2] = 0;
pAdapter->TxDp[2][3] = TXDP2_PRISEL;
pAdapter->TxDp[3][0] = TXDP3;
pAdapter->TxDp[3][1] = 0;
pAdapter->TxDp[3][2] = 0;
pAdapter->TxDp[3][3] = TXDP3_PRISEL;

pAdapter->RxDp[0][0] = RXDP;
pAdapter->RxDp[0][1] = 0;
pAdapter->RxDp[0][2] = 0;
pAdapter->RxDp[0][3] = RXDP0_PRISEL;
pAdapter->RxDp[1][0] = RXDP1;
pAdapter->RxDp[1][1] = 0;
pAdapter->RxDp[1][2] = 0;
pAdapter->RxDp[1][3] = RXDP1_PRISEL;
pAdapter->RxDp[2][0] = RXDP2;
pAdapter->RxDp[2][1] = 0;
pAdapter->RxDp[2][2] = 0;
pAdapter->RxDp[2][3] = RXDP2_PRISEL;
pAdapter->RxDp[3][0] = RXDP3;
pAdapter->RxDp[3][1] = 0;
pAdapter->RxDp[3][2] = 0;
pAdapter->RxDp[3][3] = RXDP3_PRISEL;

#elif _DP83815_

pAdapter->TxDp[0][0] = TXDP;
pAdapter->TxDp[0][1] = 0;
pAdapter->TxDp[0][2] = 0;
pAdapter->TxDp[0][3] = TXDP0_PRISEL;

pAdapter->RxDp[0][0] = RXDP;
pAdapter->RxDp[0][1] = 0;
pAdapter->RxDp[0][2] = 0;
pAdapter->RxDp[0][3] = RXDP0_PRISEL;

UINT phyConfigData[] = { 0x0005e000,
                         0x00044000,
                         0x00040000,
                         0x0005a000,
                         0x00058000 };

#endif

#ifdef _GA621_
	for (i=0; i<MAXPRI_ADAPTER; i++) {
	
		pAdapter->TxDp[i][MINDESCCNT] = (pAdapter->TxQueueSz[i]/2);
		pAdapter->TxDp[i][DESCCNT] = pAdapter->TxQueueSz[i];
		pAdapter->RxDp[i][MINDESCCNT] = (pAdapter->RxQueueSz[i]/2);
		pAdapter->RxDp[i][DESCCNT] = pAdapter->RxQueueSz[i];
	
	}
#elif _DP83815_
	pAdapter->TxDp[0][MINDESCCNT] = (pAdapter->TxQueueSz[0]/2);
	pAdapter->TxDp[0][DESCCNT] = pAdapter->TxQueueSz[0];

	pAdapter->RxDp[0][MINDESCCNT] = (pAdapter->RxQueueSz[0]/2);
	pAdapter->RxDp[0][DESCCNT] = pAdapter->RxQueueSz[0];
#endif

	/* Default vaules , they must be reintialized after calling InitContext */
	pAdapter->IntrHoldoff  = 1;
	pAdapter->NcBit = 1;
	pAdapter->TxDrth = 0;					/*	Tx Drain Threshold */
	pAdapter->RxDrth = 0;					/*	Rx Drain Threshold */
	pAdapter->TxFlth = 1;					/*	Tx Fill Threshold */
	pAdapter->PauseCounterVal = 65535;		/* Pause Frames Counter Delay */
	pAdapter->RxFFLO = 4;
	pAdapter->RxFFHI = 8;
	pAdapter->RxSTLO = 4;
	pAdapter->RxSTHI = 4;
	pAdapter->NsmPhySleep = 0;				/* Do not use the AUTONEG routine in ISR */
	pAdapter->VLANId = ((pAdapter->VLANId & 0xFF) << 8) | ((pAdapter->VLANId >> 8) & 0xF);  
	pAdapter->FlowControl = RX_PAUSE_FRAMES_ENABLE;	/* Enable Pause Frames Rx and Tx */


/* Adding Code for loading of EEPROM Registers */

	NsmRegRead32(pAdapter->pNsmContext,(pAdapter->RegAddr+PTSCR), &Ptscr_val);
	Ptscr_val |= EELOAD;
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr+PTSCR), Ptscr_val);
	
	i = 0;
	do {
		NsmSleep(pAdapter->pNsmContext, 10);    
		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + PTSCR), &Ptscr_val);
	} while ( (Ptscr_val & EELOAD) && ++i<500 ); 

	if(i == 500)
		return FAILURE;

	HsmGetMacAddress(pAdapter);
#ifdef NSCDEBUG
    NsmDbgMsg1("HsmInitContext: The factory MAC address is %x \n", pAdapter->PermMacAddr);
#endif
#ifdef _GA621_
	pAdapter->PhysCapabilities  = 
		( VLAN_TAG_INSERTION_GEN_ON | TX_CHKSUM_OFFLOAD_ON_GEN | 
			SET_RX_CHKSUM_OFFLOAD_ON | JUMBO_FRAMES_ON | AUTO_NEG_ON | 
			SET_WOL_ON | BIG_ENDIAN );
#elif _DP83815_
	pAdapter->PhysCapabilities  = 
		( JUMBO_FRAMES_ON | AUTO_NEG_ON | SET_WOL_ON | BIG_ENDIAN );
#endif

/*
 *      Determine the number of priority queues to be created based on Adapter 
 *      supported PQ and operating system supported PQ.
 */
	AdapterPQ = MAXPRI_ADAPTER;

#ifdef _GA621_
/*
 *      In DP83815 priority queues are not supported.
 */
	if (pAdapter->OsPrio < AdapterPQ)
		AdapterPQ = pAdapter->OsPrio;   
#endif
        
	pAdapter->NumPrio = pAdapter->TxNumPrio = pAdapter->RxNumPrio = AdapterPQ;

	return SUCCESS;

}       /*      End of HsmInitContext() */

/******************************************************************************
*f*
*   Name:               
*                       HsmInitRegs
*
*   Description:        
*                       Initialize the following registers. This is called from HsmOpen().
*
*                       1. Command Register(CR)
*                       2. Configuration Register (CFG)
*                       3. Interrupt Mask Register (IMR)
*                       4. Interrupt Hold-off Register (IHR)
*                       5. Transmit Configuration Register (TXCFG)
*                       6. Receive Configuration Register (RXCFG)
*                       7. Priority Queue Control Register (PQCR)
*
*   Parameters:     
*                       pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*                       NONE.
*
*f*
******************************************************************************/
VOID
HsmInitRegs(AdapterContext *pAdapter) 
{
	UCHAR           priIdx;
	UINT            TxFlth, TxDrth, RxDrth, Mibc_val;
	UINT            Cr_val , Cfg_val , Imr_val;
	UINT            Pcr_val , Ihr_val , Txcfg_val , Rxcfg_val , Pqcr_val;
	UINT            Bmcr_val;
	UINT 			Gpior_val;
	UINT 			Vdr_val;

	Cr_val = Cfg_val = Imr_val =  0;
	Pcr_val = Ihr_val = Txcfg_val = Rxcfg_val = Pqcr_val = 0;
	Bmcr_val = 0;

#ifdef NSCDEBUG
	NsmDbgMsg("HsmInitRegs: Initializing the registers \n");
#endif
/*
 *      Set the physical capabilties of the adapter. 
 */
	HsmSetPhyCapabilities(pAdapter, pAdapter->PhysCapabilities, 1);
/*
 *      CFG Register Setting. 
 *
 *      Read the Speed and Duplex mode and store the values in Adapter context.
 *      Set BEM bit if BIG_ENDIAN is set in pAdapter->PhysCapabilities.
 *      Set EXSTS_EN if VLAN/CHKSUM offloading is set in 
 *		pAdapter->PhysCapabilities.
 */
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), &Cfg_val);

#ifdef _GA621_
	if ((Cfg_val & SPEEDMASK) == SPEED10)
		pAdapter->MediaSpeed = 10;
	if ((Cfg_val & SPEEDMASK) == SPEED100)
		pAdapter->MediaSpeed = 100;
	if ((Cfg_val & SPEEDMASK) == SPEED1000)
		pAdapter->MediaSpeed = 1000;

	if ((Cfg_val & DUPSTS) == FULL_DUPLEX)
		pAdapter->DuplexMode = FULL_DUPLEX;
	else
		pAdapter->DuplexMode = HALF_DUPLEX;
#elif _DP83815_
	if (Cfg_val & SPEED100)
		pAdapter->MediaSpeed = 100;
	else
		pAdapter->MediaSpeed = 10;

	if (Cfg_val & FDUP)
		pAdapter->DuplexMode = FULL_DUPLEX;
	else
		pAdapter->DuplexMode = HALF_DUPLEX;
#endif
	if (pAdapter->PhysCapabilities & BIG_ENDIAN)
		Cfg_val |= BEM;

/*
 *      Set ED (Excessive Deferral) and PINT_CTL (Phy.Interrupt control).
 */
#ifdef _GA621_
		/*Enable 64 bit data transfer and increase internal clock speed
		Cfg_val |= (EXD | PINT_DUPSTS | PINT_LNKSTS | PINT_SPDSTS);*/
		Cfg_val |= (EXD | PINT_DUPSTS | PINT_LNKSTS | PINT_SPDSTS | TMRTEST);

		if(Cfg_val & PCI64_DET)
			Cfg_val |= DATA64_EN;
		else
			Cfg_val &= ~DATA64_EN;
#else
		Cfg_val |= (EXD);
#endif

		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr+CFG), Cfg_val);
#ifdef _GA621_
/*
 *      CR - Command Register
 *
 *      Enable the TXPRI and RXPRI bits in the Command Register(CR).
 */
		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), &Cr_val);
		Cr_val = 0;
		for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++)
			Cr_val |= (pAdapter->RxDp[priIdx][PRIQSEL]) ; /* Enable only RX queues*/

		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), Cr_val);
#endif 
/*
 *      IMR     - Interrupt Mask Register.
 *
 *      Enable the bits in the Interrupt Mask Register (IMR).
 */
		Imr_val = (RXOK | RXERR | RXORN |RXSOVR | RXIDLE | TXOK |  
			TXERR | TXURN | MIB | SWI_INTR | PME | PHY | 
			RTABT | RMABT | TXRCMP | RXRCMP); 
#ifdef _GA621_
		for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++) { 
			Imr_val |= ( 1 << (27+priIdx) );     /* Tx descriptor priority */
			Imr_val |= ( 1 << (23+priIdx) );     /* Rx descriptor priority */
		} 
#endif
		NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr+ IMR), Imr_val);

#ifdef _GA621_
/*
 *      IHR     - Interrupt Hold-off Register.
 *
 *      Set the Interrupt-holdoff value in IHR.
 */
		if (pAdapter->IntrHoldoff) {
			/* NsmRegRead32(pAdapter->pNsmContext,(pAdapter->RegAddr + IHR), 
				&Ihr_val);*/
			Ihr_val = (pAdapter->IntrHoldoff | IHCTL);
			NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + IHR), 
				Ihr_val);
		}
#endif
/*
 *      TXCFG - Transmit Configuration register. 
 *
 *      Set the TX drain threshold, Tx Fill threshold, Max DMA burst size , 
 *      Automatic Transmit Padding, Carrier Sense Ignore bits , 
 *      Heart Beat Ignore in TXCFG register
 */
		Txcfg_val = 0;
		
        TxDrth = (pAdapter->TxDrth & 0xFF);
		TxFlth = (pAdapter->TxFlth & 0xFF); 
		
		if (TxFlth == 0)
			TxFlth = 1;
        
		/*The TxDrth Threshold should not exceed TxFIFO/32(bytes) Size - TxFlth*/
		if (TxDrth > ( (TX_FIFO / 32) - TxFlth ) )
			TxDrth = ( ((TX_FIFO / 32) - 1) - TxFlth );
        
		TxFlth <<= 8;
        
		Txcfg_val = (TxDrth | TxFlth);
        
        switch (pAdapter->TxMaxDMASize ) {
                case 8:
                        Txcfg_val |= MXDMA8;
                        break;
                case 16:
                        Txcfg_val |= MXDMA16;
                        break;
                case 32:
                        Txcfg_val |= MXDMA32;
                        break;
                case 64:
                        Txcfg_val |= MXDMA64;
                        break;
                case 128:
                        Txcfg_val |= MXDMA128;
                        break;
				default:
                case 256:
                        Txcfg_val |= MXDMA256;
                        break;
                case 512:
                        Txcfg_val |= MXDMA512;
                        break;
                case 1024:
                        Txcfg_val |= MXDMA1024;
                        break;
        }               /*      end of switch(pAdapter->CacheLineSize)  */

		if (pAdapter->UserDuplexMode == FULL_DUPLEX)
			Txcfg_val |= ( HBI | CSI );
		/*CSI only in FULL DUPLEX MODE */
		Txcfg_val |= (ATP | ECRETRY);

		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TXCFG),
			Txcfg_val);
/*
 *      RXCFG - Receive Configuration register. 
 *
 *      Set the RX drain threshold, Max DMA burst size, Strip CRC, Rx Full 
 *      Duplex, Accept Errored packets , Accept Runt packets , Accept Long 
 *		Packets.
 */
		Rxcfg_val = 0;
        
		/* The Maximum value is 5 bits  and start from 1st bit */
		RxDrth = (pAdapter->RxDrth & 0x1F);
      	RxDrth <<= 1; 

		Rxcfg_val = RxDrth;

        switch (pAdapter->RxMaxDMASize) {
                case 8:
                        Rxcfg_val |= MXDMA8;
                        break;
                case 16:
                        Rxcfg_val |= MXDMA16;
                        break;
                case 32:
                        Rxcfg_val |= MXDMA32;
                        break;
                case 64:
                        Rxcfg_val |= MXDMA64;
                        break;
                case 128:
                        Rxcfg_val |= MXDMA128;
                        break;
				default:
                case 256:
                        Rxcfg_val |= MXDMA256;
                        break;
				case 512:
                        Rxcfg_val |= MXDMA512;
                        break;
				case 1024:
                        Rxcfg_val |= MXDMA1024;
                        break;
        }        /*      end of switch(pAdapter->CacheLineSize)  */

		if (pAdapter->PhysCapabilities & JUMBO_FRAMES_ON)
                Rxcfg_val |= (ALP);

#ifdef _GA621_
		/*
		 Do not accept ERRORED and RUNT packets
        Rxcfg_val |= (AEP | ARP | STRIPCRC | RX_FD | AIRL);*/
        Rxcfg_val |= ( STRIPCRC | AIRL );

		/*
		 * If we have VLAN Enabled then we Accept Runt Packets.
		 * this is to solve the problem of card not accepting 64 bytes
		 * VLAN Tagged packets.
		 */
		if(pAdapter->PhysCapabilities & (VLAN_TAG_INSERTION_PP_ON | VLAN_TAG_INSERTION_GEN_ON))
			Rxcfg_val |= ARP;

		/* RX_FD only in FULL DUPLEX mode*/
		if (pAdapter->UserDuplexMode == FULL_DUPLEX)
        	Rxcfg_val |= RX_FD;
		
#elif _DP83815_
        Rxcfg_val |= (ARP);
#endif

		NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + RXCFG),
			Rxcfg_val);

#ifdef _GA621_
/*
 *      PQCR    - Priority Queue Control Register. 
 *
 *      Set TXPQEN and RXPQ.
 */
		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + PQCR), 
			&Pqcr_val);

		if (pAdapter->TxNumPrio > 1)
			Pqcr_val |= TXPQEN;
        
		if (pAdapter->RxNumPrio == 4)
			Pqcr_val |= RXPQ4;
		if (pAdapter->RxNumPrio == 3)
			Pqcr_val |= RXPQ3;
		if (pAdapter->RxNumPrio == 2)
			Pqcr_val |= RXPQ2;

        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PQCR), 
			Pqcr_val);
#endif 

/*
 *      PCR - Pause Control Register. 
 *
 *      Set Rx stat FIFO HI threshold, RX stat FIFO LO threshold, Rx Data Fifo 
 *      Hi threshold, Rx Data FIFO Lo threshold, Pause Length select, Pause 
 *      Counter value.
 */

		Pcr_val = 0;
        
/*
 * 		Do not activate Pause Frames for Half Duplex mode 
 */
		if (pAdapter->UserDuplexMode == FULL_DUPLEX)
		{
			/* 
			 * Tx Flow Control
 			 * Check if Tx Pause Control is required.
			 */
			if (pAdapter->FlowControl & TX_PAUSE_FRAMES_ENABLE)
			{
#ifdef NSCDEBUG
				NsmDbgMsg("HsmInitRegs : Enable Tx Flow Control\n");  
#endif
				if (pAdapter->RxFFLO > pAdapter->RxFFHI)
					pAdapter->RxFFLO = pAdapter->RxFFHI;

				if (pAdapter->RxSTLO > pAdapter->RxSTHI)
					pAdapter->RxSTLO = pAdapter->RxSTHI;
				
				if (pAdapter->RxFFLO == 2)
					Pcr_val |= PS_FFLO_2K;
				if (pAdapter->RxFFLO == 4)
					Pcr_val |= PS_FFLO_4K;
				if (pAdapter->RxFFLO == 8)
					Pcr_val |= PS_FFLO_8K;

				if (pAdapter->RxFFHI == 2)
					Pcr_val |= PS_FFHI_2K;
				if (pAdapter->RxFFHI == 4)
					Pcr_val |= PS_FFHI_4K;
				if (pAdapter->RxFFHI == 8)
					Pcr_val |= PS_FFHI_8K;

				if (pAdapter->RxSTLO == 2)
					Pcr_val |= PS_STLO_2;
				if (pAdapter->RxSTLO == 4)
					Pcr_val |= PS_STLO_4;
				if (pAdapter->RxSTLO == 8)
					Pcr_val |= PS_STLO_8;

				if (pAdapter->RxSTHI == 2)
					Pcr_val |= PS_STHI_2;
				if (pAdapter->RxSTHI == 4)
					Pcr_val |= PS_STHI_4;
				if (pAdapter->RxSTHI == 8)
					Pcr_val |= PS_STHI_8;
				
				Pcr_val |= pAdapter->PauseCounterVal;
			}
				
			/* 
			 * Rx Flow Control
 			 * Check if Rx Pause Control is required.
			 */
			if (pAdapter->FlowControl & RX_PAUSE_FRAMES_ENABLE)
			{
#ifdef NSCDEBUG
				NsmDbgMsg("HsmInitRegs : Enable Rx Flow Control\n");  
#endif
				Pcr_val |= (PS_MCAST | PS_DA | PSEN);
			}
		}


        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), 
			Pcr_val);

		
#ifndef PRIORITY
/*		
 *		Set up the VLAN tagging for Global Generation if set
 *		If we DONT have PRIORITY flag defined then we are
 *		using Global Generation since OS does not support
 *		Priorities, else we use Per Packet Generation.
 */
		NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + VDR, &Vdr_val);
		Vdr_val |= (pAdapter->VLANId << 16);
		NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + VDR, Vdr_val);
#endif

		
/* 
 *      MIBC    - MIB Control/Status Register.
 *
 *      Clear all the counters in the MIBC register. 
 */
        NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + MIBC), 
			&Mibc_val);
        Mibc_val |= ACLR;
        Mibc_val &= ~(FRZ);
        NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + MIBC), 
			Mibc_val);

/*
 *	Set the default bits (APM , AAB) in RFCR. 
 */
		HsmRxFilter(pAdapter, 0);
		if(pAdapter->tbi)
		{
			/* Initialize the GPIOR */
        	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), &Gpior_val);
			Gpior_val |= 0x3e8; /* Places in TBI mode. */
        	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), Gpior_val);
		}

}       /*      end of HsmInitRegs()    */

#ifdef _GA621_
/******************************************************************************
*f*
*   Name:               
*			HsmCreateMapValue
*
*   Description:        
*			Create the mapping value and store it in pAdpater->PriMapVal.
*
*   Parameters:     
*			pAdapter        - Pointer to the adapter context.
*
*   Return Value:   
*			NONE.
*
*f*
******************************************************************************/
VOID
HsmCreateMapValue(AdapterContext *pAdapter)
{ 
	USHORT  AdapterPQ, OsPQ;

	AdapterPQ = pAdapter->TxNumPrio;
	OsPQ = pAdapter->OsPrio;
        
	if (pAdapter->OsPrio < AdapterPQ)
		AdapterPQ = OsPQ;

	if (pAdapter->OsPrio == AdapterPQ)
		pAdapter->TxPriMapVal = PRI_QUOTIENT;
	else 
		pAdapter->TxPriMapVal = ( OsPQ * PRI_QUOTIENT / AdapterPQ );

	AdapterPQ = pAdapter->RxNumPrio;
	if (pAdapter->OsPrio < AdapterPQ)
		AdapterPQ = OsPQ;

	if (pAdapter->OsPrio == AdapterPQ)
		pAdapter->RxPriMapVal = PRI_QUOTIENT;
	else 
		pAdapter->RxPriMapVal = ( OsPQ * PRI_QUOTIENT / AdapterPQ );

}       /*      End of HsmCreateMapValue        */ 
#endif 

/*
 *      Functions related to ISR.
 */

/******************************************************************************
*f*
*       Name :
*			HsmIsr
*
*       Description     :
*			This routine is called from NSM interrupt service routine. 
*			HsmIsr determines the interrupt type by reading Interrupt Status
*			Register and handles them appropriately.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext  
*    
*       Return Value :
*			INTR_CLAIMED   - If interrupt is claimed.
*			INTR_UNCLAIMED - if otherwise.
*    
*f*
******************************************************************************/
UCHAR
HsmIsr(AdapterContext *pAdapter)
{
	UINT interruptStatus = pAdapter->interruptStatus;
	UINT phyStatus = 0;
	UINT Cr_val = 0;
	
	UINT Ihr_val;
	UCHAR status = INTR_UNCLAIMED;
	UCHAR priIdx;
	UINT	Reg_val=0;
	UINT	Bmsr_val=0;			
	UINT	Bmcr_val;
	UINT	i = 0, Tx = 0, Rx = 0;
	UINT	N_stat;		
	UINT	Tanlpar_val;		
	UINT	Anlpar_val;
	UINT    Pcr_val;
	UINT	Tanar_val;		
	UINT	Tbisr_val;
	UINT	Gpior_val = 0;		

#ifdef FWARE_DOWNLOAD
	UCHAR Stat;
#endif

	/* 
	 * First thing in the ISR, disable all interrupts from the adapter 
	 * by writing a 0 to the interrupt enable flag in the Interrupt 
	 * Enable Register. Read the interrupt from the ISR.
	 */

	HsmDisableInterrupts(pAdapter);
	if(pAdapter->tbi)
	{
/*   Added to spread long enough duration in ISR for LED to light.*/
		if (interruptStatus & ( RXOK | RXERR | RXIDLE | RXORN | RXSOVR | TXOK | TXERR) ) {
				NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + GPIOR,
					&Gpior_val);
				Gpior_val |= GP3_OUT;
				NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + GPIOR,
					Gpior_val);
			}
	}		

	if ( !(interruptStatus) ) {
		NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + ISR, &interruptStatus );	
		pAdapter->interruptStatus = interruptStatus;
	}

	/* while ( interruptStatus ) */
	if ( interruptStatus ) {
		status = INTR_CLAIMED;
		pAdapter->interruptStatus = interruptStatus;
#ifdef NSCDEBUG
		NsmDbgMsg1("HsmIsr : Interrupt Status = %d\n",interruptStatus);
#endif

		
/* 
 * 		If HsmClose forces NIC to generate software interrupt (SWI) 
 * 		or HsmReset forces NIC to a soft reset state (RST triggers 
 * 		TXRCMP event) then process the packets posted to the adapter 
 * 		for transmission.
 */
/*
 * 		Power management (indicating the idleness of the adapter) 
 *		can be handled in  HsmTxCompleted().
 *     		if (interruptStatus & TXIDLE)
 *     				pAdapter->TxEnableFlag = 1;
 */


			
#ifdef NSCDEBUG
			/* Checking for an active timing Pause Frame */
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), &Pcr_val);
			if(Pcr_val & PS_ACT )  
				NsmDbgMsg1("HsmIsr : Pause frame actively timing 0x%x\n", Pcr_val );
			if(Pcr_val & PS_RCVD )  
				NsmDbgMsg("HsmIsr : Pause frame Recieved\n");
#endif
		
		
		
/* 
 *		Check if there's a receive interrupt and handle the same 
 */
		/*Combining both HsmRxPackets*/
		if (interruptStatus & ( RXOK | RXERR | RXIDLE | RXORN | RXSOVR) ) {

#ifdef NSCDEBUG
			NsmDbgMsg("HsmIsr: Got Receive interrupt \n");  
#endif
			HsmRxPackets (pAdapter);
			if ((pAdapter->CurrHoldOff) && (interruptStatus & RXOK))
			{
				/*Don't bring it back, if we still have IDLE*/
				if (!(interruptStatus & ( RXIDLE | RXORN | RXSOVR) )) {
					if (pAdapter->IntrHoldoff) {
						Ihr_val = 0;
						pAdapter->CurrHoldOff = 0;
						Ihr_val = pAdapter->IntrHoldoff | IHCTL;
						NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + IHR), 
						Ihr_val);
					}
				}
			}

		}







		
/* 
 *		Check if there's a transmit interrupt and handle the same 
 */ 
		if (interruptStatus & (TXOK | TXERR | TXURN) ) {
#ifdef NSCDEBUG
			NsmDbgMsg("HsmIsr: Got Transmit interrupt \n");  
#endif
			HsmTxCompleted (pAdapter);
		} 		/*	end of if (interruptStatus & (TXOK | TXERR) ) */






		
		

		if (interruptStatus & (SWI_INTR) ) { 

/*
 *	Reset the Adapter (setting RST bit in CR register) and wait till the reset
 *	is complete.
 */
		
		/*Wait for TXD and RXD and then read the ISR
		If we have a RXOK and TXOK then we set a bit and call 
		TxCompleted and RxPackets after the ResetComplete
		Following which we check for any pending Tx packets and start
		the TXEngine.*/
        		i = 0;
				do {
           	   		  	NsmSleep(pAdapter->pNsmContext, 5);   
                		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
							&Cr_val);
        		} while ( (Cr_val & (RXE | TXE)) && ++i<100);
			
			
				/*new Status*/
				NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + ISR, &N_stat );	
				/*Include the reset status*/
				pAdapter->interruptStatus |= N_stat;
				interruptStatus = pAdapter->interruptStatus;
				
				/*check for the TXOK and RXOK*/
				if ( N_stat & (TXOK | TXERR) )
					HsmTxCompleted (pAdapter);
				
				if ( N_stat & (RXOK | RXERR) )
					HsmRxPackets (pAdapter);

			
			if (pAdapter->AdapterStatus & ADAPTER_RESETTING)
			{
        		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), RST);

        		i = 0;
				do {
           	   		  	NsmSleep(pAdapter->pNsmContext, 5);   
                		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
							&Cr_val);
        		} while ( (Cr_val & RST) && ++i<400 ); 
		if(!(pAdapter->tbi))
		{
/*
 * Reset the PHY register using BMCR
 */
#ifdef _DP83815_
        		NsmRegWrite16(pAdapter->pNsmContext,
						(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
	        		WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif 
/*
 *      Wait for the BMCR_RESET bit to clear, for reset complete.
 */
        		i = 0;
				do {

	        		NsmSleep(pAdapter->pNsmContext, 5 );
#ifdef _DP83815_
					NsmRegRead16(pAdapter->pNsmContext,
							(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
					Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
        		} while ( (Bmcr_val & BMCR_RESET) && ++i<800 ); 
			/* Clear the statistics MIB counter */
		}
        		HsmClearStatistics(pAdapter);

/* There is a potential problem here if the BMCR_RESET has not completed the download won't have any effect */ 
	if(!(pAdapter->tbi))
	{
#ifdef FWARE_DOWNLOAD
		if (pAdapter->FileHandle) {
			
			/* Wait For the Phy to reset properly */
			NsmSleep(pAdapter->pNsmContext, 500 );
			
			HsmDownLoadFirmwareInit(pAdapter);

			Stat = NsmDownLoadFirmwareFromFileX(pAdapter);
			
			if( Stat == FAILURE ) {
			
				/* Event log */
				NsmDownLoadFailed(pAdapter);
				/*
				 * Reset the PHY register using BMCR incase of a DownloadFail
				 */
#ifdef _DP83815_
								NsmRegWrite16(pAdapter->pNsmContext,
										(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
								WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif
				/*
				 *      Wait for the BMCR_RESET bit to clear, for reset complete.
				 */
								i = 0;
								do {

									NsmSleep(pAdapter->pNsmContext, 5 );
#ifdef _DP83815_
									NsmRegRead16(pAdapter->pNsmContext,
											(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
									Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
								} while ( (Bmcr_val & BMCR_RESET) && ++i<800 ); 

			}
			
			else { /* if the download is successful */
				
				HsmStartFirmWareCode(pAdapter);
		 
				Stat = HsmVerifyDownLoad(pAdapter);

				if(Stat == FAILURE)
				{
					/* Event log */
					NsmDownLoadFailed(pAdapter);
				/*
				 * Reset the PHY register using BMCR incase of a DownloadFail
				 */
#ifdef _DP83815_
								NsmRegWrite16(pAdapter->pNsmContext,
										(pAdapter->RegAddr + BMCR), BMCR_RESET);
#else
								WriteMiiReg(pAdapter, BMCR, BMCR_RESET);
#endif
				/*
				 *      Wait for the BMCR_RESET bit to clear, for reset complete.
				 */
								i = 0;
								do {

									NsmSleep(pAdapter->pNsmContext, 5 );
#ifdef _DP83815_
									NsmRegRead16(pAdapter->pNsmContext,
											(pAdapter->RegAddr + BMCR), &Bmcr_val);
#else
									Bmcr_val = ReadMiiReg(pAdapter, BMCR);
#endif
								} while ( (Bmcr_val & BMCR_RESET) && ++i<800 ); 

				}
			}
		}
#endif
	} /* end of if (!(pAdapter->tbi))*/

				
/*
 *	Set the MAC address stored in pAdapter->CurrMacAddr and load the filter 
 *	memory with the multicast addresses stored in the Adapter context.
 *	Add the Pause Multicast address for Rx Pause Control.
 */
				refresh_mca_tbl(pAdapter);
				HsmSetMacAddress(pAdapter, pAdapter->CurrMacAddr);
				
				pAdapter->AdapterStatus &= ~LINK_UP;
				NsmIndicateLinkStatus(pAdapter->pNsmContext);
				
				HsmOpen(pAdapter);

				/*Status already indicated*/
				pAdapter->interruptStatus &= ~PHY;
				interruptStatus = pAdapter->interruptStatus;
			}

		}

							/* End of SWI_INTR*/





	
	
/* 
 *		Collect adapter's MIB statistics if one of the MIB counters has reached 
 *		its interrupt threshold.
 */
		if ( interruptStatus & MIB ) 
			ReadMIBCounters(pAdapter);









/* 
 *  	Handle phy interrupt 
 */
		if ( interruptStatus & PHY ) {
			if(pAdapter->tbi) {
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TBISR), 
				&Tbisr_val);
			}
			else {
				/*The PHYSUP register is showing the wrong value*/
				phyStatus = ReadMiiReg(pAdapter, PHYSUP);

				/*checking Link Up using BMSR
					Read it twice according to ERRATA in Documentation */
			
				Bmsr_val = ReadMiiReg(pAdapter, BMSR);
				Bmsr_val = ReadMiiReg(pAdapter, BMSR);
			}

/* 
 * If this is the result of a link detection, adjust our transmit 
 * and receive conigurations for the new duplex setting and 
 * report the cable connection.
 */

/* 
 * As phy status can be generated before auto neg has completed, 
 * we must wait for auto neg to complete, if we were configured for 
 * auto neg, in order for our configuration to occur properly.  
 */

/*If Link has come up and was down last time then tell NDIS
link came up, and then check if currently link is down and report accrodingly*/
			if(pAdapter->tbi)
			{
				if( Tbisr_val & MR_LINK_STATUS )  
				{
					if ( !(pAdapter->AdapterStatus & LINK_UP) ) 
					{
						pAdapter->AdapterStatus |= LINK_UP;
						NsmIndicateLinkStatus(pAdapter->pNsmContext);
					}

					if ( (pAdapter->AdapterStatus & ADAPTER_RESETTING) ) 	
					{
						NsmSleep(pAdapter->pNsmContext, 2500 );
						NsmResetComplete(pAdapter->pNsmContext);
						NsmAcquireDPCLock(pAdapter->pNsmContext, 
							pAdapter->AdapterLock);
						pAdapter->AdapterStatus &= ~ADAPTER_RESETTING;
						NsmReleaseDPCLock(pAdapter->pNsmContext, 
							pAdapter->AdapterLock);
					}
				}
			}
			else {
				if ( ((Bmsr_val & LINK_STATUS_UP) && (!(pAdapter->AdapterStatus & LINK_UP))) ) 
				{
					if (pAdapter->NsmPhySleep)
					{
					
/* 						If we are in Compliant Mode then
 * 						we have no problems and use the LINK_UP Bit
 * 						directly to indicate for NDIS.
 * 						Otherwise do the wait for Auto Neg to stabilize
 */
						Tx = 0;
						if ( !(pAdapter->NcBit) )
						{
							
/* 							The link is not always up
 * 							when the AUTO NEG is complete, Reset test 
 * 							fails sometimes.
 */
							i = 0;
							do
							{
								NsmSleep(pAdapter, 300);
								Tx = ReadMiiReg(pAdapter, BMSR);
								
								if ( Tx & AUTONEG_COMPLETE ) 
								{
									
/* 									Wait for the Link to get ready
 * 									before sending reset complete and 
 * 									getting ready to accept packets and 
 * 									see if the AUTONEG is actually complete
 * 									or a second Link is coming if we are not 
 * 									in IEEE mode.
 */
									NsmSleep(pAdapter, 300);
									Tx = ReadMiiReg(pAdapter, BMSR);
								}
							} while( (!(Tx & AUTONEG_COMPLETE)) && (++i < 30) );
						}
						
						if ( (pAdapter->NcBit) || (Tx & AUTONEG_COMPLETE) )
						{
							pAdapter->AdapterStatus |= LINK_UP;
							
#ifdef LINK_AGGR
							if (pAdapter->nFlags && (GetNumberOfLinks(pAdapter) == 1)) 
							{
								/* 
								 * Get current status of aggregator port
								 */
								UCHAR curstat;
								curstat = pAdapter->pAggregatorContext->AdapterStatus;
								
								pAdapter->pAggregatorContext->AdapterStatus |= LINK_UP;
								NsmIndicateLinkStatus(pAdapter->pAggregatorContext->pNsmContext);
								
								/* 
								 * Restore link status of aggregator port
								 */
								pAdapter->pAggregatorContext->AdapterStatus = curstat;
							}
							else if (pAdapter->nFlags == 0)
								NsmIndicateLinkStatus(pAdapter->pNsmContext);
#else
							NsmIndicateLinkStatus(pAdapter->pNsmContext);
#endif							
							if ( (pAdapter->AdapterStatus & ADAPTER_RESETTING) ) 	
							{
								
/* 								Wait for the Link to get ready for data xfer
 * 								before sending reset complete and 
 * 								getting ready to accept packets.
 */
								NsmSleep(pAdapter, 2000);

								NsmAcquireDPCLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
								pAdapter->AdapterStatus &= ~ADAPTER_RESETTING;
								NsmReleaseDPCLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
								NsmResetComplete(pAdapter->pNsmContext);
							}
						}
					}
					else
					{
						pAdapter->AdapterStatus |= LINK_UP;
#ifdef LINK_AGGR
							if (pAdapter->nFlags && (GetNumberOfLinks(pAdapter) == 1)) 
							{
								/* 
								 * Get current status of aggregator port
								 */
								UCHAR curstat;
								curstat = pAdapter->pAggregatorContext->AdapterStatus;
								
								pAdapter->pAggregatorContext->AdapterStatus |= LINK_UP;
								NsmIndicateLinkStatus(pAdapter->pAggregatorContext->pNsmContext);
								
								/* 
								 * Restore link status of aggregator port
								 */
								pAdapter->pAggregatorContext->AdapterStatus = curstat;
							}
							else if (pAdapter->nFlags == 0)
								NsmIndicateLinkStatus(pAdapter->pNsmContext);
#else
							NsmIndicateLinkStatus(pAdapter->pNsmContext);
#endif							
					}

				}
			}
				
/*If Link has come down and was up last time then tell NDIS
link came down, and then check if currently link is up and report accrodingly*/
			if(pAdapter->tbi)
			{
					if(!(Tbisr_val & MR_LINK_STATUS)) 
					{
						if ( pAdapter->AdapterStatus & LINK_UP) 
						{
							pAdapter->AdapterStatus &= ~(LINK_UP);
							NsmIndicateLinkStatus(pAdapter->pNsmContext);
						}
					}
			}
			else
			{
				if ( (!(Bmsr_val & LINK_STATUS_UP)) && (pAdapter->AdapterStatus & LINK_UP)) 
				{
					
					pAdapter->AdapterStatus &= ~(LINK_UP);
#ifdef LINK_AGGR
					if (pAdapter->nFlags && (GetNumberOfLinks(pAdapter) == 0))
						NsmIndicateLinkStatus(pAdapter->pAggregatorContext->pNsmContext);
					else if (pAdapter->nFlags == 0)
						NsmIndicateLinkStatus(pAdapter->pNsmContext);
#else
					NsmIndicateLinkStatus(pAdapter->pNsmContext);
#endif
				}
			}
			if (pAdapter->tbi) 
			{
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
				&Tanar_val);
				
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANLPAR),
				&Tanlpar_val);
					
				if ( (Tanlpar_val & FULL_DUP) && (Tanar_val & FULL_DUP) ) 
				{	 /*If partner full and we are full, configure full duplex */
					NsmRegRead32(pAdapter->pNsmContext, 
						pAdapter->RegAddr + TXCFG , &Reg_val);

					Reg_val |= (CSI | HBI | ATP);

					NsmRegWrite32(pAdapter->pNsmContext, 
						pAdapter->RegAddr + TXCFG , Reg_val);

					NsmRegRead32(pAdapter->pNsmContext, 
						pAdapter->RegAddr + RXCFG , &Reg_val);

					Reg_val |= (RX_FD);

					NsmRegWrite32(pAdapter->pNsmContext, 
						pAdapter->RegAddr + RXCFG, Reg_val );
					/* Light LED if full duplex */
					NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
						&Gpior_val);
					Gpior_val |= GP1_OUT;
					NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
						Gpior_val);
					
					/*
					 * If Link Partner supports Tx and Rx Flow Control.
					 * Then we enable Rx and Tx Flow control
					 * according to the user selection.
					 */

					/*
					 * First turn off all Flow control and then enable 
					 * Tx and Rx depending upon the partners capabilities.
					 */
					Pcr_val = Rx = Tx = 0;
					
					NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), 
						Pcr_val);
				
					/*
					 * Following the algorithm taken from the 
					 * 802.3 document table 37-4.
					 */
					
					/*
					 * If we support ASM_DIR.
					 * TX_PAUSE_FRAME_ENABLE turns on only ASM_DIR.
					 */
					if (pAdapter->FlowControl & TX_PAUSE_FRAMES_ENABLE)
					{
						/*
						 * If the partner has both ASM_DIR and PAUSE
						 */
						if((Tanlpar_val & (PS2 | PS1)) == (PS2 | PS1))
						{
							/*
							 * Enable our Transmit
							 */
							Tx = 1;
						}
					}

					/*
					 * If we support ASM_DIR and PAUSE.
					 * RX_PAUSE_FRAME_ENABLE turns on ASM_DIR and PAUSE.
					 */
					if (pAdapter->FlowControl & RX_PAUSE_FRAMES_ENABLE)
					{
						/*
						 * If the partner has PAUSE
						 */
						if(Tanlpar_val & PS1)
						{
							/*
							 * Enable our Transmit and Receive
							 */
							Tx = Rx = 1;
						}
						
						/*
						 * If the partner supports only ASM_DIR
						 */
						else if(Tanlpar_val & PS2)
						{
							/*
							 * Enable our Receive
							 */
							Rx = 1;
						}
					}

					
					if(Rx == 1)
					{
						
						/* 
						 * Rx Flow Control
						 */
						Pcr_val |= (PS_MCAST | PS_DA | PSEN);

						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), Pcr_val);
#ifdef NSCDEBUG
						NsmDbgMsg("HsmIsr: Rx Flow Control \n");
#endif

					}
					
					if(Tx == 1)
					{
						/* 
						 * Tx Flow Control
						 */
						if (pAdapter->RxFFLO > pAdapter->RxFFHI)
							pAdapter->RxFFLO = pAdapter->RxFFHI;

						if (pAdapter->RxSTLO > pAdapter->RxSTHI)
							pAdapter->RxSTLO = pAdapter->RxSTHI;
						
						if (pAdapter->RxFFLO == 2)
							Pcr_val |= PS_FFLO_2K;
						if (pAdapter->RxFFLO == 4)
							Pcr_val |= PS_FFLO_4K;
						if (pAdapter->RxFFLO == 8)
							Pcr_val |= PS_FFLO_8K;

						if (pAdapter->RxFFHI == 2)
							Pcr_val |= PS_FFHI_2K;
						if (pAdapter->RxFFHI == 4)
							Pcr_val |= PS_FFHI_4K;
						if (pAdapter->RxFFHI == 8)
							Pcr_val |= PS_FFHI_8K;

						if (pAdapter->RxSTLO == 2)
							Pcr_val |= PS_STLO_2;
						if (pAdapter->RxSTLO == 4)
							Pcr_val |= PS_STLO_4;
						if (pAdapter->RxSTLO == 8)
							Pcr_val |= PS_STLO_8;

						if (pAdapter->RxSTHI == 2)
							Pcr_val |= PS_STHI_2;
						if (pAdapter->RxSTHI == 4)
							Pcr_val |= PS_STHI_4;
						if (pAdapter->RxSTHI == 8)
							Pcr_val |= PS_STHI_8;
						
						Pcr_val |= pAdapter->PauseCounterVal;

						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), Pcr_val);
#ifdef NSCDEBUG
						NsmDbgMsg("HsmIsr: Tx Flow Control \n");
#endif

					}
				
				}
				else if(((Tanlpar_val & HALF_DUP) && (Tanar_val & HALF_DUP))
						|| ((Tanlpar_val & FULL_DUP) && (Tanar_val & HALF_DUP))
						|| ((Tanlpar_val & HALF_DUP) && (Tanar_val & FULL_DUP)))
				{	
							/* If partner full and we are half, configure half duplex
								 If partner half and we are half, configure half duplex
								 If partner half and we are full, configure half duplex
							 */
						NsmRegRead32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + TXCFG , &Reg_val);

						Reg_val &= ~(CSI | HBI);
						Reg_val |= (ATP);

						NsmRegWrite32(pAdapter->pNsmContext,
							pAdapter->RegAddr + TXCFG , Reg_val );

						NsmRegRead32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + RXCFG , &Reg_val);

						Reg_val &= ~(RX_FD);

						NsmRegWrite32(pAdapter->pNsmContext,
							pAdapter->RegAddr + RXCFG , Reg_val );
						/* Turn off Full Duplex Light */
						NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
							&Gpior_val);
						Gpior_val &= ~GP1_OUT;
						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
							Gpior_val);
				}
				else
				{	/* Default case when partner is forced, we default 1000FDx.*/
						NsmRegRead32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + TXCFG , &Reg_val);

						Reg_val |= (CSI | HBI | ATP);

						NsmRegWrite32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + TXCFG , Reg_val);

						NsmRegRead32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + RXCFG , &Reg_val);

						Reg_val |= (RX_FD);

						NsmRegWrite32(pAdapter->pNsmContext, 
							pAdapter->RegAddr + RXCFG, Reg_val );
						/* Turn on Full Duplex Light.*/
						NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
							&Gpior_val);
						Gpior_val |= GP1_OUT;
						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + GPIOR), 
							Gpior_val);
				}

			}
			else
			{
				/* 
				 * Read the Speed and Duplex again after
				 * the link is stable and then set the values.
				 */
				phyStatus = ReadMiiReg(pAdapter, PHYSUP);


				/* 
				 * Check the Duplex Mode.
				 * Update the AdapterContext and
				 * update the MAC to reflect the changes
				 * in the duplex mode, otherwise it starts
				 * dropping packets.
				 */
				if ( phyStatus & PHY_DUPLEX_MASK ) 
				{
					pAdapter->DuplexMode = FULL_DUPLEX;
					
					/*
					 * Enable Carrier Sense Ignore and Heart Beat Ignore.
					 */
					NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + TXCFG , &Reg_val);
					Reg_val |= (CSI | HBI | ATP);
					NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + TXCFG , Reg_val);

					/*
					 * Enable Full Duplex in Rx Cfg Register.
					 */
					NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RXCFG , &Reg_val);
					Reg_val |= (RX_FD);
					NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RXCFG, Reg_val );

					/*
					 * If Link Partner supports Tx and Rx Flow Control.
					 * Then we enable Rx and Tx Flow control
					 * according to the user selection.
					 */
					Anlpar_val = ReadMiiReg(pAdapter, ANLPAR);

					/*
					 * First turn off all Flow control and then enable 
					 * Tx and Rx depending upon the partners capabilities.
					 */
					Pcr_val = Tx = Rx = 0;
					
					NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), 
						Pcr_val);
				
					/*
					 * Following the algorithm taken from the 
					 * 802.3 document table 37-4.
					 */
					
					/*
					 * If we support ASM_DIR.
					 * TX_PAUSE_FRAME_ENABLE turns on only ASM_DIR.
					 */
					if (pAdapter->FlowControl & TX_PAUSE_FRAMES_ENABLE)
					{
						/*
						 * If the partner has both ASM_DIR and PAUSE
						 */
						if((Anlpar_val & (ASY_PAUSE | PAUSE)) == (ASY_PAUSE | PAUSE))
						{
							/*
							 * Enable our Transmit
							 */
							Tx = 1;
						}
					}

					/*
					 * If we support ASM_DIR and PAUSE.
					 * RX_PAUSE_FRAME_ENABLE turns on ASM_DIR and PAUSE.
					 */
					if (pAdapter->FlowControl & RX_PAUSE_FRAMES_ENABLE)
					{
						/*
						 * If the partner has PAUSE
						 */
						if(Anlpar_val & PAUSE)
						{
							/*
							 * Enable our Transmit and Receive
							 */
							Tx = Rx = 1;
						}
						
						/*
						 * If the partner supports only ASM_DIR
						 */
						else if(Anlpar_val & ASY_PAUSE)
						{
							/*
							 * Enable our Receive
							 */
							Rx = 1;
						}
					}

					
					if(Rx == 1)
					{
						
						/* 
						 * Rx Flow Control
						 */
						Pcr_val |= (PS_MCAST | PS_DA | PSEN);

						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), Pcr_val);
#ifdef NSCDEBUG
                       	NsmDbgMsg("HsmIsr: Rx Flow Control \n");
#endif

					}
					
					if(Tx == 1)
					{
						/* 
						 * Tx Flow Control
						 */
						if (pAdapter->RxFFLO > pAdapter->RxFFHI)
							pAdapter->RxFFLO = pAdapter->RxFFHI;

						if (pAdapter->RxSTLO > pAdapter->RxSTHI)
							pAdapter->RxSTLO = pAdapter->RxSTHI;
						
						if (pAdapter->RxFFLO == 2)
							Pcr_val |= PS_FFLO_2K;
						if (pAdapter->RxFFLO == 4)
							Pcr_val |= PS_FFLO_4K;
						if (pAdapter->RxFFLO == 8)
							Pcr_val |= PS_FFLO_8K;

						if (pAdapter->RxFFHI == 2)
							Pcr_val |= PS_FFHI_2K;
						if (pAdapter->RxFFHI == 4)
							Pcr_val |= PS_FFHI_4K;
						if (pAdapter->RxFFHI == 8)
							Pcr_val |= PS_FFHI_8K;

						if (pAdapter->RxSTLO == 2)
							Pcr_val |= PS_STLO_2;
						if (pAdapter->RxSTLO == 4)
							Pcr_val |= PS_STLO_4;
						if (pAdapter->RxSTLO == 8)
							Pcr_val |= PS_STLO_8;

						if (pAdapter->RxSTHI == 2)
							Pcr_val |= PS_STHI_2;
						if (pAdapter->RxSTHI == 4)
							Pcr_val |= PS_STHI_4;
						if (pAdapter->RxSTHI == 8)
							Pcr_val |= PS_STHI_8;
						
						Pcr_val |= pAdapter->PauseCounterVal;

						NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + PCR), Pcr_val);
#ifdef NSCDEBUG
						NsmDbgMsg("HsmIsr: Tx Flow Control \n");
#endif

					}
				}
				else 
				{
					pAdapter->DuplexMode = HALF_DUPLEX;
					
					/*
					 * Disable CSI and HBI and turn off Full Duplex Recieve.
					 */
					NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + TXCFG , &Reg_val);
					Reg_val &= ~(CSI | HBI);
					Reg_val |= ATP;
					NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + TXCFG , Reg_val );

					NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RXCFG , &Reg_val);
					Reg_val &= ~(RX_FD);
					NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RXCFG , Reg_val );
				}
			}
				/* 
				 * Check the Speed.
				 * Update the AdapterContext.
				 */
			if(!(pAdapter->tbi))
			{
				phyStatus &= PHY_SPEED_MASK;

				/* 
				 * Turn off the 1000 Mbps mode
				 */
				NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + CFG, &Reg_val );
				Reg_val &= ~(MODE_1000 | AUTO_1000);

				switch ( phyStatus ) {

					case PHY_SPEED_10:

						pAdapter->MediaSpeed = 10;

						break;

					case PHY_SPEED_100:

						pAdapter->MediaSpeed = 100;

						break;

					case PHY_SPEED_1000:

						pAdapter->MediaSpeed = 1000;

						/* 
						 * Turn on the 1000 Mbps mode, required for normal
						 * operation, else communications stops and card does
						 * not send any packets.
						 */
						Reg_val |= MODE_1000;

						break;

				}	/*	end of switch()	*/
				NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + CFG, Reg_val );
				}
				else
				{
					pAdapter->MediaSpeed = 1000;

					NsmRegRead32(pAdapter->pNsmContext,
						pAdapter->RegAddr + CFG, &Reg_val );

					Reg_val |= MODE_1000;

					NsmRegWrite32(pAdapter->pNsmContext,
						pAdapter->RegAddr + CFG, Reg_val );
				}
#ifdef LINK_AGGR
				/* 
				 * If not independent port, invoke callback 
				 */
				if (pAdapter->nFlags)
					LacpAdapterStatusCheck(pAdapter);
#endif

		}







		
/* 		
 *		If we have RXIDLE interrupt, then receive state machine enters 
 * 		idle state from a running state. This will happen whenever the 
 * 		state machine encounters an end-of-list condition ( NULL link
 * 		field of a descriptor with OWN bit set). 
 */
		if ( interruptStatus & (RXIDLE | RXORN | RXSOVR) ) {


			for(priIdx = 0; priIdx < pAdapter->RxNumPrio; priIdx++) 
				HsmReplenishRcbs(pAdapter, priIdx, 1);
#ifdef _GA621_
/*
 *      IHR     - Interrupt Hold-off Register.
 *
 *      Set the Interrupt-holdoff value in IHR.
 */
/*instead fo multiplying we go linear to avoid high values and place a upper limit*/	
		if (pAdapter->IntrHoldoff) {
			if (pAdapter->CurrHoldOff & 0x100)
			{
					pAdapter->CurrHoldOff &= ~(0x100);
			}
			else
			{
				Ihr_val = 0;
				if (pAdapter->CurrHoldOff)
					pAdapter->CurrHoldOff++;
				else
					pAdapter->CurrHoldOff = (pAdapter->IntrHoldoff + 1);
				pAdapter->CurrHoldOff &= 0xFF;
				if (pAdapter->CurrHoldOff == 0)
					pAdapter->CurrHoldOff = pAdapter->IntrHoldoff;
				Ihr_val |= (pAdapter->CurrHoldOff | IHCTL);
				NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + IHR), 
					Ihr_val);
				pAdapter->CurrHoldOff |= (0x100);
			}
		}
#endif
		}

		}	/*	end of while(interruptStatus)	*/
			
		
		
		
	
	
	
	
	
		pAdapter->interruptStatus = 0;

/* 
 *		Enable interrupts from the adapter by writing the Interrupt
 * 		Enable Flag into the Interrupt Enable Register.
 */
		HsmEnableInterrupts(pAdapter);
		
/*   	Turn of Activity LED at end of function to ensure longer duration */
		if(pAdapter->tbi)
		{
			NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + GPIOR, &Gpior_val );
			Gpior_val &= ~GP3_OUT;
			NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + GPIOR,
				Gpior_val);
		}

	return(status);

}               /*      end of HsmIsr() */







/******************************************************************************
*f*
*       Name :
*                       HsmInterruptPresent
*
*   Description :
*			Read Interrupt Status Register and return TRUE if we have an
*			interrupt. Otherwise return FALSE.
*
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			TRUE  - If interrupt is from our adapter. 
*			FALSE - If otherwise.
*f*
******************************************************************************/
UCHAR
HsmInterruptPresent(AdapterContext *pAdapter)
{
	UINT interruptStatus;

	if(pAdapter->interruptStatus)
	{
		return FALSE;
	}


/* 
 *		Read interrupts from Interrupt Status Register 
 */

	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + ISR,
		&interruptStatus );

	if ( interruptStatus ) {
		pAdapter->interruptStatus = interruptStatus;
		HsmDisableInterrupts(pAdapter);
		return TRUE;
	}
	else {
/* 
 *		our device didn't generate this interrupt 
 */
		return FALSE;
	}
}		/*	end of HsmInterruptPresent	*/

/******************************************************************************
*f*
*       Name :
*			HsmGetMacAddress
*
*       Description :
*			This function reads the factory MAC address from the adapter and 
*			stores in AdapterContext. The RFCR/RFDR registers are used in 
*			combination to access Perfect Match register to read the address. 
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			None
*f*
*****************************************************************************/
VOID
HsmGetMacAddress(AdapterContext *pAdapter)
{
	INT     i;
	USHORT  *mac_addr_ptr = (USHORT *)&pAdapter->PermMacAddr;
	UINT    Rfcr_val;
	UINT	TempMac;

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_val);
	/* RFCR write fix*/
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), (Rfcr_val & ~RFEN));

	for ( i = 0; i < MAC_ADDR_LEN / 2; i++, mac_addr_ptr++ ) {
		/*32 bit writes*/
		NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
			((i * 2)) );        
		NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFDR,
				&TempMac);
		*mac_addr_ptr = (USHORT)TempMac;
	}
	NsmCopy(pAdapter->PermMacAddr, pAdapter->CurrMacAddr, MAC_ADDR_LEN);
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), Rfcr_val);

}       /*      end of HsmGetMacAddress()       */

/******************************************************************************
*f*
*       Name :
*			HsmSetMacAddress
*
*       Description :
*			This function sets the given MAC address in the adapter's register. 
*			The RFCR/RFDR registers are used in combination to access Perfect 
*			Match register to set the address.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*			addr            - pointer to MacAddr
*
*       Return Value :
*			None
*f*
*****************************************************************************/
UCHAR
HsmSetMacAddress(AdapterContext *pAdapter, UCHAR *addr)
{
	INT     i;
	USHORT  *mac_addr_ptr = (USHORT *) addr;
	UINT    Rfcr_val;

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_val);
	/* RFCR write fix*/
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), (Rfcr_val & ~RFEN));

	for ( i = 0; i < MAC_ADDR_LEN / 2; i++, mac_addr_ptr++ ) {

	/* RFCR write fix
		NsmRegWrite16(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		(Rfcr_val | (i * 2)) );
		32 bit writes*/
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		 (i * 2) );

	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFDR,
		*mac_addr_ptr);
}
/*RFCR write fix*/
NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), (Rfcr_val));
#ifdef LINK_AGGR
/* 
 * If non-aggregator port, set receive filter
 * Uncomment if required later.
 * 

 if ((pAdapter->pAggregatorContext) &&
		(pAdapter->pAggregatorContext != pAdapter)) {
	NsmRegRead32(pAdapter->pAggregatorContext->pNsmContext, (pAdapter->pAggregatorContext->RegAddr + RFCR), &Rfcr_val);
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 0);
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), (Rfcr_val));
} 
 
 * 
 */

/* 
 * Invoke LACP callback 
 */
if (pAdapter->nFlags)
	LacpSetMacAddress(pAdapter, addr);
#endif
	return SUCCESS;

}       /*      end of HsmSetMacAddress()       */

/******************************************************************************
*f*
*       Name :
*			HsmGetStatistics
*
*       Description :
*			Read MIB counter registers in the adapter and update statistics
*			structure in AdapterContext.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			None
*f*
*****************************************************************************/
UCHAR
HsmGetStatistics(AdapterContext *pAdapter)
{
/* 
 *	Just call this function to update the statistics 
 */
	ReadMIBCounters(pAdapter);
	return (SUCCESS);
}

/******************************************************************************
*f*
*       Name :
*			HsmClearStatistics
*
*       Description :
*			Clear the statistics maintained in the AdapterContext.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			None
*f*
******************************************************************************/
UCHAR
HsmClearStatistics(AdapterContext *pAdapter)
{
/* 
 *		Clear the statistics maintained in MacStats member of AdapterContext 
 */
	NsmZeroMemory(&pAdapter->MacStats, sizeof(pAdapter->MacStats) );

/* 
 *	Clear all the MIB counters in the adapter also 
 */
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + MIBC, ACLR);

	return (SUCCESS);
}

/******************************************************************************
*f*
*       Name :
*			HsmRxFilter
*
*       Description :
* 			This function configures receive filter mechanism by setting the 
*			receive filter control bits in RFCR register. 
*    
*       Parameters :
*			pAdapter                - pointer to AdapterContext
*			RxFilterFlag    - receive filter control bits
*
*       Return Value :
*			None
*f*
*****************************************************************************/
UCHAR
HsmRxFilter(AdapterContext *pAdapter, UINT rxFilterFlag)
{
	UINT    rxMatchControl = 0;

/* 
 *	Start with a default receive match control value, that is
 * 	receive all broadcasts and receive on perfect match.
 */
/*	rxMatchControl |= ( APM | AAB | RFEN);*/
	rxMatchControl |= (RFEN);

	/*
	 * Turn off Promiscuous Mode by default.
	 */
	SetPromiscuousMode(pAdapter, FALSE);
	
/* 
 *	Set/clear other filter bits depending on the value passed 
 * 	in rxFilterFlag.
 */
	if ( rxFilterFlag & PROMISCUOUS_ON ) 
	{
		SetPromiscuousMode(pAdapter, TRUE);
		rxMatchControl |=  (MHEN | APM | AAB | AAM | AAU);
	}

	if (rxFilterFlag & PROMISCUOUS_OFF)
		rxMatchControl &= ~(AAU | AAM);

	if ( rxFilterFlag & ACCEPT_ALL_MULTICAST_ON ) 
		rxMatchControl |= AAM;

	if ( rxFilterFlag & ACCEPT_ALL_UNICAST_ON ) 
		rxMatchControl |= AAU;

	if ( rxFilterFlag & ACCEPT_ALL_BROADCAST_ON ) 
		rxMatchControl |= AAB;

	if ( rxFilterFlag & MULTICAST_HASH_ENABLE ) 
		rxMatchControl |= MHEN;

	if ( rxFilterFlag & ACCEPT_PERFECT_MATCH_ON ) 
		rxMatchControl |= APM;

	if (rxFilterFlag & ACCEPT_ALL_MULTICAST_OFF )
		rxMatchControl &= ~(AAM);

	pAdapter->rxMatchControl = (rxMatchControl);
	
/* 
 *	Zero the RFEN bit so that the new data will be read  and
 *	Write the new receive filter control bits.
 */

	/*RFCR write fix*/
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, 0);
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		pAdapter->rxMatchControl );
#ifdef LINK_AGGR
	/* 
	 * Add callback 
	 */ 
	pAdapter->lacprxFilterFlag = rxFilterFlag;

	if (pAdapter->nFlags)
		LacpSetRxFilter(pAdapter, rxFilterFlag);
#endif

	return (SUCCESS);

}


/******************************************************************************
*f*
*       Name :
*			SetPromiscuousMode
*
*       Description :
*			Turns on/off the promiscuous Mode as required
*			and also turns on/off extended features as applicable.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*			Mode            - OFF / ON 
*
*       Return Value :
*			VOID
*f*
*****************************************************************************/
static VOID
SetPromiscuousMode(AdapterContext *pAdapter, UCHAR Mode)
{
	UINT    Rxcfg_val = 0;
	UINT    Flag = 0;

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RXCFG), &Rxcfg_val);
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + VRCR), &Flag);
	
	/*
	 * Check the mode asked for, TRUE is ON
	 * and FALSE os turning it OFF.
	 */
	if(Mode == TRUE)
	{
		pAdapter->PhysCapabilities |= ADAPTER_PROMISCUOUS_ON;

		/*
		 * In Promiscious Mode, Turn on the ARP so that 
		 * we can accept runt packets and also accept Errored Packets
		 * and also VLAN Tagged packet acceptance.( sniffer mode )
		 */
		Rxcfg_val |= (ARP | AEP);
		Flag &= ~DVTF;
	}
	else
	{
		/*
		 * Turn Off Errored Packet Reception which was turned on
		 * for Promiscuous Mode.
		 * By default we are not in promiscuous mode :
		 * Discard any VLAN tagged packets if the VLAN is not enabled.
		 * Also turn off RUNT Packet reception.
		 */
		pAdapter->PhysCapabilities &= ~ADAPTER_PROMISCUOUS_ON;
		
		Rxcfg_val &= ~AEP;
			
		if(!(pAdapter->PhysCapabilities & (VLAN_TAG_INSERTION_PP_ON | VLAN_TAG_INSERTION_GEN_ON)))
		{
			Rxcfg_val &= ~ARP;
			Flag |= DVTF;
		}
	}
	
	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + RXCFG), Rxcfg_val);
	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + VRCR), Flag);

	return;
}

		

/******************************************************************************
*f*
*       Name :
*			HsmMultiCastAdd
*
*       Description :
*			This function either reloads the existing multicast address 
*			table with the new list in the adapter's filter memory or just 
*			appends the passed address to the list.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*			pMulti          - pointer to MultiList structure 
*			ReloadFlag      - If this flag is TRUE then multicast addresses
*				in the table are reloaded with new list passed.
*				Otherwise just append to the existing list.
*       Return Value :
*			SUCCESS - If multicast addresses are added to the card 
*			FAILURE - if otherwise
*f*
*****************************************************************************/
UCHAR
HsmMulticastAdd(AdapterContext *pAdapter, MultiList *pMulti, UCHAR ReloadFlag )
{
	mca_hash_t *hashEntry, *prevEntry;
	USHORT hashbit;
	USHORT wordindex;
	USHORT bitindex;
	UINT hashValue;
	UINT TempRFCR;
	INT ret_val;
	INT cnt = 0;
#ifdef LINK_AGGR
	MultiList *tempMulti = pMulti;
	INT numaddr = 0;
#endif
	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		&TempRFCR);
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		(TempRFCR & ~RFEN));

/* 
 *		Reload the existing multicast address table with the new list 
 */
	if ( ReloadFlag == TRUE ) {
/* 
 *		clear mca_tbl and adapter's filter memory 
 */
		clear_mca_tbl(pAdapter);        
	}

	while ( pMulti ) {

		getHashValue(pMulti->MulticastAddr, &wordindex, &bitindex,  &hashbit);
		hashEntry = pAdapter->mca_tbl[wordindex][bitindex];
		ret_val = search_mca_tbl(pMulti->MulticastAddr, &prevEntry, &hashEntry);

		if ( ret_val != SUCCESS ) {

/* 
 *	address not present, add to the begining of the list 
 */
			hashEntry = (mca_hash_t *)NsmMalloc(sizeof(mca_hash_t));
			if ( hashEntry == NULL ) {
				/* release lock */
				/* return error */
#ifdef LINK_AGGR
				/* 
				 * Invoke LACP callback 
				 */
				if (numaddr && pAdapter->nFlags)
					LacpMulticastAdd(pAdapter, tempMulti, numaddr, ReloadFlag);
#endif
				return FAILURE;
			}
			NsmCopy(pMulti->MulticastAddr, hashEntry->MulticastAddr, 
				MAC_ADDR_LEN); 
			hashEntry->next = pAdapter->mca_tbl[wordindex][bitindex];
			pAdapter->mca_tbl[wordindex][bitindex] = hashEntry;

			cnt++; 	/* keep track of count */
			pAdapter->MultiCastTableSize += MAC_ADDR_LEN;

	/*RFCR write fix*/

/* 
 *	write hash entry to chip 
 */
			NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
				(0x100 + (wordindex * 2)));
			NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFDR,
				&hashValue);

			hashValue |= hashbit;

			NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFDR,
				hashValue);

		}		/* end of if (ret_val == SUCCESS) */

#ifdef LINK_AGGR
		numaddr++;
#endif
		pMulti = pMulti->Next;

	}			/* end of while(pMulti)	*/


/*
 * 
 */
	/*RFCR write fix*/
	if (cnt != 0)
		TempRFCR |= (RFEN | MHEN);
	else
		TempRFCR |= RFEN;
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, TempRFCR);

#ifdef LINK_AGGR
	/* 
	 * Invoke LACP callback which adds the multicast addresses to the rest 
	 * of the members in aggregation if this is an aggregator port
	 */
	if ((numaddr || ReloadFlag) && pAdapter->nFlags)
		LacpMulticastAdd(pAdapter, tempMulti, numaddr, ReloadFlag);
#endif		
		
	/* 	release the lock */

	return SUCCESS;

}	/* end of HsmMulticastAdd	*/

/******************************************************************************
*f*
*       Name :
* 			HsmMultiCastDelete
*
*       Description :
*			This function deletes the multicast address from the multicast
*			table in adapter Context and also removes the corresponding hash
*			value from the hash table in the adapter's receive filter memory.
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*			pMulti          - pointer to MultiList structure 
*
*       Return Value :
*			SUCCESS - If multicast addresses are deleted
*			FAILURE - if otherwise
*f*
*****************************************************************************/
UCHAR
HsmMultiCastDelete(AdapterContext *pAdapter, MultiList *pMulti)
{
	mca_hash_t *hashEntry, *prevEntry;
	USHORT hashbit, wordindex, bitindex;
	UINT hashValue;
	INT ret_val;
	UINT TempRFCR;
#ifdef LINK_AGGR
    MultiList *tempMulti = pMulti;
#endif

	/*RFCR write fix*/
	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		&TempRFCR);
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		(TempRFCR & ~RFEN));
	while ( pMulti ) {
		getHashValue(pMulti->MulticastAddr, &wordindex, &bitindex, &hashbit);
		hashEntry = pAdapter->mca_tbl[wordindex][bitindex];
		ret_val = search_mca_tbl(pMulti->MulticastAddr, &prevEntry, &hashEntry);
		if ( ret_val == SUCCESS ) {
/* 
 *	none is using, delete the entry 
 */
				if ( pAdapter->mca_tbl[wordindex][bitindex] == hashEntry )
					pAdapter->mca_tbl[wordindex][bitindex] = hashEntry->next;
				else
					prevEntry->next = hashEntry->next;
/* 
 *	free the node 
 */
				NsmFree(hashEntry,sizeof(mca_hash_t));  

				if ( pAdapter->mca_tbl[wordindex][bitindex] == NULL ) {
/* 
 *	no more entries, reset the entry in filter memory 
 */
					NsmRegWrite32(pAdapter->pNsmContext, 
						pAdapter->RegAddr + RFCR, 0x100 + (wordindex * 2));
					NsmRegRead32(pAdapter->pNsmContext,
						pAdapter->RegAddr + RFDR, &hashValue);

					hashValue &= ~hashbit;

					NsmRegWrite32(pAdapter->pNsmContext,
						pAdapter->RegAddr + RFDR, hashValue);
				}
                                
				pAdapter->MultiCastTableSize -= MAC_ADDR_LEN;
			} else {
			NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, TempRFCR);
			return FAILURE;
		}
		pMulti = pMulti->Next;
	}

	/*RFCR write fix*/
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, TempRFCR);
#ifdef LINK_AGGR
	if (tempMulti  && pAdapter->nFlags)
		LacpMulticastDelete(pAdapter, tempMulti);
#endif

	return SUCCESS;
        
}

/******************************************************************************
*f*
*       Name :
*			ReadMIBCounters
*
*       Description :
*			Read MIB counters from the adapter and update the counters
*			maintained in the AdapterContext structure.     
*    
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			None
*f*
*****************************************************************************/
VOID
ReadMIBCounters(AdapterContext *pAdapter)
{

	USHORT dword;
	UCHAR dword8;

	/* Number of receive errored packets */
	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXErroredPkts, &dword);

	pAdapter->MacStats.rxErrorCount += dword;

	/* Number of packets received with FCS errors */
	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXFCSErrors, &dword);

	pAdapter->MacStats.rxCrcErrorCount += dword;
        
	/* Number of packets missed FIFO overruns */
	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXMsdPktErrors, &dword);

	pAdapter->MacStats.rxNoBufferCount += dword;

	/* packets received with FAE errors */
	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXFAErrors, &dword);

	pAdapter->MacStats.rxFaeCount += dword;

	/* packets receive with invalid symbols */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXSymbolErrors, &dword);

	pAdapter->MacStats.rxSymbolErrors += dword;

	/* packets received > 1518 bytes in length */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXFrameTooLong, &dword);

	pAdapter->MacStats.rxFramesTooLong += dword;

	/* packets received in range length errors */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXIRLErrors, &dword);

	pAdapter->MacStats.rxIRLErrors += dword;

	/* packets received bad opcodes */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXBadOpcodes, &dword);

	pAdapter->MacStats.rxBadOpcodes += dword;

	/* packets received pause frames */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + RXPauseFrames, &dword);

	pAdapter->MacStats.rxPauseFrames += dword;

	/* packets transmitted pause frames */

	NsmRegRead16(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + TXPauseFrames, &dword);

	pAdapter->MacStats.txPauseFrames += dword;

	/* packets sent with SQE detected */

	NsmRegRead8(pAdapter->pNsmContext,
		pAdapter->RegAddr + MIBS + TXSQEErrors, &dword8);

	pAdapter->MacStats.txSQEerrors += dword8;

	/* 		Clear the statistics MIB counter since we are handling
			it using a software counter */
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + MIBC, ACLR);

}

/**********************************************************************
*f*
*       Name :
*			search_mca_tbl
*
*       Description :
*			This function searches mca_tbl for an entry with MulticastAddr
*			and returns SUCCESS if found, FAILURE otherwise.
*
*       Parameters :
*			MulticastAddr   - UCHAR pointer to multicast address
*			prevEntry       - a pointer to mca_hash_t is returned in this
*          					variable.
*			hashEntry       -       
*
*       Return Value :
*			SUCCESS / FAILURE
*
*f*********************************************************************/

INT
search_mca_tbl ( UCHAR *MulticastAddr, mca_hash_t **prevEntry, 
                mca_hash_t **hashEntry)
{
	while ( *hashEntry != NULL ) {

		if(NsmCompare((*hashEntry)->MulticastAddr, MulticastAddr, MAC_ADDR_LEN) == 0)
			return SUCCESS;

		*prevEntry = *hashEntry;
		*hashEntry = (*hashEntry)->next;
	}

	return FAILURE ;
}

/**********************************************************************
*f*
*       Name :
*			getHashValue
*
*       Description :
*			This function calculates the hash index and hash bit for the
*			multicast address pointed to by MulticastAddr and stores the
*			values in wordindex and hashbit.
*
*       Parameters :
*			MulticastAddr   - UCHAR pointer to multicast address
*			wordindex       - points to a variable in which this fucntion
*			bitindex		- points to a variable in which this 
*							function returns the bit index.
*                                                 returns the hash index.
*			hashbit         - points to a variable in which this function
*							returns the hash bit to be set/reset.
*
*       Return Value :
*                       NONE
*
*f*********************************************************************/

VOID
getHashValue(UCHAR *MulticastAddr, USHORT *wordindex, USHORT *bitindex, USHORT *hashbit)
{
	INT i1, i2;
	UINT crc, msb;
	UCHAR currentByte;
	UCHAR *pMulticastAddress = MulticastAddr;

	crc = 0xffffffffL;
	for ( i1 = 0; i1 < MAC_ADDR_LEN; i1++ ) {
		currentByte = * pMulticastAddress++;
		for ( i2 = 0; i2 < 8; i2++ ) {
			msb = crc >> 31;
			crc <<= 1;
			if ( msb ^ ( currentByte & 1 ) ) {
				crc ^= 0x04c11db6L;
				crc |= 1;
			}
			currentByte >>= 1;
		}
	}
#ifdef _GA621_
	crc >>= 21;
	*wordindex = ( crc >> 4 ) & 0x7fL;
	*bitindex = ( crc & 0xfL );
	*hashbit = ( 1 << ( crc & 0xfL ));
#elif _DP83815_
	*wordindex = ( crc >> 4 ) & 0x0000001f;
	*bitindex = ( crc & 0xfL );
	*hashbit = ( 1 << ( crc & 0x0000000f ));
#endif
}

/**********************************************************************
*f*
*       Name :
*			refresh_mca_tbl
*
*       Description :
*			This function reloads the multicast address from the
*			mca_tbl and updates multicast receive filter memory.
*
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			NONE
*
*f*********************************************************************/

VOID
refresh_mca_tbl(AdapterContext *pAdapter)
{
	INT i, j;
	INT TempRFCR;
	USHORT	HashWord = 0;

	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, &TempRFCR);
	/*RFCR write fix*/
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		(TempRFCR & ~RFEN));

	for ( i = 0; i < 128; ++i) {
		for ( j = 0; j < 16; ++j ) {
			if (pAdapter->mca_tbl[i][j])
			    	HashWord |= (1 << j);
		}

/*
 * 	Update the hash bits in filter memory
 */
		/*All 32 bit writes*/
		NsmRegWrite32(pAdapter->pNsmContext,
			pAdapter->RegAddr + RFCR, 0x100 + (i * 2));
		NsmRegWrite32(pAdapter->pNsmContext,
			pAdapter->RegAddr + RFDR, HashWord);
	}

	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, TempRFCR);
}

/**********************************************************************
*f*
*       Name :
*			clear_mca_tbl
*
*       Description :
*			This function deletes all the multicast address from the 
*			mca_tbl and resets adapter's multicast receive filter memory.
*
*       Parameters :
*			pAdapter        - pointer to AdapterContext
*
*       Return Value :
*			NONE
*
*f*********************************************************************/

VOID
clear_mca_tbl(AdapterContext *pAdapter)
{
	INT i, j;
	mca_hash_t *start, *next;
	UINT	Rfcr_val = 0;
	UINT	Rfcr_old_val = 0;

	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, &Rfcr_val);
	Rfcr_old_val = Rfcr_val & ~RFEN;
	NsmRegWrite32(pAdapter->pNsmContext,
			pAdapter->RegAddr + RFCR, (Rfcr_old_val))  ;

	for ( i = 0; i < 128; ++i) {
        
		for ( j = 0; j < 16; ++j ) {
			start = pAdapter->mca_tbl[i][j];
			while ( start ) {
				next = start->next;
				/* The following  lines added To fix HCT failure in NDIS5 */
				NsmRegWrite32(pAdapter->pNsmContext,
					pAdapter->RegAddr + RFCR, 0x100 + (i * 2));
				/*All 32 bits*/
				NsmRegWrite32(pAdapter->pNsmContext,
					pAdapter->RegAddr + RFDR, 0x0);
				/* End */
				NsmFree(start, sizeof(mca_hash_t));
				start = next;
			}
			pAdapter->mca_tbl[i][j] = NULL;
		}

	}

	pAdapter->MultiCastTableSize = 0;

	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, Rfcr_val);
	
}




/*
 * Priority Mapping Routines.
 */

UCHAR 
GetHardwarePriority(AdapterContext *pAdap, UCHAR OsPriority) 
{

#ifdef _GA621_
	UCHAR counter;

	for( counter=1 ; counter<=((pAdap)->TxNumPrio) ; counter++ )
	{
		if(((OsPriority) * PRI_QUOTIENT) <= (((pAdap)->TxPriMapVal) * counter)) 
			break; 
	}

	counter-- ;

	return (counter);
#else 
	return (0);

#endif

}

UCHAR 
GetOsPriority(AdapterContext *pAdap, UCHAR AdapPriority)
{

#ifdef _GA621_
	UCHAR counter;

	for( counter=(((pAdap)->OsPrio)-1) ; counter>=0 ; counter-- ) {

		if((((pAdap)->RxPriMapVal)* ((AdapPriority) + 1)) >= 
				(counter * PRI_QUOTIENT)) 
			break;
	}

	return (counter);
#else

	return (0);

#endif

}

/******************************************************************************
*f*
*   Name:           HsmSendPkts 
*
*   Description:    This is called from the NSM. It posts the packets of a 
*   particular priority, indicated by Priority, to the adapter for 
*   transmission. 
*
*   Parameters:     pAdapter        Pointer to the AdapterContext structure
*
*                   pPkts           Pointer to the PktStruct, in which the 
*                   data to be sent down is encapsulated
*
*                   Priority        Priority queue in to which this set of 
*                   packets is to be put.
*
*   Return Value:   The number of packets that was queued for transmission 
*
*f*
******************************************************************************/
#ifdef LINK_AGGR
USHORT HsmSendPkts(AdapterContext *pAdapter, PktStruct *pPkts, UCHAR Prio, USHORT StartIndex)
#else
USHORT HsmSendPkts(AdapterContext *pAdapter, PktStruct *pPkts, UCHAR Prio)
#endif
{
	UCHAR           Priority;
	HsmTCB          *pFirstTcb, *pLastTcb;
	volatile DevDesc         *pFirstDesc, *pLastDesc;
	volatile DevDesc         *CurrDesc;
	volatile DevDesc         *pFirstDescPa, *pLastDescPa, *CurrDescPa;
/*
 *	 Fix for the race condition between h/w and driver. 
 */
	UINT            PktSent, NumFrags;
	UINT          NumDesc, FragCount;
	USHORT			PktIndex;
	PktInfo         *CurrPkt;
	USHORT          FreeCount;
	HsmTCB          *pTcbBase;
	volatile DevDesc         *DescBase;
	volatile DevDesc         *DescBasePa;
#if TXCHECKSUM && TCPCHECKSUM_HOTFIX
/* The size of the array should be atleast +1, for odd number of Packet sizes*/
	UCHAR 			EtherTcpPkt[HOTFIX_TCPPACKETLENGTH]; 
#endif
	PUCHAR			pChksumoffset[2];
	USHORT			PktLength;
	USHORT			Chksum;
	UINT			NumberOfDescriptors;
	UCHAR	bSwPadding=0;
#if TXCHECKSUM && UDPCHECKSUM_HOTFIX
/* The size of the array should be atleast +1, for odd number of Packet sizes*/
	UCHAR			EtherUdpPkt[HOTFIX_UDPPACKETLENGTH]; 
	UINT			DataLength;
#endif
/* 
 *	Get the hardware Priority on which the packets have to be sent 
 */
	Priority = GetHardwarePriority(pAdapter, Prio);
/* 
 *	Acquire the lock before entering a critical section 
 */
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->TxLock);

/* 
 *	Get the next pointer for the HsmTCB list, from AdapterContext 
 */
	pFirstTcb = GET_TCB_NEXT(pAdapter, Priority);

/* 
 *	Get the pointer to the start descriptor pointed to by the first HsmTCB 
 */
	CurrDesc = pFirstDesc = pFirstTcb->pStartDesc;
	CurrDescPa = pFirstDescPa = pFirstTcb->pStartDescPa;

/* 
 *	Intialise the indexes to count the packets and the descriptors 
 */
#ifdef LINK_AGGR
	PktIndex = StartIndex;
#else
	PktIndex = 0;
#endif
	NumDesc = 0;

/* 
 *	For all the packets do the following 
 */
#ifdef LINK_AGGR
	while(PktIndex < (UINT)(StartIndex + pPkts->PktCount)) 
#else
	while(PktIndex < pPkts->PktCount) 
#endif
	{
/* 
 *	Get the pointer to the next packet 
 */
		FreeCount = FreeTxDesc(pAdapter, Priority);

/* 
 *	Update the number of descriptors 
 */
		NSMGETNUMFRAGS(NumFrags,(&(pPkts->PktArray[PktIndex])));
		NumDesc += NumFrags;

/* 
 *	Check if there are enough descriptors available 
 */
		if(NumDesc > FreeCount)
		{
			NumDesc -= NumFrags;
			break;
		}

/* 
 *	Increment the count of the packets 
 */
		PktIndex ++;
	}


#ifdef LINK_AGGR
	NSMMAPPKTS(pAdapter, pPkts, Priority, NumDesc, PktIndex, StartIndex);
#else
	NSMMAPPKTS(pAdapter, pPkts, Priority, NumDesc, PktIndex);
#endif

	
/* 
 *	Check if no reservations could be made 
 */
#ifdef LINK_AGGR
	if(PktIndex == StartIndex)
#else
	if(PktIndex == 0)
#endif
	{
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->TxLock);

#ifdef LINK_AGGR
		return 0;
#else
		return PktIndex;
#endif
	}
  
	pTcbBase = pAdapter->PriQue[Priority].pTcbArray;
#ifdef LINK_AGGR
	pLastTcb = (HsmTCB *)INC_CURR_TCB(pAdapter, Priority, 
   			pFirstTcb,(PktIndex - StartIndex),pTcbBase);
#else
	pLastTcb = (HsmTCB *)INC_CURR_TCB(pAdapter, Priority, 
   			pFirstTcb,PktIndex,pTcbBase);
#endif
/* 
 *	Get the pointer to the next descriptor of the last descriptor that is 
 *	reserved 
 */
     
	DescBase = pAdapter->PriQue[Priority].pTxdArray;
	DescBasePa = pAdapter->PriQue[Priority].pTxdArrayPa;

	pLastDesc = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
   		pFirstDesc, NumDesc, DescBase);
	pLastDescPa = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
   		pFirstDescPa, NumDesc, DescBasePa);

/* 
 *	Set the descriptor for its pStartDesc field accordingly 
 */
	pLastTcb->pStartDesc = pLastDesc;
	pLastTcb->pStartDescPa = pLastDescPa;

/* 
 *	Set the next pointer of the HsmTCB list 
 */
	SET_TCB_NEXT(pAdapter, Priority, pLastTcb);

/* 
 *	Release the transmit lock .Re-initialise the counts 
 */
	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->TxLock);
#ifdef LINK_AGGR
	PktSent = StartIndex;
#else
	PktSent = 0;
#endif
	FragCount = 0;

/* 
 *	Set the buffer pointers etc in the reserved Txd list 
 */
	while (PktSent < PktIndex)
	{
/* 
 *	Get the current packet and set the fragment count.
 */
		CurrPkt = &pPkts->PktArray[PktSent];
		pFirstTcb->pOsCtrlBlk = CurrPkt->pOSCtrlBlk;
#ifdef LINK_AGGR
		pFirstTcb->SlowProtocolType = CurrPkt->SlowProtocolType;
#endif
		FragCount = 0;
		NumFrags = CurrPkt->NumFrags;

#ifdef TXCHECKSUM 
#ifdef TCPCHECKSUM_HOTFIX
		/* Start of Bug Fix for H/W  Checksum */
		/* The conditions for  calculating TCP checksum :
			* ----------------------------------------------------------------
			* OPTION                     FAILING TCP           Packet Sizes
			*                            Data Sizes             (w/o CRC)
			* ----------------------------------------------------------------
			* (A) SW Padding             0,1,2,10              54,55,56,64
			*     Single Descriptor
			*
			* (B) SW Padding             0                     54
			*     Two Descriptors
			*
			* (C) Auto Padding           2,10                  56,64
			*     Single Descriptor
			*
			* (D) Auto Padding           No Failures
			*     Two Descriptors
			*
			* ----------------------------------------------------------------
			*/
		if (CurrPkt->ChkSum & TCPPKT) 
		{
			if (CurrPkt->TotalDataLength <= HOTFIX_TCPPACKETLENGTH)
			{
				bSwPadding = 0;
				NsmGetPkt(pAdapter->pNsmContext,CurrPkt->pOSCtrlBlk,
				          EtherTcpPkt, pChksumoffset,&PktLength,
				          CurrPkt->ChkSum,&NumberOfDescriptors);
				if ((UINT) (PktLength+ETHER_HEADER_LENGTH) < (CurrPkt->TotalDataLength))
					bSwPadding = 1;
				if ((NumberOfDescriptors == 1) && ((PktLength == 42) || 
				                                   (PktLength == 50)))
				{
					Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,CurrPkt->ChkSum);
					*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
					*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  1 checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
					CurrPkt->ChkSum &= ~(TCPPKT);
				} else if (bSwPadding)
				{
					if (PktLength == 40) 
					{
						Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,CurrPkt->ChkSum);
						*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
						*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  2 checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
						CurrPkt->ChkSum &= ~(TCPPKT);
					}
					else if (NumberOfDescriptors == 1)
					{
						if (PktLength == 41)
						{
							Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,CurrPkt->ChkSum);
							*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
							*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  3 checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
							CurrPkt->ChkSum &= ~(TCPPKT);
						}
					}
				}
			}
		}
		/* End of Bug fix */
#endif
#if TCPCHECKSUM_HOTFIX && UDPCHECKSUM_HOTFIX
	else {
#endif
#ifdef UDPCHECKSUM_HOTFIX
		/* Start of Bug Fix for H/W UDP Checksum */
		if (CurrPkt->ChkSum & UDPPKT) 
		{
			if (CurrPkt->TotalDataLength <= HOTFIX_UDPPACKETLENGTH)
			{
				NsmGetPkt(pAdapter->pNsmContext,CurrPkt->pOSCtrlBlk,
				          EtherUdpPkt, pChksumoffset,&PktLength,
				          CurrPkt->ChkSum,&NumberOfDescriptors);
		
				DataLength = PktLength - IP_HLEN(EtherUdpPkt[IP_HEADERLEN_OFFSET]) - UDP_HEADER_LENGTH;
				if (DataLength <= 3)
				{
					Hsmchksum(pAdapter,EtherUdpPkt,&Chksum,CurrPkt->ChkSum);
					*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
					*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
					CurrPkt->ChkSum &= ~(UDPPKT);
				}
			}
		}
		/* End of Bug fix */
#endif
#if TCPCHECKSUM_HOTFIX && UDPCHECKSUM_HOTFIX
	}
#endif
#endif
/* For all the fragments do the following */
/*
 *	Fix for the race condition between h/w and driver. 
 */
		/*while(FragCount < pPkts->PktArray[PktSent].NumFrags)	*/
		while(FragCount < NumFrags)
		{

			CLEAN_UP_DESC(CurrDesc);
                        
/* 
 * 	Set the buffer pointer in the descriptor 
 * 	Update the length field in the descriptor 
 *	Clear the intr. and set the OWN bit.
 */
			TX_DESC_SET_BUF(CurrDesc, 
				CurrPkt->FragArray[FragCount].pFrag);

			TX_DESC_SET_SIZE(CurrDesc, 
				CurrPkt-> FragArray[FragCount].FragLen );

/*
 *	Fix for the race condition between h/w and driver. 
 *			Foll. stmt. is unneccessary as cmdsts is set to 0 in CLEAN_UP_DESC.
 */
/*			TX_DESC_SET_INTR(CurrDesc,0);*/

/* 
 *			Check if this is the first fragment of the packet and if so set 
 *			the checksum offload feature if required
 * 			
 * 			Set the VLAN Tagging information on the descriptor
 * 			if we have VLAN Tagging enabled.
 */
			
#if TXCHECKSUM || PRIORITY
			if( FragCount == 0)
			{
#ifdef TXCHECKSUM
				SET_TCB_CHKSUM(CurrDesc, CurrPkt->ChkSum);
#endif
				
#ifdef PRIORITY
				if(pAdapter->PhysCapabilities & VLAN_TAG_INSERTION_PP_ON)
					SET_VLAN(CurrDesc, pAdapter->VLANId, CurrPkt->Priority);
#endif
			}
#endif


/* 
 *	Set the MORE bit of the descriptor to indicate that there are 
 *	no more to this packet 
 */
/*
 *			Fix for the race condition between h/w and driver. 
 *			Setting the MORE bit for all the fragments except the last .
 *			Setting the INTR bit for the last fragment.
 */
			if (FragCount != (NumFrags - 1)) {
				TX_DESC_SET_MORE(CurrDesc, 1);
				TX_DESC_SET_OWN(CurrDesc);
			}
			else
			{
				TX_DESC_SET_INTR(CurrDesc,1); 
				TX_DESC_SET_OWN(CurrDesc);
				/*Need to do this only for last desc.*/
				pFirstTcb->pEndDesc = CurrDesc;
				pFirstTcb->pEndDescPa = CurrDescPa;
			}
			/* Moving it up for removing race condition
			which can exist within the small window of 4 lines */
			/*TX_DESC_SET_OWN(CurrDesc);*/
				

			CurrDesc = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
				CurrDesc, 1, DescBase);
			CurrDescPa = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
				CurrDescPa, 1, DescBasePa);

			FragCount ++;		/* Increment the fragment count */

		}

/*
 *			Fix for the race condition between h/w and driver. 
 *			Commenting the foll. statements as they are done in while loop.
 */
/*		TX_DESC_SET_MORE(pFirstTcb->pEndDesc,0);

		TX_DESC_SET_INTR(pFirstTcb->pEndDesc,1); */ 

		pFirstTcb = pFirstTcb->pNext;

		pFirstTcb->pStartDesc = CurrDesc;

		pFirstTcb->pStartDescPa = CurrDescPa;           

		PktSent ++; 		/* Increment the packet count */
	}

/* 
 *	Start the transmission if the adapter is in the OPEN state and return 
 *	number of packets processed 
 */
	if(pAdapter->AdapterStatus & ADAPTER_OPEN)
		HsmTxStart(pAdapter, Priority);
#ifdef LINK_AGGR
	return (PktIndex - StartIndex);
#else
	return PktIndex;
#endif
}

/******************************************************************************
*f*
*   Name:           HsmSendPacket
*
*   Description:    
*		This is called from the NSM. It posts a single packet of a
*   	particular priority, indicated by Priority, to the adapter for
*   	transmission.
*
*   Parameters:     
*		pAdapter        Pointer to the AdapterContext structure
* 		pPkt			Pointer to the PktInfo structure, in which 
*                   	the packet to be sent down is encapsulated 
*
*		Prio			Priority queue in to which this set of 
*                   	packet is to be put.
*
*   Return Value:   
*			SUCCESS or FAILURE 
*
*f*
******************************************************************************/
UCHAR HsmSendPacket(AdapterContext *pAdapter, PktInfo *pPkt, UCHAR Prio)
{
        HsmTCB          *pCurrTcb;
        volatile DevDesc         *StartDesc;
        volatile DevDesc         *CurrDesc;
        volatile DevDesc         *StartDescPa, *CurrDescPa;
        UCHAR           Priority;
        UCHAR           i;
        USHORT          FreeCount;
        volatile DevDesc         *DescBase;
        volatile DevDesc         *DescBasePa;
#if TXCHECKSUM && TCPCHECKSUM_HOTFIX
		UCHAR 			EtherTcpPkt[HOTFIX_TCPPACKETLENGTH]; 
/* The size of the array should be even number for calculating checksum*/
#endif
		PUCHAR			pChksumoffset[2];
		USHORT			PktLength;
		USHORT			Chksum;
		UINT		NumberOfDescriptors;
		UCHAR	bSwPadding=0;
#if TXCHECKSUM && UDPCHECKSUM_HOTFIX
/* The size of the array should be even number for calculating checksum*/
		UCHAR			EtherUdpPkt[HOTFIX_UDPPACKETLENGTH]; 
		UINT			DataLength;
#endif
        
        /* Acquire the lock before manipulating a critical section */
        NsmAcquireLock(pAdapter->pNsmContext, pAdapter->TxLock);

        /* Get the hardware Priority on which the packets have to be sent */
        Priority = GetHardwarePriority(pAdapter, Prio);

        FreeCount = FreeTxDesc(pAdapter, Priority);     

        /* Check whether the number of free descriptors in the priority level is 
    		enough to accommodate the fragments in the packet */
        if (pPkt->NumFrags >  FreeCount)
        {
                /* Release the lock */
                NsmReleaseLock(pAdapter->pNsmContext, pAdapter->TxLock);

                return FAILURE;
        }

        /* Get the Next pointer of the HsmTCB list from the AdapterContext */
        pCurrTcb = GET_TCB_NEXT(pAdapter, Priority);

        /* Get the pointer to the descriptor, pointed to by the start field of the 
    		HsmTCB */
        CurrDesc = StartDesc = pCurrTcb->pStartDesc;
        CurrDescPa = StartDescPa = pCurrTcb->pStartDescPa;

#ifdef TXCHECKSUM 
#ifdef TCPCHECKSUM_HOTFIX
		/* Start of Bug Fix for H/W TCP Checksum */
		/* The conditions for  calculating TCP checksum :
			* ----------------------------------------------------------------
			* OPTION                     FAILING TCP           Packet Sizes
			*                            Data Sizes             (w/o CRC)
			* ----------------------------------------------------------------
			* (A) SW Padding             0,1,2,10              54,55,56,64
			*     Single Descriptor
			*
			* (B) SW Padding             0                     54
			*     Two Descriptors
			*
			* (C) Auto Padding           2,10                  56,64
			*     Single Descriptor
			*
			* (D) Auto Padding           No Failures
			*     Two Descriptors
			*
			* ----------------------------------------------------------------
			*/
		if (pPkt->ChkSum & TCPPKT) 
		{
			if (pPkt->TotalDataLength <= HOTFIX_TCPPACKETLENGTH)
			{
				NsmGetPkt(pAdapter->pNsmContext,pPkt->pOSCtrlBlk,
				          EtherTcpPkt, pChksumoffset,&PktLength,
				          pPkt->ChkSum,&NumberOfDescriptors);
				if ((UINT)(PktLength+ETHER_HEADER_LENGTH) < pPkt->TotalDataLength)
					bSwPadding = 1;
				if ((NumberOfDescriptors == 1) && ((PktLength == 42) || 
				                                   (PktLength == 50)))
				{
					Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,pPkt->ChkSum);
					*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
					*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
					pPkt->ChkSum &= ~(TCPPKT);
				} else if (bSwPadding)
				{
					if (PktLength == 40) 
					{
						Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,pPkt->ChkSum);
						*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
						*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
						pPkt->ChkSum &= ~(TCPPKT);
					}
					else if (NumberOfDescriptors == 1)
					{
						if (PktLength == 41)
						{
							Hsmchksum(pAdapter,EtherTcpPkt,&Chksum,pPkt->ChkSum);
							*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
							*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
					NsmDbgMsg2("\n  checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
							pPkt->ChkSum &= ~(TCPPKT);
						}
					}
				}
			}
		}
		/* End of Bug fix */
#endif
#if TCPCHECKSUM_HOTFIX && UDPCHECKSUM_HOTFIX
		else {
#endif
#ifdef UDPCHECKSUM_HOTFIX
		/* Start of Bug Fix for H/W UDP Checksum */
			if (pPkt->ChkSum & UDPPKT) 
			{
				if (pPkt->TotalDataLength <= HOTFIX_UDPPACKETLENGTH)
				{
					NsmGetPkt(pAdapter->pNsmContext,pPkt->pOSCtrlBlk,
					          EtherUdpPkt, pChksumoffset,&PktLength,
					          pPkt->ChkSum,&NumberOfDescriptors);
	
					DataLength = PktLength - IP_HLEN(EtherUdpPkt[IP_HEADERLEN_OFFSET]) - UDP_HEADER_LENGTH;
					if (DataLength <= 3)
					{
						Hsmchksum(pAdapter,EtherUdpPkt,&Chksum,pPkt->ChkSum);
						*pChksumoffset[0] = (UCHAR )(Chksum &0x00ff);
						*pChksumoffset[1] = (UCHAR )((Chksum &0xff00) >> 8);
#ifdef CHECKSUM_DEBUG
				NsmDbgMsg2("\n  checksum Byte 0= %x Byte1 = %x", *pChksumoffset[0],*pChksumoffset[1]);
#endif
						pPkt->ChkSum &= ~(UDPPKT);
					}
				}
			}
	/* End of Bug fix */
#endif
#if TCPCHECKSUM_HOTFIX && UDPCHECKSUM_HOTFIX
	}
#endif
#endif
#ifdef NSCDEBUG
		NsmDbgMsg("Setting the checksum in the descriptor\n");
#endif

/* 
 * 		Set the VLAN Tagging information on the descriptor
 * 		if we have VLAN Tagging enabled.
 */
		
#ifdef TXCHECKSUM
		SET_TCB_CHKSUM(CurrDesc, pPkt->ChkSum);
#endif

#ifdef PRIORITY
		if(pAdapter->PhysCapabilities & VLAN_TAG_INSERTION_PP_ON)
			SET_VLAN(CurrDesc, pAdapter->VLANId, pPkt->Priority);
#endif

        pCurrTcb->pOsCtrlBlk = pPkt->pOSCtrlBlk;
#ifdef LINK_AGGR
		pCurrTcb->SlowProtocolType = pPkt->SlowProtocolType;
#endif

        DescBase = pAdapter->PriQue[Priority].pTxdArray;
        DescBasePa = pAdapter->PriQue[Priority].pTxdArrayPa;

        /* For all the fragments in the packet do the following */
        for(i = 0 ; i  < pPkt->NumFrags; i++) 
        {

                CLEAN_UP_DESC(CurrDesc);
                
                /* Set the BufPtr in the descriptor */
                TX_DESC_SET_BUF(CurrDesc, pPkt->FragArray[i].pFrag);

                /* Update the length field in the descriptor */
                TX_DESC_SET_SIZE(CurrDesc, pPkt->FragArray[i].FragLen );

                /*TX_DESC_SET_INTR(CurrDesc,0);*/

				if (i != (pPkt->NumFrags - 1))
					TX_DESC_SET_MORE(CurrDesc, 1);
				else
				{
					TX_DESC_SET_INTR(CurrDesc,1); 
					pCurrTcb->pEndDesc = CurrDesc;
					pCurrTcb->pEndDescPa = CurrDescPa;
				}
                
				/*TX_DESC_SET_MORE(CurrDesc,1);*/

                /* Set the OWN bit */
                TX_DESC_SET_OWN(CurrDesc);

                /* pCurrTcb->pEndDesc = CurrDesc;

                pCurrTcb->pEndDescPa = CurrDescPa;  */

                CurrDesc = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
                                                                        CurrDesc,1, DescBase);
                CurrDescPa = (DevDesc *)INC_CURR_DESC(pAdapter, Priority, 
                                                                        CurrDescPa,1, DescBasePa);

        }

        /*TX_DESC_SET_INTR(pCurrTcb->pEndDesc,1);
        TX_DESC_SET_MORE(pCurrTcb->pEndDesc,0); */

		pCurrTcb = pCurrTcb->pNext;

		pCurrTcb->pStartDesc = CurrDesc;
		pCurrTcb->pStartDescPa = CurrDescPa;

        /* Set the Next pointer in the RCB list */
        SET_TCB_NEXT(pAdapter, Priority, pCurrTcb);

        /* Release the lock */
        NsmReleaseLock(pAdapter->pNsmContext, pAdapter->TxLock);

        /* Start the transmission if the adapter is in the OPEN state */
        if(pAdapter->AdapterStatus & ADAPTER_OPEN)
        {
                /* Enable the TxState machine if it is not already enabled */  
                HsmTxStart(pAdapter, Priority);

        }

        return SUCCESS; 
}

/******************************************************************************
*f*
*   Name:           HsmSetPhyCapabilities 
*
*   Description:    HsmSetPhyCapabilities is called from the NSM. It sets the 
*   physical capabilities like checksum offloading, which will be represented 
*   by the PhysFlags. The description of the different physical capabilities 
*   is explained in the CDI.
*
*   Parameters:     pAdapter    Pointer to the AdapterContext structure
*
*                   PhysFlags   The flag representing the physical capabilities
* 
*   Return Value:   SUCCESS or FAILURE 
*
*f*
******************************************************************************/

UCHAR 
HsmSetPhyCapabilities(AdapterContext *pAdapter, UINT PhysFlags, UINT SetSpeed)
{
	NsmContext      *pNsm = (NsmContext *)pAdapter->pNsmContext;
   	UINT            Flag;
	UINT            Bmcr_val;
	UINT            Bmcr_val_temp;
	UINT            Anar_val;
	UINT            Cfg_val;
	UINT            Ktcr_val;
	UINT            RegBase = (UINT)pAdapter->RegAddr;
	UINT			ExtSts = 0;
	UINT			Nc_val;
	UINT			Tanar_val;
	UINT			Tbicr_val;

	if(!(pAdapter->tbi))
	{

/*Disable the Non-IEEE Compliant mode from register 0x10, disable bit 10 in Phy*/
	Nc_val = ReadMiiReg(pAdapter, STROP);
	
/* If IEEE Compliance then bit AdapterContext NcBit should be value 1 
 * but the value on the card must be 0 for IEEE compliant mode.
 */
	if (pAdapter->NcBit) 
		Nc_val &= ~(NCBIT);
	else 
		Nc_val |= NCBIT;
	
	WriteMiiReg(pAdapter, STROP, Nc_val);
	}

#ifdef _GA621_
	
	Flag = 0;

	if(PhysFlags & TX_CHKSUM_OFFLOAD_ON_PP)
		Flag |= PPCHK;

	if(PhysFlags & TX_CHKSUM_OFFLOAD_ON_GEN)
		Flag |= GCHK;

	/*	
	 *	If the OS supports Priority then we use Per
	 *	Packet Generation else we use Global VLAN
	 *	Tag Generation.
	 */
#ifdef PRIORITY
	if(PhysFlags & VLAN_TAG_INSERTION_PP_ON)
		Flag |= VPPTI;
#else
	if(PhysFlags & VLAN_TAG_INSERTION_GEN_ON)
		Flag |= VGTI;
#endif

	NsmRegWrite32(pNsm, RegBase + VTCR, Flag);
	ExtSts |= Flag;

	Flag = 0;

	/*  
	 * Turn On VLAN Tag Detection on by default.
	 * If we have VLAN Disabled, Let the NIC detect VLAN Tagged frames
	 * and discard them.
	 */

	Flag |= VTDEN;

	if(!(PhysFlags & (VLAN_TAG_INSERTION_PP_ON | VLAN_TAG_INSERTION_GEN_ON)))
		Flag |= DVTF;

	if(PhysFlags & SET_RX_CHKSUM_OFFLOAD_ON)
		Flag |= IPEN;

	if(PhysFlags & RX_UDP_CHKSUM_DISCARD_ON)
		Flag |= RUDPE;

	if(PhysFlags & RX_TCP_CHKSUM_DISCARD_ON)
		Flag |= RTCPE;

	if(PhysFlags & RX_IP_CHKSUM_DISCARD_ON)
		Flag |= RIPE;

	if(PhysFlags & VLAN_TAG_REMOVAL_ON)
		Flag |= VTREN;


	NsmRegWrite32(pNsm, RegBase + VRCR, Flag);              
	
	/*Enable ExtSts*/
	ExtSts |= Flag;
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				&Cfg_val);
	if (ExtSts)
	{
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				(Cfg_val | EXTSTS_EN));
	}
	else
	{
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				(Cfg_val & ~EXTSTS_EN));
	}
#endif 
/* Set Wake On LAN if required */

	NsmRegRead32(pNsm, (RegBase + WCSR), &Flag);

	if(PhysFlags & SET_WOL_ON)
		Flag |= WOL_FLAG; 

	if(PhysFlags & SET_WOL_OFF)
		Flag &= ~WOL_FLAG; 
 
	NsmRegWrite32(pNsm, (RegBase + WCSR), Flag);
	if (!SetSpeed)
	{
		return SUCCESS;
	}

	if(pAdapter->tbi)
	{
		/* Enabling Pause frame only in FULL DUPLEX mode.
		 * Since we are doing this for copper, doing the same for TBI. 
		 * Need to be verified for TBI.
		 */
		if(pAdapter->UserDuplexMode == FULL_DUPLEX) 
		{
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
									&Tanar_val);

			/*
			 * For either Rx Flow control or
			 * Tx and Rx, both enabled.
			 */
			if(pAdapter->FlowControl & RX_PAUSE_FRAMES_ENABLE)
				Tanar_val |= (PS1 | PS2);

			/* 
			 * For Tx Flow Control only
			 */
			else if(pAdapter->FlowControl & TX_PAUSE_FRAMES_ENABLE)
			{
				Tanar_val |= PS2;
				Tanar_val &= ~PS1;
			}
			
			/*
			 * For no Flow Control, default
			 */
			else
				Tanar_val &= ~(PS1 | PS2);
			
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
				Tanar_val);
		}

		if(PhysFlags & AUTO_NEG_ON)
		{ 
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				&Cfg_val);

			/* Revisit, may not be required */
			Cfg_val &= ~(AUTO_1000 );

			Cfg_val |= (MODE_1000);
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				Cfg_val);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
				&Tanar_val);

			Tanar_val |= (HALF_DUP | FULL_DUP);

			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
				Tanar_val);
		}
		else
		{
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				&Cfg_val);

			Cfg_val &= ~(AUTO_1000);
			Cfg_val |=  MODE_1000;
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), 
				Cfg_val);

			/* Revisit, check whether this is required */			
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
				&Tanar_val);
			
			if( pAdapter->UserDuplexMode == HALF_DUPLEX ) 
			{
				Tanar_val |= HALF_DUP;
				Tanar_val &= ~FULL_DUP;
			}
/*   Commented out because no need for this case, Autoneg full duplex only.
			else 
			{
				Tanar_val &= ~HALF_DUP;
				Tanar_val |= FULL_DUP;
			}
*/
		}

		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TANAR), 
			Tanar_val);

		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + TBICR), 
			&Tbicr_val);

		Tbicr_val |= (MR_AN_ENABLE | MR_RESTART_AN);

		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TBICR), 
			Tbicr_val);

/*  - Added to clear MR_RESTART_AN, must do to link.*/
		Tbicr_val = (MR_AN_ENABLE);
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TBICR), 
			Tbicr_val);

/*  - Added for case when Force full duplex. Writing a 0 to tbicr allows for link 
			on forced full duplex switches and NICs. May use another defined conditional 
			for forced full duplex operation.*/
		if( !(PhysFlags & AUTO_NEG_ON) && !(pAdapter->UserDuplexMode == HALF_DUPLEX) ) {
			Tbicr_val = 0;
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + TBICR), 
				Tbicr_val);
		}

	}
	else
	{
		/* Enable the Pause Frames only in Full Duplex Mode */
		if(pAdapter->UserDuplexMode == FULL_DUPLEX)
		{
			Anar_val = ReadMiiReg(pAdapter, ANAR);

			/*
			 * When Rx is enabled we advertise both
			 * Symmetrical and Asymmetrical Pause frames.
			 *
			 * For Tx we only advertise Asymmetrical.
			 */
			if(pAdapter->FlowControl & RX_PAUSE_FRAMES_ENABLE)
			{
				/*
				 * Enable Symmetrical Pause Frames.
				 */
				Anar_val |= PAUSE;
				
				/*
				 * Enable advertising of Assymetrical
				 * Pause frames, using the following method.
				 */
				WriteMiiReg(pAdapter, EMM, 0x0D); /* Expanded Memory Mode */
				WriteMiiReg(pAdapter, EMA, 0x8084); /* Expanded Memory Access */
				WriteMiiReg(pAdapter, EMD, 0x0001); /* Expanded Memory Data */
			}

			/* 
			 * For Tx Flow Control only
			 */
			else if(pAdapter->FlowControl & TX_PAUSE_FRAMES_ENABLE)
			{
				/*
				 * Enable advertising of Assymetrical
				 * Pause frames, using the following method.
				 */
				WriteMiiReg(pAdapter, EMM, 0x0D); /* Expanded Memory Mode */
				WriteMiiReg(pAdapter, EMA, 0x8084); /* Expanded Memory Access */
				WriteMiiReg(pAdapter, EMD, 0x0001); /* Expanded Memory Data */
				
				/*
				 * Disable Symmetrical Pause Frames.
				 */
				Anar_val &= ~PAUSE;
			}
			
			/*
			 * For no Flow Control
			 */
			else
			{
				/*
				 * Disable Symmetrical Pause Frames.
				 */
				Anar_val &= ~PAUSE;

				/*
				 * Disable advertising of Assymetrical
				 * Pause frames, using the following method.
				 */
				WriteMiiReg(pAdapter, EMM, 0x0D); /* Expanded Memory Mode */
				WriteMiiReg(pAdapter, EMA, 0x8084); /* Expanded Memory Access */
				WriteMiiReg(pAdapter, EMD, 0x0000); /* Expanded Memory Data */
			}

			WriteMiiReg(pAdapter, ANAR, Anar_val);
		}

		/* 
		 * Setting the Card Speed based on the new Algorithm
		 * according to which the modes are backward compatible
		 * and modes are advertised only when working in AUTONEG
		 * and the forced mode is only Valid if we are working
		 * in IEEE compliant mode, if not then we AutoNegotiate
		 * since in this mode and the NsmPhySleep enabled, 
		 * ie: we are waiting for the AUTONEG_COMPLETE indication
		 * to indicate the link up status.
		 */
		
		/*
		 * Turn off AUTO_1000 bit since it malfunctions for all modes.
		 */
		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), &Cfg_val);
		Cfg_val &= ~(AUTO_1000 | MODE_1000);

		if((PhysFlags & AUTO_NEG_ON) || ((!(pAdapter->NcBit)) && pAdapter->NsmPhySleep)) /* Auto Neg Mode */
		{
			/* 
			 * Default vaules required for all modes.
			 */
			Bmcr_val = (AUTONEGENABLE | RESTARTAUTONEG);
			Ktcr_val = 0;
			Anar_val = ReadMiiReg(pAdapter, ANAR);
			Anar_val &= ~(A100BASETFD | A100BASETHD | A10BASETFD | A10BASETHD);

			/* 
			 * Using a fall though switch case statement since
			 * in AUTONEG mode the modes must be backwards compatible
			 * When the user selects Half Duplex then he is backwards
			 * compatible only in Half duplex modes and does not enter
			 * any Full Duplex modes, but when in Full Duplex mode he
			 * can get into any backward compatible mode.
			 */
			switch(pAdapter->UserMediaSpeed)
			{
				default :
				case 1000 :	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Ktcr_val |= A1000BASETFD;
							
							/* Half duplex and backward compatible */
							Ktcr_val |= A1000BASETHD;
							Cfg_val |= MODE_1000;

				case 100 :	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Anar_val |= A100BASETFD;
							
							/* Half duplex and backward compatible */
							Anar_val |= A100BASETHD;
							
				case 10 :	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Anar_val |= A10BASETFD;
							
							/* Half duplex and backward compatible */
							Anar_val |= A10BASETHD;
							break;
			}
		}
		else /* Forced Speed modes */
		{
			/* 
			 * Default vaules required for all modes.
			 */
			Ktcr_val = Bmcr_val = 0;
			Anar_val = ReadMiiReg(pAdapter, ANAR);
			Anar_val &= ~(A100BASETFD | A100BASETHD | A10BASETFD | A10BASETHD);

			/* 
			 * Set the speed on the card individually
			 * based on the user selection and force all the 
			 * modes except the 1000M Mode where we Auto Neg.
			 */
			switch(pAdapter->UserMediaSpeed)
			{
				default :
				case 1000 :	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Ktcr_val |= A1000BASETFD;
							else
								Ktcr_val |= A1000BASETHD;

							/* Common to both Duplex Modes */
							Bmcr_val |= (AUTONEGENABLE | RESTARTAUTONEG);
							Cfg_val |= MODE_1000;
							break;
							
				case 100 :	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Bmcr_val |= FORCEFD;

							/* Common to both Duplex Modes */
							Bmcr_val |= FORCESPEED100;
							break;

				case 10:	if(pAdapter->UserDuplexMode == FULL_DUPLEX)
								Bmcr_val |= FORCEFD;

							/* Common to both Duplex Modes */
							Bmcr_val |= FORCESPEED10;
							break;
			}
		} /* end of speed selection */

		/* 
		 * Write the Values into the register in the order that
		 * we write the data first to Negotiate and then
		 * start the mode forcing or AutoNegotiation.
		 */
		WriteMiiReg(pAdapter, KTCR, Ktcr_val);
		WriteMiiReg(pAdapter, ANAR, Anar_val); /* Write the Advetise details */
		
		/* 
		 * If we need to do/restart and AutoNegtiation then we
		 * first check if we are in forced mode, if we are in forced
		 * mode then we clear bit 12 of the BMCR (AUTO_NEG_ENABLE) and
		 * then reset the bit to 1 and then write to register to restart
		 * Auto Negotiation if required.
		 * 
		 * Restarting AUTONEG if required else updating the speed
		 * in the Phy to the forced speed.
		 */
		if((PhysFlags & AUTO_NEG_ON) || ((!(pAdapter->NcBit)) && pAdapter->NsmPhySleep)) /* Auto Neg Mode */
		{
			Bmcr_val_temp = ReadMiiReg(pAdapter, BMCR); 
			
			/*
			 * Check if we are changing from forced mode.
			 */
			if(!(Bmcr_val_temp & AUTONEGENABLE))
			{
				/*
				 * We clear the AUTONEGENABLE bit and then reset the bit
				 * before we start a AutoNegotiate process.
				 */
				Bmcr_val_temp &= ~AUTONEGENABLE;
				WriteMiiReg(pAdapter, BMCR, Bmcr_val_temp); 
				
				Bmcr_val_temp |= AUTONEGENABLE;
				WriteMiiReg(pAdapter, BMCR, Bmcr_val_temp); 
			}
		}
		
		WriteMiiReg(pAdapter, BMCR, Bmcr_val); /* Activate the new speed */
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CFG), Cfg_val);
	}
#ifdef LINK_AGGR
	/* 
	 * Add callback 
	 *
	 
	 if (pAdapter->nFlags)
		LacpSetPhyCapabilities(pAdapter, PhysFlags, SetSpeed);

	 *
	 */
#endif
	return SUCCESS;
}

/******************************************************************************
*f*
*   Name:           HsmTxCompleted 
*
*   Description:    This is called by HSM to take care of the packets for which
*   the transmission is complete. This is typically called from the Interrupt 
*   Service Routine. 
*
*   Parameters:     pAdapter    Pointer to the AdapterContext structure 
*
*   Return Value:   None 
*
*f*
******************************************************************************/

VOID
HsmTxCompleted(AdapterContext *pAdapter)
{
	UCHAR    Priority=0;
	UINT    TxPriorities;
	HsmTCB          *pTcbListHead;
	HsmTCB          *pTcbList;
	HsmTCB          *pTcbListNext;
	UINT            DescCnt;

#ifdef STATISTICS
	UINT            ccnt_val;
	UINT            col_val;
#endif

#ifdef LINK_AGGR
	HsmTCB			*pStart, *pCurrent, *pHead, *pTail;
#endif
#ifdef _GA621_
	TxPriorities = (pAdapter->interruptStatus & (TX_QUEUES | 0x80));
#elif _DP83815_
	TxPriorities = (pAdapter->interruptStatus );
#endif 
        
/* 
 *	For each priority level supported . 
 *	If we have Priority Queues enabled we get the 0x80 along
 *	with the TXDESCx, if it not enabled then we get only 0x80.
 */
	if(TxPriorities & TX_QUEUES)
		TxPriorities &= ~(0x80);

	while(TxPriorities)
	{
#ifdef _GA621_
		if(TxPriorities & TXDESC3)
		{
			Priority = 3;
			TxPriorities &= ~TXDESC3;
		} 

		else if(TxPriorities & TXDESC2)
		{
			Priority = 2;
			TxPriorities &= ~TXDESC2;
		} 

		else if(TxPriorities & TXDESC1)
		{
			Priority = 1;
			TxPriorities &= ~TXDESC1;
		}

		else 
		{
			Priority = 0;
			TxPriorities &= ~(TXDESC0|0x80);
		} 
#elif _DP83815_
		Priority = 0;
		TxPriorities = 0;
#endif

/* 
 *	Get the head of the HsmTCB list 
 */
		pTcbListHead = GET_TCB_HEAD(pAdapter, Priority);

/* 
 *	Assign the head to a local variable and get the next pointer in HsmTCB list.
 */
		pTcbList = pTcbListHead; 
		pTcbListNext = GET_TCB_NEXT(pAdapter, Priority);
/* 
 *		Initialise the count of descriptors for which transmission is complete 
 * 		For each HsmTCB for which transmission has completed do the following, 
 * 		also check whether the HsmTCB list is full, to ensure that, the 
 *		processing of the packets is done when the HsmTCB list is full too. Do 
 *		the processing till the entire list from the Head to the Next has been 
 *		scanned.
 */
		/*Not needed should be removed*/
		DescCnt = FreeTxDesc(pAdapter,Priority);

		if (pTcbList->pEndDesc && 
			/*Not needed should be removed*/
			(DescCnt != pAdapter->PriQue[Priority].iMaxTxDesc) &&
			TX_COMPLETE(pTcbList->pEndDesc) ) {

/*
 *	Date : 25/7/2000
 *	Non-NULL condition check for pTcbList->pEndDesc added in 
 *	while() condition.  
 */
			while( pTcbList->pEndDesc && TX_COMPLETE(pTcbList->pEndDesc) )
			{
/* 
 *	Mark the status as OK if not errored packets 
 */
				if(TX_ERRORED(pTcbList->pEndDesc))
				{

					pTcbList->TxStatus = TCB_ERROR; /* Revisit */
#ifdef STATISTICS
					pAdapter->MacStats.txErrorCount++;
#endif
#ifdef NSCDEBUG
					NsmDbgMsg1("TxError : Cmdsts = %x\n",pTcbList->pEndDesc->CmdSts);
#endif
				}
				else	
				{
					pTcbList->TxStatus = TCB_OK;
#ifdef STATISTICS
					pAdapter->MacStats.txOkCount++;
#endif
				}

#ifdef STATISTICS
				if(pTcbList->pEndDesc->CmdSts & CRS)
					pAdapter->MacStats.txCrsLostCount++;
				
				if(pTcbList->pEndDesc->CmdSts & TXA)
					pAdapter->MacStats.txAbortCount++;
				
				if(pTcbList->pEndDesc->CmdSts & TFU)
					pAdapter->MacStats.txUnderrunCount++;
	
				if(pTcbList->pEndDesc->CmdSts & TD)
					pAdapter->MacStats.txDeferredCount++;

				if (pTcbList->pEndDesc->CmdSts & CCNT)
				{
					ccnt_val = ((pTcbList->pEndDesc->CmdSts & CCNT) >> 16);
					
					if(ccnt_val & 1)
					{
						pAdapter->MacStats.txOneCollisionCount++;
						pAdapter->MacStats.txTotCollisionCount++;
					}
					
					if(ccnt_val & 2)
					{
						pAdapter->MacStats.txMultiCollisionCount++;
						pAdapter->MacStats.txTotCollisionCount += 2;
					}
					
					if(ccnt_val)
					{
						col_val = (ccnt_val >> 2);
						pAdapter->MacStats.txExcessiveCollisionCount += col_val;
						pAdapter->MacStats.txTotCollisionCount += (col_val * 64);
					}
				}
#endif

                        
/* 
 *	Get the next HsmTCB in the list 
 */
				pTcbList->pEndDesc = NULL;
				pTcbList = pTcbList->pNext;
			}

#ifdef LINK_AGGR
			/* 
			 * If LACP is not enabled, call NSM
			 */
			if ((pAdapter->nFlags & LACP_FLAG) == 0) {
				NsmTxCompleted(pAdapter, pTcbListHead, pTcbList);
			}
			else
			{
				/* 
				 * Call NSM or LACP completion routine based on type of packet 
				 */
				pCurrent = pStart = pHead = pTcbListHead;
				pTail = pTcbList;
				do
				{
					/* 
					 * Check if Slow protocol type 
					 */
					if(pHead->SlowProtocolType)
					{
						if (pStart != pHead) /* If any MAC client PDUs */
							NsmTxCompleted(pAdapter->pAggregatorContext, pStart, pCurrent->pNext);
						LacpTxCompleted(pAdapter, pHead);
						pStart = pCurrent = pHead->pNext;
					}
					else
					{
						/* 
						 * MAC Client PDUs 
						 */
						pCurrent = pHead;
					}
					pHead = pHead->pNext;
				} while(pHead != pTail);
				
				/* 
				 * Process MAC Client PDUs if any 
				 */
				if(pCurrent != pTail)
					NsmTxCompleted(pAdapter->pAggregatorContext, pStart, pCurrent->pNext);
			}
#else
			NsmTxCompleted(pAdapter, pTcbListHead, pTcbList);
#endif        
        
/* 
 *	Set the new head of the list 
 */
		SET_TCB_HEAD(pAdapter, Priority, pTcbList);
		}
	}	/*	while()	*/
}

#define	MIN_FREE_RX_DESC	5

/******************************************************************************
*f*
*   Name:           HsmReplenishRcbs 
*
*   Description:    This is a utility routine provided for the HSM. It uses 
*   this to restore the free RCBs to the tail of the RCB list. 
*
*   Parameters:     pAdapter    Pointer to the AdapterContext structure
*
*                                       Priority    The priority queue, for which the RCBs need to 
*                                       be replenished
*
*   Return Value:   None 
*
*f*
******************************************************************************/
VOID HsmReplenishRcbs(AdapterContext *pAdapter, UCHAR Priority, UINT LoadRxdp)
{
	HsmRCB      *pRcb;
	HsmRCB      *Prev;
    HsmRCB      *pRcbListNext;
    HsmRCB      *pRcbTail;
    HsmRCB      *pRcbTempTail;
    AddrStruct  Addr;
    UCHAR       stat;

/* 
 *	Get the Head of the RCB list from the AdapterContext 
 * 	Get the Next pointer of the RCB list from the AdapterContext 
 * 	Get the Tail of the RCB list from the AdapterContext 
 */
    Prev = pRcb = GET_RCB_HEAD(pAdapter, Priority);
    pRcbListNext =  GET_RCB_NEXT(pAdapter, Priority);
    pRcbTail = GET_RCB_TAIL(pAdapter, Priority);
    pRcbTempTail = pRcbTail;

/* 
 *	Traverse through the list of RCBs till the Next pointer is reached 
 */
	while (pRcb != pRcbListNext)
    {
/* 
 *	Macro to set the free field. Here an OS specific method is used to find 
 *	whether a buffer is free and thereby mark the RCB free 
 */
		NsmMarkRcbFree(pRcb);

/* 
 *	If the RCB is free do the following  
 */
		if (pRcb->Status == RCB_FREE)
		{
			/*Not needed. Remove later*/
			DESC_CLEAR_OWN(pRcb->pRxDp); 

			pRcb->pRxDp->CmdSts = (pAdapter->MaxPktSize | INTR);

/* 
 *	If this is the RCB pointed to by the Head pointer itself then do the 
 *	following 
 */
			if( pRcb == Prev)
            {
/* 
 *	Set the new head within the AdapterContext. Set the new Prev pointer .
 */
				SET_RCB_HEAD(pAdapter, Priority, pRcb->pNext);
				Prev = pRcb->pNext;
/* 
 *	Put the pulled out RCB at the tail of the RCB list  
 */
				UPDATE_RCB_TAIL(pRcbTail, pRcb);

/* 
 *	Update the current pointer to the RCB  
 */
				pRcb = Prev;
			}
            else 
            {

				Prev->pNext = pRcb->pNext;

				Prev->pRxDp->link = pRcb->pRxDp->link;

/* 
 *	Put the pulled out RCB at the tail of the RCB list  
 *	Update the current pointer to the RCB  
 */
				UPDATE_RCB_TAIL(pRcbTail, pRcb);

                pRcb = Prev->pNext;
            }

/*  
 *	Increment the free count of RCBs for this priority  
 */
			/*Do the increment just once in the end.*/
			INC_FREE_RX_DESC(pAdapter, Priority);

        }

/* 
 *	Check if the RCB doesn't have a valid OS control block  
 */
		else if(pRcb->Status == RCB_BAD)
        {
			Addr.VirtAddr = (void *)pRcb->pDataBuf;
			Addr.pCookie = (void *)pRcb->pOsCtrlBlk;
			Addr.BufSize = pAdapter->MaxPktSize;

			if((stat = NsmAllocatePacket((NsmContext *)pAdapter->pNsmContext,
				pRcb, &Addr)) == SUCCESS)
			{
				pRcb->Status = RCB_FREE;
				pRcb->pOsCtrlBlk = Addr.pCookie;
				pRcb->pDataBuf = Addr.VirtAddr;
				pRcb->pRxDp->BufPtr = (UINT)Addr.PhysAddr;
			}
			else
			{
				pRcb->pOsCtrlBlk = NULL;
				Prev = pRcb;
				pRcb = pRcb->pNext;
			}
		}
		else
		{
/* 
 *	Update the Prev pointer 
 * 	Update the pointer to RCB to point to the next in the list 
 */
			Prev = pRcb;
            pRcb = pRcb->pNext;
        }
    }
    if (pRcbTail != pRcbTempTail)
    {
		SET_OWN(pRcbTail->pRxDp, 1);
		SET_OWN(pRcbTempTail->pRxDp, 0);
/* 
 *	Set the new tail pointer of the RCB list  
 */
    	SET_RCB_TAIL(pAdapter, Priority, pRcbTail);
    }
	
/* 
 *	Set the new tail pointer of the RCB list  
 */
	if (!(pAdapter->interruptStatus & RXRCMP))
    	HsmRxStart(pAdapter, Priority);

}


/******************************************************************************
*f*
*   Name:           HsmRxPackets 
*
*   Description:    This is a utility routine provided for the HSM. It uses 
*   this to handle the packets that have been received. This is typically 
*   called from the Interrupt Service Routine.
*
*   Parameters:     pAdapter    Pointer to the AdapterContext structure
*
*   Return Value:   None
*
*f*
******************************************************************************/
VOID HsmRxPackets(AdapterContext *pAdapter)
{
	UCHAR   PriIndex;
	UINT    RxPriorities;
	HsmRCB          *pRcbListNext = NULL;
	HsmRCB          *pRcbListTail = NULL;
	UCHAR           Priority;
	HsmRCB          *LastFullPacket = NULL;
	HsmRCB          *TempLastFullPacket = NULL;
	UINT		count=0;
#ifdef LINK_AGGR
	HsmRCB			*pStart, *pCurrent, *pHead, *pTail;
#endif

#ifdef _GA621_
	RxPriorities = (pAdapter->interruptStatus & (RX_QUEUES | 0x2));
#elif _DP83815_
	RxPriorities = (pAdapter->interruptStatus );
#endif 
/* 
 *	For each priority level supported   
 *	If we have Priority Queues enabled we get the 0x2 along
 *	with the TXDESCx, if it not enabled then we get only 0x2.
 */
	if(RxPriorities & RX_QUEUES)
		RxPriorities &= ~(0x2);

	while(RxPriorities)
	{
#ifdef _GA621_
		if(RxPriorities & RXDESC3)
		{
			PriIndex = 3;
			RxPriorities &= ~RXDESC3;
		} 
		else if(RxPriorities & RXDESC2)
		{
			PriIndex = 2;
			RxPriorities &= ~RXDESC2;
		} 
		else if(RxPriorities & RXDESC1)
		{
			PriIndex = 1;
			RxPriorities &= ~RXDESC1;
		}
		else 
		{
			PriIndex = 0;
			RxPriorities &= ~(RXDESC0 | 0x2) ;
		} 
#elif _DP83815_
		PriIndex = 0;
		RxPriorities = 0;
#endif
		LastFullPacket = NULL;
		count = 0;

/* 
 *	If the number of free RCBs in the list are less than a particular 
 *	threshold call the replenish function which would restore the freed 
 *	RCBs  
 */
		/* Tunable Parameter */
		/*if (FREE_RX_DESC(pAdapter, PriIndex) < RCB_THRESH)*/
		if ( FREE_RX_DESC(pAdapter, PriIndex) < (pAdapter->RxDp[PriIndex][MINDESCCNT]) )
		{	


/*
 *	To generate pause frames HsmReplenishRcbs() should not be called  for
 *	testing purpose.
 */
			HsmReplenishRcbs(pAdapter, PriIndex, 0);
		}

/* 
 *	Get the next pointer of the RCB list , Get the tail pointer of the RCB list 
 */
		pRcbListNext = GET_RCB_NEXT(pAdapter, PriIndex);

		pRcbListTail = GET_RCB_TAIL(pAdapter, PriIndex);

/* 
 *	For all the RCBs for which receive is completed do the following  
 */
		while ( (pRcbListNext != pRcbListTail) && 
			(RX_COMPLETE(pRcbListNext->pRxDp)) )
		{
/* 
 *	Get the size of the packet received  
 */
			pRcbListNext->PktSize = 
				RX_DESC_GET_SIZE(pRcbListNext->pRxDp);

			pRcbListNext->Status = RCB_INUSE;
/* 
 *	Set the More bit if MORE set in the descriptor  
 */
			pRcbListNext->More = (pRcbListNext->pRxDp->CmdSts & MORE) ? 1 : 0;
			/*If last descriptor then process*/
			if  (pRcbListNext->More == 0)
			{
#ifdef NSCDEBUG
				if(IS_VLAN_PACKET(pRcbListNext->pRxDp))  
					NsmDbgMsg1("Recv VLAN ID = %d\n",GET_VLAN_ID(pRcbListNext->pRxDp));
#endif

#ifdef RXCHECKSUM
				pRcbListNext->ExtSts = pRcbListNext->pRxDp->ExtSts;
#endif
				if((!(RX_ERRORED(pRcbListNext->pRxDp))) || (pAdapter->PhysCapabilities & ADAPTER_PROMISCUOUS_ON))
				{

					/*
					 * If the VLAN is turned on then we drop any packets
					 * that do not match our VLAN ID.
					 * 
					 * If we have a Errored packet then we goto the ERRORED
					 * section.
					 * 
					 * We accept all packets in Promiscuous Mode.
					 * No VLAN ID check is required if in Promiscuous Mode.
					 */

					if((!(pAdapter->PhysCapabilities & ADAPTER_PROMISCUOUS_ON)) && (IS_VLAN_PACKET(pRcbListNext->pRxDp))) 
					{
						/*
						 * The first 8 Bits and the last 4 bits of the 
						 * VTCI field in the ExtSts represents the VLAN ID.
						 *
						 * VTCI[15:0] = VID[7:0],user_priority[2:0],CFI[0],VID[11:8]
						 *
						 * The pAdapter->VLANId contains the VLAN ID in the card format.
					 	 */
						if(pAdapter->VLANId != (pRcbListNext->pRxDp->ExtSts & 0xFF0F))
							goto DROP_PACKET;
					}
						
#ifdef PRIORITY
					/*
					 * Store the priority information inside
					 * the packet itself as got from VLAN ID
					 */
					pRcbListNext->Priority = GET_PRIORITY(pAdapter, pRcbListNext->pRxDp);
#endif
#ifdef STATISTICS
					pAdapter->MacStats.rxOkCount++;

					/*
					 * If we are in Promiscusous mode, then we accept
					 * errored packets also, so we update the error counter
					 * for them also.
					 */
					if(pRcbListNext->pRxDp->CmdSts & CRCE)
						pAdapter->MacStats.rxCrcErrorCount++;
#endif
					count++;
					DEC_FREE_RX_DESC(pAdapter,PriIndex,count);
					LastFullPacket = pRcbListNext;
					pRcbListNext = pRcbListNext->pNext;
					count =0;
				}
				else /* Handle all Errored packets */
				{
/*
 * Sent here if the VLAN Id does not
 * match our VLAN ID.
 */

DROP_PACKET:

/* 
 *	Update statistics  
 */
#ifdef STATISTICS
					/* Update statistics */
					pAdapter->MacStats.rxDroppedCount++;

					if(pRcbListNext->pRxDp->CmdSts & CRCE)
						pAdapter->MacStats.rxCrcErrorCount++;
/*						
					pAdapter->MacStats.rxErrorCount++;
					if(pRcbListNext->pRxDp->CmdSts & FAE)
						pAdapter->MacStats.rxFaeCount++;
					
					if(pRcbListNext->pRxDp->CmdSts & RXE_LONG)
						pAdapter->MacStats.rxFramesTooLong++;
*/
#endif					
/* 
 *	Get the OS priority level on which the packet has to be sent  
 */
#ifdef NSCDEBUG				
					NsmDbgMsg1("RxError1 : Cmdsts = %x\n",pRcbListNext->pRxDp->CmdSts);
#endif
					Priority = GetOsPriority(pAdapter, PriIndex);

					if (LastFullPacket == NULL) { 
						/*No need of this FREE*/
						pRcbListNext->Status = RCB_FREE;
						pRcbListNext = pRcbListNext->pNext; 
						TempLastFullPacket = 
						pAdapter->PriQue[PriIndex].pRcbListNext;
					} 

/* 
 *	Call the NSM routine to send the packets received, up  
 */
					if (LastFullPacket != NULL) 
					{ 
#ifdef LINK_AGGR
						/* 
						 * Send packets to NSM or LACP as appropriate.
						 * If non-zero priority or LACP is not enabled on this 
						 * port, it's a MAC Client PDU.
						 * 
						 * Check for LACP flag first
						 */
						if (((pAdapter->nFlags & LACP_FLAG) == FALSE) || 
							(PriIndex > 0)) {
							NsmRxPackets(pAdapter, 
								pAdapter->PriQue[PriIndex].pRcbListNext,
								LastFullPacket->pNext, Priority);
						}
						else
						{
							pCurrent = pStart = pHead = pAdapter->PriQue[PriIndex].pRcbListNext;
							pTail = LastFullPacket->pNext;
							do
							{
								/* 
								 * Check if Slow protocol type 
								 */
								if(*((USHORT *)(pHead->pDataBuf + 12)) == SLOW_PROTOCOL_TYPE_BIG_ENDIAN)
								{
									/* 
									 * Using a fall through switch for
									 * certain cases.
									 */
									switch(*(pHead->pDataBuf + 14))
									{
										case 1:  /* LACPDU */
										
										case 2:  /* MARKER PDU */
											if (pStart != pHead) /* If any MAC client PDUs to be passed up */
												NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
											AggrRxPackets(pAdapter,pHead);
											pStart = pCurrent = pHead->pNext;
											break;
										
										case 0:
										
										case 11-255: /* Drop the Packet */
											if (pStart != pHead) /* If any MAC client PDUs to be passed up */
												NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
											pHead->Status = RCB_FREE;
											pStart = pCurrent = pHead->pNext;
											break;
										
										default:  /* Unsupported format. Pass it to Mac Client. */
											pCurrent = pHead;
											break;
									}
								}
								else /* MAC Client PDUs */
									pCurrent = pHead;
								
								pHead = pHead->pNext;
							} while(pHead != pTail);
							
							/* 
							 * Process MAC Client PDUs if any 
							 */
							if(pCurrent != pTail)
								NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
						}
#else
						NsmRxPackets(pAdapter, 
						pAdapter->PriQue[PriIndex].pRcbListNext,
						LastFullPacket->pNext, Priority);
#endif
						pRcbListNext = pRcbListNext->pNext; 

						if (LastFullPacket->pNext) {
							TempLastFullPacket = LastFullPacket->pNext;
						}

					} 
					do
					{        
						TempLastFullPacket->Status = RCB_FREE;
						TempLastFullPacket = TempLastFullPacket->pNext;
					} while( TempLastFullPacket != pRcbListNext) ;

/* 
 *	Set the new next pointer of the RCB list  
 */
					SET_RCB_NEXT(pAdapter, PriIndex, pRcbListNext);
					LastFullPacket = NULL;
					count++;
					DEC_FREE_RX_DESC(pAdapter,PriIndex,count);
					count = 0;
				}
			}

			else
			{
/* 
 *	Get to the next RCB in the list 
 */
				pRcbListNext = pRcbListNext->pNext;
				count++;
			}
                
/* 
 *	Decrement free Rx descriptors 
 */

		}

/* 
 *	Get the OS priority level on which the packet has to be sent 
 */
		Priority = GetOsPriority(pAdapter, PriIndex);

/* 
 *	Call the NSM routine to send the packets received, up 
 */
		if (LastFullPacket != NULL) 
		{ 
#ifdef LINK_AGGR
			/* 
			 * Send packets to NSM or LACP as appropriate.
			 * If non-zero priority or LACP is not enabled on this port,
			 * it's a MAC Client PDU.
			 * 
			 * Check for LACP flag first.
			 */
			if (((pAdapter->nFlags & LACP_FLAG) == FALSE) || 
				(PriIndex > 0)) {
#ifdef NSCDEBUG
				NsmDbgMsg("HsmRxPackets: Before calling NsmRxPackets\n");
#endif
				NsmRxPackets(pAdapter, pAdapter->PriQue[PriIndex].pRcbListNext,
					LastFullPacket->pNext, Priority);
#ifdef NSCDEBUG
				NsmDbgMsg("HsmRxPackets: After calling NsmRxPackets\n");
#endif
			}
			else
			{
				pCurrent = pStart = pHead = pAdapter->PriQue[PriIndex].pRcbListNext;
				pTail = LastFullPacket->pNext;
				do
				{
					/* Check if Slow protocol type */
					if(*((USHORT *)(pHead->pDataBuf + 12)) == SLOW_PROTOCOL_TYPE_BIG_ENDIAN)
					{
						/* 
						 * Using a fall through switch for
						 * certain cases.
						 */
						switch(*(pHead->pDataBuf + 14))
						{
							case 1:  /* LACPDU */
							
							case 2:  /* MARKER PDU */
								if (pStart != pHead) /* If any MAC client PDUs to be passed up*/
									NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
                                AggrRxPackets(pAdapter,pHead);
								pStart = pCurrent = pHead->pNext;
								break;
							
							case 0:
							
							case 11-255: /* Drop the Packet */
								if (pStart != pHead) /* If any MAC client PDUs to be passed up */
									NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
								pHead->Status = RCB_FREE;
								pStart = pCurrent = pHead->pNext;
								break;
							
							default:  /* Unsupported format. Pass it to Mac Client. */
								pCurrent = pHead;
								break;
						}
					}
					else /* MAC Client PDUs */
						pCurrent = pHead;
					
					pHead = pHead->pNext;
				} while(pHead != pTail);
				
				/* 
				 * Process MAC Client PDUs if any 
				 */
				if(pCurrent != pTail)
					NsmRxPackets(pAdapter->pAggregatorContext, pStart, pCurrent->pNext, Priority);
			}
#else
			NsmRxPackets(pAdapter, pAdapter->PriQue[PriIndex].pRcbListNext,
				LastFullPacket->pNext, Priority);
#endif
/* 
 *	Set the new next pointer of the RCB list 
 */
			SET_RCB_NEXT(pAdapter, PriIndex, LastFullPacket->pNext);
		} 
	}
}

USHORT FreeTxDesc(AdapterContext *pAdapter,UCHAR Prio)
{
	volatile DevDesc *Head = pAdapter->PriQue[Prio].pTcbListHead->pStartDesc; 
	volatile DevDesc *Next = pAdapter->PriQue[Prio].pTcbListNext->pStartDesc;
    USHORT   FreeCount;

    if(Head == Next) 
    {
		if(Head->CmdSts & OWN) 
            FreeCount = 0;  
        else
            FreeCount = pAdapter->PriQue[Prio].iMaxTxDesc - 1; 
    }
    else 
    {
        if(Head > Next) 
            FreeCount = (Head - Next - 1);
        else
            FreeCount = (pAdapter->PriQue[Prio].iMaxTxDesc - (Next-Head) - 1);
    }
    return FreeCount;
}



/*
 * Media Independent Interface routines (MII routines)
 */


#ifdef _GA621_
VOID
WriteMiiReg(AdapterContext *pAdapter, UINT phyReg, UINT phyData)
{
	UINT * pMear = ( UINT * )( ( UINT )pAdapter->RegAddr + MEAR );

	UINT miiData = MIIwrite | ( pAdapter->phyAddress << 23 ) | 
		( phyReg << 18 ) | phyData; 
	UINT i = 32;
	UINT mdio;

	NsmContext *pNsm = pAdapter->pNsmContext;
	WriteMiiPreamble( pAdapter, pMear );
	WriteMiiIdle( pAdapter, pMear );

	for ( i = 32; i != 0; i--, miiData <<= 1 ) 
	{
		mdio = ( miiData & 0x80000000l ) ? MDIO : 0;
		NsmRegWrite32( pNsm, pMear, MDDIR | mdio );
		NsmRegWrite32( pNsm, pMear, MDDIR | mdio | MDC );
	}

	WriteMiiIdle( pAdapter, pMear );
}

UINT
ReadMiiReg(AdapterContext *pAdapter, UINT phyReg)
{
	UINT * pMear = ( UINT * )( ( UINT )pAdapter->RegAddr + MEAR );
	UINT i;
	UINT data = MIIread | ( pAdapter->phyAddress << 23 ) | ( phyReg << 18 );
                        
	UINT mdio;

	VOID *pNsm = pAdapter->pNsmContext;

	WriteMiiPreamble(pAdapter, pMear );
	WriteMiiIdle(pAdapter, pMear );

	for ( i = 14; i != 0; i--, data <<= 1 ) 
	{
		mdio = ( data & 0x80000000l ) ? MDIO : 0;
		NsmRegWrite32( pNsm, pMear, MDDIR | mdio );
		NsmRegWrite32( pNsm, pMear, MDDIR | mdio | MDC );
	}

	NsmRegWrite32( pNsm, pMear, 0 );
	NsmRegWrite32( pNsm, pMear, MDC );
	NsmRegRead32( pNsm, pMear, &mdio );

	for ( data = 0, i = 16; i != 0; i-- ) 
	{
		NsmRegWrite32( pNsm, pMear, 0 );
		NsmRegWrite32( pNsm, pMear, MDC );
		NsmRegRead32( pNsm, pMear, &mdio );
		data <<= 1;
		if ( mdio & MDIO ) 
		{
			data |= 1;
		}
	}

	NsmRegWrite32( pNsm, pMear, 0 );
	NsmRegWrite32( pNsm, pMear, MDC );
	NsmRegRead32( pNsm, pMear, &mdio );

	return( data );
}

VOID
WriteMiiPreamble(AdapterContext *pAdapter,UINT * pMear)
{
	NsmContext *pNsm = (NsmContext *)pAdapter->pNsmContext;
	UINT i;

	for ( i = 0; i != 32; i++ ) 
	{
		NsmRegWrite32(pNsm, pMear, MDDIR | MDIO );
		NsmRegWrite32(pNsm, pMear, MDDIR | MDIO | MDC );
	}
}

VOID
WriteMiiIdle(AdapterContext *pAdapter, UINT * pMear)
{
	NsmContext *pNsm = (NsmContext *)pAdapter->pNsmContext;
	NsmRegWrite32(pNsm, pMear, MDDIR | MDIO );
	NsmRegWrite32(pNsm, pMear, MDDIR | MDIO | MDC );
}
#endif


/* Function HsmgetMulticastSize added on 17072000 -*/
UINT
HsmGetMulticastSize(
AdapterContext *pAdapter
)
{

	return (pAdapter->MultiCastTableSize);

}


/* Function HsmGetMulticastList added on 17072000 -*/
UINT
HsmGetMulticastList(
AdapterContext *pAdapter,
CHAR *Buffer,
UINT Size
)
{
        UINT i,j;
        mca_hash_t      *mca_entry;

		if (Size < pAdapter->MultiCastTableSize)
               return (FAILURE);

		
		if (pAdapter->MultiCastTableSize == 0)
               return (SUCCESS);


        for (i = 0; i < 128; i++)
        {
                for (j = 0; j < 16; j++)
                {
                        mca_entry = pAdapter->mca_tbl[i][j];
						
						while(mca_entry)
                        {
                                NsmCopy(mca_entry->MulticastAddr, Buffer, 
										MAC_ADDR_LEN);
                                Buffer += MAC_ADDR_LEN;
                                mca_entry = mca_entry->next;
                        }
                }
        }

        return (SUCCESS);

}



#ifdef PM_WOL
UCHAR 
HsmAddWakeupPattern(AdapterContext *pAdapter, UCHAR *PowerPattern, 
			UINT PatternLen, UINT MaskLen, UCHAR *MaskPtrn)
{
	UCHAR	PatternIdx; 
	UINT	wcsr_val;
	UINT	i;

/*
 *	If pAdapter->Pattern array is full then return FAILURE.
 *	Add the power pattern to the pAdapter->Pattern array if it doesn't exist.
 *	Return SUCCESS if it exists.
 */
	
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock); 

	if (pAdapter->PatternCnt == MAX_POWER_PTRN) 
	{
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

	if (IsPowerPatternExsts(pAdapter, PowerPattern,&PatternIdx,PatternLen) 
			== SUCCESS) 
	{ 
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return SUCCESS;
	} 

/* 
 *  Copying the pattern sent, in to the private data structure  
 */

	NsmCopy(PowerPattern, &pAdapter->PowerPattern[PatternIdx][0], PatternLen);
	
/* 
 *  Copying the mask sent, in to the private data structure  
 */
	NsmCopy(MaskPtrn, &pAdapter->MaskArray[PatternIdx][0], MaskLen);

/* 
 *  Masking the first 14 bits in the mask that was sent   
 */


	for(i=0; i< MaskLen; i++)
	{
		pAdapter->MaskArray[PatternIdx][i] = 
			~pAdapter->MaskArray[PatternIdx][i];
	}

	pAdapter->PatLen[PatternIdx] = PatternLen;
	
	pAdapter->PatternCnt++;
	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

/*
 * Adding the pattern in to the pattern buffer only if, it is the second 
 * pattern, so that we can write into the pattern buffer in pairs, this 
 * would mean that we write pattern 0 & pattern 1 together and so are 
 * pattern 2 & pattern 3 
 */
	
 	if(PatternIdx & 0x01)
		AddPattern(pAdapter, PatternIdx, PowerPattern, PatternLen, MaskLen, 
				MaskPtrn);

	pAdapter->WakePatCount |= PATTERN[PatternIdx][WKPAT_MASK];
	
	return SUCCESS;

}	/*	end of HsmAddWakeupPattern()	*/



/******************************************************************************
*f*
*   Name:       	
*			AddPattern
*
*   Description:    	
*			Add the pattern to the pattern buffer memory.
*
*   Parameters:     
*			pAdapter	- Pointer to the adapter context.
*		
*			PowerPattern- Pattern to be added .
*
*			PatternLen	- Length of the pattern.
*
*			MatchLen	- Match Length.
*
*			MaskPtrn	- Mask pattern array. 
*
*
*   Return Value:   
*			NONE. 
*
*f*
******************************************************************************/
USHORT
AddPattern(AdapterContext *pAdapter, UCHAR PatternIdx, UCHAR *PowerPattern,
			UINT PatternLen, UINT MatchLen, UCHAR *MaskPtrn)
{
	UCHAR	MaskIdx;
	UINT	Rfcr_val, Rfcr_orig ;
	UINT	WordOffset, Pattern=0;
	USHORT	*pPattern, WordIdx=0;
	UCHAR	bitno, byteno;
	UINT	MIdx, i;
	UINT	PatMatchLen;
	UINT	rfdr_val;
	UINT	j,k;
/*
 *	Write the Pattern offset into RFCR. 
 */ 
	NsmRegRead32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		&Rfcr_val);
	NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR,
		(Rfcr_val & ~RFEN));

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_val);
	Rfcr_orig = Rfcr_val;
	Rfcr_val |= PATTERN[PatternIdx][ARR_OFFSET];
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), Rfcr_val);

/*
 *	Write the Match length into RFDR.
 */

	if (MatchLen == 0) 
		MatchLen = PatternLen;

/* 
 * For the pattern counts 1 and 3 the value to be written to the RFDR 
 * should be the 8 most significant bits 
 */
		
	PatMatchLen = (pAdapter->PatLen[PatternIdx] << 8);
	PatMatchLen |= pAdapter->PatLen[PatternIdx-1];
	
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFDR), 
			PatMatchLen);

/*
 *	Write the pattern into the pattern buffer memory. 
 */

	for(j=PatternIdx-1, k=0; k<2; j++, k++)
	{
	
		MaskIdx = 0;
		
		pPattern = (USHORT *)(&pAdapter->PowerPattern[j][0]);	

		MaskPtrn = &pAdapter->MaskArray[j][0]; 

		PatternLen = pAdapter->PatLen[j];

		for( WordIdx = 0; ((WordIdx < (MAX_PTRN_SZ / 2)) && 
			(pPattern != NULL) && (MaskIdx < PatternLen)); 
				pPattern++, WordIdx++) 
		{ 

			WordOffset = (WordIdx * 2) + 0x200 + (j * PAT_OFFSET);

			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
				WordOffset);

/*
 * Masking the bytes in the pattern, based on the corresponding bits in the 
 * Mask. The bits in the mask will be representing the bytes in the pattern. 
 * For eg: byte 0 in the pattern will be represented by the bit 0 in the mask.
 * The most significant bit in the first byte of the mask will be the bit 
 * number 7, which will represent the byte number 7 in the pattern. Similarly 
 * the most significant bit in the byte number 1 of the mask will indicate the
 * byte number 15 of the pattern
 */

			for(MIdx = MaskIdx, i=0; i<2; i++, MIdx++)
			{

				bitno = MIdx % 8;
				byteno = MIdx / 8;

				if(MaskPtrn[byteno] & (0x01 << bitno))
				{
					if(bitno & 0x01)
						Pattern |= 0x20000;
					else
						Pattern |= 0x10000;
				}
			}
	
			Pattern |= *pPattern;
		
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFDR), 
				Pattern);
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFDR), 
				&Pattern);
	
			Pattern = 0;
		
			MaskIdx += 2;
		} 	/*	end of for()	*/
	}
	
	Rfcr_orig |= RFEN;

	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
				Rfcr_orig);

	Rfcr_orig |= APAT_ALL;

	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), Rfcr_orig);
	
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_orig);

	return SUCCESS;

}	/* end of AddPattern()	*/


/******************************************************************************
*f*
*   Name:       	
*			HsmEnableWakeupPattern
*
*   Description:    	
*			Enable the wake up pattern passed by the adapter. 
*
*   Parameters:     
*			pAdapter	- Pointer to the adapter context.
*		
*			PowerPattern- Pattern to be added .
*
*   Return Value:   
*			SUCCESS	- If the pattern is added successfully.
*			FAILURE - If the Pattern array is full.
*
*f*
******************************************************************************/
UCHAR 
HsmEnableWakeupPattern(AdapterContext *pAdapter, UCHAR *PowerPattern, 
			UINT PatternLen)
{
	UCHAR	PatternIdx; 
	UINT	Wcsr_val;

/*
 *	Enable the power pattern passed in WCSR.
 */
	
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock); 

	if (IsPowerPatternExsts(pAdapter, PowerPattern,&PatternIdx,PatternLen) 
			== FAILURE) 
	{ 
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);


	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), &Wcsr_val);
	
	Wcsr_val |= PATTERN[PatternIdx][WKPAT_MASK];

	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), Wcsr_val);

	return SUCCESS;
}

UCHAR 
HsmEnableWakeup(AdapterContext *pAdapter, UINT WakeType)
{

/*
 *	Enable the power pattern passed in WCSR.
 */
	UINT	Wcsr_val;

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), &Wcsr_val);

	if(WakeType == WKPAT)
		Wcsr_val = pAdapter->WakePatCount;
	else
		Wcsr_val = WakeType;
	
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), Wcsr_val);

	return SUCCESS;
}

UCHAR 
HsmDisableWakeup(AdapterContext *pAdapter, UINT WakeType)
{

/*
 *	Disable the power pattern passed in WCSR.
 */
	UINT Wcsr_val;

	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), &Wcsr_val);

	if(WakeType == WKPAT)
		Wcsr_val &= ~(pAdapter->WakePatCount);
	else
		Wcsr_val &= ~WakeType;

	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), Wcsr_val);

	return SUCCESS;
}


/******************************************************************************
*f*
*   Name:       	
*			HsmDisableWakeupPattern
*
*   Description:    	
*			Disable the wake up pattern passed by the adapter. 
*
*   Parameters:     
*			pAdapter	- Pointer to the adapter context.
*		
*			PowerPattern- Pattern to be disabled .
*
*   Return Value:   
*			SUCCESS	- If the pattern is added successfully.
*			FAILURE - If the Pattern array is full.
*
*f*
******************************************************************************/
UCHAR 
HsmDisableWakeupPattern(AdapterContext *pAdapter, UCHAR *PowerPattern,
			UINT PatternLen)
{
	UCHAR	PatternIdx; 
	UINT	Wcsr_val;
/*
 *	Enable the power pattern passed in WCSR.
 */
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

	if (IsPowerPatternExsts(pAdapter, PowerPattern, &PatternIdx,PatternLen) 
			== FAILURE) 
	{
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

	NsmRegRead32(pAdapter->pNsmContext,(pAdapter->RegAddr + WCSR), &Wcsr_val);
	
	Wcsr_val &= ~(PATTERN[PatternIdx][WKPAT_MASK]);

	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + WCSR), Wcsr_val);

	return SUCCESS;
}

/******************************************************************************
*f*
*   Name:       	
*			HsmRemoveWakeupPattern
*
*   Description:    	
*			Remove the wake up pattern passed to the adapter.   
*
*   Parameters:     
*			pAdapter	- Pointer to the adapter context.
*		
*			PowerPattern- Pattern to be disabled .
*
*   Return Value:   
*			SUCCESS	- If the pattern is added successfully.
*			FAILURE - If the Pattern array is full.
*f*
******************************************************************************/
UCHAR 
HsmRemoveWakeupPattern(AdapterContext *pAdapter, UCHAR *PowerPattern,
			UINT	PatternLen, UCHAR *MaskPtrn)
			
{
	UCHAR	PatternIdx; 
	UINT	Wcsr_val;
	UINT	i;
/*
 *	If pAdapter->Pattern array is full then return FAILURE.
 *	Add the power pattern to the pAdapter->Pattern array if it doesn't exist.
 *	Return SUCCESS if it exists.
 */
	NsmAcquireLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

/*
 * If no patterns, then return
 */
	
 	if (pAdapter->PatternCnt == 0) 
	{ 
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

/*
 * If pattern already exists, then return
 */
	
	if (IsPowerPatternExsts(pAdapter, PowerPattern,&PatternIdx,PatternLen) 
			== FAILURE) 
	{ 
		NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);
		return FAILURE;
	} 

	for(i=0; i<MAX_PAT_LEN; i++)
		pAdapter->PowerPattern[PatternIdx][i] = 0;

	pAdapter->PatternCnt--;
	NsmReleaseLock(pAdapter->pNsmContext, pAdapter->AdapterLock);

/*
 *	Disable the appropriate WKPAT bit in WCSR register.
 */
	NsmRegRead32(pAdapter->pNsmContext,(pAdapter->RegAddr + WCSR), &Wcsr_val);
	
	Wcsr_val &= ~(PATTERN[PatternIdx][WKPAT_MASK]);

	NsmRegWrite32(pAdapter->pNsmContext,(pAdapter->RegAddr + WCSR), Wcsr_val);

	pAdapter->WakePatCount &= ~(PATTERN[PatternIdx][WKPAT_MASK]);

	return SUCCESS;

} /*	end of HsmRemoveWakeupPattern()	*/


UINT HsmGetWakeStatus(AdapterContext *pAdapter)
{

	UINT Wcsr_val;
	
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), &Wcsr_val);
	
	return Wcsr_val;
}

VOID HsmChangeState(AdapterContext *pAdapter, UINT PmcsrVal)
{
	UINT	i = 0, Tx = 0;
	UINT	Rfcr_val;
	UINT 	cr_val;
	UINT 	cr_val_orig = 0;
	UINT	isr_val;
	UINT	imr_val;
	UINT	wcsr_val;
	UINT	rfcr_val;
	UINT	rfcr_val_orig;
	UINT	priIdx;



	if(pAdapter->CurrPowerStatus & WAKE_STATE) 
	{
		if(PmcsrVal & (POWER_STATE_D3C | POWER_STATE_D3H | POWER_STATE_D2 | POWER_STATE_D1) )
		{
/* 
 * Going to sleep state from the wake state
 */

			pAdapter->AdapterStatus &= ~ADAPTER_OPEN;

			pAdapter->AdapterStatus |= ADAPTER_SLEEPING;
		
			HsmDisableInterrupts(pAdapter);
			
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
					&rfcr_val_orig);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					&cr_val);
			
			cr_val_orig = cr_val;

			cr_val |= (RXR);

			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					cr_val);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + ISR), 
					&isr_val);
			
			while(!(isr_val & RXRCMP))
			{
				NsmSleep(pAdapter->pNsmContext, 10);
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + ISR), 
						&isr_val);				
			}

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					&cr_val);
			
			cr_val |= (RXE);
			cr_val &= ~(RXD|RST);
			
			for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++)
			{
				cr_val |= (pAdapter->RxDp[priIdx][3]); 
				NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + pAdapter->RxDp[priIdx][0]), 0);
			}

			
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					cr_val);
        
			NsmSleep(pAdapter->pNsmContext, 50);    

			/* HsmDumpPattern(pAdapter); */
		}
	}
	else if(pAdapter->CurrPowerStatus &  (POWER_STATE_D3C | POWER_STATE_D3H | POWER_STATE_D2 | POWER_STATE_D1))
	{

		if(PmcsrVal & WAKE_STATE)
		{
/*
 * Going to the wake state from the sleep state
 */

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + ISR), 
					&isr_val);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + WCSR), 
					&wcsr_val);

			/*Reinitialize the adapter after coming out of power down state*/
			
			if(!(wcsr_val & WAKE_ON_LAN_MODES))
			{
				/* Fix for standby, after calling HsmOpen
				 * the filter is cleared, so we have to reinitialize it.
				 */
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_val);

				HsmOpen(pAdapter);
				
				/*RFCR write fix*/
				NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, 0);
				NsmRegWrite32(pAdapter->pNsmContext, pAdapter->RegAddr + RFCR, Rfcr_val);
				
				/* The link is not always up
				 * when the AUTO NEG is complete, Reset test fails sometimes
				 */
				i = 0;
				do
				{
					NsmSleep(pAdapter, 100);
					Tx = ReadMiiReg(pAdapter, BMSR);
					if ( Tx & AUTONEG_COMPLETE ) 
					{
						/* Wait for it to get ready
						 * before sending reset complete and 
						 * getting ready to accept packets and 
						 * see if the AUTONEG is actually complete
						 * or a second one is coming
						 */
						NsmSleep(pAdapter, 300);
						Tx = ReadMiiReg(pAdapter, BMSR);
						
						if ( Tx & AUTONEG_COMPLETE )
						{
							pAdapter->AdapterStatus |= LINK_UP;
						}
					}
				} while( (!(Tx & AUTONEG_COMPLETE)) && (++i < 70) );
			
				pAdapter->AdapterStatus &= ~ADAPTER_SLEEPING;
				pAdapter->AdapterStatus |= ADAPTER_OPEN;
				HsmEnableInterrupts(pAdapter);
				return; 
			}
	
			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					&cr_val);

			cr_val_orig = cr_val;

			cr_val |= (RXR);

			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					cr_val);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + ISR), 
					&isr_val);
			
			while(!(isr_val & RXRCMP))
			{
				NsmSleep(pAdapter->pNsmContext, 10);
				NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + ISR), 
						&isr_val);				
			}
			

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					&cr_val);

			cr_val |= (RXE);
			cr_val &= ~(RXD|RST);
			
			for (priIdx = 0; priIdx < pAdapter->NumPrio; priIdx++)
			{
				cr_val |= (pAdapter->RxDp[priIdx][3]); 
				NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + pAdapter->RxDp[priIdx][0]), pAdapter->PriQue[priIdx].pRcbListNext->pRxDpPa);
			}
			
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + CR), 
					cr_val);

			/* The link is not always up
			 * when the AUTO NEG is complete, Reset test fails sometimes
			 */
			i = 0;
			do
			{
				NsmSleep(pAdapter, 100);
				Tx = ReadMiiReg(pAdapter, BMSR);
				if ( Tx & AUTONEG_COMPLETE ) 
				{
					/* Wait for it to get ready
					 * before sending reset complete and 
					 * getting ready to accept packets and 
					 * see if the AUTONEG is actually complete
					 * or a second one is coming
					 */
					NsmSleep(pAdapter, 300);
					Tx = ReadMiiReg(pAdapter, BMSR);
					
					if ( Tx & AUTONEG_COMPLETE )
					{
						pAdapter->AdapterStatus |= LINK_UP;
					}
				}
			} while( (!(Tx & AUTONEG_COMPLETE)) && (++i < 70) );
			
			pAdapter->AdapterStatus |= ADAPTER_OPEN;

			pAdapter->AdapterStatus &= ~ADAPTER_SLEEPING;
		
			HsmEnableInterrupts(pAdapter);

			/*HsmDumpPattern(pAdapter);*/
		}
		
	}
	pAdapter->CurrPowerStatus = PmcsrVal;
}


UINT HsmGetLowestPowerState(AdapterContext *pAdapter)
{
	/* More to be done here, Revisit */
	/*return POWER_STATE_D3;*/
 	
	if(pAdapter->pmcsr_val & PM_D3C)
		return POWER_STATE_D3C;
	else if(pAdapter->pmcsr_val & PM_D3H)
		return POWER_STATE_D3H;
	else if(pAdapter->pmcsr_val & PM_D2)
		return POWER_STATE_D2;
	else if(pAdapter->pmcsr_val & PM_D1)
		return POWER_STATE_D1;
	else if(pAdapter->pmcsr_val & PM_D0)
		return POWER_STATE_D0;
	else
	{
		return POWER_STATE_D3H;
	}	
}

UINT HsmPowerStateSupport(AdapterContext *pAdapter, UINT PowerState)
{

	UINT status = 1;

	switch (PowerState)
	{
		case POWER_STATE_D3C :
			if(pAdapter->pmcsr_val & PM_D3C)
				status = 1;
			break;
		case POWER_STATE_D3H :
			if(pAdapter->pmcsr_val & PM_D3H)
				status = 0;
			break;
		case POWER_STATE_D2 :
			if(pAdapter->pmcsr_val & PM_D2)
				status = 0;
			break;
		case POWER_STATE_D1 :
			if(pAdapter->pmcsr_val & PM_D1)
				status = 0;
			break;
		case POWER_STATE_D0 :
			if(pAdapter->pmcsr_val & PM_D0)
				status = 0;
			break;
		default :
			break;
	}
	return status;
}

VOID HsmDumpPattern(AdapterContext *pAdapter)
{
	UCHAR	MaskIdx;
	UINT	Rfcr_val, Rfcr_orig ;
	UINT	WordOffset, Pattern=0;
	USHORT	*pPattern, WordIdx=0;
	UCHAR	bitno, byteno;
	UINT	MIdx, i ;
	UINT	PatMatchLen;
	UINT	rfdr_val;
	UINT	j,k;
	
	NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), &Rfcr_val);
	Rfcr_orig = Rfcr_val;

	for(i=0; i<pAdapter->PatternCnt ; i++)
	{
		Rfcr_val |= PATTERN[i][ARR_OFFSET];
		NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
				Rfcr_val);

		NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFDR), 
			&rfdr_val);

		MaskIdx = 0;

		for( WordIdx = 0; ((WordIdx < (MAX_PTRN_SZ / 2)) && 
			(MaskIdx < pAdapter->PatLen[i])); WordIdx++) 
		{ 

			WordOffset = (WordIdx * 2) + 0x200 + (i * PAT_OFFSET);
			NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
				WordOffset);

			NsmRegRead32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFDR), 
				&Pattern);
	
			MaskIdx += 2;
		} 	/*	end of for()	*/
	
		Rfcr_val = Rfcr_orig;
	}
	NsmRegWrite32(pAdapter->pNsmContext, (pAdapter->RegAddr + RFCR), 
		Rfcr_orig);
}

#endif

#ifdef FWARE_DOWNLOAD

void HsmDownLoadFirmwareInit(AdapterContext *pAdapter)
{
	UINT	RegVal = 0;
	USHORT	frData;
	UINT	i;


	/* Place the EnGigPHYTER in power down mode */
	
	RegVal = ReadMiiReg(pAdapter, BMCR);
	RegVal |= 0x0800;
	WriteMiiReg(pAdapter, BMCR, RegVal);

	/*
	 Perform a series of register writes to the internal RAM Space using the 
	 MDIO register interface to download the firmware code.
	*/

	/*
	Enable mode 2, 16-bit expanded access mode */
	

	WriteMiiReg(pAdapter, F_EAM, 0x0006);

	/*
	Write the starting address where the RAM-based firmware will be downloaded
	*/

    WriteMiiReg(pAdapter, F_AR, F_START_ADDRESS);
	/* frData = ReadMiiReg(pAdapter, F_DR); */

	return;
}

/* Auto increment write */
void HsmDownLoadFirmwareWORD(AdapterContext *pAdapter, USHORT  frData)
{

	/*
	Write a single word to the EEPROM
	Assumes that DownLoadFirmWareInit is called before the first WORD
	write. 
	Call 'DownLoadFirmWareWord' multiple times to populate the EEPROM
	*/

	WriteMiiReg(pAdapter, F_DR, frData);

	return;
}

UINT HsmStartFirmWareCode(AdapterContext *pAdapter)	
{
	/*UINT	frData;
	int i;*/
	UINT	RegVal = 0;

	/*
	Enable mode 2, 16-bit expanded access mode
	*/

	/* WriteMiiReg(pAdapter, F_EAM, 0x0006); */

	/*
	Write the jump address to start executing firmware code
	
	Note that we are writing JUMP address as "F_START_ADDRESS+0x2",
	After downloading firmware we found that "F_START_ADDRESS + 0" and "F_START_ADDRESS + 2" address
	in 16 bit mode always contains same data. Hence we ask PHY to start running 
	the code from "F_START_ADDRESS+0x2" address
	*/
	
	/*WriteMiiReg(pAdapter, F_JAR, F_START_ADDRESS+0x2);*/
	WriteMiiReg(pAdapter, F_JAR, F_START_ADDRESS);

  
	/*
	Wait for 1.024 milli-seconds
	*/
	NsmSleep(pAdapter, 1);

	/* This read is needed to clear interrupt problem */
	ReadMiiReg(pAdapter, BMCR); 

	/*
	Power ON EnGigPHYTER
	*/
	RegVal = ReadMiiReg(pAdapter, BMCR);
	RegVal &= ~(0x0800);
	WriteMiiReg(pAdapter, BMCR, RegVal);
	NsmSleep(pAdapter, 100);

	
	return 1; 
}

 
UCHAR HsmVerifyDownLoad(AdapterContext *pAdapter)
{
        UINT RegByte = 0;
		UINT RegVal = 0;
		
		/*Re Enable 16 bit mode according to  Vu*/
		/*WriteMiiReg(pAdapter, 0x16, 0x000D);*/
		WriteMiiReg(pAdapter, F_EAM, 0x0006);
		WriteMiiReg(pAdapter, F_AR, F_VERIFY_ADDRESS);
		RegVal = ReadMiiReg(pAdapter, F_DR);

		RegByte = (RegVal & 0xF000);

		if(RegByte < 0xC000)
		{
#ifdef NSCDEBUG					
			NsmDbgMsg2("\nCode executing from RAM = %x %x\n", RegVal, RegByte);
#endif
			return SUCCESS;
		}
		else
		{
#ifdef NSCDEBUG					
			NsmDbgMsg2("\nCode executing from ROM = %x %x\n", RegVal, RegByte);
#endif
			return FAILURE;
		}
		
		NsmSleep(pAdapter, 100);

}

#endif /* FWARE_DOWNLOAD */

#ifdef TXCHECKSUM
#if UDPCHECKSUM_HOTFIX || TCPCHECKSUM_HOTFIX

/* 
 * Name:					Hsmchksum
 *
 * Description:
 * 			Algoritm for calcualting tcp checksum :
 * 			TCP Checksum calculated by taking the 16-bit one's 
 * 			complement sum of the one's complement sum of the 
 * 			16-bit words in the header (including pseudo-header) 
 * 								and text  together.
 *
 * Parameters: 	pAdapter - Pointer to the AdapterContext structure
 *
 * 				pEtherPkt - Pointer to the UCHAR , in 
 * 						 	parameter the packet will be passed by caller.
 *
 * 				CheckSum  - Pointer to USHORT. The final checksum 
 * 							will be return to the caller in this variable.
 *
 * 				Protocol -  Indicates it is TCP or UDP. This is passed 
 *							by caller.
 * 						 							
 * 						 						
 *
 * Return Value:  None.
 *
 */


VOID
Hsmchksum(AdapterContext *pAdapter, UCHAR   *pEtherPkt, USHORT *CheckSum,INT Protocol)
{
	USHORT	*sptr,len;
	ULONG lchksum;
	UINT	i;
	USHORT  ipHeaderLen=0;
	USHORT *iplen;

	iplen =  (USHORT *)(pEtherPkt + IP_LENGTH_OFFSET);

	*iplen = SWAP_BYTE(*iplen);


	ipHeaderLen = IP_HLEN(pEtherPkt[IP_HEADERLEN_OFFSET]);

	lchksum = 0; 
	if (Protocol & TCPPKT)
	{
			/* Making tcp checksum values 0*/
			pEtherPkt[ETHER_HEADER_LENGTH+ipHeaderLen+TCP_CHECKSUM_OFFSET]=0x00;
			pEtherPkt[ETHER_HEADER_LENGTH+ipHeaderLen+TCP_CHECKSUM_OFFSET+1]=0x00;
	} else if  (Protocol & UDPPKT)
	{
			/* Making udp checksum values 0*/
			pEtherPkt[ETHER_HEADER_LENGTH+ipHeaderLen+UDP_CHECKSUM_OFFSET]=0x00;
			pEtherPkt[ETHER_HEADER_LENGTH+ipHeaderLen+UDP_CHECKSUM_OFFSET+1]=0x00;
	}
	/* 
	 * Starting  pseudo checksum calculation.
	 * Pseudo checksum calculation fields (12 Bytes):
	 * From IP Header take the following fields :
	 * 4 Bytes of SRC address
	 * 4 Bytes of Destinarion address
	 * 2 Bytes of Packet Length ( The value to be taken in the packet 
	 *                             length is : Packet_Length - IP Header 
	 *                             ilength)
	 * 1 Byte of Padding with value 0.
	 * 1 Byte of Protocol Type.
	 */

	/*  IP src and IP destination address [8bytes]
	 * Summing up src address and destination address 
	 * they are in net order.		
	 */
	sptr = (USHORT *)(pEtherPkt + IP_SRCADDR);
	for (i=0; i<IP_ALEN; ++i)
		lchksum += *sptr++;

	/* 
	 * Calculating pseudo checksum.
	 * protcol [1 byte] , (packetlength - ipheader length) [2 bytes] 
	 * 1 byte padding with the value 0.The padding will be added to the 
	 * MSB 8 bits of protocol.
	 */

	len  = *iplen - ipHeaderLen;
	if (Protocol & TCPPKT)
			lchksum += SWAP_BYTE(IP_PROTOCOL_TCP+len); 
	else if (Protocol & UDPPKT)
			lchksum += SWAP_BYTE(IP_PROTOCOL_UDP+len); 

	/* End of pseuo checksum calculation */

	if (len % 2) {
		pEtherPkt[ETHER_HEADER_LENGTH+*iplen]=0x00;	
		len += 1;	/* for the following division */
	}

	len >>= 1;	/* convert to length in shorts */
	
	/* Calculate the 16-bit sum, starting from TCP header to data */

	sptr = (USHORT *) (pEtherPkt+ ipHeaderLen+ETHER_HEADER_LENGTH);

	for (i=0; i<len; ++i)
		lchksum += *sptr++;

	lchksum = (lchksum >> 16) + (lchksum & 0xffff);
	lchksum += (lchksum >> 16);

	*CheckSum =  (SHORT )(~lchksum & 0xffff);
#ifdef CHECKSUM_DEBUG

	NsmDbgMsg1("\n Checksum = %x",*CheckSum);

#endif
}
#endif
#endif



#ifdef ALLOC_PKTSTRUCT

/*
 * We statically allocate the PktStruct for a deserial
 * driver to avoid the stack overflow.
 */

/***************************************************************************
 *
 * Function Name	:
 * 			StackInit()
 *
 * Description	:
 * 			Initialization of the packet Struct Node
 * 			Also initializes the stack to hold the packets.
 *
 * 			NO_OF_NODES needs to be defined in the Nsm.
 *	
 * Return Value :
 * 			FAILURE	-	Allocation has failed.
 * 			SUCCESS -	Allocation Successful.
 * 		
 ***************************************************************************/
UCHAR
StackInit(AdapterContext *pAdapter)
{
		
	PktStruct **stk;
	PktStruct *p1;
	UINT i;		

	/*
	 * Make the count in the stack indicate an empty stack
	 */ 
	SET_STACK_TOP(pAdapter, -1);
	
	/*
	 * Allocate the stack array to hold the pointer to the PktStruct's
	 */ 
	stk = NsmMalloc((NO_OF_NODES) * sizeof(PktStruct **));
	if(stk == NULL)
		return(FAILURE);

#ifdef NSCDEBUG
	NsmDbgMsg1("STACK_INIT: Stack_ptr=0x%x \n",stk);
#endif
	
	/*	
	 * Store the pointer to the top of the stack
	 */
	SET_STACK_PTR(pAdapter, stk);
	


	/*
	 * Packet Structures.
	 */
	for (i = 0; i < NO_OF_NODES; i++) 
	{
		/*
		 * Allocate the PktStruct
		 */ 
		p1 = (PktStruct *)NsmMalloc((sizeof(PktStruct)));
		if(p1 != NULL)
		{	
			/*
			 * Push it onto the stack
			 */ 
			HSMPUSH_PKTSTRUCT(pAdapter, p1);

#ifdef NSCDEBUG
			NsmDbgMsg1("PACKETINIT: Push_packet ADDR=0x%x \n", p1);
#endif

		}
		else
		{

#ifdef NSCDEBUG
			NsmDbgMsg1("PACKETINIT:In the Addr_failure=0x%x \n", p1);
#endif
		
			/*
			 *  Check we have allocated PktStruct's above the 
			 *  Minimum Threshold, then we continue, else
			 *  we free up all the resources allocated and return.
			 *
			 *  GET_STACK_TOP is a zero based index, so we add 1.
			 */
			if((GET_STACK_TOP(pAdapter) + 1) < MINIMUM_NO_OF_NODES)
			{
				/*
				 * Free the Allocated PktStruct's
				 */
				StackFree(pAdapter);
					
				return(FAILURE);
			}
			else
				return (SUCCESS);
		}
		
	}

	return(SUCCESS);
}



/***************************************************************************
 *
 * Function Name	:
 * 			StackFree()
 *
 * Description	:
 *			De-allocartes all the packets allocated using PacketInit.
 *			Also free's up the stack space allocated.
 *	
 * Return Value :
 * 			None.
 * 		
 ***************************************************************************/
VOID
StackFree(AdapterContext *pAdapter)
{
	PktStruct **stk;
	PktStruct *item;

	/*
	 * Free all PktStruct's after removing them from the stack
	 */
	HSMPOP_PKTSTRUCT(pAdapter, item);
	while(item != NULL)
	{
		NsmFree(item, (sizeof(PktStruct)));
		HSMPOP_PKTSTRUCT(pAdapter, item);
	}
	
	stk = GET_STACK_PTR(pAdapter);
	NsmFree(stk, (NO_OF_NODES * sizeof(PktStruct **)));

	return;
}

#endif /* ALLOC_PKTSTRUCT */

