/******************************************************************************
 *
 * Name:	sky2le.h
 * Project:	Gigabit Ethernet Adapters, Common Modules
 * Version:	$Revision: 1.7 $
 * Date:	$Date: 2004/03/04 14:20:51 $
 * Purpose:	Common list element definitions and access macros.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *	(C)Copyright 2003 Marvell.
 *	All Rights Reserved
 *
 *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL
 *	The copyright notice above does not evidence any
 *	actual or intended publication of such source code.
 *
 *	This Module contains Proprietary Information of Marvell
 *	and should be treated as Confidential.
 *
 *	The information in this file is provided for the exclusive use of
 *	the licensees of Marvell.
 *	Such users have the right to use, modify, and incorporate this code
 *	into products for purposes authorized by the license agreement
 *	provided they include this notice and the associated copyright notice
 *	with any such product.
 *	The information in this file is provided "AS IS" without warranty.
 *
 ******************************************************************************/

#ifndef __INC_SKY2LE_H
#define __INC_SKY2LE_H

#ifdef __cplusplus
extern "C" {
#endif	/* __cplusplus */


/* defines ********************************************************************/

#define MIN_LEN_OF_LE_TAB	128
#define MAX_LEN_OF_LE_TAB	4096
#ifdef USE_POLLING_UNIT
#define NUM_LE_POLLING_UNIT	2
#endif
#define MAX_FRAG_OVERHEAD       10

/* Macro for aligning a given value */
#define SK_ALIGN_SIZE(Value, Alignment, AlignedVal)	{						\
	(AlignedVal) = (((Value) + (Alignment) - 1) & (~((Alignment) - 1)));	\
}

/******************************************************************************
 *
 * LE2DWord() - Converts the given Little Endian value to machine order value
 *
 * Description:
 *	This function converts the Little Endian value received as an argument to
 *  the machine order value.
 *
 * Returns:
 *	The converted value
 *
 */

#ifdef SK_LITTLE_ENDIAN

#define LE2DWord(value)	(value)

#else	/* !SK_LITTLE_ENDIAN */

#define LE2DWord(value)				\
	((((value)<<24L)&0xff000000L) +	\
	(((value)<< 8L)&0x00ff0000L) +	\
	(((value)>> 8L)&0x0000ff00L) +	\
	(((value)>>24L)&0x000000ffL))

#endif	/* !SK_LITTLE_ENDIAN */

/******************************************************************************
 *
 * DWord2LE() - Converts the given value to a Little Endian value
 *
 * Description:
 *	This function converts the value received as an argument to a Little Endian
 *  value on Big Endian machines. If the machine running the code is Little
 *  Endian, then no conversion is done.
 *
 * Returns:
 *	The converted value
 *
 */

#ifdef SK_LITTLE_ENDIAN

#define DWord2LE(value) (value)

#else	/* !SK_LITTLE_ENDIAN */

#define DWord2LE(value) 			\
	((((value)<<24L)&0xff000000L) +	\
	(((value)<< 8L)&0x00ff0000L) +	\
	(((value)>> 8L)&0x0000ff00L) +	\
	(((value)>>24L)&0x000000ffL))

#endif	/* !SK_LITTLE_ENDIAN */

/******************************************************************************
 *
 * LE2Word() - Converts the given Little Endian value to machine order value
 *
 * Description:
 *	This function converts the Little Endian value received as an argument to
 *  the machine order value.
 *
 * Returns:
 *	The converted value
 *
 */

#ifdef SK_LITTLE_ENDIAN

#define LE2Word(value) (value)

#else	/* !SK_LITTLE_ENDIAN */

#define LE2Word(value)			\
	((((value)<< 8L)&0xff00) +	\
	(((value)>> 8L)&0x00ff))

#endif	/* !SK_LITTLE_ENDIAN */

/******************************************************************************
 *
 * Word2LE() - Converts the given value to a Little Endian value
 *
 * Description:
 *	This function converts the value received as an argument to a Little Endian
 *  value on Big Endian machines. If the machine running the code is Little
 *  Endian, then no conversion is done.
 *
 * Returns:
 *	The converted value
 *
 */

#ifdef SK_LITTLE_ENDIAN

#define Word2LE(value) (value)

#else	/* !SK_LITTLE_ENDIAN */

#define Word2LE(value) 			\
	((((value)<< 8L)&0xff00) +	\
	(((value)>> 8L)&0x00ff))

#endif	/* !SK_LITTLE_ENDIAN */

/******************************************************************************
 *
 * Transmit list element macros
 *
 */

