www.pudn.com > at91rm9200bsp.rar > AT91emacend.c
/* at91End.c - SNDS END network interface driver for Ethernet */
/* Copyright 1984-1997 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
*/
/*
DESCRIPTION
*/
/* includes */
#include "vxWorks.h"
#include "etherMultiLib.h" /* multicast stuff. */
#include "end.h" /* Common END structures. */
#include "endLib.h"
#include "lstLib.h" /* Needed to maintain protocol list. */
#include "cacheLib.h"
#include "stdlib.h"
#include "stdio.h"
#include "intLib.h"
#include "iv.h"
#include "netLib.h"
#include "config.h"
#include "at91Emac.h"
#if defined(CPU_920T)
#include "arch/arm/mmuArmLib.h"
#include "private/vmLibP.h"
/*#include "dllLib.h"*/
#endif /* defined(720T/740T/920T/940T/946ES) */
/* defines */
/* Configuration items */
#define ENET_HDR_REAL_SIZ 14
#define END_BUFSIZ ( ETHERMTU + ENET_HDR_REAL_SIZ + 8 )
#define END_SPEED 10000000
#define AT91END_CL_SIZE ( ETHERMTU + ENET_HDR_REAL_SIZ + 8 )
#define END_MBLK_NUM 256
#define END_CL_NUM (END_MBLK_NUM/2)
#define RX_FD_NUM 32
#define TX_FD_NUM 32
#define LS_POLLING 0x20
#define AT91EMAC_MAX_MULTI 3
/*
* Default macro definitions for BSP interface.
* These macros can be redefined in a wrapper file, to generate
* a new module with an optimized interface.
*/
/* Macro to connect interrupt handler to vector */
/* Macro to get the ethernet address from the BSP */
unsigned char at91EndEnetAddr[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
#ifndef SYS_ENET_ADDR_GET
# define SYS_ENET_ADDR_GET(pDevice) \
{ \
bcopy ((char *)at91EndEnetAddr, (char *)(&pDevice->enetAddr), 6); \
}
#endif
/*
* Macros to do a short (UINT16) access to the chip. Default
* assumes a normal memory mapped device.
*/
/*A shortcut for getting the hardware address from the MIB II stuff. */
#define END_HADDR(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
#define END_HADDR_LEN(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
/* typedefs */
typedef struct _AT91_END_RECV_FD
{
UINT32 bufaddr;
UINT32 recvstatus;
}AT91_END_RECV_FD;
struct _AT91_END_TRAN_FD;
typedef struct _AT91_END_TRAN_FD
{
char* bufaddr;
UINT32 len;
UINT32 owner;
}AT91_END_TRAN_FD;
typedef struct etherStatistics
{
UINT32 ESTAT_FRA;
UINT32 ESTAT_SCOL;
UINT32 ESTAT_MCOL;
UINT32 ESTAT_OK;
UINT32 ESTAT_SEQE;
UINT32 ESTAT_ALE;
UINT32 ESTAT_DTE;
UINT32 ESTAT_LCOL;
UINT32 ESTAT_ECOL;
UINT32 ESTAT_CSE;
UINT32 ESTAT_TUE;
UINT32 ESTAT_CDE;
UINT32 ESTAT_ELR;
UINT32 ESTAT_RJB;
UINT32 ESTAT_USF;
UINT32 ESTAT_SQEE;
UINT32 ESTAT_DRFC;
} ETHER_STATISTICS;
#define TXFIFOEMPTY 1
#define TXFIFOFULL 2
#define TXFIFONORMAL 3
/* The definition of the driver control structure */
/*
* for addrListLow and addrListHigh:
* ETH addr = E0 E1 E2 E3 E4 E5
* addrListLow( in byte address order ) = E3 E2 E1 E0
* addrListHigh( in byte address order ) = E5 E4
* so we can use htol and htos to convert the ETH address
*/
typedef struct _at91end_device
{
END_OBJ end; /* The class we inherit from. */
int unit; /* unit number */
int level; /* bdmaTx interrupt vector */
long flags; /* Our local flags. */
CL_POOL_ID pClPoolId;
UCHAR* clPointBuf[ RX_FD_NUM ];
UCHAR* TranFifoBuf;
UCHAR* RecvFifoBuf;
UINT32 TranPkgNumber;
UINT32 TranPkgSize;
AT91_END_TRAN_FD pTxBufStart[TX_FD_NUM];
UINT32 TxPtr; /* point to desc sending */
UINT32 TxTailPtr; /* point to desc may writing */
UINT32 TXFifoStat;
UINT32 NetJobDoing;
AT91_END_RECV_FD* RecvBufDesc;
UINT32 rxBufPtr;
UCHAR enetAddr[6]; /* ethernet address */
UCHAR netSpeed; /* 10 or 100 */
UCHAR duplexMode; /* HDX = 0. FDX = 1 */
UCHAR autoNeg; /* 1 = autoneg enabled */
BOOL fdInitialized; /* Set to TRUE after FD allocation */
ETHER_STATISTICS statistics; /* Ethernet statistics counters */
UINT32 addrListHigh[(AT91EMAC_MAX_MULTI+1)]; /* Array for storing addresses Max = 4, i.e. 32 long words */
UINT32 addrListLow[(AT91EMAC_MAX_MULTI+1)]; /* Array for storing addresses Max = 4, i.e. 32 long words */
UINT32 mcastAddrCount; /* Number of valid multicast addresses */
} at91end_device;
/* globals*/
/*
* This will only work if there is only a single unit, for multiple
* unit device drivers these should be integrated into the at91end_device
* structure.
*/
M_CL_CONFIG at91endMclConfig = /* network mbuf configuration table */
{
/*
no. mBlks no. clBlks memArea memSize
----------- ---------- ------- -------
*/
0, 0, NULL, 0
};
CL_DESC at91endClDescTbl [] = /* network cluster pool configuration table */
{
/*
clusterSize num memArea memSize
----------- ---- ------- -------
*/
{AT91END_CL_SIZE, 0, NULL, 0}
};
int endClDescTblNumEnt = (NELEMENTS(at91endClDescTbl));
/* new additions */
/* Definitions for the flags field */
#define END_PROMISCUOUS_FLAG 0x1
#define END_RCV_HANDLING_FLAG 0x2
/* DEBUG MACROS */
#undef END_DEBUG
/*
#define END_DEBUG
*/
#ifdef END_DEBUG
#include "LogLib.h" /* Needed to debug polled mode. */
int endDebug = 1;
#define ENDLOGMSG(x) \
if (endDebug) \
{ \
logMsg x;\
}
#else
#define ENDLOGMSG(x)
#endif /* END_DEBUG */
/* LOCALS */
#ifdef INCLUDE_AT91EMAC_END
/* forward static functions */
LOCAL void at91EmacReset (at91end_device *pDrvCtrl); /**/
LOCAL void at91EndInt (at91end_device *pDrvCtrl); /**/
LOCAL void at91EndMacInitialize (at91end_device *pDevice); /**/
LOCAL STATUS at91EndFdInitialize (at91end_device *pDrvCrtl); /**/
LOCAL void at91EndFdFree (at91end_device *pDrvCtrl); /**/
LOCAL void at91EndHandleRcvInt (at91end_device *pDrvCtrl, UINT32 stat);/**/
LOCAL STATUS at91EndRecv (at91end_device *pDrvCtrl, UINT32 recvdescptr );/**/
LOCAL void at91EndConfig (at91end_device *pDrvCtrl);/**/
LOCAL UINT32 at91EndPhyRead (UINT32 phyRegAddr, UINT32 phyAddr);/**/
LOCAL void at91EndPhyWrite (UINT32 phyRegAddr, UINT32 phyAddr, UINT32 phyData);/**/
LOCAL void at91EndAddrFilterSet (at91end_device *pDrvCtrl);/**/
/* END Specific interfaces. */
/* This is the only externally visible interface. */
END_OBJ* at91EndLoad (char* initString);
LOCAL STATUS at91EndStart (at91end_device* pDrvCtrl);/**/
LOCAL STATUS at91EndStop (at91end_device* pDrvCtrl);/**/
LOCAL STATUS at91EndUnload ();/**/
LOCAL int at91EndIoctl (at91end_device* pDrvCtrl, int cmd, caddr_t data);
LOCAL STATUS at91EndSend (at91end_device* pDrvCtrl, M_BLK_ID pBuf);/**/
LOCAL STATUS at91EndMCastAdd (at91end_device* pDrvCtrl, char* pAddress);/**/
LOCAL STATUS at91EndMCastDel (at91end_device* pDrvCtrl, char* pAddress);/**/
LOCAL STATUS at91EndMCastGet (at91end_device* pDrvCtrl, MULTI_TABLE* pTable);/**/
LOCAL STATUS at91EndPollSend (at91end_device* pDrvCtrl, M_BLK_ID pBuf);/**/
LOCAL STATUS at91EndPollRcv (at91end_device* pDrvCtrl, M_BLK_ID pBuf);/**/
LOCAL STATUS at91EndPollStart (at91end_device* pDrvCtrl);/**/
LOCAL STATUS at91EndPollStop (at91end_device* pDrvCtrl);/**/
LOCAL STATUS at91EndParse ();/*---*/
LOCAL STATUS at91EndMemInit ();/*---*/
LOCAL void FreeEndMemory( at91end_device* pDrvCtrl );
/*
* Declare our function table. This is static across all driver
* instances.
*/
LOCAL NET_FUNCS at91endFuncTable =
{
(STATUS (*) (END_OBJ*))at91EndStart, /* Function to start the device. */
(STATUS (*) (END_OBJ*))at91EndStop, /* Function to stop the device. */
(STATUS (*) (END_OBJ*))at91EndUnload, /* Unloading function for the driver. */
(int (*) (END_OBJ*, int, caddr_t))at91EndIoctl, /* Ioctl function for the driver. */
(STATUS (*) (END_OBJ* , M_BLK_ID))at91EndSend, /* Send function for the driver. */
(STATUS (*) (END_OBJ*, char*))at91EndMCastAdd, /* Multicast address add function for the driver. */
(STATUS (*) (END_OBJ*, char*))at91EndMCastDel, /* Multicast address delete function for the driver. */
(STATUS (*) (END_OBJ*, MULTI_TABLE*))at91EndMCastGet, /* Multicast table retrieve function for the driver. */
(STATUS (*) (END_OBJ*, M_BLK_ID))at91EndPollSend, /* Polling send function for the driver. */
(STATUS (*) (END_OBJ*, M_BLK_ID))at91EndPollRcv, /* Polling receive function for the driver. */
endEtherAddressForm, /* Put address info into a packet. */
endEtherPacketDataGet, /* Get a pointer to packet data. */
endEtherPacketAddrGet /* Get packet addresses. */
};
/*******************************************************************************
*
* at91EndLoad - initialize the driver and device
*
* This routine initializes the driver and the device to the operational state.
* All of the device specific parameters are passed in the initString.
*
* The string contains the target specific parameters like this:
*
* ":::"
*
* RETURNS: An END object pointer or NULL on error.
*/
END_OBJ* at91EndLoad
(
char* initString /* String to be parsed by the driver. */
)
{
at91end_device *pDrvCtrl;
ENDLOGMSG (("Loading at91EndEnd...\n", 1, 2, 3, 4, 5, 6));
if ( initString[0] == 0 )
{
strcpy (initString, "atemac");
return (END_OBJ *)NULL;
}
/* allocate the device structure */
pDrvCtrl = (at91end_device *)calloc (sizeof (at91end_device), 1);
if ( pDrvCtrl == NULL )
goto errorExit;
bzero( (void*)pDrvCtrl, sizeof (at91end_device) );
pDrvCtrl ->TXFifoStat = TXFIFOEMPTY;
/* parse the init string, filling in the device structure */
if ( at91EndParse ( pDrvCtrl, initString ) == ERROR )
goto errorExit;
pDrvCtrl->level = INT_LVL_EMAC;
/* Ask the BSP to provide the ethernet address. */
SYS_ENET_ADDR_GET( pDrvCtrl );
/* initialize the END and MIB2 parts of the structure */
strcpy (pDrvCtrl->end.devObject.name, "atemac");
strcpy (pDrvCtrl->end.devObject.description, "AT91RM9200 EMAC END Driver");
/*
* The M2 element must come from m2Lib.h
* This at91End is set up for a DIX type ethernet device.
*/
if ( END_OBJ_INIT ( &pDrvCtrl->end, (DEV_OBJ *)pDrvCtrl, "atemac",
pDrvCtrl->unit, &at91endFuncTable,
"AT91RM9200 EMAC END Driver" ) == ERROR
|| END_MIB_INIT (&pDrvCtrl->end, M2_ifType_ethernet_csmacd,
&pDrvCtrl->enetAddr[0], 6, ETHERMTU,
END_SPEED) == ERROR )
goto errorExit;
/* Perform memory allocation/distribution */
if ( at91EndMemInit (pDrvCtrl) == ERROR )
goto errorExit;
/* reset and reconfigure the device */
at91EndConfig (pDrvCtrl);
/* set the flags to indicate readiness */
END_OBJ_READY ( &pDrvCtrl->end, IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST );
ENDLOGMSG (("Loading at91EndEnd success EXIT...\n", 1, 2, 3, 4, 5, 6));
return ( &pDrvCtrl->end );
errorExit:
if ( pDrvCtrl != NULL )
{
FreeEndMemory( pDrvCtrl );
pDrvCtrl = NULL;
}
ENDLOGMSG (("Loading at91EndEnd Failure EXIT...\n", 1, 2, 3, 4, 5, 6));
return NULL;
}
/*******************************************************************************
*
* at91EndParse - parse the init string
*
* Parse the input string. Fill in values in the driver control structure.
*
* The initialization string format is:
* ":::"
*
* .bS
* unit Device unit number, a small integer.
* Speed 10 (10Mbps) or 100 (100 Mbps)
* duplex 0 (HDX) or 1 (FDX)
* autoneg Autonegotiation disabled (0) or enabled (1)
* .bE
*
* RETURNS: OK or ERROR for invalid arguments.
*/
STATUS at91EndParse
(
at91end_device * pDrvCtrl, /* device pointer */
char * initString /* information string */
)
{
char* tok;
char* pHolder = NULL;
/* Parse the initString */
/* Unit number. */
tok = strtok_r (initString, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->unit = atoi (tok);
/* netSpeed */
tok = strtok_r (NULL, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->netSpeed = atoi (tok);
/* DuplexMode */
tok = strtok_r (NULL, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->duplexMode = atoi (tok);
/* auto Negotiation */
tok = strtok_r (NULL, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->autoNeg = atoi (tok);
return OK;
}
/*
* format AT91 Special address REG word
*/
LOCAL void FormatETHSpecialAddrWord( UINT32 *wordHigh, UINT32 *wordLow, BYTE *macadd )
{
(*wordLow) = /*htonl( *((UINT32*)( pDevice->enetAddr )) );*/
((UINT32)(macadd[3])<<24) | ((UINT32)(macadd[2])<<16) | ((UINT32)(macadd[1])<<8) | ((UINT32)(macadd[0]));
(*wordHigh) = /*htons( *((UINT16*)( pDevice->enetAddr + 4 )) )*/
((UINT32)(macadd[5])<<8) | ((UINT32)(macadd[4])) ;
}
/*******************************************************************************
*
* at91EndMemInit - initialize memory for the chip
*
* This routine is highly specific to the device.
*
* RETURNS: OK or ERROR.
*/
STATUS at91EndMemInit
(
at91end_device * pDrvCtrl /* device to be initialized */
)
{
UINT32 recvfdsize;
UINT32 txbufsize;
UINT32 rxbufsize;
UINT32 tmp;
/*
* This is how we would set up and END netPool using netBufLib(1).
* This code is pretty generic.
*/
if ( (pDrvCtrl->end.pNetPool = (NET_POOL_ID) malloc (sizeof(NET_POOL))) == NULL )
return (ERROR);
/*
* allocate the Trans desc buffer
*/
at91endMclConfig.mBlkNum = END_MBLK_NUM;
at91endClDescTbl[0].clNum = END_CL_NUM;
at91endMclConfig.clBlkNum = at91endClDescTbl[0].clNum;
/* Calculate the total memory for all the M-Blks and CL-Blks. */
at91endMclConfig.memSize =
(at91endMclConfig.mBlkNum * (MSIZE + sizeof (long))) +
(at91endMclConfig.clBlkNum * (CL_BLK_SZ + sizeof(long)));
at91endMclConfig.memArea =
(char *) memalign (sizeof(UINT32), at91endMclConfig.memSize );
if ( at91endMclConfig.memArea == NULL)
{
ENDLOGMSG(( " allocate m and cl block memory failure ", 1, 2, 3, 4, 5, 6 ));
return (ERROR);
}
at91endClDescTbl[0].clSize = ROUND_UP( at91endClDescTbl[0].clSize, 4 );
/* Calculate the memory size of all the clusters. */
at91endClDescTbl[0].memSize =
ROUND_UP( (at91endClDescTbl[0].clNum) * (at91endClDescTbl[0].clSize+4)+sizeof(int), _CACHE_ALIGN_SIZE );
/*
* allocate Received Buffer Descriptor List memory space, this also should be
* none cached
sizeof(AT91_END_RECV_FD) )*2 is for align
*/
recvfdsize = ROUND_UP( RX_FD_NUM*( sizeof(AT91_END_RECV_FD) )*2, _CACHE_ALIGN_SIZE );
rxbufsize = ROUND_UP( RX_FD_NUM*at91endClDescTbl[0].clSize, _CACHE_ALIGN_SIZE );
/*
* allocate Tx fifo buffer space
* each block size same as receive buffer
*/
txbufsize = ROUND_UP( TX_FD_NUM*at91endClDescTbl[0].clSize, _CACHE_ALIGN_SIZE );
/* Allocate the memory for the clusters , tx buffer and recv descriptor
* each memory is insert with a _CACHE_ALIGN_SIZE space for ascess safety
*/
at91endClDescTbl[0].memArea = (char*)malloc( at91endClDescTbl[0].memSize + _CACHE_ALIGN_SIZE );
/*
= (char *) cacheDmaMalloc ( at91endClDescTbl[0].memSize + txbufsize + recvfdsize + _CACHE_ALIGN_SIZE*3 );
*/
if ( at91endClDescTbl[0].memArea == NULL )
{
ENDLOGMSG(( " allocate none cached clusters memory failure ", 1, 2, 3, 4, 5, 6 ));
return (ERROR);
}
/*
* save the points
*/
pDrvCtrl ->TranFifoBuf = (char*)cacheDmaMalloc( txbufsize + recvfdsize + rxbufsize + _CACHE_ALIGN_SIZE*3 );
if( pDrvCtrl ->TranFifoBuf == NULL )
{
ENDLOGMSG(( " allocate none cached recv and transmit failure ", 1, 2, 3, 4, 5, 6 ));
return (ERROR);
}
/*
pDrvCtrl ->TranFifoBuf =
at91endClDescTbl[0].memArea + at91endClDescTbl[0].memSize + _CACHE_ALIGN_SIZE;
*/
pDrvCtrl ->RecvFifoBuf = (char*)( pDrvCtrl ->TranFifoBuf + txbufsize + _CACHE_ALIGN_SIZE );
tmp = (UINT32)( (UINT32)(pDrvCtrl ->RecvFifoBuf) + rxbufsize + _CACHE_ALIGN_SIZE + (RX_FD_NUM*( sizeof(AT91_END_RECV_FD) )) -1 );
tmp &= (~( (RX_FD_NUM*( sizeof(AT91_END_RECV_FD) )) -1) );
pDrvCtrl ->RecvBufDesc = (AT91_END_RECV_FD*)( tmp );
pDrvCtrl ->TranPkgNumber = TX_FD_NUM;
pDrvCtrl ->TranPkgSize = at91endClDescTbl[0].clSize;
bzero( (void*)(pDrvCtrl ->RecvBufDesc), RX_FD_NUM*sizeof(AT91_END_RECV_FD) );
/* Initialize the memory pool. */
if ( netPoolInit(pDrvCtrl->end.pNetPool, &at91endMclConfig,
&at91endClDescTbl[0], endClDescTblNumEnt, NULL ) == ERROR )
{
ENDLOGMSG(( " initial net pool for at91 END failure ", 1, 2, 3, 4, 5, 6 ));
return (ERROR);
}
pDrvCtrl->pClPoolId = clPoolIdGet ( pDrvCtrl->end.pNetPool,
at91endClDescTbl[0].clSize, FALSE);
return OK;
}
/*******************************************************************************
*
* at91EndStart - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*
*/
LOCAL STATUS at91EndStart
(
at91end_device *pDrvCtrl /* device to be started */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
UINT32 dummy;
/*
ENDLOGMSG ((" Enter at91EndStart...\n", 1, 2, 3, 4, 5, 6));
*/
/*
* load control register: for back pressure we don't use, start here ?
*/
pemac ->EMAC_CTL = EMAC_CTL_RE | EMAC_CTL_TE ;
pemac ->EMAC_IDR = 0xFFFFFFFF;
dummy = pemac ->EMAC_ISR;
/* Connect BDMA and MAC TX and RX interrupts */ /*modified by knp/nts 27/9/99 */
intConnect ( (VOIDFUNCPTR *)INUM_TO_IVEC ( pDrvCtrl->level ), at91EndInt, (UINT32) pDrvCtrl );
/* Enable all the four interrupts */ /*modified by knp/nts 27/9/9/99 */
intEnable ( pDrvCtrl->level );
/*
* enable interrupt if not in polling mode.
*/
if ( (pDrvCtrl->flags & LS_POLLING) == 0 )
pemac ->EMAC_IER = EMAC_ISR_RBNA /*| EMAC_ISR_TOVR*/ | EMAC_ISR_TUND | EMAC_ISR_RTRY
/*| EMAC_ISR_TBRE */| EMAC_ISR_TCOM | EMAC_ISR_ROVR | EMAC_ISR_HRESP | EMAC_ISR_RCOM;
/* Set the flags to indicate that the device is up */
END_FLAGS_SET (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
/*
ENDLOGMSG ((" leave at91EndStart...\n", 1, 2, 3, 4, 5, 6));
*/
return (OK);
}
/*******************************************************************************
* at91EndBdmaRxInt - handle controller interrupt
*
* This routine is called at interrupt level in response to an interrupt from
* the BdmaTx controller.
*
* RETURNS: N/A.
*/
LOCAL void TranNextPackage( at91end_device* pDrvCtrl )
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
if(
( (pDrvCtrl ->TxPtr) != (pDrvCtrl ->TxTailPtr) )
|| ( pDrvCtrl ->TXFifoStat == TXFIFOFULL )
)
{
/*
ENDLOGMSG ((" END:Interrupt pack sended ...\n", 1, 2, 3, 4, 5, 6));
*/
pemac ->EMAC_TAR = (UINT32)((pDrvCtrl ->pTxBufStart[pDrvCtrl ->TxPtr]).bufaddr);
/*
* write a length start the tans
*/
pemac ->EMAC_TCR = ( pDrvCtrl ->pTxBufStart[pDrvCtrl ->TxPtr]).len&(0x7FF) ;
if( pDrvCtrl ->TxPtr == (TX_FD_NUM - 1) )
pDrvCtrl ->TxPtr = 0;
else
pDrvCtrl ->TxPtr ++;
if( pDrvCtrl ->TxPtr == pDrvCtrl ->TxTailPtr )
{
pDrvCtrl ->TXFifoStat = TXFIFOEMPTY;
}
else
pDrvCtrl ->TXFifoStat = TXFIFONORMAL;
}
}
LOCAL void at91EndInt
(
at91end_device *pDrvCtrl /* interrupting device */
)
{
UINT32 status, txstatus;
EMAC_S* pemac = (EMAC_S*)(EMAC_BASE_ADDR);
char *nextp;
/*
* read the Int status register, clear ISR status at same time
*/
status = pemac ->EMAC_ISR;
if( status &
( EMAC_ISR_RBNA | EMAC_ISR_TOVR | EMAC_ISR_TUND | EMAC_ISR_TBRE
| EMAC_ISR_ROVR | EMAC_ISR_HRESP ) )
{
logMsg( "END: error occured, interrupt status reg is %x", status, 2,3,4,5,6 );
}
/*
* avoid dead lock of receive buf if not available
*/
/*
if( status & EMAC_ISR_RBNA )
{
pemac ->EMAC_CTL &= ( ~EMAC_CTL_RE );
pemac ->EMAC_CTL |= EMAC_CTL_RE;
}
*/
/*
* reflash error counter
*/
pDrvCtrl ->statistics.ESTAT_FRA += pemac ->ESTAT.EMAC_FRA;
pDrvCtrl ->statistics.ESTAT_SCOL+= pemac ->ESTAT.EMAC_SCOL;
pDrvCtrl ->statistics.ESTAT_MCOL+= pemac ->ESTAT.EMAC_MCOL;
pDrvCtrl ->statistics.ESTAT_OK += pemac ->ESTAT.EMAC_OK;
pDrvCtrl ->statistics.ESTAT_SEQE+= pemac ->ESTAT.EMAC_SEQE;
pDrvCtrl ->statistics.ESTAT_ALE += pemac ->ESTAT.EMAC_ALE;
pDrvCtrl ->statistics.ESTAT_DTE += pemac ->ESTAT.EMAC_DTE;
pDrvCtrl ->statistics.ESTAT_LCOL+= pemac ->ESTAT.EMAC_LCOL;
pDrvCtrl ->statistics.ESTAT_ECOL+= pemac ->ESTAT.EMAC_ECOL;
pDrvCtrl ->statistics.ESTAT_CSE += pemac ->ESTAT.EMAC_CSE;
pDrvCtrl ->statistics.ESTAT_TUE += pemac ->ESTAT.EMAC_TUE;
pDrvCtrl ->statistics.ESTAT_CDE += pemac ->ESTAT.EMAC_CDE;
pDrvCtrl ->statistics.ESTAT_ELR += pemac ->ESTAT.EMAC_ELR;
pDrvCtrl ->statistics.ESTAT_RJB += pemac ->ESTAT.EMAC_RJB;
pDrvCtrl ->statistics.ESTAT_USF += pemac ->ESTAT.EMAC_USF;
pDrvCtrl ->statistics.ESTAT_SQEE+= pemac ->ESTAT.EMAC_SQEE;
pDrvCtrl ->statistics.ESTAT_DRFC+= pemac ->ESTAT.EMAC_DRFC;
/*
* do receive job
*/
if( (pDrvCtrl ->NetJobDoing == FALSE) && ( status & EMAC_ISR_RCOM ) )
{
ENDLOGMSG ((" END:Interrupt pack received ...\n", 1, 2, 3, 4, 5, 6));
netJobAdd ((FUNCPTR)at91EndHandleRcvInt, (int)pDrvCtrl, status, 0 , 0 , 0 );
pDrvCtrl ->NetJobDoing = TRUE;
}
/*
* do transmit job
*/
txstatus = pemac ->EMAC_TSR;
if( /*(status&EMAC_ISR_TCOM )&&*/( txstatus & EMAC_TSR_BNQ ) )
{
/*
* TxPtr ->next ready to send package
* TxTailPtr ->Next to accept transmit package
*/
TranNextPackage( pDrvCtrl );
}
}
/*******************************************************************************
*
* at91EndHandleRcvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*
* RETURNS: N/A.
*/
LOCAL void at91EndHandleRcvInt
(
at91end_device *pDrvCtrl, /* interrupting device */
UINT32 stat /* receive status */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
AT91_END_RECV_FD* startadd = pDrvCtrl->RecvBufDesc;
ENDLOGMSG ((" Enter at91EndHandleRcvInt routine...\n", 1, 2, 3, 4, 5, 6));
pDrvCtrl ->NetJobDoing = FALSE;
while( (startadd[pDrvCtrl ->rxBufPtr].bufaddr) & EMAC_RECV_DESC_HAVE_DATA )
{
at91EndRecv ( pDrvCtrl, pDrvCtrl ->rxBufPtr );
/*
if( pDrvCtrl ->rxBufPtr == (RX_FD_NUM -1) )
{
pDrvCtrl ->rxBufPtr = 0;
}
else
pDrvCtrl ->rxBufPtr ++;
*/
}
ENDLOGMSG ((" Leave at91EndHandleRcvInt routine...\n", 1, 2, 3, 4, 5, 6));
}
/*******************************************************************************
*
* at91EndRecv - process the next incoming packet
*
* Handle one incoming packet. The packet is checked for errors.
*
* RETURNS: N/A.
*/
LOCAL STATUS at91EndRecv
(
at91end_device *pDrvCtrl, /* device structure */
UINT32 recvdescptr
)
{
M_BLK_ID pMblk;
char* pNewCluster;
CL_BLK_ID pClBlk;
UINT32 tmp;
UINT32 len;
/* Add one to our unicast data. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
/*
* We implicitly are loaning here, if copying is necessary this
* step may be skipped, but the data must be copied before being
* passed up to the protocols.
*/
pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId );
if (pNewCluster == NULL)
{
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
goto cleanRXD;
}
if( ((UINT32)pNewCluster)&3 )
{
ENDLOGMSG(( "END:handle recv get clust buffer not word aligned",(UINT32)pNewCluster,2,3,4,5,6 ));
}
/* Grab a cluster block to marry to the cluster we received. */
if ( (pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT) ) == NULL)
{
netClFree ( pDrvCtrl->end.pNetPool, pNewCluster );
END_ERR_ADD ( &pDrvCtrl->end, MIB2_IN_ERRS, +1 );
goto cleanRXD;
}
/*
* OK we've got a spare, let's get an M_BLK_ID and marry it to the
* one in the ring.
*/
if ((pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL)
{
netClBlkFree ( pDrvCtrl->end.pNetPool, pClBlk );
netClFree ( pDrvCtrl->end.pNetPool, pNewCluster );
END_ERR_ADD ( &pDrvCtrl->end, MIB2_IN_ERRS, +1 );
goto cleanRXD;
}
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
/* Join the cluster to the MBlock */
len = (pDrvCtrl ->RecvBufDesc[recvdescptr].recvstatus&(0x7ff));
bcopy ( pDrvCtrl ->clPointBuf[recvdescptr], pNewCluster+2, len );
/*
netClBlkJoin ( pClBlk, pDrvCtrl ->clPointBuf[recvdescptr], at91endClDescTbl[0].clSize, NULL, 0, 0, 0);
*/
netClBlkJoin ( pClBlk, pNewCluster, at91endClDescTbl[0].clSize, NULL, 0, 0, 0);
netMblkClJoin (pMblk, pClBlk);
tmp = 2;
/*
( ((pDrvCtrl ->RecvBufDesc)[recvdescptr].bufaddr&0xFFFFFFFC)
- (UINT32)(pDrvCtrl ->clPointBuf[recvdescptr]) );*/
pMblk->mBlkHdr.mData += tmp;
pMblk->mBlkHdr.mLen = len;
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = pMblk->mBlkHdr.mLen;
(pDrvCtrl ->RecvBufDesc)[recvdescptr].bufaddr &= 0xFFFFFFFE;
if( pDrvCtrl ->rxBufPtr == (RX_FD_NUM -1) )
{
pDrvCtrl ->rxBufPtr = 0;
}
else
pDrvCtrl ->rxBufPtr ++;
/* Call the upper layer's receive routine. */
END_RCV_RTN_CALL( &pDrvCtrl->end, pMblk );
/*
(pDrvCtrl ->clPointBuf)[recvdescptr] = pNewCluster;
tmp = ( ( (UINT32)pNewCluster+3 )&0xFFFFFFFC );
if( recvdescptr == (RX_FD_NUM -1) )
tmp |= EMAC_RECV_DESC_WRAP;
(pDrvCtrl ->RecvBufDesc)[recvdescptr].bufaddr = tmp;
*/
ENDLOGMSG( ( "END: leave at91EndRecv *******.\n", 1,2,3,4,5,6) );
return (OK);
cleanRXD:
ENDLOGMSG( ( "END: packet lost because of get cl or m or clust buffer failure.\n", 1,2,3,4,5,6) );
(pDrvCtrl ->RecvBufDesc)[recvdescptr].bufaddr &= 0xFFFFFFFE;
return (OK);
}
/*******************************************************************************
*
* at91EndSend - the driver send routine
*
* This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
* The buffer must already have the addressing information properly installed
* in it. This is done by a higher layer. The last arguments are a free
* routine to be called when the device is done with the buffer and a pointer
* to the argument to pass to the free routine.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndSend
(
at91end_device *pDrvCtrl, /* device ptr */
M_BLK_ID pNBuff /* data to send */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
BOOL freeNow = TRUE;
UINT32 curtailptr, txdelta;
UINT32 oldlevel;
char *txbuf;
/*
ENDLOGMSG ((" Enter at91EndSend routine...\n", 1, 2, 3, 4, 5, 6));
*/
oldlevel = intLock ();
curtailptr = pDrvCtrl ->TxTailPtr;
txdelta = TX_FD_NUM - curtailptr + (pDrvCtrl ->TxPtr);
if( txdelta >= TX_FD_NUM )
txdelta -= TX_FD_NUM;
if( (txdelta < 3) && ( pDrvCtrl ->TXFifoStat != TXFIFOEMPTY ) )
{
intUnlock( oldlevel );
return ERROR;
}
intUnlock( oldlevel );
/*
* Obtain exclusive access to transmitter. This is necessary because
* we might have more than one stack transmitting at once.
*/
END_TX_SEM_TAKE ( &pDrvCtrl->end, WAIT_FOREVER );
/*
* fifo now have space for new packet
*/
txbuf = (pDrvCtrl ->pTxBufStart)[curtailptr].bufaddr;
(pDrvCtrl ->pTxBufStart)[curtailptr].len = pNBuff->mBlkPktHdr.len;
/* Set pointers in local structures to point to data. */
netMblkToBufCopy( pNBuff, (void *)txbuf, NULL ) ;
/* place a transmit request */
oldlevel = intLock (); /* now at91EndInt won't get confused */
if( pDrvCtrl ->TxTailPtr == (TX_FD_NUM-1) )
pDrvCtrl ->TxTailPtr = 0;
else
pDrvCtrl ->TxTailPtr ++;
if( pDrvCtrl ->TxTailPtr == pDrvCtrl ->TxPtr )
pDrvCtrl ->TXFifoStat = TXFIFOFULL;
else
pDrvCtrl ->TXFifoStat = TXFIFONORMAL;
if( (pemac ->EMAC_TSR) & EMAC_TSR_BNQ )
{
/*
* TxPtr ->next ready to send package
* TxTailPtr ->Next to accept transmit package
*/
TranNextPackage( pDrvCtrl );
}
intUnlock (oldlevel); /* now at91EndInt won't get confused */
END_TX_SEM_GIVE (&pDrvCtrl->end);
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
/*
* Cleanup. The driver must either free the packet now or
* set up a structure so it can be freed later after a transmit
* interrupt occurs.
*/
if (freeNow)
netMblkClChainFree (pNBuff);
/*
ENDLOGMSG ((" Leave at91EndSend routine...\n", 1, 2, 3, 4, 5, 6));
*/
return (OK);
}
/*******************************************************************************
*
* at91EndIoctl - the driver I/O control routine
*
* Process an ioctl request.
*
* RETURNS: A command specific response, usually OK or ERROR.
*/
LOCAL int at91EndIoctl
(
at91end_device *pDrvCtrl, /* device receiving command */
int cmd, /* ioctl command code */
caddr_t data /* command argument */
)
{
int error = 0;
long value;
/*
ENDLOGMSG ((" Enter at91EndIoctl routine...\n", 1, 2, 3, 4, 5, 6));
*/
switch (cmd)
{
case EIOCSADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->end),
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCGADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)END_HADDR(&pDrvCtrl->end), (char *)data,
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCSFLAGS:
value = (long)data;
if (value < 0)
{
value = ~value;
END_FLAGS_CLR (&pDrvCtrl->end, value);
}
else
{
END_FLAGS_SET (&pDrvCtrl->end, value);
}
at91EndConfig (pDrvCtrl);
break;
case EIOCGFLAGS:
*(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
break;
case EIOCPOLLSTART:
at91EndPollStart (pDrvCtrl);
break;
case EIOCPOLLSTOP:
at91EndPollStop (pDrvCtrl);
break;
case EIOCGMIB2:
if (data == NULL)
return (EINVAL);
bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
sizeof(pDrvCtrl->end.mib2Tbl));
break;
case EIOCGFBUF:
if (data == NULL)
return (EINVAL);
*(int *)data = 0; /**END_MIN_FBUF;**/
break;
default:
error = EINVAL;
}
/*
ENDLOGMSG ((" Leave at91EndIoctl routine...\n", 1, 2, 3, 4, 5, 6));
*/
return (error);
}
/******************************************************************************
*
* at91EndConfig - reconfigure the interface under us.
*
* Reconfigure the interface setting promiscuous mode
*
* RETURNS: N/A.
*/
LOCAL void at91EndConfig
(
at91end_device *pDrvCtrl /* device to be re-configured */
)
{
at91EmacReset(pDrvCtrl); /* reset the chip */
/* Set up address filter for multicasting. */
if ( END_MULTI_LST_CNT( &pDrvCtrl->end ) > 0 )
at91EndAddrFilterSet ( pDrvCtrl );
at91EndFdFree(pDrvCtrl); /* Free the FDs */
at91EndFdInitialize(pDrvCtrl); /* Reinitialize FDs */
at91EndMacInitialize( pDrvCtrl ); /* Initialize MAC */
/* Was started before in interrupt mode? */
if ( (END_FLAGS_GET(&pDrvCtrl->end) & IFF_RUNNING) &&
((pDrvCtrl->flags & LS_POLLING) == 0) )
at91EndStart(pDrvCtrl); /* Start again */
return;
}
/*******************************************************************************
*
* at91EndPollStart - start polled mode operations
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndPollStart
(
at91end_device* pDrvCtrl /* device to be polled */
)
{
int oldLevel;
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
oldLevel = intLock (); /* disable ints during update */
intDisable (pDrvCtrl->level);
pDrvCtrl->flags |= LS_POLLING;
intUnlock (oldLevel); /* now at91EndInt won't get confused */
ENDLOGMSG (( "POLLing STARTED\n", 1, 2, 3, 4, 5, 6 ));
at91EndConfig (pDrvCtrl); /* reconfigure device */
/*
* enable receive
*/
pemac ->EMAC_CTL = EMAC_CTL_RE | EMAC_CTL_TE;
/* Set the flags to indicate that the device is up */
END_FLAGS_SET (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
return (OK);
}
/*******************************************************************************
*
* at91EndPollStop - stop polled mode operations
*
* This function terminates polled mode operation. The device returns to
* interrupt mode.
*
* The device interrupts are enabled, the current mode flag is switched
* to indicate interrupt mode and the device is then reconfigured for
* interrupt operation.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndPollStop
(
at91end_device* pDrvCtrl /* device to be changed */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
int oldLevel;
/*
* stop all
*/
pemac ->EMAC_CTL = 0;
oldLevel = intLock (); /* disable ints during register updates */
pDrvCtrl->flags &= ~LS_POLLING;
intUnlock (oldLevel);
/*
* Restart in interrupt mode. Calling at91EndConfig without clearing
* IFF_RUNNING flag will result in calling at91EndStart automatically
*/
at91EndConfig (pDrvCtrl);
ENDLOGMSG (("END POLLing STOPPED\n", 1, 2, 3, 4, 5, 6));
return (OK);
}
/*******************************************************************************
*
* at91EndPollRcv - routine to receive a packet in polled mode.
*
* This routine is called by a user to try and get a packet from the
* device.
*
* RETURNS: OK upon success. EAGAIN is returned when no packet is available.
*/
LOCAL STATUS at91EndPollRcv
(
at91end_device *pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* ptr to buffer */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
int len;
UINT32 rxptr;
STATUS retVal = EAGAIN;
ENDLOGMSG (( "entering at91EndPollRcv\n", 1, 2, 3, 4, 5, 6 ));
rxptr = pDrvCtrl ->rxBufPtr;
if( ( (pDrvCtrl ->RecvBufDesc[rxptr].bufaddr) & EMAC_RECV_DESC_HAVE_DATA ) == 0 )
return EAGAIN;
/* Upper layer must provide a valid buffer. */
len = pDrvCtrl ->RecvBufDesc[rxptr].recvstatus & (0x7FF) ;
if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
{
ENDLOGMSG( ( "END: poll receive buffer too small to fit received buffer\n", 1,2,3,4,5,6 ) );
goto pollRcvExit;
}
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
bcopy ( (char*)(pDrvCtrl ->RecvBufDesc[rxptr].bufaddr&0xFFFFFFFC), pMblk->m_data, len );
pMblk->m_len = len;
/*pMblk->mBlkHdr.mData += OFFSET;*/
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = len;
retVal = OK;
ENDLOGMSG ((" proces at91EndPollRcv OK\n", 1, 2, 3, 4, 5, 6));
pollRcvExit:
pDrvCtrl ->RecvBufDesc[rxptr].bufaddr &= 0xFFFFFFFE;
if( rxptr == (RX_FD_NUM-1) )
pDrvCtrl ->rxBufPtr = 0;
else
pDrvCtrl ->rxBufPtr ++;
return retVal;
}
/*******************************************************************************
*
* at91EndPollSend - routine to send a packet in polled mode.
*
* This routine is called by a user to try and send a packet on the
* device.
*
* RETURNS: OK upon success. EAGAIN if device is busy.
*/
LOCAL STATUS at91EndPollSend
(
at91end_device* pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* packet to send */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
UINT32 curTxptr = pDrvCtrl ->TxPtr;
int len;
ENDLOGMSG ((" enter at91EndPollSend\n", 1, 2, 3, 4, 5, 6 ));
if( !(pemac ->EMAC_TSR&EMAC_TSR_TXIDLE ) )
{
return EAGAIN;
}
len = pMblk->mBlkPktHdr.len;
/* Set pointers in local structures to point to data. */
netMblkToBufCopy(pMblk, (void *)pDrvCtrl ->pTxBufStart[curTxptr].bufaddr, NULL) ;
pDrvCtrl ->pTxBufStart[curTxptr].len = len;
/*
* start transmit
*/
pemac ->EMAC_TAR = (UINT32)pDrvCtrl ->pTxBufStart[curTxptr].bufaddr;
pemac ->EMAC_TCR = len&(0x7FF);
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
/*
* Cleanup. The driver must either free the packet now or
* set up a structure so it can be freed later after a transmit
* interrupt occurs.
*/
netMblkClChainFree (pMblk);
ENDLOGMSG (("leaving at91EndPollSend\n", 1, 2, 3, 4, 5, 6));
return (OK);
}
/******************************************************************************
*
* at91EndAddrFilterSet - set the address filter for multicast addresses
*
* This routine goes through all of the multicast addresses on the list
* of addresses (added with the endAddrAdd() routine) and sets the
* device's filter correctly.
*
* RETURNS: N/A.
*/
LOCAL void at91EndAddrFilterSet
(
at91end_device *pDrvCtrl /* device to be updated */
)
{
ETHER_MULTI* pCurr;
UINT32 count;
ENDLOGMSG ((" Enter at91EndAddrFilterSet routine...\n", 1, 2, 3, 4, 5, 6));
for ( count = 0; count < (AT91EMAC_MAX_MULTI+1); count++ )
{
pDrvCtrl->addrListLow[count] = /* Zero the addresses */
pDrvCtrl->addrListHigh[count] = 0;
}
pDrvCtrl->mcastAddrCount = 0; /* Init the multi count */
pCurr = END_MULTI_LST_FIRST ( &pDrvCtrl->end );
/*
* Now copy the addresses from ether_multi_list to our own array. In our
* array, the first 6 bytes are for our own MAC address. This array is
* an exact replica of the internal CAM registers of Ethernet controller.
* The CAM registers will be updated in at91EndMacInitialize() function
*/
while ( pCurr != NULL )
{
if (pDrvCtrl->mcastAddrCount > AT91EMAC_MAX_MULTI )
break;
FormatETHSpecialAddrWord( &( pDrvCtrl ->addrListHigh[ pDrvCtrl ->mcastAddrCount + 1 ] ),
&(pDrvCtrl ->addrListLow[ pDrvCtrl ->mcastAddrCount + 1 ]), (BYTE*)(pCurr->addr) );
pDrvCtrl ->mcastAddrCount++; /* Bump the multicast address count */
pCurr = END_MULTI_LST_NEXT(pCurr); /* Get the next address in the list */
}
ENDLOGMSG ((" Leave at91EndAddrFilterSet routine...\n", 1, 2, 3, 4, 5, 6));
}
/*****************************************************************************
*
* at91EndMCastAdd - add a multicast address for the device
*
* This routine adds a multicast address to whatever the driver
* is already listening for. It then resets the address filter.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndMCastAdd
(
at91end_device *pDrvCtrl, /* device pointer */
char* pAddress /* new address to add */
)
{
int error;
if ( (error = etherMultiAdd (&pDrvCtrl->end.multiList,
pAddress)) == ENETRESET )
at91EndConfig (pDrvCtrl);
return (OK);
}
/*****************************************************************************
*
* at91EndMCastDel - delete a multicast address for the device
*
* This routine removes a multicast address from whatever the driver
* is listening for. It then resets the address filter.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndMCastDel
(
at91end_device* pDrvCtrl, /* device pointer */
char* pAddress /* address to be deleted */
)
{
int error;
if ((error = etherMultiDel (&pDrvCtrl->end.multiList,
(char *)pAddress)) == ENETRESET)
at91EndConfig (pDrvCtrl);
return (OK);
}
/*****************************************************************************
*
* at91EndMCastGet - get the multicast address list for the device
*
* This routine gets the multicast list of whatever the driver
* is already listening for.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndMCastGet
(
at91end_device* pDrvCtrl, /* device pointer */
MULTI_TABLE* pTable /* address table to be filled in */
)
{
int error;
error = etherMultiGet (&pDrvCtrl->end.multiList, pTable);
return (error);
}
/*******************************************************************************
*
* at91EndStop - stop the device
*
* This function calls BSP functions to disconnect interrupts and stop
* the device from operating in interrupt mode.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndStop
(
at91end_device *pDrvCtrl /* device to be stopped */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
ENDLOGMSG ((" Enter at91EndStop routine...\n", 1, 2, 3, 4, 5, 6));
/*
* disable rx and tx, and int
*/
pemac ->EMAC_CTL = EMAC_CTL_CSR;
pemac ->EMAC_IDR = 0xFFFFFFFF;
intDisable ( pDrvCtrl->level );
END_FLAGS_CLR (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
ENDLOGMSG ((" Leave at91EndStop routine...\n", 1, 2, 3, 4, 5, 6));
return (OK);
}
/******************************************************************************
*
* at91EndUnload - unload a driver from the system
*
* This function first brings down the device, and then frees any
* stuff that was allocated by the driver in the load function.
*
* RETURNS: OK or ERROR.
*/
LOCAL void FreeEndMemory( at91end_device* pDrvCtrl )
{
if ( pDrvCtrl->end.pNetPool )
{
netPoolDelete (pDrvCtrl->end.pNetPool);
free (pDrvCtrl->end.pNetPool);
pDrvCtrl->end.pNetPool = (NET_POOL_ID)0;
}
if (at91endClDescTbl[0].memArea)
{
cacheDmaFree (at91endClDescTbl[0].memArea);
at91endClDescTbl[0].memArea = (char *)0;
}
if( pDrvCtrl ->TranFifoBuf )
{
cacheDmaFree( pDrvCtrl ->TranFifoBuf );
pDrvCtrl ->RecvBufDesc = NULL;
pDrvCtrl ->TranFifoBuf = NULL;
pDrvCtrl ->RecvFifoBuf = NULL;
bzero( (void*)&(pDrvCtrl->pTxBufStart[0]), sizeof( AT91_END_TRAN_FD )*TX_FD_NUM );
}
if (at91endMclConfig.memArea)
{
free (at91endMclConfig.memArea);
at91endMclConfig.memArea = (char *)0;
}
if (pDrvCtrl)
{
free (pDrvCtrl);
(at91end_device*)pDrvCtrl = 0;
}
}
LOCAL STATUS at91EndUnload
(
at91end_device* pDrvCtrl /* device to be unloaded */
)
{
END_OBJECT_UNLOAD (&pDrvCtrl->end); /*this call will indicate */
/* protocol that the device will be unloaded */
/* TODO - Free any shared DMA memory */
at91EndStop(pDrvCtrl); /*before unloading the device will stop functioning*/
at91EmacReset(pDrvCtrl); /*then it will reset the registers in order to clear any pending interrupts */
at91EndFdFree(pDrvCtrl);
FreeEndMemory( pDrvCtrl );
return (OK);
}
/******************************************************************************
* at91EmacReset - Reset the device
* This function resets the driver after initializing from at91EndLoad
*/
LOCAL void at91EmacReset
(
at91end_device* pDrvCtrl /* device to be reset */
)
{
UINT32 dummy, i;
UINT32 tmp = 0xFFFFFFFF;
EMAC_S *pemac = (EMAC_S*)EMAC_BASE_ADDR;
if(pDrvCtrl->unit != 0)
return;
/*
* disable interrupt first
*/
pemac ->EMAC_IDR = 0xFFFFFFFF;
/*
* disable recive and transmit
*/
pemac ->EMAC_CTL = EMAC_CTL_CSR;
/*
* config EMAC state, MAX HCLK = (60-100)/16 < 8M (for LXT971)
*/
pemac ->EMAC_CFG = EMAC_CFG_CLK_HCLK_16 | EMAC_CFG_SPD | EMAC_CFG_RMII /*| EMAC_CFG_MTI | EMAC_CFG_UNI*/;
/*
* clear transmit and receive status bit
*/
pemac ->EMAC_TSR = tmp;
pemac ->EMAC_RSR = tmp;
/*
* clear interrupt status REG
*/
dummy = pemac ->EMAC_ISR;
/*
* set all statistic regoster by read it
*/
for( i = 0; i< sizeof(ETH_STAT_S)/sizeof(AT91_REG); i++ )
{
dummy = ( (AT91_REG*)( &(pemac ->ESTAT ) ) )[i];
}
/*
* after reset, we need to set address for mac
*/
/*
*
*/
return;
}
/******************************************************************************
* at91EndPhyRead - Read PHY device
* This function is used to read a byte from the PHY device
*/
LOCAL UINT32 at91EndPhyRead
(
UINT32 phyRegAddr, /* Address of PHY register to be read */
UINT32 phyAddr /* Address of the PHY chip (usually 0 for single PHY) */
)
{
EMAC_S* regs = (EMAC_S*)EMAC_BASE_ADDR;
UINT32 dummy;
regs->EMAC_MAN = EMAC_PHY_HIGH | EMAC_PHY_CODE | EMAC_PHY_RW_R
| (phyRegAddr << 18);
/* Wait until IDLE bit in Network Status register is cleared */
/* TODO: Enforce some maximum loop-count?*/
dummy = 0;
while ( !(regs->EMAC_SR & EMAC_SR_IDLE)&& (dummy++ < 10000) ) ;
return ( regs->EMAC_MAN & 0x0000ffff );
}
/******************************************************************************
* at91EndPhyWrite - Wrire into PHY device
* This function is used to write a byte to the PHY device
*/
LOCAL void at91EndPhyWrite
(
UINT32 phyRegAddr, /* Address of PHY register to be written */
UINT32 phyAddr, /* Address of the PHY chip (usually 0 for single PHY) */
UINT32 phyData /* Data to be written */
)
{
EMAC_S* regs = (EMAC_S*)EMAC_BASE_ADDR;
UINT32 dummy;
regs->EMAC_MAN = (EMAC_PHY_HIGH | EMAC_PHY_CODE | EMAC_PHY_RW_R
| (phyRegAddr << 18)) + (phyData & 0xffff);
/* Wait until IDLE bit in Network Status register is cleared */
/* TODO: Enforce some maximum loop-count?*/
dummy = 0;
while (!(regs->EMAC_SR & EMAC_SR_IDLE)&(dummy++ < 10000) ) ;
}
/******************************************************************************
* at91EndMacIntialize - Initialize MAC/BDMA registers
* Initialize the MAC and BDMA registers to make the Ethernet interface functional
*/
LOCAL void at91EndMacInitialize
(
at91end_device *pDevice /* Device that has to be initialized */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
/*
* set the first address as the IF mac address
*/
FormatETHSpecialAddrWord( &(pDevice ->addrListHigh[0]),
&(pDevice ->addrListLow[0]), (BYTE*)pDevice->enetAddr );
/*
* write the special address to chip
*/
pemac ->EMAC_SA1L = pDevice ->addrListLow[0];
pemac ->EMAC_SA1H = pDevice ->addrListHigh[0];
if( pDevice ->mcastAddrCount > 0 )
{
pemac ->EMAC_SA2L = pDevice ->addrListLow[1];
pemac ->EMAC_SA2H = pDevice ->addrListHigh[1];
}
else
{
pemac ->EMAC_SA2L = 0;
pemac ->EMAC_SA2H = 0;
}
if( pDevice ->mcastAddrCount > 1 )
{
pemac ->EMAC_SA3L = pDevice ->addrListLow[2];
pemac ->EMAC_SA3H = pDevice ->addrListHigh[2];
}
else
{
pemac ->EMAC_SA3L = 0;
pemac ->EMAC_SA3H = 0;
}
if( pDevice ->mcastAddrCount > 2 )
{
pemac ->EMAC_SA4L = pDevice ->addrListLow[3];
pemac ->EMAC_SA4H = pDevice ->addrListHigh[3];
}
else
{
pemac ->EMAC_SA4L = 0;
pemac ->EMAC_SA4H = 0;
}
/*
* what use for hash reg?, write all one first
*/
pemac ->EMAC_HSH = 0xFFFFFFFF;
pemac ->EMAC_HSL = 0xFFFFFFFF;
/*
* setup receive buffer address
*/
pemac ->EMAC_RBQP = (AT91_REG)(pDevice ->RecvBufDesc);
/*
* write configuration register again, do not allow mulitcast and unicast
*/
pemac ->EMAC_CFG = EMAC_CFG_CLK_HCLK_16 | EMAC_CFG_SPD | EMAC_CFG_RMII /*| EMAC_CFG_MTI | EMAC_CFG_UNI*/;
return;
}
/**********************************************************************************
* at91EndFdInitialize - Initialize TX and RX FD lists
* Make a circular list of Rx and TX frame descriptors and buffers.
* Two global variables gpReceiveFrameDescStart and gpTransmitFrameDescStart
* stores the pointer to the start of the list. BDMA TX/RX PTR registers are
* also initialized with the start of the appropriate list.
*/
LOCAL STATUS at91EndFdInitialize
(
at91end_device* pDrvCtrl /* device to be initialized */
)
{
int count;
char *pNewCluster;
if( pDrvCtrl ->RecvFifoBuf == NULL )
{
ENDLOGMSG( ( "END: at91EndFdInitialize find RX fifo have no buffer, something gong wrong ! ", 1,2,3,4,5,6 ));
at91EndFdFree( pDrvCtrl );
return (ERROR);
}
for( count = 0; count < RX_FD_NUM; count++ )
{
pNewCluster = pDrvCtrl ->RecvFifoBuf + count*(pDrvCtrl ->TranPkgSize);
/* netClusterGet ( pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId );*/
/*
if ( pNewCluster == NULL )
{
ENDLOGMSG(( "END:Get clust failure in routine at91EndFdInitialize\n", 1,2,3,4,5, 6 ));
at91EndFdFree( pDrvCtrl );
return ERROR;
}
*/
pDrvCtrl ->clPointBuf[ count ] = pNewCluster;
if( ((UINT32)pNewCluster)&0x3 != 0 )
{
ENDLOGMSG(( "END:receive buffer address not at wordalign in routine at91EndFdInitialize. point: %x\n", (UINT32)pNewCluster ,2,3,4,5, 6 ))
}
/*
* just make the point align to word
*/
(pDrvCtrl ->RecvBufDesc)[count].bufaddr = ( ( ((UINT32)pNewCluster)+3 )&(0xFFFFFFFC) );
(pDrvCtrl ->RecvBufDesc)[count].recvstatus = 0;
}/* end of for loop*/
(pDrvCtrl ->RecvBufDesc)[RX_FD_NUM - 1].bufaddr |= EMAC_RECV_DESC_WRAP;
pDrvCtrl ->rxBufPtr = 0;
/*
* initialize tx desc query
*/
if( (pDrvCtrl ->TranFifoBuf) == NULL )
{
ENDLOGMSG( ( "END: at91EndFdInitialize find TX fifo have no buffer, something gong wrong ! ", 1,2,3,4,5,6 ));
at91EndFdFree( pDrvCtrl );
return (ERROR);
}
for( count = 0; count < TX_FD_NUM; count ++ )
{
(pDrvCtrl ->pTxBufStart)[ count ].bufaddr =
pDrvCtrl ->TranFifoBuf + count*(pDrvCtrl ->TranPkgSize);
(pDrvCtrl ->pTxBufStart)[ count ].owner = 0; /*init owner to software */
}
pDrvCtrl ->TxTailPtr = pDrvCtrl ->TxPtr = 0;
pDrvCtrl ->TXFifoStat = TXFIFOEMPTY;
pDrvCtrl->fdInitialized = TRUE;
return OK;
}
/******************************************************************************
* at91EndFdFree - Free the allocated TX and RX FD lists and buffers
* This function frees all the allocated TX and RX FDs and the associated
* buffers
*/
LOCAL void at91EndFdFree
(
at91end_device* pDrvCtrl /* device to be freed */
)
{
UINT32 count;
char* tmpcl;
/*
if (pDrvCtrl->fdInitialized == FALSE)
return;
*/
/*
if( pDrvCtrl ->RecvBufDesc )
{
for ( count = 0; count < RX_FD_NUM; count++ )
{
tmpcl = pDrvCtrl ->clPointBuf[ count ];
if( tmpcl )
{
netClFree (pDrvCtrl->end.pNetPool, tmpcl );
}
(pDrvCtrl ->RecvBufDesc)[count].bufaddr = 0;
pDrvCtrl ->clPointBuf[ count ] = NULL;
}
}
*/
pDrvCtrl->fdInitialized = FALSE;
}
#endif /* INCLUDE_SNDS_END */