#define TXLE_SET_ADDR(pLE, Addr)	\
	((pLE)->Tx.TxUn.BufAddr = DWord2LE(Addr))
#define TXLE_SET_LSLEN(pLE, Len)	\
	((pLE)->Tx.TxUn.LargeSend.Length = Word2LE(Len))
#define TXLE_SET_STACS(pLE, Start)	\
	((pLE)->Tx.TxUn.ChkSum.TxTcpSp = Word2LE(Start))
#define TXLE_SET_WRICS(pLE, Write)	\
	((pLE)->Tx.TxUn.ChkSum.TxTcpWp = Word2LE(Write))
#define TXLE_SET_INICS(pLE, Ini)	((pLE)->Tx.Send.InitCsum = Word2LE(Ini))
#define TXLE_SET_LEN(pLE, Len)		((pLE)->Tx.Send.BufLen = Word2LE(Len))
#define TXLE_SET_VLAN(pLE, Vlan)	((pLE)->Tx.Send.VlanTag = Word2LE(Vlan))
#define TXLE_SET_LCKCS(pLE, Lock)	((pLE)->Tx.ControlFlags = (Lock))
#define TXLE_SET_CTRL(pLE, Ctrl)	((pLE)->Tx.ControlFlags = (Ctrl))
#define TXLE_SET_OPC(pLE, Opc)		((pLE)->Tx.Opcode = (Opc))


#define TXLE_GET_ADDR(pLE)		LE2DWord((pLE)->Tx.TxUn.BufAddr)
#define TXLE_GET_LSLEN(pLE)		LE2Word((pLE)->Tx.TxUn.LargeSend.Length)
#define TXLE_GET_STACS(pLE)		LE2Word((pLE)->Tx.TxUn.ChkSum.TxTcpSp)
#define TXLE_GET_WRICS(pLE)		LE2Word((pLE)->Tx.TxUn.ChkSum.TxTcpWp)
#define TXLE_GET_INICS(pLE)		LE2Word((pLE)->Tx.Send.InitCsum)
#define TXLE_GET_LEN(pLE) 		LE2Word((pLE)->Tx.Send.BufLen)
#define TXLE_GET_VLAN(pLE)		LE2Word((pLE)->Tx.Send.VlanTag)
#define TXLE_GET_LCKCS(pLE)		((pLE)->Tx.ControlFlags)
#define TXLE_GET_CTRL(pLE)		((pLE)->Tx.ControlFlags)
#define TXLE_GET_OPC(pLE)		((pLE)->Tx.Opcode)

/******************************************************************************
 *
 * Receive list element macros
 *
 */

#define RXLE_SET_ADDR(pLE, Addr)	\
	((pLE)->Rx.RxUn.BufAddr = (SK_U32) DWord2LE(Addr))
#define RXLE_SET_STACS2(pLE, Offs)	\
	((pLE)->Rx.RxUn.ChkSum.RxTcpSp2 = Word2LE(Offs))
#define RXLE_SET_STACS1(pLE, Offs)	\
	((pLE)->Rx.RxUn.ChkSum.RxTcpSp1 = Word2LE(Offs))
#define RXLE_SET_LEN(pLE, Len)		((pLE)->Rx.BufferLength = Word2LE(Len))
#define RXLE_SET_CTRL(pLE, Ctrl)	((pLE)->Rx.ControlFlags = (Ctrl))
#define RXLE_SET_OPC(pLE, Opc)		((pLE)->Rx.Opcode = (Opc))


#define RXLE_GET_ADDR(pLE)		LE2DWord((pLE)->Rx.RxUn.BufAddr)
#define RXLE_GET_STACS2(pLE)	LE2Word((pLE)->Rx.RxUn.ChkSum.RxTcpSp2)
#define RXLE_GET_STACS1(pLE)	LE2Word((pLE)->Rx.RxUn.ChkSum.RxTcpSp1)
#define RXLE_GET_LEN(pLE) 		LE2Word((pLE)->Rx.BufferLength)
#define RXLE_GET_CTRL(pLE)		((pLE)->Rx.ControlFlags)
#define RXLE_GET_OPC(pLE)		((pLE)->Rx.Opcode)

/******************************************************************************
 *
 * Status list element macros
 *
 */

#define STLE_SET_OPC(pLE, Opc)		((pLE)->St.Opcode = (Opc))

#define STLE_GET_FRSTATUS(pLE)	LE2DWord((pLE)->St.StUn.StRxStatWord)
#define STLE_GET_TIST(pLE)		LE2DWord((pLE)->St.StUn.StRxTimeStamp)
#define STLE_GET_TCP1(pLE)		LE2Word((pLE)->St.StUn.StRxTCPCSum.RxTCPSum1)
#define STLE_GET_TCP2(pLE)		LE2Word((pLE)->St.StUn.StRxTCPCSum.RxTCPSum2)
#define STLE_GET_LEN(pLE)		LE2Word((pLE)->St.Stat.BufLen)
#define STLE_GET_VLAN(pLE)		LE2Word((pLE)->St.Stat.VlanTag)
#define STLE_GET_LINK(pLE)		((pLE)->St.Link)
#define STLE_GET_OPC(pLE)		((pLE)->St.Opcode)
#define STLE_GET_DONE_IDX(pLE,LowVal,HighVal) {			\
	(LowVal) = LE2DWord((pLE)->St.StUn.StTxStatLow);	\
	(HighVal) = LE2Word((pLE)->St.Stat.StTxStatHi);		\
}

#define STLE_GET_RSS(pLE)		LE2DWord((pLE)->St.StUn.StRxRssValue)
#define STLE_GET_IPBIT(pLE)		((pLE)->St.Stat.Rss.FlagField & RSS_IP_FLAG)
#define STLE_GET_TCPBIT(pLE)	((pLE)->St.Stat.Rss.FlagField & RSS_TCP_FLAG)


/* I always take both values as a paramter to avoid typos */
#define STLE_GET_DONE_IDX_TXA1(LowVal,HighVal)			\
	(((LowVal) & STLE_TXA1_MSKL) >> STLE_TXA1_SHIFTL)
#define STLE_GET_DONE_IDX_TXS1(LowVal,HighVal)			\
	((LowVal & STLE_TXS1_MSKL) >> STLE_TXS1_SHIFTL)
#define STLE_GET_DONE_IDX_TXA2(LowVal,HighVal)			\
	(((LowVal & STLE_TXA2_MSKL) >> STLE_TXA2_SHIFTL) + 	\
	((HighVal & STLE_TXA2_MSKH) << STLE_TXA2_SHIFTH))
#define STLE_GET_DONE_IDX_TXS2(LowVal,HighVal)			\
	((HighVal & STLE_TXS2_MSKL) >> STLE_TXS2_SHIFTL)


#define SK_Y2_RXSTAT_CHECK_PKT(Len, RxStat, IsOk) {				\
	(IsOk) = (((RxStat) & GMR_FS_RX_OK) == GMR_FS_RX_OK) &&		\
			 (((RxStat) & GMR_FS_ANY_ERR) == 0);				\
																\
	if ((IsOk) && ((SK_U16)(((RxStat) & GMR_FS_LEN_MSK) >>  	\
		GMR_FS_LEN_SHIFT) != (Len))) {							\
		/* length in MAC status differs from length in LE */	\
		(IsOk) = SK_FALSE;										\
	}															\
}


/******************************************************************************
 *
 * Polling unit list element macros
 *
 * NOTE: the Idx must be <= 0xfff and PU_PUTIDX_VALID makes them valid
 *
 */

#ifdef USE_POLLING_UNIT

#define POLE_SET_OPC(pLE, Opc)		((pLE)->Sa.Opcode = (Opc))
#define POLE_SET_LINK(pLE, Port)	((pLE)->Sa.Link = (Port))
#define POLE_SET_RXIDX(pLE, Idx)	((pLE)->Sa.RxIdxVld = Word2LE(Idx))
#define POLE_SET_TXAIDX(pLE, Idx)	((pLE)->Sa.TxAIdxVld = Word2LE(Idx))
#define POLE_SET_TXSIDX(pLE, Idx)	((pLE)->Sa.TxSIdxVld = Word2LE(Idx))

#define POLE_GET_OPC(pLE)		((pLE)->Sa.Opcode)
#define POLE_GET_LINK(pLE)		((pLE)->Sa.Link)
#define POLE_GET_RXIDX(pLE)		LE2Word((pLE)->Sa.RxIdxVld)
#define POLE_GET_TXAIDX(pLE)	LE2Word((pLE)->Sa.TxAIdxVld)
#define POLE_GET_TXSIDX(pLE)	LE2Word((pLE)->Sa.TxSIdxVld)

#endif	/* USE_POLLING_UNIT */

/******************************************************************************
 *
 * Debug macros for list elements
 *
 */

#ifdef DEBUG

#define SK_DBG_DUMP_RX_LE(pLE)	{										\
	SK_U8	Opcode;														\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=== RX_LIST_ELEMENT @addr: %p cont: %02x %02x %02x %02x %02x %02x %02x %02x\n",	\
		pLE, ((SK_U8 *) pLE)[0], ((SK_U8 *) pLE)[1], ((SK_U8 *) pLE)[2],\
		((SK_U8 *) pLE)[3], ((SK_U8 *) pLE)[4], ((SK_U8 *) pLE)[5],		\
		((SK_U8 *) pLE)[6], ((SK_U8 *) pLE)[7])); 						\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (16bit) %04x %04x %04x %04x\n",							\
		((SK_U16 *) pLE)[0], ((SK_U16 *) pLE)[1], ((SK_U16 *) pLE)[2],	\
		((SK_U16 *) pLE)[3])); 											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (32bit) %08x %08x\n",										\
		((SK_U32 *) pLE)[0], ((SK_U32 *) pLE)[1])); 					\
	Opcode = RXLE_GET_OPC(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					   	\
		("\tOwn belongs to %s\n", ((Opcode & HW_OWNER) == HW_OWNER) ? 	\
		 "Hardware" : "Software"));										\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\tOpc: 0x%x ",Opcode));								   		\
	switch (Opcode & (~HW_OWNER)) {									  	\
	case OP_BUFFER:														\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_BUFFER\n"));									   		\
		break;															\
	case OP_PACKET:									  	  	   			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_PACKET\n"));								   			\
		break;															\
	case OP_ADDR64:												   		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_ADDR64\n"));								   			\
		break;															\
	case OP_TCPSTART:												   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TCPPAR\n"));									   		\
		break;															\
	case SW_OWNER:														\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tunused LE\n"));									   		\
		break;															\
	default:														   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tunknown Opcode!!!\n"));								   	\
		break;															\
	}																	\
	if ((Opcode & OP_BUFFER) == OP_BUFFER) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tControl: 0x%x\n", RXLE_GET_CTRL(pLE)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tBufLen: 0x%x\n", RXLE_GET_LEN(pLE)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tLowAddr: 0x%x\n", RXLE_GET_ADDR(pLE)));					\
	}																	\
	if ((Opcode & OP_ADDR64) == OP_ADDR64) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tHighAddr: 0x%x\n", RXLE_GET_ADDR(pLE)));				\
	}																	\
	if ((Opcode & OP_TCPSTART) == OP_TCPSTART) {	  		  			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTCP Sum Start 1 : 0x%x\n", RXLE_GET_STACS1(pLE)));		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTCP Sum Start 2 : 0x%x\n", RXLE_GET_STACS2(pLE)));		\
	}																	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=====================\n"));									\
}

#define SK_DBG_DUMP_TX_LE(pLE)	{										\
	SK_U8	Opcode;														\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=== TX_LIST_ELEMENT @addr: %p cont: %02x %02x %02x %02x %02x %02x %02x %02x\n",	\
		pLE, ((SK_U8 *) pLE)[0], ((SK_U8 *) pLE)[1], ((SK_U8 *) pLE)[2],\
		((SK_U8 *) pLE)[3], ((SK_U8 *) pLE)[4], ((SK_U8 *) pLE)[5],		\
		((SK_U8 *) pLE)[6], ((SK_U8 *) pLE)[7])); 						\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (16bit) %04x %04x %04x %04x\n",							\
		((SK_U16 *) pLE)[0], ((SK_U16 *) pLE)[1], ((SK_U16 *) pLE)[2],	\
		((SK_U16 *) pLE)[3])); 											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (32bit) %08x %08x\n",										\
		((SK_U32 *) pLE)[0], ((SK_U32 *) pLE)[1])); 					\
	Opcode = TXLE_GET_OPC(pLE);										   	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					   	\
		("\tOwn belongs to %s\n", ((Opcode & HW_OWNER) == HW_OWNER) ? 	\
		"Hardware" : "Software"));										\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					   	\
		("\tOpc: 0x%x ",Opcode));								   		\
	switch (Opcode & (~HW_OWNER)) {									   	\
	case OP_TCPCHKSUM:										 	      	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TCPCHKSUM\n"));									   	\
		break;											   		 		\
	case OP_TCPIS:										  		  	   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TCPIS\n"));										   	\
		break;												  		  	\
	case OP_TCPLCK:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,		   	    	\
			("\tOP_TCPLCK\n"));								   	    	\
		break;												   		 	\
	case OP_TCPLW:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,		   	    	\
			("\tOP_TCPLW\n"));								   	    	\
		break;															\
	case OP_TCPLSW:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TCPLSW\n"));										   	\
		break;															\
	case OP_TCPLISW:												   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TCPLISW\n"));						 		   	   	\
		break;											 		   		\
	case OP_ADDR64:										 		   	   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,	  	     	   	\
			("\tOP_ADDR64\n"));										   	\
		break;															\
	case OP_VLAN:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_VLAN\n"));										   	\
		break;															\
	case OP_ADDR64VLAN:												   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_ADDR64VLAN\n"));								   		\
		break;															\
	case OP_LRGLEN:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_LRGLEN\n"));										   	\
		break;															\
	case OP_LRGLENVLAN:												   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_LRGLENVLAN\n"));									   	\
		break;															\
	case OP_BUFFER:													   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_BUFFER\n"));									   		\
		break;															\
	case OP_PACKET:												   		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_PACKET\n"));										   	\
		break;															\
	case OP_LARGESEND:													\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_LARGESEND\n"));									   	\
		break;															\
	case SW_OWNER:														\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tunused LE\n"));										   	\
		break;															\
	default:														   	\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tunknown Opcode!!!\n"));								   	\
		break;															\
	}																	\
	if ((Opcode & OP_BUFFER) == OP_BUFFER) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tControl: 0x%x\n", TXLE_GET_CTRL(pLE)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tBufLen: 0x%x\n", TXLE_GET_LEN(pLE)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tLowAddr: 0x%x\n", TXLE_GET_ADDR(pLE)));					\
	}																	\
	if ((Opcode & OP_ADDR64) == OP_ADDR64) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tHighAddr: 0x%x\n", TXLE_GET_ADDR(pLE)));				\
	}																	\
	if ((Opcode & OP_VLAN) == OP_VLAN) {								\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tVLAN Id: 0x%x\n", TXLE_GET_VLAN(pLE)));					\
	}																	\
	if ((Opcode & OP_LRGLEN) == OP_LRGLEN) {				   			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tLarge send length: 0x%x\n", TXLE_GET_LSLEN(pLE)));		\
	}																	\
	if ((Opcode &(~HW_OWNER)) <= OP_ADDR64) {							\
		if ((Opcode & OP_TCPWRITE) == OP_TCPWRITE) {					\
			SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				\
				("\tTCP Sum Write: 0x%x\n", TXLE_GET_WRICS(pLE)));		\
		}																\
		if ((Opcode & OP_TCPSTART) == OP_TCPSTART) {					\
			SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				\
				("\tTCP Sum Start: 0x%x\n", TXLE_GET_STACS(pLE)));		\
		}																\
		if ((Opcode & OP_TCPINIT) == OP_TCPINIT) {					  	\
			SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				\
				("\tTCP Sum Init: 0x%x\n", TXLE_GET_INICS(pLE)));		\
		}																\
		if ((Opcode & OP_TCPLCK) == OP_TCPLCK) {					  	\
			SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				\
				("\tTCP Sum Lock: 0x%x\n", TXLE_GET_LCKCS(pLE)));		\
		}																\
	}																	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=====================\n"));									\
}
	
#define SK_DBG_DUMP_ST_LE(pLE)	{ 										\
	SK_U8	Opcode;														\
	SK_U16	HighVal;													\
	SK_U32	LowVal;														\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=== ST_LIST_ELEMENT @addr: %p contains: %02x %02x %02x %02x %02x %02x %02x %02x\n",	\
		pLE, ((SK_U8 *) pLE)[0], ((SK_U8 *) pLE)[1], ((SK_U8 *) pLE)[2],\
		((SK_U8 *) pLE)[3], ((SK_U8 *) pLE)[4], ((SK_U8 *) pLE)[5],		\
		((SK_U8 *) pLE)[6], ((SK_U8 *) pLE)[7])); 						\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (16bit) %04x %04x %04x %04x\n",							\
		((SK_U16 *) pLE)[0], ((SK_U16 *) pLE)[1], ((SK_U16 *) pLE)[2],	\
		((SK_U16 *) pLE)[3])); 											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (32bit) %08x %08x\n",										\
		((SK_U32 *) pLE)[0], ((SK_U32 *) pLE)[1])); 					\
	Opcode = STLE_GET_OPC(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					   	\
		("\tOwn belongs to %s\n", ((Opcode & HW_OWNER) == SW_OWNER) ? 	\
		"Hardware" : "Software"));										\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\tOpc: 0x%x",	Opcode));										\
	Opcode &= (~HW_OWNER);												\
	switch (Opcode) {													\
	case OP_RXSTAT:										 	     		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_RXSTAT\n"));								   			\
		break;															\
	case OP_RXTIMESTAMP:												\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_RXTIMESTAMP\n"));									\
		break;															\
	case OP_RXVLAN:											  			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_RXVLAN\n"));										   	\
		break;															\
	case OP_RXCHKS:											  			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,	 		   	   	\
			("\tOP_RXCHKS\n"));										   	\
		break;											 		   		\
	case OP_RXCHKSVLAN:									 	     		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,	 		   	   	\
			("\tOP_RXCHKSVLAN\n"));						 		   	   	\
		break;											 		   		\
	case OP_RXTIMEVLAN:									 	     		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,	   		 	   	\
			("\tOP_RXTIMEVLAN\n"));						   		 	   	\
		break;											   		 		\
	case OP_RSS_HASH:											  		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_RSS_HASH\n"));									   	\
		break;															\
	case OP_TXINDEXLE:											  		\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tOP_TXINDEXLE\n"));						  		  	   	\
		break;															\
	case HW_OWNER:											  			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tunused LE\n"));						  		  	   		\
		break;															\
	default:												  			\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tunknown status list element!!!\n"));				   	\
		break;															\
	}																	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\tPort: %c\n", 'A' + STLE_GET_LINK(pLE)));					\
	if (Opcode == OP_RXSTAT) {											\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tFrameLen: 0x%x\n", STLE_GET_LEN(pLE)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tFrameStat: 0x%x\n", STLE_GET_FRSTATUS(pLE)));			\
	}																	\
	if ((Opcode & OP_RXVLAN) == OP_RXVLAN) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tVLAN Id: 0x%x\n", STLE_GET_VLAN(pLE)));					\
	}																	\
	if ((Opcode & OP_RXTIMESTAMP) == OP_RXTIMESTAMP) {					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTimestamp: 0x%x\n", STLE_GET_TIST(pLE)));				\
	}																	\
	if ((Opcode & OP_RXCHKS) == OP_RXCHKS) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTCP: 0x%x 0x%x\n", STLE_GET_TCP1(pLE),					\
			STLE_GET_TCP2(pLE)));										\
	}																	\
	if (Opcode == OP_TXINDEXLE) {										\
		STLE_GET_DONE_IDX(pLE, LowVal, HighVal);						\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTx Index TxA1: 0x%x\n",									\
			STLE_GET_DONE_IDX_TXA1(LowVal,HighVal)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTx Index TxS1: 0x%x\n",									\
			STLE_GET_DONE_IDX_TXS1(LowVal,HighVal)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTx Index TxA2: 0x%x\n",									\
			STLE_GET_DONE_IDX_TXA2(LowVal,HighVal)));					\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,					\
			("\tTx Index TxS2: 0x%x\n",									\
			STLE_GET_DONE_IDX_TXS2(LowVal,HighVal)));					\
	}																	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=====================\n"));									\
}

#ifdef USE_POLLING_UNIT
#define SK_DBG_DUMP_PO_LE(pLE)	{										\
	SK_U8	Opcode;														\
	SK_U16	Idx;														\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=== PO_LIST_ELEMENT @addr: %p cont: %02x %02x %02x %02x %02x %02x %02x %02x\n",	\
		pLE, ((SK_U8 *) pLE)[0], ((SK_U8 *) pLE)[1], ((SK_U8 *) pLE)[2],\
		((SK_U8 *) pLE)[3], ((SK_U8 *) pLE)[4], ((SK_U8 *) pLE)[5],		\
		((SK_U8 *) pLE)[6], ((SK_U8 *) pLE)[7])); 						\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (16bit) %04x %04x %04x %04x\n",							\
		((SK_U16 *) pLE)[0], ((SK_U16 *) pLE)[1], ((SK_U16 *) pLE)[2],	\
		((SK_U16 *) pLE)[3])); 											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("\t (32bit) %08x %08x\n",										\
		((SK_U32 *) pLE)[0], ((SK_U32 *) pLE)[1])); 					\
	Opcode = POLE_GET_OPC(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		 ("\tOwn belongs to %s\n", ((Opcode & HW_OWNER) == HW_OWNER) ? 	\
		  "Hardware" : "Software"));									\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		 ("\tOpc: 0x%x ",Opcode));										\
	if ((Opcode & ~HW_OWNER) == OP_PUTIDX) {							\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   		\
			("\tOP_PUTIDX\n"));								   			\
	}																	\
	else {																\
		SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,				   	\
			("\tunknown Opcode!!!\n"));								   	\
	}																	\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   			\
		("\tPort %c\n", 'A' + POLE_GET_LINK(pLE)));						\
	Idx = POLE_GET_TXAIDX(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   			\
		("\tTxA Index is 0x%X and %svalid\n", Idx,						\
		(Idx & PU_PUTIDX_VALID) ? "" : "not "));						\
	Idx = POLE_GET_TXSIDX(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   			\
		("\tTxS Index is 0x%X and %svalid\n", Idx,						\
		(Idx & PU_PUTIDX_VALID) ? "" : "not "));						\
	Idx = POLE_GET_RXIDX(pLE);											\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,			   			\
		("\tRx Index is 0x%X and %svalid\n", Idx,						\
		(Idx & PU_PUTIDX_VALID) ? "" : "not "));						\
	SK_DBG_MSG(pAc, SK_DBGMOD_HWM, SK_DBGCAT_INIT,						\
		("=====================\n"));									\
}
#endif	/* USE_POLLING_UNIT */

#else	/* !DEBUG */

#define SK_DBG_DUMP_RX_LE(pLE)
#define SK_DBG_DUMP_TX_LE(pLE)
#define SK_DBG_DUMP_ST_LE(pLE)
#define SK_DBG_DUMP_PO_LE(pLE)

#endif	/* !DEBUG */

/******************************************************************************
 *
 * Macros for listelement tables
 *
 *
 */

#define LE_SIZE sizeof(SK_HWLE)
#define LE_TAB_SIZE(NumElements)	((NumElements) * LE_SIZE)

/* Number of unused list elements in table
 * this macro always returns the number of free listelements - 1
 * this way we want to guarantee that always one LE remains unused
 */
#define NUM_FREE_LE_IN_TABLE(pTable) 									\
	( ((pTable)->Put >= (pTable)->Done) ?									\
	(NUM_LE_IN_TABLE(pTable) - (pTable)->Put + (pTable)->Done - 1) :	\
	((pTable)->Done - (pTable)->Put - 1) )

/* total number of list elements in table */
#define NUM_LE_IN_TABLE(pTable)		((pTable)->Num)
	
/* get next unused rx list element */
#define GET_RX_LE(pLE, pTable) {										\
	pLE = &(pTable)->pLETab[(pTable)->Put];								\
	(pTable)->Put = ((pTable)->Put + 1) % NUM_LE_IN_TABLE(pTable);		\
}
	
/* get next unused tx list element */
#define GET_TX_LE(pLE, pTable)	GET_RX_LE(pLE, pTable)

/* get next status list element expected to be finished by hw */
#define GET_ST_LE(pLE, pTable) {										\
	pLE = &(pTable)->pLETab[(pTable)->Done];							\
	(pTable)->Done = ((pTable)->Done +1) % NUM_LE_IN_TABLE(pTable);		\
}

#ifdef USE_POLLING_UNIT
/* get next polling unit list element for port */
#define GET_PO_LE(pLE, pTable, Port) {									\
	pLE = &(pTable)->pLETab[(Port)];									\
}
#endif	/* USE_POLLING_UNIT */

#define GET_PUT_IDX(pTable)			((pTable)->Put)

#define UPDATE_HWPUT_IDX(pTable)	{(pTable)->HwPut = (pTable)->Put; }

/*
 * get own bit of next status LE
 * if the result is != 0 there has been at least one status LE finished
 */
#define OWN_OF_FIRST_LE(pTable)											\
	(STLE_GET_OPC(&(pTable)->pLETab[(pTable)->Done]) & HW_OWNER)

#define SET_DONE_INDEX(pTable, Idx)	(pTable)->Done = (Idx);

#define GET_DONE_INDEX(pTable)	((pTable)->Done)

#ifdef SAFE_BUT_SLOW

/* check own bit of LE before current done idx */
#define CHECK_STLE_OVERFLOW(pTable, IsOk) {						\
		unsigned i;												\
		if ((i = (pTable)->Done) == 0) {						\
			i = NUM_LE_IN_TABLE(pTable);						\
		}														\
		else {													\
			i = i - 1; 											\
		}														\
		if (STLE_GET_OPC(&(pTable)->pLETab[i]) == HW_OWNER) {	\
			(IsOk) = SK_TRUE;									\
		}														\
		else {													\
			(IsOk) = SK_FALSE;									\
		}														\
	}


/*
 * for Yukon2 the hardware is not polling the list elements, so it
 * is not necessary to change the own-bit of rx or tx-LEs before
 * reusing them
 * but it might make debugging easier if one simply can see whether
 * a LE has been worked on
 */
	
#define CLEAR_LE_OWN(pTable, Idx)								\
	STLE_SET_OPC(&(pTable)->pLETab[(Idx)], SW_OWNER)

/*
 * clear all own bits starting from old done index up to the LE before
 * the new done index
 */
#define CLEAR_LE_OWN_FROM_DONE_TO(pTable, To) {					\
		int i;													\
		i = (pTable)->Done;										\
		while (i != To) {										\
			CLEAR_LE_OWN(pTable, i);							\
			i = (i + 1) % NUM_LE_IN_TABLE(pTable);				\
		}														\
	}

#else	/* !SAFE_BUT_SLOW */

#define CHECK_STLE_OVERFLOW(pTable, IsOk)
#define CLEAR_LE_OWN(pTable, Idx)
#define CLEAR_LE_OWN_FROM_DONE_TO(pTable, To)

#endif	/* !SAFE_BUT_SLOW */


/* typedefs *******************************************************************/

typedef struct s_LetRxTx {
	SK_U16	VlanId;			/* VLAN Id given down last time */
	SK_U16	TcpWp;			/* TCP Checksum Write Position */
	SK_U16	TcpSp1;			/* TCP Checksum Calculation Start Position 1 */
	SK_U16	TcpSp2;			/* TCP Checksum Calculation Start Position 2 */
	SK_U16	MssValue;		/* Maximum Segment Size */
	SK_U16	Reserved1;		/* reserved word for furture extensions */
	SK_U16	Reserved2;		/* reserved word for furture extensions */
	SK_U16	Reserved3;		/* reserved word for furture extensions */
} SK_LET_RX_TX;

typedef struct s_LetStat {
	SK_U32	RxTimeStamp;	/* Receive Timestamp */
	SK_U32	RssHashValue;	/* RSS Hash Value */
	SK_BOOL	RssIsIp;		/* RSS Hash Value: IP packet detected */
	SK_BOOL	RssIsTcp;		/* RSS Hash Value: IP+TCP packet detected */
	SK_U16	VlanId;			/* VLAN Id given received by Status BMU */
	SK_U16	TcpSum1;		/* TCP checksum 1 (status BMU) */
	SK_U16	TcpSum2;		/* TCP checksum 2 (status BMU) */
} SK_LET_STAT;


typedef union s_LetBmuSpec {
	SK_LET_RX_TX	RxTx;	/* Rx/Tx BMU specific variables */
	SK_LET_STAT		Stat;	/* Status BMU specific variables */
} SK_LET_BMU_S;



typedef	struct s_le_table SK_LE_TABLE;

struct s_le_table {
	/* all LE's between Done and HWPut are owned by the hardware */
	/* all LE's between Put and Done can be used from Software */
	/* all LE's between HWPut and Put are currently processed in DriverSend */
	unsigned Done;			/* done index - consumed from HW and available */
	unsigned Put;			/* put index - to be given to hardware */
	unsigned HwPut;			/* put index actually given to hardware */
	unsigned Num;			/* total number of list elements */
	SK_HWLE *pLETab;		/* virtual address of list element table */
	SK_U32	pPhyLETABLow;	/* physical address of list element table */
	SK_U32	pPhyLETABHigh;	/* physical address of list element table */
	/* values to remember in order to save some LEs */
	SK_U32	BufHighAddr;	/* high addr given down last time */
	SK_LET_BMU_S Bmu;		/* contains BMU specific information */
	SK_U32	private;		/* driver private variable free usable */
	SK_U16	TcpInitCsum;	/* Init. Checksum */
};

/* function prototypes ********************************************************/

#ifndef	SK_KR_PROTO

/*
 * public functions in sky2le.c
 */
extern void SkGeY2SetPutIndex(
	SK_AC	*pAC,
	SK_IOC	IoC,
	SK_U32 StartAddrPrefetchUnit,
	SK_LE_TABLE *pLETab);

extern void SkGeY2InitPrefetchUnit(
	SK_AC	*pAC,
	SK_IOC	IoC,
	unsigned int Queue,
	SK_LE_TABLE *pLETab);

extern void SkGeY2InitStatBmu(
	SK_AC	*pAC,
	SK_IOC	IoC,
	SK_LE_TABLE *pLETab);

extern void SkGeY2InitPollUnit(
	SK_AC	*pAC,
	SK_IOC	IoC,
	SK_LE_TABLE *pLETab);

extern void SkGeY2InitSingleLETable(
	SK_AC	*pAC,
	SK_LE_TABLE *pLETab,
	unsigned int NumLE,
	void	*pVMem,
	SK_U32	PMemLowAddr,
	SK_U32	PMemHighAddr);

#else	/* SK_KR_PROTO */
extern void SkGeY2SetPutIndex();
extern void SkGeY2InitPrefetchUnit();
extern void SkGeY2InitStatBmu();
extern void SkGeY2InitPollUnit();
extern void SkGeY2InitSingleLETable();
#endif	/* SK_KR_PROTO */

#ifdef __cplusplus
}
#endif	/* __cplusplus */

#endif	/* __INC_SKY2LE_H */

