You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2986 lines
81 KiB
2986 lines
81 KiB
/* vxbFtGmacEnd.c - GMAC driver */
|
|
|
|
/*
|
|
*
|
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <intLib.h>
|
|
#include <logLib.h>
|
|
#include <muxLib.h>
|
|
#include <netLib.h>
|
|
#include <netBufLib.h>
|
|
#include <semLib.h>
|
|
#include <sysLib.h>
|
|
#include <vxBusLib.h>
|
|
#include <wdLib.h>
|
|
#include <etherMultiLib.h>
|
|
#include <end.h>
|
|
#define END_MACROS
|
|
|
|
#include <endLib.h>
|
|
#include <cacheLib.h>
|
|
#include <vxAtomicLib.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/vxbus/hwConf.h>
|
|
#include <hwif/vxbus/vxbPlbLib.h>
|
|
#include <hwif/util/vxbParamSys.h>
|
|
#include <../src/hwif/h/mii/miiBus.h>
|
|
#include <../src/hwif/h/vxbus/vxbAccess.h>
|
|
#include <../src/hwif/h/hEnd/hEnd.h>
|
|
#include "vxbFtGmacEnd.h"
|
|
|
|
IMPORT int uartf(const char * fmt, ...);
|
|
|
|
#define GMAC_MTU 1500
|
|
|
|
#define MAC_MAX_FRAME_SZ (2048)
|
|
|
|
#define RX_FRAME_ERROR_TYPE1 \
|
|
(RDES0_DESCRIPTOR_ERROR | RDES0_SA_FILTER_FAIL | \
|
|
RDES0_OVERFLOW_ERROR | RDES0_IPC_CSUM_ERROR | RDES0_COLLISION | \
|
|
RDES0_CRC_ERROR | RDES0_DRIBBLING | RDES0_LENGTH_ERROR | RDES0_MII_ERROR)
|
|
|
|
#define RX_FRAME_ERROR_TYPE2 \
|
|
(/*RDES0_DRIBBLING |*/ RDES0_LENGTH_ERROR | RDES0_MII_ERROR)
|
|
|
|
#define GMAC_END_DEBUG
|
|
|
|
#ifdef GMAC_END_DEBUG
|
|
# define GMAC_DEBUG(fmt,a,b,c,d,e,f) \
|
|
if (_func_logMsg) \
|
|
(* _func_logMsg) (fmt,a,b,c,d,e,f)
|
|
#else /* GMAC_END_DEBUG */
|
|
# define GMAC_DEBUG(fmt,a,b,c,d,e,f)
|
|
#endif /* GMAC_END_DEBUG */
|
|
|
|
/* forward declarations */
|
|
|
|
IMPORT FUNCPTR _func_m2PollStatsIfPoll;
|
|
|
|
IMPORT STATUS sysNetMacNVRamAddrGet (char *, int, UINT8 *, int);
|
|
|
|
/* VxBus methods */
|
|
|
|
LOCAL void ftGmacInstInit (VXB_DEVICE_ID);
|
|
LOCAL void ftGmacInstInit2 (VXB_DEVICE_ID);
|
|
LOCAL void ftGmacInstConnect (VXB_DEVICE_ID);
|
|
LOCAL STATUS ftGmacInstUnlink (VXB_DEVICE_ID, void *);
|
|
|
|
/* miiBus methods */
|
|
|
|
LOCAL STATUS ftGmacPhyRead (VXB_DEVICE_ID, UINT8, UINT8, UINT16 *);
|
|
LOCAL STATUS ftGmacPhyWrite (VXB_DEVICE_ID, UINT8, UINT8, UINT16);
|
|
LOCAL STATUS ftGmacLinkUpdate (VXB_DEVICE_ID);
|
|
LOCAL STATUS ftGmacReset (VXB_DEVICE_ID);
|
|
|
|
/* mux methods */
|
|
|
|
LOCAL void ftGmacMuxConnect (VXB_DEVICE_ID, void *);
|
|
LOCAL int ftGmacPhyAddrGet (VXB_DEVICE_ID pDev);
|
|
|
|
LOCAL struct drvBusFuncs ftGmacFuncs =
|
|
{
|
|
ftGmacInstInit, /* devInstanceInit */
|
|
ftGmacInstInit2, /* devInstanceInit2 */
|
|
ftGmacInstConnect /* devConnect */
|
|
};
|
|
|
|
LOCAL struct vxbDeviceMethod ftGmacMethods[] =
|
|
{
|
|
DEVMETHOD(miiRead, ftGmacPhyRead),
|
|
DEVMETHOD(miiWrite, ftGmacPhyWrite),
|
|
DEVMETHOD(miiMediaUpdate, ftGmacLinkUpdate),
|
|
DEVMETHOD(muxDevConnect, ftGmacMuxConnect),
|
|
DEVMETHOD(vxbDrvUnlink, ftGmacInstUnlink),
|
|
{ 0, 0 }
|
|
};
|
|
|
|
/* default queue parameters */
|
|
|
|
LOCAL HEND_RX_QUEUE_PARAM ftGmacRxQueueDefault =
|
|
{
|
|
NULL, /* jobQueId */
|
|
0, /* priority */
|
|
0, /* rbdNum */
|
|
0, /* rbdTupleRatio */
|
|
0, /* rxBufSize */
|
|
NULL, /* pBufMemBase */
|
|
0, /* rxBufMemSize */
|
|
0, /* rxBufMemAttributes */
|
|
NULL, /* rxBufMemFreeMethod */
|
|
NULL, /* pRxBdBase */
|
|
0, /* rxBdMemSize */
|
|
0, /* rxBdMemAttributes */
|
|
NULL /* rxBdMemFreeMethod */
|
|
};
|
|
|
|
LOCAL HEND_TX_QUEUE_PARAM ftGmacTxQueueDefault =
|
|
{
|
|
NULL, /* jobQueId */
|
|
0, /* priority */
|
|
0, /* tbdNum */
|
|
0, /* allowedFrags */
|
|
NULL, /* pTxBdBase */
|
|
0, /* txBdMemSize */
|
|
0, /* txBdMemAttributes */
|
|
NULL /* txBdMemFreeMethod */
|
|
};
|
|
|
|
LOCAL VXB_PARAMETERS ftGmacParamDefaults[] =
|
|
{
|
|
{"rxQueue00", VXB_PARAM_POINTER, {(void *)&ftGmacRxQueueDefault}},
|
|
{"txQueue00", VXB_PARAM_POINTER, {(void *)&ftGmacTxQueueDefault}},
|
|
{NULL, VXB_PARAM_END_OF_LIST, {NULL}}
|
|
};
|
|
|
|
LOCAL struct vxbPlbRegister ftGmacDevPlbRegistration =
|
|
{
|
|
{
|
|
NULL, /* pNext */
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
VXB_BUSID_PLB, /* busID = PLB */
|
|
VXB_VER_4_0_0, /* vxbVersion */
|
|
GMAC_NAME, /* drvName */
|
|
&ftGmacFuncs, /* pDrvBusFuncs */
|
|
NULL, /* pMethods */
|
|
NULL, /* devProbe */
|
|
ftGmacParamDefaults /* pParamDefaults */
|
|
},
|
|
};
|
|
|
|
/* END functions */
|
|
|
|
/*LOCAL STATUS ftGmacReset (VXB_DEVICE_ID pDev);*/
|
|
LOCAL END_OBJ * ftGmacEndLoad (char *, void *);
|
|
LOCAL STATUS ftGmacEndUnload (END_OBJ *);
|
|
LOCAL int ftGmacEndIoctl (END_OBJ *, int, caddr_t);
|
|
LOCAL STATUS ftGmacEndMCastAddrAdd (END_OBJ *, char *);
|
|
LOCAL STATUS ftGmacEndMCastAddrDel (END_OBJ *, char *);
|
|
LOCAL STATUS ftGmacEndMCastAddrGet (END_OBJ *, MULTI_TABLE *);
|
|
LOCAL void ftGmacEndHashTblPopulate (GMAC_DRV_CTRL *);
|
|
LOCAL STATUS ftGmacEndStatsDump (GMAC_DRV_CTRL *);
|
|
LOCAL void ftGmacEndRxConfig (GMAC_DRV_CTRL *);
|
|
LOCAL STATUS ftGmacEndStart (END_OBJ *);
|
|
LOCAL STATUS ftGmacEndStop (END_OBJ *);
|
|
LOCAL int ftGmacEndSend (END_OBJ *, M_BLK_ID);
|
|
LOCAL STATUS ftGmacEndPollSend (END_OBJ *, M_BLK_ID);
|
|
LOCAL int ftGmacEndPollReceive (END_OBJ *, M_BLK_ID);
|
|
LOCAL void ftGmacEndInt (GMAC_DRV_CTRL *);
|
|
LOCAL void ftGmacEndRxHandle ( GMAC_DRV_CTRL * pDrvCtrl);
|
|
LOCAL void ftGmacEndTxHandle ( GMAC_DRV_CTRL * pDrvCtrl);
|
|
LOCAL void ftGmacEndIntHandle (void *);
|
|
LOCAL void ftGmacRxDescInit(GMAC_DESC * desc, int index, UINT32 phyAddr);
|
|
|
|
LOCAL NET_FUNCS ftGmacNetFuncs =
|
|
{
|
|
ftGmacEndStart, /* start func. */
|
|
ftGmacEndStop, /* stop func. */
|
|
ftGmacEndUnload, /* unload func. */
|
|
ftGmacEndIoctl, /* ioctl func. */
|
|
ftGmacEndSend, /* send func. */
|
|
ftGmacEndMCastAddrAdd, /* multicast add func. */
|
|
ftGmacEndMCastAddrDel, /* multicast delete func. */
|
|
ftGmacEndMCastAddrGet, /* multicast get fun. */
|
|
ftGmacEndPollSend, /* polling send func. */
|
|
ftGmacEndPollReceive, /* polling receive func. */
|
|
endEtherAddressForm, /* put address info into a NET_BUFFER */
|
|
endEtherPacketDataGet, /* get pointer to data in NET_BUFFER */
|
|
endEtherPacketAddrGet /* Get packet addresses */
|
|
};
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacRegister - register with the VxBus subsystem
|
|
*
|
|
* This routine registers the ftGmac end driver with VxBus
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
void ftGmacRegister(void)
|
|
{
|
|
vxbDevRegister((struct vxbDevRegInfo *)&ftGmacDevPlbRegistration);
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacInstInit - VxBus instInit handler
|
|
*
|
|
* This function implements the VxBus instInit handler for an ftGmac
|
|
* device instance. The only thing done here is to select a unit
|
|
* number for the device.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacInstInit
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
{
|
|
|
|
const struct hcfDevice * pHcf;
|
|
|
|
/* always use the unit number allocated in the hwconf.c file */
|
|
|
|
pHcf = hcfDeviceGet (pDev);
|
|
if (pHcf != NULL)
|
|
vxbInstUnitSet (pDev, pHcf->devUnit);
|
|
|
|
/* publish methods */
|
|
|
|
pDev->pMethods = ftGmacMethods;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacInstInit2 - VxBus instInit2 handler
|
|
*
|
|
* This function implements the VxBus instInit2 handler for an ftGmac
|
|
* device instance. Once we reach this stage of initialization, it's
|
|
* safe for us to allocate memory, so we can create our pDrvCtrl
|
|
* structure and do some initial hardware setup. The important
|
|
* steps we do here are to create a child miiBus instance, connect
|
|
* our ISR to our assigned interrupt vector, read the station
|
|
* address from NVRAM.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacInstInit2
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
const struct hcfDevice * pHcf;
|
|
FUNCPTR ifCachedFunc = NULL;
|
|
BOOL exFlag = FALSE;
|
|
|
|
pDrvCtrl = malloc (sizeof (GMAC_DRV_CTRL));
|
|
|
|
if (pDrvCtrl == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pHcf = hcfDeviceGet(pDev);
|
|
if (pHcf == NULL)
|
|
{
|
|
free (pDrvCtrl);
|
|
return;
|
|
}
|
|
|
|
bzero ((char *)pDrvCtrl, sizeof(GMAC_DRV_CTRL));
|
|
|
|
pDev->pDrvCtrl = pDrvCtrl;
|
|
pDrvCtrl->gmacDev = pDev;
|
|
pDrvCtrl->unit = pDev->unitNumber;
|
|
|
|
pDrvCtrl->gmacBar = pDev->pRegBase[0];
|
|
vxbRegMap (pDev, 0, &pDrvCtrl->gmacHandle);
|
|
|
|
pDrvCtrl->gmacDevSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE |
|
|
SEM_INVERSION_SAFE);
|
|
|
|
SPIN_LOCK_ISR_INIT (&pDrvCtrl->gmacLock, 0);
|
|
|
|
if (pHcf != NULL)
|
|
{
|
|
|
|
(void) devResourceGet (pHcf, "ifCached", HCF_RES_ADDR,
|
|
(void *) &ifCachedFunc);
|
|
|
|
if (ifCachedFunc != NULL)
|
|
pDrvCtrl->ifCached = ifCachedFunc;
|
|
else
|
|
pDrvCtrl->ifCached = NULL;
|
|
|
|
|
|
(void) devResourceGet (pHcf, "isExPhy", HCF_RES_INT,
|
|
(void *) &exFlag);
|
|
pDrvCtrl->gmacExPhy = exFlag;
|
|
}
|
|
|
|
(void) vxbIntConnect (pDev, 0, ftGmacEndInt, pDrvCtrl);
|
|
|
|
pDrvCtrl->gmacMiiSem = semMCreate (SEM_Q_PRIORITY |
|
|
SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
|
|
|
|
|
|
if ((pDrvCtrl->gmacRxDescMem =
|
|
cacheDmaMalloc (sizeof(GMAC_DESC) * GMAC_RX_DESC_CNT +
|
|
sizeof(GMAC_DESC) * GMAC_TX_DESC_CNT + 128)) == NULL)
|
|
printf ("gmac%d: could not allocate descriptor memory\n",
|
|
pDev->unitNumber, 0, 0, 0, 0, 0);
|
|
|
|
pDrvCtrl->gmacRxDescMem = (GMAC_DESC *)ROUND_UP (pDrvCtrl->gmacRxDescMem, 128);
|
|
pDrvCtrl->gmacTxDescMem = (GMAC_DESC *)(pDrvCtrl->gmacRxDescMem + GMAC_RX_DESC_CNT);
|
|
|
|
|
|
|
|
/*pDrvCtrl->gmacIntrs = GEM_INTRS;*/
|
|
|
|
/* reset the device */
|
|
|
|
/*ftGmacReset(pDev);*/
|
|
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacInstConnect - VxBus instConnect handler
|
|
*
|
|
* This function implements the VxBus instConnect handler for an ftGmac
|
|
* device instance.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacInstConnect
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacInstUnlink - VxBus unlink handler
|
|
*
|
|
* This function shuts down an ftGmac device instance in response to an
|
|
* unlink event from VxBus. This may occur if our VxBus instance has
|
|
* been terminated, or if the ftGmac driver has been unloaded. When an
|
|
* unlink event occurs, we must shut down and unload the END interface
|
|
* associated with this device instance and then release all the
|
|
* resources allocated during instance creation. We also must destroy
|
|
* our child miiBus and PHY devices.
|
|
*
|
|
* RETURNS: OK if device was successfully destroyed, otherwise ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacInstUnlink
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
void * unused
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
|
|
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
/*
|
|
* Stop the device and detach from the MUX.
|
|
* Note: it's possible someone might try to delete
|
|
* us after our vxBus instantiation has completed,
|
|
* but before anyone has called our muxConnect method.
|
|
* In this case, there'll be no MUX connection to
|
|
* tear down, so we can skip this step.
|
|
*/
|
|
|
|
if (pDrvCtrl->gmacMuxDevCookie != NULL)
|
|
{
|
|
if (muxDevStop (pDrvCtrl->gmacMuxDevCookie) != OK)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
/* Detach from the MUX. */
|
|
|
|
if (muxDevUnload (GMAC_NAME, pDev->unitNumber) != OK)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
}
|
|
/* free descBuf */
|
|
|
|
(void) cacheDmaFree (pDrvCtrl->gmacRxDescMem);
|
|
|
|
/* Disconnect the ISR. */
|
|
|
|
vxbIntDisconnect (pDev, 0, ftGmacEndInt, pDrvCtrl);
|
|
|
|
/* Destroy our MII bus and child PHYs. */
|
|
|
|
if (pDrvCtrl->gmacMiiBus != NULL)
|
|
{
|
|
(void) miiBusDelete (pDrvCtrl->gmacMiiBus);
|
|
(void) semDelete (pDrvCtrl->gmacMiiSem);
|
|
}
|
|
|
|
/* Destroy the adapter context. */
|
|
|
|
free (pDrvCtrl);
|
|
pDev->pDrvCtrl = NULL;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
|
|
|
|
LOCAL STATUS ftGmacMiiTimeoutPoll
|
|
(VXB_DEVICE_ID pDev, UINT32 offset, UINT32 value, UINT32 timeout)
|
|
{
|
|
volatile UINT32 counter;
|
|
volatile UINT32 status;
|
|
|
|
counter = 0;
|
|
|
|
do
|
|
{
|
|
status = CSR_READ_4(pDev, offset) & value;
|
|
}while((counter++ < timeout) && (status == value));
|
|
|
|
if(counter >= timeout)
|
|
{
|
|
printf(" ftGmacMiiTimeoutPoll !!!!!. offset: 0x%0x value: 0x%x \n", offset, value);
|
|
return ERROR;
|
|
}
|
|
else
|
|
return OK;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacPhyRead - miiBus miiRead method
|
|
*
|
|
* This function implements an miiRead() method that allows PHYs on the miiBus
|
|
* to access our MII managmacent registers.
|
|
*
|
|
* RETURNS: ERROR if invalid PHY addr or register is specified, else OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacPhyRead
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 phyAddr,
|
|
UINT8 regAddr,
|
|
UINT16 * dataVal
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
UINT32 mii_val;
|
|
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
if (pDrvCtrl->gmacMiiDev == NULL)
|
|
{
|
|
*dataVal = 0xFFFF;
|
|
return (ERROR);
|
|
}
|
|
|
|
if ((pDrvCtrl->gmacMiiPhyAddr != -1) && (phyAddr != pDrvCtrl->gmacMiiPhyAddr) && (phyAddr < 32))
|
|
{
|
|
*dataVal = 0xFFFF;
|
|
return (ERROR);
|
|
}
|
|
|
|
semTake (pDrvCtrl->gmacMiiSem, WAIT_FOREVER);
|
|
|
|
mii_val = 0;
|
|
mii_val |= (pDrvCtrl->clkMDC<<2) & 0x0000003C;
|
|
mii_val |= (phyAddr << 11) & 0x0000F800;
|
|
mii_val |= (regAddr << 6) & 0x000007C0;
|
|
mii_val |= MII_BUSY;
|
|
|
|
if(ftGmacMiiTimeoutPoll(pDev, GMAC_MII_ADDR, MII_BUSY, 10000000) == -1)
|
|
{
|
|
*dataVal = 0xFFFF;
|
|
semGive (pDrvCtrl->gmacMiiSem);
|
|
return ERROR;
|
|
}
|
|
|
|
CSR_WRITE_4(pDev, GMAC_MII_ADDR, mii_val);
|
|
|
|
if(ftGmacMiiTimeoutPoll(pDev, GMAC_MII_ADDR, MII_BUSY, 10000000) == -1)
|
|
{
|
|
*dataVal = 0xFFFF;
|
|
semGive (pDrvCtrl->gmacMiiSem);
|
|
return ERROR;
|
|
}
|
|
|
|
*dataVal = CSR_READ_4(pDev, GMAC_MII_DATA);
|
|
semGive (pDrvCtrl->gmacMiiSem);
|
|
return OK;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacPhyWrite - miiBus miiWrite method
|
|
*
|
|
* This function implements an miiWrite() method that allows PHYs on the miiBus
|
|
* to access our MII managmacent registers.
|
|
*
|
|
* RETURNS: ERROR if invalid PHY addr or register is specified, else OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacPhyWrite
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 phyAddr,
|
|
UINT8 regAddr,
|
|
UINT16 dataVal
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
UINT32 mii_val;
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
if (pDrvCtrl->gmacMiiDev == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (phyAddr != pDrvCtrl->gmacMiiPhyAddr && phyAddr < 32)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
semTake (pDrvCtrl->gmacMiiSem, WAIT_FOREVER);
|
|
|
|
mii_val = 0;
|
|
mii_val |= (pDrvCtrl->clkMDC<<2) & 0x0000003C;
|
|
mii_val |= (phyAddr << 11) & 0x0000F800;
|
|
mii_val |= (regAddr << 6) & 0x000007C0;
|
|
mii_val |= MII_BUSY|MII_WRITE;
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_MII_DATA, dataVal);
|
|
CSR_WRITE_4(pDev, GMAC_MII_ADDR, mii_val);
|
|
|
|
if(ftGmacMiiTimeoutPoll(pDev, GMAC_MII_ADDR, MII_BUSY, 1000000) == -1)
|
|
{
|
|
uartf("phy write error\r\n");
|
|
semGive (pDrvCtrl->gmacMiiSem);
|
|
return ERROR;
|
|
}
|
|
|
|
semGive (pDrvCtrl->gmacMiiSem);
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacLinkUpdate - miiBus miiLinkUpdate method
|
|
*
|
|
* This function implements an miiLinkUpdate() method that allows
|
|
* miiBus to notify us of link state changes. This routine will be
|
|
* invoked by the miiMonitor task when it detects a change in link
|
|
* status. Normally, the miiMonitor task checks for link events every
|
|
* two seconds.
|
|
*
|
|
* Once we determine the new link state, we will announce the change
|
|
* to any bound protocols via muxError(). We also update the ifSpeed
|
|
* fields in the MIB2 structures so that SNMP queries can detect the
|
|
* correct link speed.
|
|
*
|
|
* RETURNS: ERROR if obtaining the new media setting fails, else OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS ftGmacLinkUpdate
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
UINT32 oldStatus;
|
|
|
|
if (pDev->pDrvCtrl == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pDev->pDrvCtrl;
|
|
|
|
if (pDrvCtrl->gmacMiiBus == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
semTake (pDrvCtrl->gmacDevSem, WAIT_FOREVER);
|
|
|
|
oldStatus = pDrvCtrl->gmacCurStatus;
|
|
if (miiBusModeGet(pDrvCtrl->gmacMiiBus,
|
|
&pDrvCtrl->gmacCurMedia, &pDrvCtrl->gmacCurStatus) == ERROR)
|
|
{
|
|
semGive (pDrvCtrl->gmacDevSem);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* configure full duplex mode accordingly */
|
|
|
|
if (pDrvCtrl->gmacCurMedia & IFM_FDX)
|
|
{
|
|
CSR_SETBIT_4 (pDev, GMAC_CONTROL, CFG_DPLX_MODE);
|
|
}
|
|
else
|
|
{
|
|
CSR_CLRBIT_4 (pDev, GMAC_CONTROL, CFG_DPLX_MODE);
|
|
}
|
|
|
|
if (!(pDrvCtrl->gmacEndObj.flags & IFF_UP))
|
|
{
|
|
semGive (pDrvCtrl->gmacDevSem);
|
|
return (OK);
|
|
}
|
|
|
|
/* if status went from down to up, announce link up */
|
|
|
|
if (pDrvCtrl->gmacCurStatus & IFM_ACTIVE && !(oldStatus & IFM_ACTIVE))
|
|
{
|
|
switch (IFM_SUBTYPE (pDrvCtrl->gmacCurMedia))
|
|
{
|
|
case IFM_1000_T:
|
|
|
|
/* clear MII port, select gmac mode */
|
|
|
|
CSR_CLRBIT_4 (pDev, GMAC_CONTROL, CFG_MII_PORT_SEL);
|
|
|
|
pDrvCtrl->gmacEndObj.mib2Tbl.ifSpeed = 1000000000;
|
|
|
|
break;
|
|
|
|
case IFM_100_TX:
|
|
|
|
/* select MII port and 100Mbps mode */
|
|
|
|
CSR_SETBIT_4 (pDev, GMAC_CONTROL,
|
|
CFG_MII_PORT_SEL | CFG_FES_100);
|
|
|
|
pDrvCtrl->gmacEndObj.mib2Tbl.ifSpeed = 100000000;
|
|
|
|
break;
|
|
|
|
case IFM_10_T:
|
|
|
|
/* select MII port and 10Mbps mode */
|
|
|
|
CSR_SETBIT_4 (pDev, GMAC_CONTROL, CFG_MII_PORT_SEL);
|
|
CSR_CLRBIT_4 (pDev, GMAC_CONTROL, CFG_FES_100);
|
|
|
|
pDrvCtrl->gmacEndObj.mib2Tbl.ifSpeed = 10000000;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pDrvCtrl->gmacEndObj.pMib2Tbl != NULL)
|
|
pDrvCtrl->gmacEndObj.pMib2Tbl->m2Data.mibIfTbl.ifSpeed =
|
|
pDrvCtrl->gmacEndObj.mib2Tbl.ifSpeed;
|
|
|
|
jobQueueStdPost (pDrvCtrl->gmacJobQueue, NET_TASK_QJOB_PRI,
|
|
muxLinkUpNotify, &pDrvCtrl->gmacEndObj,
|
|
NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
/* if status went from up to down, announce link down */
|
|
|
|
else if (!(pDrvCtrl->gmacCurStatus & IFM_ACTIVE) && oldStatus & IFM_ACTIVE)
|
|
{
|
|
jobQueueStdPost(pDrvCtrl->gmacJobQueue, NET_TASK_QJOB_PRI,
|
|
muxLinkDownNotify, &pDrvCtrl->gmacEndObj,
|
|
NULL, NULL, NULL, NULL);
|
|
}
|
|
semGive (pDrvCtrl->gmacDevSem);
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacMuxConnect - muxConnect method handler
|
|
*
|
|
* This function handles muxConnect() events, which may be triggered
|
|
* manually or (more likely) by the bootstrap code. Most VxBus
|
|
* initialization occurs before the MUX has been fully initialized,
|
|
* so the usual muxDevLoad()/muxDevStart() sequence must be defered
|
|
* until the networking subsystem is ready. This routine will ultimately
|
|
* trigger a call to ftGmacEndLoad() to create the END interface instance.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacMuxConnect
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
void * unused
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
const struct hcfDevice * pHcf;
|
|
VXB_DEVICE_ID miiDev;
|
|
char * miiIfName;
|
|
int miiIfUnit;
|
|
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
/*
|
|
* Initialize MII bus.
|
|
* Note that we defer this until the muxConnect stage in this driver,
|
|
* unlike the others. This is because all of the PHYs are managed through
|
|
* the GMAC interface, and we have to allow primary initialization of GMAC
|
|
* to complete before we can start searching for PHYs.
|
|
*/
|
|
|
|
pHcf = hcfDeviceGet(pDev);
|
|
if (pHcf == NULL)
|
|
return;
|
|
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The miiIfName resource specifies the name of the
|
|
* driver that provides the MII interface for this
|
|
* GMAC unit. On boards that have multiple GMAC
|
|
* devices, the managmacent pins for all of the PHYs
|
|
* will all be wired to the MDIO pins on just one
|
|
* controller. The <miiIfName> resource (and the
|
|
* <miiIfUnit> resource below) are used to tell
|
|
* each GMAC instance which one is the managmacent
|
|
* controller. If a device is not the managmacent
|
|
* controller, it will just forward its PHY register
|
|
* read and write requests to the one that is. }
|
|
*/
|
|
|
|
(void) devResourceGet(pHcf, "miiIfName", HCF_RES_STRING,
|
|
(void *)&miiIfName);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The miiIfUnit resource specifies the unit number
|
|
* of the device that provides the MII managmacent
|
|
* methods for this GMAC instance. }
|
|
*/
|
|
|
|
(void) devResourceGet(pHcf, "miiIfUnit", HCF_RES_INT, (void *)&miiIfUnit);
|
|
|
|
miiDev = vxbInstByNameFind(miiIfName, miiIfUnit);
|
|
|
|
pDrvCtrl->gmacMiiDev = miiDev;
|
|
pDrvCtrl->gmacMiiPhyRead = vxbDevMethodGet(miiDev, (UINT32)&miiRead_desc);
|
|
pDrvCtrl->gmacMiiPhyWrite = vxbDevMethodGet(miiDev, (UINT32)&miiWrite_desc);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The clkMDC resource specifies the CSR clock range. Use clk_csr_i frequency
|
|
* to compute MDC clock frequency. To be sure MDC clock is in [1.0MHz ~2.5MHz] }
|
|
*/
|
|
|
|
(void) devResourceGet(pHcf, "clkMDC", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->clkMDC);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The phyAddr resource specifies the MII managmacent
|
|
* address (0-31) of the PHY for this particular GMAC
|
|
* device. Each GMAC typically has at least one PHY
|
|
* allocated to it. }
|
|
*/
|
|
|
|
if((ERROR == devResourceGet(pHcf, "phyAddr", HCF_RES_INT,(void *)&pDrvCtrl->gmacMiiPhyAddr))
|
|
||(-1 == pDrvCtrl->gmacMiiPhyAddr))
|
|
{
|
|
|
|
/* (after ->gmacMiiDev assigned) get phy addr dynamicly... */
|
|
|
|
pDrvCtrl->gmacMiiPhyAddr = ftGmacPhyAddrGet(pDev);
|
|
}
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The macAddrFun resource used to get mac address }
|
|
*/
|
|
(void) devResourceGet (pHcf, "macAddrSet", HCF_RES_ADDR,(void *)&pDrvCtrl->gmacAddrSet);
|
|
|
|
/* create our MII bus */
|
|
|
|
if(miiBusCreate (pDev, &pDrvCtrl->gmacMiiBus) == ERROR)
|
|
{
|
|
printf(" ftgmac. miiBusCreate creat fail!!! \n");
|
|
}
|
|
miiBusMediaListGet (pDrvCtrl->gmacMiiBus, &pDrvCtrl->gmacMediaList);
|
|
/*
|
|
force to 100M FDX
|
|
miiBusMediaDefaultSet (pDrvCtrl->gmacMiiBus, IFM_ETHER|IFM_100_TX|IFM_FDX);
|
|
*/
|
|
miiBusModeSet (pDrvCtrl->gmacMiiBus,
|
|
pDrvCtrl->gmacMediaList->endMediaListDefault);
|
|
|
|
/* save the cookie */
|
|
|
|
pDrvCtrl->gmacMuxDevCookie = muxDevLoad(pDev->unitNumber,
|
|
ftGmacEndLoad, "", TRUE, pDev);
|
|
|
|
|
|
if (pDrvCtrl->gmacMuxDevCookie != NULL)
|
|
{
|
|
muxDevStart(pDrvCtrl->gmacMuxDevCookie);
|
|
}
|
|
|
|
|
|
if (_func_m2PollStatsIfPoll != NULL)
|
|
{
|
|
endPollStatsInit(pDrvCtrl->gmacMuxDevCookie, _func_m2PollStatsIfPoll);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacIsValidMac - Check if the given MAC address is zero
|
|
*
|
|
* This routine check if the given MAC address is zero
|
|
*
|
|
* RETURNS: TRUE/FALSE
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL BOOL ftGmacIsZeroMac(UINT8 *gmacAddr)
|
|
{
|
|
UINT8 i = 0;
|
|
|
|
/* Check that the MAC is 00:00:00:00:00:00*/
|
|
for(i = 0; i < ETHER_ADDR_LEN; i++)
|
|
{
|
|
if(gmacAddr[i] != 0x0)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacIsValidMac - Check if the given MAC address is multicast address
|
|
*
|
|
* This routine check if the given MAC address is multicast address
|
|
*
|
|
* RETURNS: TRUE/FALSE
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL BOOL ftGmacIsmulticastMac(UINT8 *gmacAddr)
|
|
{
|
|
UINT8 i = 0;
|
|
|
|
/* Check that the MAC is FF:FF:FF:FF:FF:FF.*/
|
|
for(i = 0; i < ETHER_ADDR_LEN; i++)
|
|
{
|
|
if(gmacAddr[i] != 0xff)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacMacSet - get the GMAC mac address
|
|
*
|
|
* This routine get the GMAC mac address.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void ftGmacMacSet(GMAC_DRV_CTRL * pDrvCtrl)
|
|
{
|
|
UINT32 macLo;
|
|
UINT32 macHi;
|
|
|
|
macLo = CSR_READ_4(pDrvCtrl->gmacDev, GMAC_ADDR0_LOW);
|
|
macHi = CSR_READ_4(pDrvCtrl->gmacDev, GMAC_ADDR0_HIGH);
|
|
pDrvCtrl->gmacAddr[0] = macLo & 0xFF;
|
|
pDrvCtrl->gmacAddr[1] = (macLo >> 8) & 0xFF;
|
|
pDrvCtrl->gmacAddr[2] = (macLo >> 16) & 0xFF;
|
|
pDrvCtrl->gmacAddr[3] = (macLo >> 24) & 0xFF;
|
|
pDrvCtrl->gmacAddr[4] = macHi & 0xFF;
|
|
pDrvCtrl->gmacAddr[5] = (macHi >> 8) & 0xFF;
|
|
|
|
if(((ftGmacIsZeroMac(pDrvCtrl->gmacAddr) == TRUE)
|
|
|| (ftGmacIsmulticastMac(pDrvCtrl->gmacAddr) == TRUE))
|
|
&& (pDrvCtrl->gmacAddrSet != NULL))
|
|
{
|
|
(*pDrvCtrl->gmacAddrSet)(pDrvCtrl->gmacAddr);
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacReset - reset the GMAC controller
|
|
*
|
|
* This routine resets the GMAC controller.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacReset
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
int i;
|
|
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
/* Init DMA module */
|
|
|
|
CSR_SETBIT_4 (pDev, DMA_BUS_MODE, DMA_BUS_SWR);
|
|
|
|
i = 0;
|
|
while (i < GMAC_TIMEOUT)
|
|
{
|
|
if (!(CSR_READ_4 (pDev, DMA_BUS_MODE) & DMA_BUS_SWR))
|
|
break;
|
|
i++;
|
|
}
|
|
|
|
if (i >= GMAC_TIMEOUT)
|
|
{
|
|
logMsg ("stmGmac DMA module reset error.\n", 1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
CSR_WRITE_4 (pDev, DMA_BUS_MODE, DMA_BUS_INIT);
|
|
|
|
CSR_SETBIT_4 (pDev, DMA_OP_MODE, DMA_OP_FTF);
|
|
|
|
i = 0;
|
|
while (i < GMAC_TIMEOUT)
|
|
{
|
|
if (!(CSR_READ_4 (pDev, DMA_OP_MODE) & DMA_OP_FTF))
|
|
break;
|
|
i++;
|
|
}
|
|
|
|
if (i >= GMAC_TIMEOUT)
|
|
{
|
|
logMsg ("stmGmac DMA module flush FIFO error.\n", 1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
CSR_WRITE_4 (pDev, DMA_OP_MODE, DMA_OP_INIT);
|
|
|
|
/*
|
|
* GMAC Init:
|
|
* TX/RX checksum offload enable,
|
|
* 1000Mbps and duplex mode,
|
|
* Frame burst enable,
|
|
* disable Rx own,
|
|
* jabber disable;
|
|
*/
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_CONTROL, GMAC_INIT);
|
|
|
|
/* disable flow control */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_FLOW_CTRL, 0);
|
|
|
|
/* Disable all the MMC Int */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_MMC_TXINT_MASK, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, GMAC_MMC_RXINT_MASK, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, GMAC_INT_MASK, 0xFFFFFFFF);
|
|
|
|
/* DMA status register clear */
|
|
|
|
CSR_WRITE_4 (pDev, DMA_STATUS, 0xFFFFFFFF);
|
|
|
|
/* DMA INT disable */
|
|
|
|
CSR_WRITE_4 (pDev, DMA_INT_EN, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndLoad - END driver entry point
|
|
*
|
|
* This routine initializes the END interface instance associated
|
|
* with this device. In traditional END drivers, this function is
|
|
* the only public interface, and it's typically invoked by a BSP
|
|
* driver configuration stub. With VxBus, the BSP stub code is no
|
|
* longer needed, and this function is now invoked automatically
|
|
* whenever this driver's muxConnect() method is called.
|
|
*
|
|
* For older END drivers, the load string would contain various
|
|
* configuration parameters, but with VxBus this use is deprecated.
|
|
* The load string should just be an empty string. The second
|
|
* argument should be a pointer to the VxBus device instance
|
|
* associated with this device. Like older END drivers, this routine
|
|
* will still return the device name if the init string is empty,
|
|
* since this behavior is still expected by the MUX. The MUX will
|
|
* invoke this function twice: once to obtain the device name,
|
|
* and then again to create the actual END_OBJ instance.
|
|
*
|
|
* When this function is called the second time, it will initialize
|
|
* the END object, perform MIB2 setup, allocate a buffer pool, and
|
|
* initialize the supported END capabilities. The only special
|
|
* capability we support is VLAN_MTU, since we can receive slightly
|
|
* larger than normal frames.
|
|
*
|
|
* RETURNS: An END object pointer, or NULL on error, or 0 and the name
|
|
* of the device if the <loadStr> was empty.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL END_OBJ *ftGmacEndLoad
|
|
(
|
|
char * loadStr,
|
|
void * pArg
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
|
|
/* make the MUX happy */
|
|
|
|
if (loadStr == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (loadStr[0] == 0)
|
|
{
|
|
bcopy (GMAC_NAME, loadStr, sizeof(GMAC_NAME));
|
|
return NULL;
|
|
}
|
|
|
|
pDev = pArg;
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
|
|
if (END_OBJ_INIT (&pDrvCtrl->gmacEndObj, NULL, pDev->pName,
|
|
pDev->unitNumber, &ftGmacNetFuncs, "GMAC VxBus END Driver") == ERROR)
|
|
{
|
|
GMAC_DEBUG ("%s%d: END_OBJ_INIT failed\n", (int)GMAC_NAME,
|
|
pDev->unitNumber, 0, 0, 0, 0);
|
|
return (NULL);
|
|
}
|
|
|
|
/* get station address */
|
|
|
|
/*
|
|
sysNetMacNVRamAddrGet (pDev->pName, pDev->unitNumber,
|
|
pDrvCtrl->gmacAddr, ETHER_ADDR_LEN);
|
|
*/
|
|
|
|
endM2Init (&pDrvCtrl->gmacEndObj, M2_ifType_ethernet_csmacd,
|
|
pDrvCtrl->gmacAddr, ETHER_ADDR_LEN, ETHERMTU, 1000000000,
|
|
IFF_NOTRAILERS | IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST);
|
|
|
|
/* allocate a buffer pool */
|
|
|
|
pDrvCtrl->gmacMaxMtu = GMAC_MTU;
|
|
if (endPoolCreate(3 * GMAC_RX_DESC_CNT, &pDrvCtrl->gmacEndObj.pNetPool) == ERROR)
|
|
{
|
|
GMAC_DEBUG ("%s%d: pool creation failed\n", (int)GMAC_NAME,
|
|
pDev->unitNumber, 0, 0, 0, 0);
|
|
return (NULL);
|
|
}
|
|
|
|
pDrvCtrl->gmacPollBuf = endPoolTupleGet(pDrvCtrl->gmacEndObj.pNetPool);
|
|
|
|
/* set up polling stats */
|
|
|
|
pDrvCtrl->gmacEndStatsConf.ifPollInterval = sysClkRateGet();
|
|
pDrvCtrl->gmacEndStatsConf.ifEndObj = &pDrvCtrl->gmacEndObj;
|
|
pDrvCtrl->gmacEndStatsConf.ifWatchdog = NULL;
|
|
pDrvCtrl->gmacEndStatsConf.ifValidCounters = (END_IFINUCASTPKTS_VALID |
|
|
END_IFINMULTICASTPKTS_VALID | END_IFINBROADCASTPKTS_VALID |
|
|
END_IFINOCTETS_VALID | END_IFINERRORS_VALID | END_IFINDISCARDS_VALID |
|
|
END_IFOUTUCASTPKTS_VALID | END_IFOUTMULTICASTPKTS_VALID |
|
|
END_IFOUTBROADCASTPKTS_VALID | END_IFOUTOCTETS_VALID |
|
|
END_IFOUTERRORS_VALID);
|
|
|
|
/* set up capabilities */
|
|
|
|
pDrvCtrl->gmacCaps.cap_available = IFCAP_VLAN_MTU | IFCAP_TXCSUM |IFCAP_RXCSUM;
|
|
pDrvCtrl->gmacCaps.cap_enabled = IFCAP_VLAN_MTU | IFCAP_TXCSUM |IFCAP_RXCSUM;
|
|
pDrvCtrl->gmacCaps.csum_flags_tx = CSUM_IP|CSUM_TCP|CSUM_UDP;
|
|
pDrvCtrl->gmacCaps.csum_flags_rx = CSUM_IP|CSUM_UDP|CSUM_TCP;
|
|
|
|
|
|
return (&pDrvCtrl->gmacEndObj);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndUnload - unload END driver instance
|
|
*
|
|
* This routine undoes the effects of ftGmacEndLoad(). The END object
|
|
* is destroyed, our network pool is released, the endM2 structures
|
|
* are released, and the polling stats watchdog is terminated.
|
|
*
|
|
* Note that the END interface instance can't be unloaded if the
|
|
* device is still running. The device must be stopped with muxDevStop()
|
|
* first.
|
|
*
|
|
* RETURNS: ERROR if device is still in the IFF_UP state, otherwise OK
|
|
*
|
|
* RETURN: ERROR or EALREADY
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndUnload
|
|
(
|
|
END_OBJ * pEnd
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
|
|
/* We must be stopped before we can be unloaded. */
|
|
|
|
if (pEnd->flags & IFF_UP)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
|
|
netMblkClChainFree (pDrvCtrl->gmacPollBuf);
|
|
|
|
/* Relase our buffer pool */
|
|
|
|
endPoolDestroy (pDrvCtrl->gmacEndObj.pNetPool);
|
|
|
|
/* terminate stats polling */
|
|
|
|
wdDelete (pDrvCtrl->gmacEndStatsConf.ifWatchdog);
|
|
|
|
endM2Free (&pDrvCtrl->gmacEndObj);
|
|
|
|
END_OBJECT_UNLOAD (&pDrvCtrl->gmacEndObj);
|
|
|
|
return (EALREADY); /* prevent freeing of pDrvCtrl */
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacMacHashClac - calculate a hash checksum
|
|
*
|
|
* This routine performs the GEM hash calculation over MAC addresses.
|
|
* The GEM implements multicast filtering using a hash table where a hash
|
|
* checksum of the multicast group address is used as the table index.
|
|
*
|
|
* RETURNS: the 32-bit checksum of the supplied buffer
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
UINT32 ftGmacMacHashCalc
|
|
(
|
|
const UINT8 * pBuf
|
|
)
|
|
{
|
|
UINT32 hash = 0;
|
|
UINT8 bit[6];
|
|
int i;
|
|
|
|
bit[5] = ((pBuf[0] >> 5) ^ (pBuf[1] >> 3) ^ (pBuf[2] >> 1) ^ (pBuf[2] >> 7)
|
|
^ (pBuf[3] >> 5) ^ (pBuf[4] >> 3) ^ (pBuf[5] >> 1) ^ (pBuf[5] >> 7))
|
|
& 1;
|
|
bit[4] = ((pBuf[0] >> 4) ^ (pBuf[1] >> 2) ^ (pBuf[2]) ^ (pBuf[2] >> 6)
|
|
^ (pBuf[3] >> 4) ^ (pBuf[4] >> 2) ^ (pBuf[5]) ^ (pBuf[5] >> 6))
|
|
& 1;
|
|
bit[3] = ((pBuf[0] >> 3) ^ (pBuf[1] >> 1) ^ (pBuf[1] >> 7) ^ (pBuf[2] >> 5)
|
|
^ (pBuf[3] >> 3) ^ (pBuf[4] >> 1) ^ (pBuf[4] >> 7) ^ (pBuf[5] >> 5))
|
|
& 1;
|
|
bit[2] = ((pBuf[0] >> 2) ^ (pBuf[1]) ^ (pBuf[1] >> 6) ^ (pBuf[2] >> 4)
|
|
^ (pBuf[3] >> 2) ^ (pBuf[4]) ^ (pBuf[4] >> 6) ^ (pBuf[5] >> 4))
|
|
& 1;
|
|
bit[1] = ((pBuf[0] >> 1) ^ (pBuf[0] >> 7) ^ (pBuf[1] >> 5) ^ (pBuf[2] >> 3)
|
|
^ (pBuf[3] >> 1) ^ (pBuf[3] >> 7) ^ (pBuf[4] >> 5) ^ (pBuf[5] >> 3))
|
|
& 1;
|
|
bit[0] = ((pBuf[0]) ^ (pBuf[0] >> 6) ^ (pBuf[1] >> 4) ^ (pBuf[2] >> 2)
|
|
^ (pBuf[3]) ^ (pBuf[3] >> 6) ^ (pBuf[4] >> 4) ^ (pBuf[5] >> 2))
|
|
& 1;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
if (bit[i])
|
|
hash += (1 << i);
|
|
|
|
return hash;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftBitReverse32 - get 32bit bit reverse value.
|
|
*
|
|
* This function compute 32bit bit reverse value.
|
|
*
|
|
* RETURNS: bit reversed value.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL UINT32 ftBitReverse32
|
|
(
|
|
UINT32 input
|
|
)
|
|
{
|
|
UINT32 ix = 0;
|
|
UINT32 output = 0;
|
|
|
|
for (; ix < 32; ix++)
|
|
{
|
|
output |= ((input & (1 << ix)) != 0) << (31 - ix);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndHashTblPopulate - populate the multicast hash filter
|
|
*
|
|
* This function programs the zynq7k controller's multicast hash
|
|
* filter to receive frames sent to the multicast groups specified
|
|
* in the multicast address list attached to the END object. If
|
|
* the interface is in IFF_ALLMULTI mode, the filter will be
|
|
* programmed to receive all multicast packets by setting all the
|
|
* bits in the hash table to one.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndHashTblPopulate
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
UINT32 h;
|
|
UINT32 hashes[2] = { 0, 0 };
|
|
ETHER_MULTI * mCastNode = NULL;
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
if (pDrvCtrl->gmacEndObj.flags & IFF_ALLMULTI)
|
|
{
|
|
/* set all multicast mode */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_LOW, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_HIGH, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, GMAC_FRAME_FILTER, FFILTER_PASSALL_MCAST);
|
|
return;
|
|
}
|
|
|
|
/* first, clear out the original filter */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_LOW, 0);
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_HIGH, 0);
|
|
|
|
/* now repopulate it */
|
|
|
|
for (mCastNode = (ETHER_MULTI *)lstFirst (&pDrvCtrl->gmacEndObj.multiList);
|
|
mCastNode != NULL;
|
|
mCastNode = (ETHER_MULTI *)lstNext (&mCastNode->node))
|
|
{
|
|
|
|
/*
|
|
* The upper 6 bits of the calculated CRC are used to
|
|
* index the contens of the hash table.
|
|
*/
|
|
|
|
h = endEtherCrc32LeGet((const UINT8 *) mCastNode->addr,
|
|
ETHER_ADDR_LEN);
|
|
h = ftBitReverse32 (~h) >> 26;
|
|
hashes[h >> 5] |= 1 << (h & 31);
|
|
}
|
|
|
|
/* reload filter */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_LOW, hashes[0]);
|
|
CSR_WRITE_4 (pDev, GMAC_HASH_HIGH, hashes[1]);
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_FRAME_FILTER, FFILTER_HASH_MCAST);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndMCastAddrAdd - 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.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndMCastAddrAdd
|
|
(
|
|
END_OBJ * pEnd,
|
|
char * pAddr
|
|
)
|
|
{
|
|
|
|
int retVal;
|
|
|
|
retVal = etherMultiAdd (&pEnd->multiList, pAddr);
|
|
|
|
if (retVal == ENETRESET)
|
|
{
|
|
pEnd->nMulti++;
|
|
ftGmacEndHashTblPopulate ((GMAC_DRV_CTRL *)pEnd);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndMCastAddrDel - 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.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndMCastAddrDel
|
|
(
|
|
END_OBJ * pEnd,
|
|
char * pAddr
|
|
)
|
|
{
|
|
|
|
int retVal;
|
|
|
|
retVal = etherMultiDel (&pEnd->multiList, pAddr);
|
|
|
|
if (retVal == ENETRESET)
|
|
{
|
|
pEnd->nMulti--;
|
|
ftGmacEndHashTblPopulate ((GMAC_DRV_CTRL *)pEnd);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndMCastAddrGet - 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.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndMCastAddrGet
|
|
(
|
|
END_OBJ * pEnd,
|
|
MULTI_TABLE * pTable
|
|
)
|
|
{
|
|
return (etherMultiGet (&pEnd->multiList, pTable));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndStatsDump - return polled statistics counts
|
|
*
|
|
* This routine is automatically invoked periodically by the polled statistics
|
|
* watchdog. All stats are available from the MIB registers.
|
|
*
|
|
* RETURNS: always OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndStatsDump
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
END_IFCOUNTERS * pEndStatsCounters;
|
|
|
|
pEndStatsCounters = &pDrvCtrl->gmacEndStatsCounters;
|
|
|
|
pEndStatsCounters->ifInOctets = pDrvCtrl->gmacInOctets;
|
|
pDrvCtrl->gmacInOctets = 0;
|
|
|
|
pEndStatsCounters->ifInUcastPkts = pDrvCtrl->gmacInUcasts;
|
|
pDrvCtrl->gmacInUcasts = 0;
|
|
|
|
pEndStatsCounters->ifInMulticastPkts = pDrvCtrl->gmacInMcasts;
|
|
pDrvCtrl->gmacInMcasts = 0;
|
|
|
|
pEndStatsCounters->ifInBroadcastPkts = pDrvCtrl->gmacInBcasts;
|
|
pDrvCtrl->gmacInBcasts = 0;
|
|
|
|
pEndStatsCounters->ifInErrors = pDrvCtrl->gmacInErrors;
|
|
pDrvCtrl->gmacInErrors = 0;
|
|
|
|
pEndStatsCounters->ifInDiscards = pDrvCtrl->gmacInDiscards;
|
|
pDrvCtrl->gmacInDiscards = 0;
|
|
|
|
pEndStatsCounters->ifOutOctets = pDrvCtrl->gmacOutOctets;
|
|
pDrvCtrl->gmacOutOctets = 0;
|
|
|
|
pEndStatsCounters->ifOutUcastPkts = pDrvCtrl->gmacOutUcasts;
|
|
pDrvCtrl->gmacOutUcasts = 0;
|
|
|
|
pEndStatsCounters->ifOutMulticastPkts = pDrvCtrl->gmacOutMcasts;
|
|
pDrvCtrl->gmacOutMcasts = 0;
|
|
|
|
pEndStatsCounters->ifOutBroadcastPkts = pDrvCtrl->gmacOutBcasts;
|
|
pDrvCtrl->gmacOutBcasts = 0;
|
|
|
|
pEndStatsCounters->ifOutErrors = pDrvCtrl->gmacOutErrors;
|
|
pDrvCtrl->gmacOutErrors = 0;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndIoctl - the driver I/O control routine
|
|
*
|
|
* This function processes ioctl requests supplied via the muxIoctl()
|
|
* routine. In addition to the normal boilerplate END ioctls, this
|
|
* driver supports the IFMEDIA ioctls, END capabilities ioctls, and
|
|
* polled stats ioctls.
|
|
*
|
|
* RETURNS: A command specific response, usually OK or ERROR.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int ftGmacEndIoctl
|
|
(
|
|
END_OBJ * pEnd,
|
|
int cmd,
|
|
caddr_t data
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
END_MEDIALIST * mediaList;
|
|
END_CAPABILITIES * hwCaps;
|
|
END_MEDIA * pMedia;
|
|
END_RCVJOBQ_INFO * qinfo;
|
|
UINT32 nQs;
|
|
VXB_DEVICE_ID pDev;
|
|
INT32 value;
|
|
int error = OK;
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
switch (cmd)
|
|
{
|
|
case EIOCSADDR:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
bcopy ((char *)data, (char *)pDrvCtrl->gmacAddr,
|
|
ETHER_ADDR_LEN);
|
|
|
|
ftGmacEndRxConfig (pDrvCtrl);
|
|
break;
|
|
|
|
case EIOCGADDR:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
bcopy ((char *)pDrvCtrl->gmacAddr, (char *)data,
|
|
ETHER_ADDR_LEN);
|
|
break;
|
|
|
|
case EIOCSFLAGS:
|
|
value = (INT32) data;
|
|
if (value < 0)
|
|
{
|
|
value = -value;
|
|
value--;
|
|
END_FLAGS_CLR (pEnd, value);
|
|
}
|
|
else
|
|
END_FLAGS_SET (pEnd, value);
|
|
|
|
ftGmacEndRxConfig (pDrvCtrl);
|
|
break;
|
|
|
|
case EIOCGFLAGS:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
*(long *)data = END_FLAGS_GET(pEnd);
|
|
break;
|
|
|
|
case EIOCMULTIADD:
|
|
error = ftGmacEndMCastAddrAdd (pEnd, (char *) data);
|
|
break;
|
|
|
|
case EIOCMULTIDEL:
|
|
error = ftGmacEndMCastAddrDel (pEnd, (char *) data);
|
|
break;
|
|
|
|
case EIOCMULTIGET:
|
|
error = ftGmacEndMCastAddrGet (pEnd, (MULTI_TABLE *) data);
|
|
break;
|
|
|
|
case EIOCPOLLSTART:
|
|
|
|
pDrvCtrl->gmacPolling = TRUE;
|
|
|
|
/* diable interrupts */
|
|
|
|
CSR_WRITE_4(pDev, DMA_INTR_ENA, 0);
|
|
|
|
/*
|
|
* We may have been asked to enter polled mode while
|
|
* there are transmissions pending. This is a problem,
|
|
* because the polled transmit routine expects that
|
|
* the TX ring will be empty when it's called. In
|
|
* order to guarantee this, we have to drain the TX
|
|
* ring here. We could also just plain reset and
|
|
* reinitialize the transmitter, but this is faster.
|
|
*/
|
|
|
|
while (pDrvCtrl->gmacTxFree < GMAC_TX_DESC_CNT)
|
|
{
|
|
volatile GMAC_DESC * pDesc;
|
|
M_BLK_ID pMblk;
|
|
volatile UINT32 desc_status;
|
|
|
|
pDesc = &pDrvCtrl->gmacTxDescMem[pDrvCtrl->gmacTxCons];
|
|
|
|
/* Wait for ownership bit to clear */
|
|
|
|
do
|
|
{
|
|
desc_status = pDesc->status;
|
|
if(!(desc_status & TDES0_OWN))
|
|
break;
|
|
}while(1);
|
|
|
|
pDesc->status = pDesc->ctrl = 0;
|
|
|
|
if(pDrvCtrl->gmacTxCons == (GMAC_TX_DESC_CNT - 1)) /* the last one */
|
|
{
|
|
pDesc->ctrl |= TDES1_END_RING;
|
|
}
|
|
|
|
pMblk = pDrvCtrl->gmacTxMblk[pDrvCtrl->gmacTxCons];
|
|
|
|
if (pMblk != NULL)
|
|
{
|
|
endPoolTupleFree (pMblk);
|
|
pDrvCtrl->gmacTxMblk[pDrvCtrl->gmacTxCons] = NULL;
|
|
}
|
|
|
|
pDrvCtrl->gmacTxFree++;
|
|
GMAC_INC_DESC (pDrvCtrl->gmacTxCons, GMAC_TX_DESC_CNT);
|
|
}
|
|
|
|
break;
|
|
|
|
case EIOCPOLLSTOP:
|
|
/* enable interrupts */
|
|
|
|
CSR_WRITE_4(pDev, DMA_INTR_ENA, DMA_INT_ENABLE);
|
|
|
|
pDrvCtrl->gmacPolling = FALSE;
|
|
break;
|
|
|
|
case EIOCGMIB2233:
|
|
case EIOCGMIB2:
|
|
error = endM2Ioctl (&pDrvCtrl->gmacEndObj, cmd, data);
|
|
break;
|
|
|
|
case EIOCGPOLLCONF:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
*((END_IFDRVCONF **)data) = &pDrvCtrl->gmacEndStatsConf;
|
|
break;
|
|
|
|
case EIOCGPOLLSTATS:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
{
|
|
error = ftGmacEndStatsDump(pDrvCtrl);
|
|
if (error == OK)
|
|
*((END_IFCOUNTERS **)data) = &pDrvCtrl->gmacEndStatsCounters;
|
|
}
|
|
break;
|
|
|
|
case EIOCGMEDIALIST:
|
|
if (data == NULL)
|
|
{
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
if (pDrvCtrl->gmacMediaList->endMediaListLen == 0)
|
|
{
|
|
error = ENOTSUP;
|
|
break;
|
|
}
|
|
|
|
mediaList = (END_MEDIALIST *)data;
|
|
if (mediaList->endMediaListLen <
|
|
pDrvCtrl->gmacMediaList->endMediaListLen)
|
|
{
|
|
mediaList->endMediaListLen =
|
|
pDrvCtrl->gmacMediaList->endMediaListLen;
|
|
error = ENOSPC;
|
|
break;
|
|
}
|
|
|
|
bcopy((char *)pDrvCtrl->gmacMediaList, (char *)mediaList,
|
|
sizeof(END_MEDIALIST) + (sizeof(UINT32) *
|
|
pDrvCtrl->gmacMediaList->endMediaListLen));
|
|
break;
|
|
|
|
case EIOCGIFMEDIA:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
{
|
|
pMedia = (END_MEDIA *)data;
|
|
pMedia->endMediaActive = pDrvCtrl->gmacCurMedia;
|
|
pMedia->endMediaStatus = pDrvCtrl->gmacCurStatus;
|
|
}
|
|
break;
|
|
|
|
case EIOCSIFMEDIA:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
{
|
|
pMedia = (END_MEDIA *)data;
|
|
miiBusModeSet (pDrvCtrl->gmacMiiBus, pMedia->endMediaActive);
|
|
ftGmacLinkUpdate (pDrvCtrl->gmacDev);
|
|
error = OK;
|
|
}
|
|
break;
|
|
|
|
case EIOCGIFCAP:
|
|
hwCaps = (END_CAPABILITIES *)data;
|
|
if (hwCaps == NULL)
|
|
{
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
hwCaps->csum_flags_tx = pDrvCtrl->gmacCaps.csum_flags_tx;
|
|
hwCaps->csum_flags_rx = pDrvCtrl->gmacCaps.csum_flags_rx;
|
|
hwCaps->cap_available = pDrvCtrl->gmacCaps.cap_available;
|
|
hwCaps->cap_enabled = pDrvCtrl->gmacCaps.cap_enabled;
|
|
break;
|
|
|
|
/*
|
|
* The only special capability we support is VLAN_MTU, and
|
|
* it can never be turned off.
|
|
*/
|
|
|
|
case EIOCSIFCAP:
|
|
error = ENOTSUP;
|
|
break;
|
|
|
|
case EIOCGIFMTU:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
*(INT32 *)data = pEnd->mib2Tbl.ifMtu;
|
|
break;
|
|
|
|
case EIOCSIFMTU:
|
|
value = (INT32)data;
|
|
if (value <= 0 || value > pDrvCtrl->gmacMaxMtu)
|
|
{
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
pEnd->mib2Tbl.ifMtu = value;
|
|
if (pEnd->pMib2Tbl != NULL)
|
|
pEnd->pMib2Tbl->m2Data.mibIfTbl.ifMtu = value;
|
|
break;
|
|
|
|
case EIOCGRCVJOBQ:
|
|
if (data == NULL)
|
|
{
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
|
|
qinfo = (END_RCVJOBQ_INFO *)data;
|
|
nQs = qinfo->numRcvJobQs;
|
|
qinfo->numRcvJobQs = 1;
|
|
if (nQs < 1)
|
|
error = ENOSPC;
|
|
else
|
|
qinfo->qIds[0] = pDrvCtrl->gmacJobQueue;
|
|
break;
|
|
|
|
default:
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndRxConfig - configure the FCC's RX filter
|
|
*
|
|
* This is a helper routine used by ftGmacEndIoctl() and ftGmacEndStart() to
|
|
* configure the controller's RX filter. The unicast address filter is
|
|
* programmed with the currently configured MAC address, and the RX
|
|
* configuration is set to allow unicast and broadcast frames to be
|
|
* received. If the interface is in IFF_PROMISC mode, the RX_PROMISC
|
|
* bit is set, which allows all packets to be received.
|
|
*
|
|
* The ftGmacEndHashTblPopulate() routine is also called to update the
|
|
* multicast filter.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndRxConfig
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
UINT32 rxCtrl;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
rxCtrl = CSR_READ_4 (pDev, GMAC_CONTROL);
|
|
/* set the MAC address - must write the low first */
|
|
|
|
CSR_WRITE_4(pDev, GMAC_ADDR0_LOW, (pDrvCtrl->gmacAddr[3] << 24) |
|
|
(pDrvCtrl->gmacAddr[2] << 16) |
|
|
(pDrvCtrl->gmacAddr[1] << 8) |
|
|
(pDrvCtrl->gmacAddr[0] << 0));
|
|
CSR_WRITE_4(pDev, GMAC_ADDR0_HIGH, (pDrvCtrl->gmacAddr[5] << 8) |
|
|
(pDrvCtrl->gmacAddr[4] << 0) | GMAC_HI_REG_AE);
|
|
|
|
/* Enable promisc mode, if specified. */
|
|
|
|
/* enable promisc mode, if specified */
|
|
|
|
if (pDrvCtrl->gmacEndObj.flags & IFF_PROMISC)
|
|
{
|
|
CSR_WRITE_4 (pDev, GMAC_FRAME_FILTER, FFILTER_PROMIS_MODE);
|
|
}
|
|
else
|
|
{
|
|
CSR_WRITE_4 (pDev, GMAC_FRAME_FILTER, FFILTER_HASH_MCAST);
|
|
}
|
|
|
|
/* jumbo frame support */
|
|
|
|
if (pDrvCtrl->gmacMaxMtu == GMAC_JUMBO_MTU)
|
|
rxCtrl |= CFG_JUMBO_EN;
|
|
else
|
|
rxCtrl &= ~CFG_JUMBO_EN;
|
|
|
|
/* program the hardware register */
|
|
|
|
CSR_WRITE_4 (pDev, GMAC_CONTROL, rxCtrl);
|
|
|
|
/* Program the multicast filter. */
|
|
|
|
ftGmacEndHashTblPopulate (pDrvCtrl);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
LOCAL STATUS ftGmacRxStatusCheck(UINT32 desc_status)
|
|
{
|
|
if ((desc_status & RDES0_ERROR_SUMMARY) && (desc_status & RX_FRAME_ERROR_TYPE1))
|
|
{
|
|
#ifdef GMAC_RX_DEBUG
|
|
printf("\r\n gmac rx error type1: 0x%x ", desc_status);
|
|
#endif
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
if (desc_status & RX_FRAME_ERROR_TYPE2)
|
|
{
|
|
#ifdef GMAC_RX_DEBUG
|
|
printf("\r\n gmac rx error type2: 0x%x ", desc_status);
|
|
#endif
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
LOCAL void ftGmacRxDescInit(GMAC_DESC * desc, int index, UINT32 phyAddr)
|
|
{
|
|
desc->ctrl = 0;
|
|
desc->next = 0;
|
|
desc->status = 0;
|
|
|
|
|
|
desc->ctrl |= ((MAC_MAX_FRAME_SZ - 1) & RDES1_BUFFER1_SIZE_MASK);
|
|
/*desc->ctrl |= (((MAC_MAX_FRAME_SZ - 1) << RDES1_BUFFER2_SIZE_SHIFT) & RDES1_BUFFER2_SIZE_MASK);*/
|
|
desc->status = RDES0_OWN;
|
|
if(phyAddr != 0)
|
|
desc->addr = phyAddr;
|
|
|
|
if(index == (GMAC_RX_DESC_CNT - 1))
|
|
{
|
|
desc->ctrl |= RDES1_END_RING;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndStart - start the device
|
|
*
|
|
* This function resets the device to put it into a known state and
|
|
* then configures it for RX and TX operation. The RX and TX configuration
|
|
* registers are initialized, and the address of the RX and TX DMA rings
|
|
* are loaded into the device. Interrupts are then enabled, and the initial
|
|
* link state is configured.
|
|
*
|
|
* Note that this routine also checks to see if an alternate jobQueue
|
|
* has been specified via the vxbParam subsystem. This allows the driver
|
|
* to divert its work to an alternate processing task, such as may be
|
|
* done with TIPC. This means that the jobQueue can be changed while
|
|
* the system is running, but the device must be stopped and restarted
|
|
* for the change to take effect.
|
|
*
|
|
* RETURNS: ERROR if device initialization failed, otherwise OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndStart
|
|
(
|
|
END_OBJ * pEnd
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
VXB_INST_PARAM_VALUE val;
|
|
HEND_RX_QUEUE_PARAM * pRxQueue;
|
|
GMAC_DESC * pDesc;
|
|
int i;
|
|
M_BLK_ID pMblk = NULL;
|
|
UINT32 physAddr;
|
|
|
|
if (pEnd->flags & IFF_UP)
|
|
return (OK);
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
semTake (pDrvCtrl->gmacDevSem, WAIT_FOREVER);
|
|
|
|
/* Initialize job queues */
|
|
|
|
pDrvCtrl->gmacJobQueue = netJobQueueId;
|
|
|
|
/* Override the job queue ID if the user supplied an alternate one. */
|
|
|
|
/*
|
|
* paramDesc {
|
|
* The rxQueue00 parameter specifies a pointer to
|
|
* a HEND_RX_QUEUE_PARAM structure, which contains,
|
|
* among other things, an ID for the job queue
|
|
* to be used for this instance. }
|
|
*/
|
|
|
|
if (vxbInstParamByNameGet (pDev, "rxQueue00",
|
|
VXB_PARAM_POINTER, &val) == OK)
|
|
{
|
|
pRxQueue = (HEND_RX_QUEUE_PARAM *) val.pValue;
|
|
if (pRxQueue->jobQueId != NULL)
|
|
pDrvCtrl->gmacJobQueue = pRxQueue->jobQueId;
|
|
}
|
|
|
|
QJOB_SET_PRI(&pDrvCtrl->gmacIntJob, NET_TASK_QJOB_PRI);
|
|
pDrvCtrl->gmacIntJob.func = ftGmacEndIntHandle;
|
|
|
|
(void)vxAtomicSet ((atomicVal_t*) &pDrvCtrl->gmacRxPending, FALSE);
|
|
(void)vxAtomicSet ((atomicVal_t*) &pDrvCtrl->gmacTxPending, FALSE);
|
|
(void)vxAtomicSet ((atomicVal_t*) &pDrvCtrl->gmacIntPending, FALSE);
|
|
|
|
ftGmacMacSet(pDrvCtrl);
|
|
|
|
/* Reset controller to known state */
|
|
ftGmacReset (pDev);
|
|
|
|
/* Set up the RX ring. */
|
|
|
|
for (i = 0; i < GMAC_RX_DESC_CNT; i++)
|
|
{
|
|
pMblk = endPoolTupleGet(pDrvCtrl->gmacEndObj.pNetPool);
|
|
if (pMblk == NULL)
|
|
{
|
|
semGive (pDrvCtrl->gmacDevSem);
|
|
GMAC_DEBUG ("get rx mblk failed\r\n", 0, 1, 2, 3, 4, 5);
|
|
return (ERROR);
|
|
}
|
|
|
|
pMblk->m_next = NULL;
|
|
pDrvCtrl->gmacRxMblk[i] = pMblk;
|
|
|
|
pDesc = &pDrvCtrl->gmacRxDescMem[i];
|
|
|
|
/* pre-invalidate the buffer */
|
|
|
|
CACHE_USER_INVALIDATE (pMblk->m_data, pMblk->m_len);
|
|
|
|
physAddr = (UINT32)GMAC_CACHE_DRV_VIRT_TO_PHYS(pMblk->m_data);
|
|
ftGmacRxDescInit(pDesc, i, physAddr);
|
|
|
|
|
|
}
|
|
|
|
/* Set up TX ring */
|
|
bzero ((char *)pDrvCtrl->gmacTxDescMem, sizeof(GMAC_DESC) * GMAC_TX_DESC_CNT);
|
|
pDesc = &pDrvCtrl->gmacTxDescMem[GMAC_TX_DESC_CNT - 1];
|
|
pDesc->ctrl |= TDES1_END_RING; /* last descriptor is end of ring */
|
|
|
|
/* Load the maps for the RX and TX DMA ring. */
|
|
|
|
/* Initialize state */
|
|
|
|
pDrvCtrl->gmacRxIdx = 0;
|
|
pDrvCtrl->gmacTxLast = 0;
|
|
pDrvCtrl->gmacTxStall = FALSE;
|
|
pDrvCtrl->gmacTxProd = 0;
|
|
pDrvCtrl->gmacTxCons = 0;
|
|
pDrvCtrl->gmacTxFree = GMAC_TX_DESC_CNT;
|
|
|
|
/* mask out MMC interrupts because we don't handle them yet */
|
|
|
|
CSR_WRITE_4 (pDev, MMC_RX_INTR_MASK, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, MMC_TX_INTR_MASK, 0xFFFFFFFF);
|
|
CSR_WRITE_4 (pDev, MMC_RX_IPC_INTR_MASK, 0xFFFFFFFF);
|
|
|
|
|
|
CSR_WRITE_4(pDev, GMAC_CONTROL, (0x00610c8c & ~(MAC_ENABLE_RX | MAC_ENABLE_TX)) );
|
|
CSR_WRITE_4(pDev, GMAC_FRAME_FILTER, 0x04);
|
|
CSR_WRITE_4(pDev, GMAC_HASH_HIGH, 0x01);
|
|
CSR_WRITE_4(pDev, GMAC_HASH_LOW, 0x22);
|
|
CSR_WRITE_4(pDev, GMAC_FLOW_CTRL, 0xffff0008);
|
|
CSR_WRITE_4(pDev, DMA_BUS_MODE, 0x01211000);
|
|
CSR_WRITE_4(pDev, DMA_CONTROL, 0x02202906 & ~(DMA_CONTROL_ST | DMA_CONTROL_SR));
|
|
CSR_WRITE_4(pDev, 0x1028, 0x0000000e);
|
|
|
|
CSR_WRITE_4(pDev, GMAC_INT_STATUS, 0x0);
|
|
|
|
CSR_WRITE_4(pDev, GMAC_INT_MASK, GMAC_INT_DISABLE_RGMII);
|
|
|
|
CSR_WRITE_4(pDev, DMA_MISSED_FRAME_CTR, 0x0);
|
|
CSR_WRITE_4(pDev, 0x1024, 0xff);
|
|
|
|
/* Set Tx/Rx pointer. */
|
|
|
|
CSR_WRITE_4(pDev, DMA_RCV_BASE_ADDR,
|
|
(UINT32)GMAC_CACHE_DRV_VIRT_TO_PHYS(pDrvCtrl->gmacRxDescMem));
|
|
|
|
|
|
|
|
CSR_WRITE_4(pDev, DMA_TX_BASE_ADDR,
|
|
(UINT32)GMAC_CACHE_DRV_VIRT_TO_PHYS(pDrvCtrl->gmacTxDescMem));
|
|
|
|
|
|
/* Zero the stats counters. */
|
|
|
|
pDrvCtrl->gmacInUcasts = pDrvCtrl->gmacInBcasts =
|
|
pDrvCtrl->gmacInMcasts = 0;
|
|
pDrvCtrl->gmacOutUcasts = pDrvCtrl->gmacOutBcasts =
|
|
pDrvCtrl->gmacOutMcasts = 0;
|
|
pDrvCtrl->gmacInOctets = pDrvCtrl->gmacOutOctets = 0;
|
|
|
|
|
|
ftGmacEndRxConfig (pDrvCtrl);
|
|
|
|
|
|
|
|
(void) vxbIntEnable (pDev, 0, ftGmacEndInt, pDrvCtrl);
|
|
|
|
/* Enable interrupts */
|
|
|
|
CSR_WRITE_4(pDev, DMA_INTR_ENA, DMA_INT_ENABLE);
|
|
|
|
/* start DMA RX/TX */
|
|
|
|
CSR_SETBIT_4(pDev, DMA_CONTROL, DMA_CONTROL_SR | DMA_CONTROL_ST);
|
|
|
|
/* Enable GMAC TX/RX */
|
|
|
|
CSR_SETBIT_4(pDev, GMAC_CONTROL, MAC_ENABLE_RX | MAC_ENABLE_TX);
|
|
|
|
/* Set initial link state */
|
|
|
|
pDrvCtrl->gmacCurMedia = IFM_ETHER | IFM_NONE;
|
|
pDrvCtrl->gmacCurStatus = IFM_AVALID;
|
|
|
|
|
|
|
|
END_FLAGS_SET (pEnd, (IFF_UP | IFF_RUNNING));
|
|
|
|
|
|
semGive (pDrvCtrl->gmacDevSem);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndStop - stop the device
|
|
*
|
|
* This function undoes the effects of ftGmacEndStart(). The device is shut
|
|
* down and all resources are released. Note that the shutdown process
|
|
* pauses to wait for all pending RX, TX and link event jobs that may have
|
|
* been initiated by the interrupt handler to complete. This is done
|
|
* to prevent tNetTask from accessing any data that might be released by
|
|
* this routine.
|
|
*
|
|
* RETURNS: ERROR if device shutdown failed, otherwise OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftGmacEndStop
|
|
(
|
|
END_OBJ * pEnd
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
int i;
|
|
|
|
if (!(pEnd->flags & IFF_UP))
|
|
return (OK);
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
END_FLAGS_CLR (pEnd, (IFF_UP | IFF_RUNNING));
|
|
|
|
/* Disable interrupts */
|
|
|
|
CSR_WRITE_4(pDev, DMA_INTR_ENA, 0);
|
|
|
|
/* stop DMA RX/TX */
|
|
|
|
CSR_CLRBIT_4(pDev, DMA_CONTROL, DMA_CONTROL_SR | DMA_CONTROL_ST);
|
|
|
|
/* Disable GMAC TX/RX */
|
|
|
|
CSR_CLRBIT_4(pDev, GMAC_CONTROL, MAC_ENABLE_RX | MAC_ENABLE_TX);
|
|
|
|
(void) vxbIntDisable (pDev, 0, ftGmacEndInt, pDrvCtrl);
|
|
|
|
/*
|
|
* Wait for all jobs to drain.
|
|
* Note: this must be done before we disable the receiver
|
|
* and transmitter below. If someone tries to reboot us via
|
|
* WDB, this routine may be invoked while the RX handler is
|
|
* still running in tNetTask. If we disable the chip while
|
|
* that function is running, it'll start reading inconsistent
|
|
* status from the chip. We have to wait for that job to
|
|
* terminate first, then we can disable the receiver and
|
|
* transmitter.
|
|
*/
|
|
|
|
for (i = 0; i < GMAC_TIMEOUT; i++)
|
|
{
|
|
if (vxAtomicGet ((atomic_t*) &pDrvCtrl->gmacRxPending) == FALSE
|
|
&& vxAtomicGet ((atomic_t*) &pDrvCtrl->gmacTxPending) == FALSE
|
|
&& vxAtomicGet ((atomic_t*) &pDrvCtrl->gmacIntPending) == FALSE)
|
|
break;
|
|
(void)taskDelay (1);
|
|
}
|
|
|
|
if (i == GMAC_TIMEOUT)
|
|
GMAC_DEBUG ("%s%d: timed out waiting for job to complete\n",
|
|
(int)GMAC_NAME, pDev->unitNumber, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* Flush the recycle cache to shake loose any of our
|
|
* mBlks that may be stored there.
|
|
*/
|
|
|
|
endMcacheFlush ();
|
|
|
|
END_TX_SEM_TAKE (pEnd, WAIT_FOREVER);
|
|
|
|
for (i = 0; i < GMAC_TX_DESC_CNT; i++)
|
|
{
|
|
if (pDrvCtrl->gmacTxMblk[i] != NULL)
|
|
{
|
|
netMblkClChainFree (pDrvCtrl->gmacTxMblk[i]);
|
|
pDrvCtrl->gmacTxMblk[i] = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < GMAC_RX_DESC_CNT; i++)
|
|
{
|
|
if (pDrvCtrl->gmacRxMblk[i] != NULL)
|
|
{
|
|
netMblkClChainFree (pDrvCtrl->gmacRxMblk[i]);
|
|
pDrvCtrl->gmacRxMblk[i] = NULL;
|
|
}
|
|
}
|
|
|
|
END_TX_SEM_GIVE (pEnd);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndInt - handle device interrupts
|
|
*
|
|
* This function is invoked whenever the FCC's interrupt line is asserted.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndInt
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
/* not necessary to check return value here */
|
|
|
|
(void)vxAtomic32Set ((atomic_t *) &pDrvCtrl->gmacIntPending, TRUE);
|
|
|
|
/* mask interrupts here */
|
|
|
|
CSR_SETBIT_4 (pDev, GMAC_INT_MASK, GMAC_INT_DISABLE_RGMII);
|
|
CSR_WRITE_4 (pDev, DMA_INTR_ENA, 0);
|
|
jobQueuePost (pDrvCtrl->gmacJobQueue, &pDrvCtrl->gmacIntJob);
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndIntHandle - process link update
|
|
*
|
|
* This function is scheduled by the ISR to run in the context of tNetTask
|
|
* whenever an link update interrupt is received.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndIntHandle
|
|
(
|
|
void * pArg
|
|
)
|
|
{
|
|
QJOB * pJob;
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
INT32 status;
|
|
pJob = pArg;
|
|
pDrvCtrl = member_to_object (pJob, GMAC_DRV_CTRL, gmacIntJob);
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
|
|
|
|
/* RGMII/SGMII Interrupt mask */
|
|
|
|
status = CSR_READ_4 (pDev, GMAC_INT_STATUS);
|
|
if ((status & GMAC_INT_STATUS_LINKCHANGED) == GMAC_INT_STATUS_LINKCHANGED)
|
|
{
|
|
|
|
/* status changed, read SGMII register to clear */
|
|
|
|
(void) CSR_READ_4 (pDev, GMAC_GMII_STATUS);
|
|
|
|
(void) ftGmacLinkUpdate (pDev);
|
|
}
|
|
|
|
|
|
|
|
status = CSR_READ_4(pDev, DMA_STATUS);
|
|
|
|
|
|
if(status & (DMA_STATUS_RI | DMA_STATUS_IRQS)) /* TX/RX NORMAL interrupts */
|
|
{
|
|
/* Receive complete */
|
|
|
|
if ((status & DMA_STATUS_RI)&&
|
|
vxAtomicSet ((atomic_t*)&pDrvCtrl->gmacRxPending, TRUE) == FALSE)
|
|
{
|
|
|
|
/* update RX watchdog timer */
|
|
|
|
CSR_WRITE_4 (pDev, DMA_RX_WATCHDOG, 0x80);
|
|
|
|
ftGmacEndRxHandle(pDrvCtrl);
|
|
}
|
|
|
|
/* Transmit complete */
|
|
|
|
if ((status & DMA_STATUS_IRQS)&&
|
|
vxAtomicSet ((atomic_t*)&pDrvCtrl->gmacTxPending, TRUE) == FALSE)
|
|
{
|
|
|
|
ftGmacEndTxHandle(pDrvCtrl);
|
|
}
|
|
}
|
|
|
|
if (status & DMA_INT_ABNORMAL)
|
|
{
|
|
|
|
/* Receive buffer unavailable */
|
|
|
|
if ((status & DMA_INT_RX_NO_BUFFER) &&
|
|
vxAtomicSet ((atomic_t*)&pDrvCtrl->gmacRxPending, TRUE) == FALSE)
|
|
{
|
|
|
|
/*
|
|
* To resume processing Receive descriptors, the host should
|
|
* change the ownership of the descriptor and issue a Receive
|
|
* Poll Demand command.
|
|
*/
|
|
|
|
CSR_WRITE_4 (pDev, DMA_RX_WATCHDOG, 0x80);
|
|
ftGmacEndRxHandle(pDrvCtrl);
|
|
CSR_WRITE_4 (pDev, DMA_RCV_POLL_DEMAND, status);
|
|
}
|
|
}
|
|
vxAtomicSet ((atomic_t*)&pDrvCtrl->gmacIntPending, FALSE);
|
|
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
|
CSR_WRITE_4 (pDev, DMA_STATUS, status/* & 0x1ffff*/);
|
|
CSR_CLRBIT_4 (pDev, GMAC_INT_MASK, GMAC_INT_DISABLE_RGMII);
|
|
CSR_WRITE_4(pDev, DMA_INTR_ENA, DMA_INT_ENABLE);
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndRxHandle - process received frames
|
|
*
|
|
* This function is scheduled by the ISR to run in the context of tNetTask
|
|
* whenever an RX interrupt is received. It processes packets from the
|
|
* RX DMA ring and encapsulates them into mBlk tuples which are handed up
|
|
* to the MUX.
|
|
*
|
|
* There may be several packets waiting in the ring to be processed.
|
|
* We take care not to process too many packets in a single run through
|
|
* this function so as not to monopolize tNetTask and starve out other
|
|
* jobs waiting in the jobQueue. If we detect that there's still more
|
|
* packets waiting to be processed, we queue ourselves up for another
|
|
* round of processing.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndRxHandle
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
|
|
VXB_DEVICE_ID pDev;
|
|
M_BLK_ID pMblk = NULL, pNewMblk = NULL;
|
|
GMAC_DESC * pDesc;
|
|
int rxLen;
|
|
UINT32 desc_status;
|
|
int loopCounter = GMAC_MAX_RX;
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
pDesc = &pDrvCtrl->gmacRxDescMem[pDrvCtrl->gmacRxIdx];
|
|
|
|
|
|
|
|
while (loopCounter )
|
|
{
|
|
desc_status = pDesc->status;
|
|
if (desc_status & RDES0_OWN)
|
|
{
|
|
break;
|
|
}
|
|
if(ftGmacRxStatusCheck(desc_status) != 0)
|
|
{
|
|
goto rx_skip;
|
|
}
|
|
|
|
pNewMblk = endPoolTupleGet(pDrvCtrl->gmacEndObj.pNetPool);
|
|
|
|
if (pNewMblk == NULL)
|
|
{
|
|
GMAC_DEBUG ("%s%d: out of mBlks at %d\n", (int)GMAC_NAME,
|
|
pDev->unitNumber, pDrvCtrl->gmacRxIdx,0,0,0);
|
|
pDrvCtrl->gmacLastError.errCode = END_ERR_NO_BUF;
|
|
muxError (&pDrvCtrl->gmacEndObj, &pDrvCtrl->gmacLastError);
|
|
pDrvCtrl->gmacInDiscards++;
|
|
rx_skip:
|
|
pDesc->status = 0;
|
|
pDesc->ctrl |= ((MAC_MAX_FRAME_SZ - 1) & RDES1_BUFFER1_SIZE_MASK);
|
|
pDesc->status = RDES0_OWN;
|
|
GMAC_INC_DESC(pDrvCtrl->gmacRxIdx, GMAC_RX_DESC_CNT);
|
|
pDesc = &pDrvCtrl->gmacRxDescMem[pDrvCtrl->gmacRxIdx];
|
|
loopCounter--;
|
|
continue;
|
|
}
|
|
|
|
rxLen = (desc_status & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT;
|
|
|
|
pMblk = pDrvCtrl->gmacRxMblk[pDrvCtrl->gmacRxIdx];
|
|
|
|
pDrvCtrl->gmacRxMblk[pDrvCtrl->gmacRxIdx] = pNewMblk;
|
|
pNewMblk->m_next = NULL;
|
|
|
|
/* pre-invalidate the new buffer */
|
|
|
|
CACHE_USER_INVALIDATE (pNewMblk->m_data, pNewMblk->m_len);
|
|
|
|
pMblk->m_len = pMblk->m_pkthdr.len = rxLen;
|
|
pMblk->m_flags = M_PKTHDR | M_EXT;
|
|
|
|
pDesc->status = 0;
|
|
pDesc->ctrl |= ((MAC_MAX_FRAME_SZ - 1) & RDES1_BUFFER1_SIZE_MASK);
|
|
pDesc->status = RDES0_OWN;
|
|
pDesc->addr = (UINT32)GMAC_CACHE_DRV_VIRT_TO_PHYS(pNewMblk->m_data);
|
|
CACHE_USER_INVALIDATE (pMblk->m_data, pMblk->m_len);
|
|
|
|
/* Bump stats counters */
|
|
|
|
pDrvCtrl->gmacInOctets += pMblk->m_len;
|
|
pDrvCtrl->gmacInUcasts++;
|
|
|
|
GMAC_INC_DESC(pDrvCtrl->gmacRxIdx, GMAC_RX_DESC_CNT);
|
|
|
|
loopCounter--;
|
|
|
|
/* Give the packet to the stack. */
|
|
|
|
END_RCV_RTN_CALL (&pDrvCtrl->gmacEndObj, pMblk);
|
|
|
|
pDesc = &pDrvCtrl->gmacRxDescMem[pDrvCtrl->gmacRxIdx];
|
|
}
|
|
|
|
|
|
vxAtomicSet((atomic_t*)&pDrvCtrl->gmacRxPending, FALSE);
|
|
|
|
#ifdef GMAC_RX_DEBUG
|
|
printf("\r\n ft_gmac_rx_handle...done ");
|
|
#endif
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndTxHandle - process TX completion events
|
|
*
|
|
* This function is scheduled by the ISR to run in the context of tNetTask
|
|
* whenever an TX interrupt is received. It runs through all of the
|
|
* TX register pairs and checks the TX status to see how many have
|
|
* completed. For each completed transmission, the associated TX mBlk
|
|
* is released, and the outbound packet stats are updated.
|
|
*
|
|
* In the event that a TX underrun error is detected, the TX FIFO
|
|
* threshold is increased. This will continue until the maximum TX
|
|
* FIFO threshold is reached.
|
|
*
|
|
* If the transmitter has stalled, this routine will also call muxTxRestart()
|
|
* to drain any packets that may be waiting in the protocol send queues,
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftGmacEndTxHandle
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
|
|
VXB_DEVICE_ID pDev;
|
|
BOOL restart = FALSE;
|
|
GMAC_DESC * pDesc;
|
|
M_BLK_ID pMblk;
|
|
UINT32 desc_status, desc_ctrl;
|
|
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
END_TX_SEM_TAKE (&pDrvCtrl->gmacEndObj, WAIT_FOREVER);
|
|
|
|
while (pDrvCtrl->gmacTxFree < GMAC_TX_DESC_CNT)
|
|
{
|
|
pDesc = &pDrvCtrl->gmacTxDescMem[pDrvCtrl->gmacTxCons];
|
|
desc_status = pDesc->status;
|
|
desc_ctrl = pDesc->ctrl;
|
|
|
|
if(desc_status & TDES0_OWN)
|
|
{
|
|
goto tx_check_fail;
|
|
}
|
|
|
|
if(desc_ctrl & TDES0_ERROR_SUMMARY)
|
|
{
|
|
pDrvCtrl->gmacOutErrors++;
|
|
}
|
|
|
|
pDesc->status = pDesc->ctrl = 0;
|
|
|
|
if(pDrvCtrl->gmacTxCons == (GMAC_TX_DESC_CNT - 1)) /* the last one */
|
|
{
|
|
pDesc->ctrl |= TDES1_END_RING;
|
|
}
|
|
|
|
pMblk = pDrvCtrl->gmacTxMblk[pDrvCtrl->gmacTxCons];
|
|
|
|
if (pMblk != NULL)
|
|
{
|
|
pDrvCtrl->gmacOutOctets += pMblk->m_pkthdr.len;
|
|
|
|
if ((UINT8)pMblk->m_data[0] == 0xFF)
|
|
pDrvCtrl->gmacOutBcasts++;
|
|
else if ((UINT8)pMblk->m_data[0] & 0x1)
|
|
pDrvCtrl->gmacOutMcasts++;
|
|
else
|
|
pDrvCtrl->gmacOutUcasts++;
|
|
|
|
endPoolTupleFree (pMblk);
|
|
pDrvCtrl->gmacTxMblk[pDrvCtrl->gmacTxCons] = NULL;
|
|
}
|
|
|
|
pDrvCtrl->gmacTxFree++;
|
|
|
|
GMAC_INC_DESC (pDrvCtrl->gmacTxCons, GMAC_TX_DESC_CNT);
|
|
|
|
/*
|
|
* We released at least one descriptor: if the transmit
|
|
* channel is stalled, unstall it.
|
|
*/
|
|
|
|
if (pDrvCtrl->gmacTxStall == TRUE)
|
|
{
|
|
pDrvCtrl->gmacTxStall = FALSE;
|
|
restart = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
tx_check_fail:
|
|
END_TX_SEM_GIVE (&pDrvCtrl->gmacEndObj);
|
|
vxAtomicSet((atomic_t*)&pDrvCtrl->gmacTxPending, FALSE);
|
|
if (restart == TRUE)
|
|
muxTxRestart (pDrvCtrl);
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndEncap - encapsulate an outbound packet in the TX DMA ring
|
|
*
|
|
* This function sets up a descriptor for a packet transmit operation.
|
|
* With the zynq7k ethrnet controller, the TX DMA ring consists of
|
|
* descriptors that each describe a single packet fragment. We consume
|
|
* as many descriptors as there are mBlks in the outgoing packet, unless
|
|
* the chain is too long. The length is limited by the number of DMA
|
|
* segments we want to allow in a given DMA map. If there are too many
|
|
* segments, this routine will fail, and the caller must coalesce the
|
|
* data into fewer buffers and try again.
|
|
*
|
|
* This routine will also fail if there aren't enough free descriptors
|
|
* available in the ring, in which case the caller must defer the
|
|
* transmission until more descriptors are completed by the chip.
|
|
*
|
|
* RETURNS: ENOSPC if there are too many fragments in the packet, EAGAIN
|
|
* if the DMA ring is full, otherwise OK.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int ftGmacEndEncap
|
|
(
|
|
GMAC_DRV_CTRL * pDrvCtrl,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
GMAC_DESC * pDesc = NULL;
|
|
GMAC_DESC * pFirst = NULL;
|
|
UINT32 firstIdx, lastIdx = 0;
|
|
int frags = 0,nFrags;
|
|
M_BLK_ID pCurr;
|
|
|
|
firstIdx = pDrvCtrl->gmacTxProd;
|
|
pDev = pDrvCtrl->gmacDev;
|
|
pFirst = &pDrvCtrl->gmacTxDescMem [pDrvCtrl->gmacTxProd];
|
|
if (pDrvCtrl->gmacTxMblk [pDrvCtrl->gmacTxProd] != NULL)
|
|
return (EAGAIN);
|
|
|
|
/*
|
|
* Load the DMA map to build the segment list.
|
|
* This will fail if there are too many segments.
|
|
*/
|
|
|
|
nFrags = 0;
|
|
for (pCurr = pMblk; pCurr != NULL; pCurr = pCurr->m_next)
|
|
{
|
|
if (pCurr->m_len != 0)
|
|
++nFrags;
|
|
}
|
|
|
|
if (nFrags > pDrvCtrl->gmacTxFree || nFrags >= GMAC_MAXFRAG)
|
|
{
|
|
return ENOSPC;
|
|
}
|
|
|
|
|
|
for (pCurr = pMblk; pCurr != NULL; pCurr = pCurr->m_next)
|
|
{
|
|
if (pCurr->m_len != 0)
|
|
{
|
|
pDesc = &pDrvCtrl->gmacTxDescMem [pDrvCtrl->gmacTxProd];
|
|
pDesc->addr = (UINT32)GMAC_CACHE_DRV_VIRT_TO_PHYS(pCurr->m_data);
|
|
pDesc->status &= ~0x1ffff;
|
|
pDesc->ctrl &= ~(DESC_TXCTRL_SIZE1MASK);
|
|
pDesc->ctrl |= TDES1_INTERRUPT;
|
|
pDesc->ctrl |= (pCurr->m_len & TDES1_BUFFER1_SIZE_MASK);
|
|
if(frags == 0)
|
|
pDesc->ctrl |= TDES1_FIRST_SEGMENT;
|
|
else
|
|
{
|
|
pDesc->status |= TDES0_OWN;
|
|
}
|
|
|
|
/* sync the data buffer */
|
|
|
|
#define TX_DESC_INT (1 << 30)
|
|
#define TX_DESC_CSUM_INSERT(x) ((x) << 22)
|
|
pDesc->status |= TX_DESC_INT;
|
|
if (pDrvCtrl->gmacCaps.cap_enabled & IFCAP_TXCSUM)
|
|
{
|
|
if (pCurr->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
|
|
pDesc->status |= TX_DESC_CSUM_INSERT(3);
|
|
else if (pCurr->m_pkthdr.csum_flags & CSUM_IP)
|
|
pDesc->status |= TX_DESC_CSUM_INSERT(3);
|
|
}
|
|
lastIdx = pDrvCtrl->gmacTxProd;
|
|
|
|
CACHE_USER_FLUSH (pCurr->m_data, pCurr->m_len);
|
|
|
|
GMAC_INC_DESC(pDrvCtrl->gmacTxProd, GMAC_TX_DESC_CNT);
|
|
|
|
frags++;
|
|
pDrvCtrl->gmacTxFree--;
|
|
}
|
|
}
|
|
|
|
pDesc->ctrl |= TDES1_LAST_SEGMENT;
|
|
pFirst->status |= TDES0_OWN;
|
|
|
|
/* Save the mBlk for later. */
|
|
|
|
pDrvCtrl->gmacTxMblk[lastIdx] = pMblk;
|
|
|
|
/* Transfer descriptors to the chip. */
|
|
|
|
CSR_SETBIT_4(pDev, DMA_CONTROL, DMA_CONTROL_ST);
|
|
|
|
CSR_WRITE_4(pDev, DMA_XMT_POLL_DEMAND, 0xff);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacEndSend - transmit a packet
|
|
*
|
|
* This function transmits the packet specified in <pMblk>.
|
|
*
|
|
* RETURNS: OK, ERROR, or END_ERR_BLOCK.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int ftGmacEndSend
|
|
(
|
|
END_OBJ * pEnd,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
M_BLK_ID pTmp;
|
|
int rval;
|
|
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
|
|
#ifdef GMAC_TX_DEBUG
|
|
printf("\r\n\r\n ft_gmac_send... begin");
|
|
#endif
|
|
|
|
if (pDrvCtrl->gmacPolling == TRUE)
|
|
{
|
|
endPoolTupleFree (pMblk);
|
|
return (ERROR);
|
|
}
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
END_TX_SEM_TAKE (pEnd, WAIT_FOREVER);
|
|
|
|
if (!pDrvCtrl->gmacTxFree || !(pDrvCtrl->gmacCurStatus & IFM_ACTIVE))
|
|
goto blocked;
|
|
|
|
/*
|
|
* First, try to do an in-place transmission, using
|
|
* gather-write DMA.
|
|
*/
|
|
|
|
rval = ftGmacEndEncap (pDrvCtrl, pMblk);
|
|
|
|
/*
|
|
* If ftGmacEndEncap returns ENOSPC, it means it ran out of TX descriptors
|
|
* and couldn't encapsulate the whole packet fragment chain. In that case,
|
|
* we need to coalesce everything into a single buffer and try again. If
|
|
* any other error is returned, then something went wrong, and we have to
|
|
* abort the transmission entirely.
|
|
*/
|
|
|
|
if (rval == ENOSPC)
|
|
{
|
|
if ((pTmp = endPoolTupleGet(pDrvCtrl->gmacEndObj.pNetPool)) == NULL)
|
|
goto blocked;
|
|
|
|
pTmp->m_len = pTmp->m_pkthdr.len =
|
|
netMblkToBufCopy(pMblk, mtod(pTmp, char *), NULL);
|
|
pTmp->m_flags = pMblk->m_flags;
|
|
|
|
/* try transmission again, should succeed this time */
|
|
|
|
rval = ftGmacEndEncap (pDrvCtrl, pTmp);
|
|
if (rval == OK)
|
|
endPoolTupleFree (pMblk);
|
|
else
|
|
endPoolTupleFree (pTmp);
|
|
}
|
|
|
|
if (rval != OK)
|
|
goto blocked;
|
|
|
|
#ifdef GMAC_TX_DEBUG
|
|
printf("\r\n\r\n ft_gmac_send... done");
|
|
#endif
|
|
|
|
|
|
END_TX_SEM_GIVE (pEnd);
|
|
return (OK);
|
|
|
|
blocked:
|
|
pDrvCtrl->gmacTxStall = TRUE;
|
|
END_TX_SEM_GIVE (pEnd);
|
|
|
|
return (END_ERR_BLOCK);
|
|
}
|
|
|
|
LOCAL STATUS ftGmacEndPollSend
|
|
(
|
|
END_OBJ * pEnd,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
GMAC_DESC * pDesc;
|
|
M_BLK_ID pTmp;
|
|
int len, i;
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
|
|
if (pDrvCtrl->gmacPolling == FALSE)
|
|
return (ERROR);
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
pTmp = pDrvCtrl->gmacPollBuf;
|
|
|
|
len = netMblkToBufCopy (pMblk, mtod(pTmp, char *), NULL);
|
|
pTmp->m_len = pTmp->m_pkthdr.len = len;
|
|
pTmp->m_flags = pMblk->m_flags;
|
|
pTmp->m_pkthdr.csum_flags = pMblk->m_pkthdr.csum_flags;
|
|
pTmp->m_pkthdr.csum_data = pMblk->m_pkthdr.csum_data;
|
|
|
|
if (ftGmacEndEncap (pDrvCtrl, pTmp) != OK)
|
|
return (EAGAIN);
|
|
|
|
pDesc = &pDrvCtrl->gmacTxDescMem [pDrvCtrl->gmacTxCons];
|
|
|
|
/* poll the status to see if the transmission is done */
|
|
|
|
i = 0;
|
|
while(i++ < GMAC_TIMEOUT)
|
|
{
|
|
if (!(pDesc->status & (UINT32)TDES0_OWN))
|
|
break;
|
|
}
|
|
|
|
if (i == GMAC_TIMEOUT)
|
|
return (ERROR);
|
|
|
|
/* reset the tx descriptor */
|
|
|
|
pDesc->status = pDesc->ctrl = 0;
|
|
if(pDrvCtrl->gmacTxCons == (GMAC_TX_DESC_CNT - 1)) /* the last one */
|
|
{
|
|
pDesc->ctrl |= TDES1_END_RING;
|
|
}
|
|
|
|
pDrvCtrl->gmacTxFree++;
|
|
GMAC_INC_DESC (pDrvCtrl->gmacTxCons, GMAC_TX_DESC_CNT);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
LOCAL int ftGmacEndPollReceive
|
|
(
|
|
END_OBJ * pEnd,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
VXB_DEVICE_ID pDev;
|
|
GMAC_DESC * pDesc;
|
|
int length;
|
|
M_BLK_ID pPkt;
|
|
int rval = EAGAIN;
|
|
|
|
pDrvCtrl = (GMAC_DRV_CTRL *)pEnd;
|
|
|
|
if (pDrvCtrl->gmacPolling == FALSE)
|
|
return (ERROR);
|
|
|
|
if (!(pMblk->m_flags & M_EXT))
|
|
return (ERROR);
|
|
|
|
pDev = pDrvCtrl->gmacDev;
|
|
|
|
pDesc = &pDrvCtrl->gmacRxDescMem [pDrvCtrl->gmacRxIdx];
|
|
|
|
pPkt = pDrvCtrl->gmacRxMblk[pDrvCtrl->gmacRxIdx];
|
|
|
|
if (pDesc->status & RDES0_OWN)
|
|
return (EAGAIN);
|
|
|
|
length = (pDesc->status & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT;
|
|
|
|
if (pMblk->m_len < length)
|
|
return (ERROR);
|
|
|
|
if(ftGmacRxStatusCheck(pDesc->status) != 0)
|
|
{
|
|
rval = ERROR;
|
|
}
|
|
else
|
|
{
|
|
pMblk->m_len = pMblk->m_pkthdr.len = length;
|
|
pMblk->m_flags = M_PKTHDR | M_EXT;
|
|
|
|
/* sync the DMA buffer */
|
|
|
|
CACHE_USER_INVALIDATE (pPkt->m_data, pMblk->m_len);
|
|
|
|
bcopy (mtod(pPkt, char *),
|
|
mtod(pMblk, char *), pMblk->m_len);
|
|
|
|
CACHE_USER_INVALIDATE (pPkt->m_data, pPkt->m_len);
|
|
|
|
rval = OK;
|
|
}
|
|
|
|
/* reset the RX descriptor */
|
|
|
|
ftGmacRxDescInit(pDesc, pDrvCtrl->gmacRxIdx, pDesc->addr);
|
|
|
|
GMAC_INC_DESC (pDrvCtrl->gmacRxIdx, GMAC_RX_DESC_CNT);
|
|
|
|
return (rval);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftGmacPhyAddrGet - probe phy address
|
|
*
|
|
* This function probe phy address from 0~31 accroding to standard.
|
|
*
|
|
* RETURNS: (0~31) phy address; 32 error address.
|
|
*
|
|
* ERRNO: N/A
|
|
*
|
|
* !NOTE: For some PHYs, such as RTL8211E, PHY address 0 is a broadcast from
|
|
* the MAC; each PHY device should respond. (RTL8211EG Datasheet.)
|
|
*
|
|
* (If so, WE HOPE user set phy address in hwconf.c by "phyAddr" resource.
|
|
* Because it will take lots of time to check all 32 addresses when boot.)
|
|
*
|
|
*/
|
|
|
|
LOCAL int ftGmacPhyAddrGet (VXB_DEVICE_ID pDev)
|
|
{
|
|
int i = 0;
|
|
UINT16 phyId1;
|
|
UINT16 phyId2;
|
|
BOOL flag = FALSE;
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
ftGmacPhyRead (pDev, i, MII_PHY_ID1_REG, &phyId1); /*read ID1 from phy reg2*/
|
|
ftGmacPhyRead (pDev, i, MII_PHY_ID2_REG, &phyId2); /*read ID2 from phy reg3*/
|
|
|
|
if((phyId2 & 0xFFFF) != 0xFFFF)
|
|
{
|
|
if((0 == i) && (0x1C == phyId1) && ((phyId2>>10) == 0x32))
|
|
{
|
|
/* skip RTL8211 broadcase address */
|
|
continue;
|
|
}
|
|
if((0 == i) && (0x00 == phyId1) && (phyId2 == 0x11a))
|
|
{
|
|
/* skip YT8521 broadcase address */
|
|
continue;
|
|
}
|
|
|
|
flag = TRUE;
|
|
break; /* get phy addr */
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
STATUS ftGmacPhyAddrShow (int verbose)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
int i, j;
|
|
UINT16 phyId1;
|
|
UINT16 phyId2;
|
|
STATUS st;
|
|
|
|
if(0 == verbose)
|
|
{
|
|
printf("verbose: *0, 1\r\n\n");
|
|
}
|
|
else if(1 == verbose)
|
|
{
|
|
printf("verbose: 0, *1\r\n\n");
|
|
}
|
|
|
|
|
|
for(i=0; i<2; i++)
|
|
{
|
|
pDev = vxbInstByNameFind("gmac", i);
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
printf("gmac%d: pDrvCtrl->gmacMiiPhyAddr = %d\r\n", i, pDrvCtrl->gmacMiiPhyAddr);
|
|
}
|
|
|
|
if(1 == verbose)
|
|
{
|
|
for(i=0; i<2; i++)
|
|
{
|
|
pDev = vxbInstByNameFind("gmac", i);
|
|
printf("---------------gmac%d probe phy addr-------------- \r\n",i);
|
|
for(j=0; j<32; j++)
|
|
{
|
|
phyId1 = phyId2 = 0;
|
|
st = ftGmacPhyRead(pDev,j,MII_PHY_ID1_REG, &phyId1);
|
|
st |= ftGmacPhyRead(pDev,j,MII_PHY_ID2_REG, &phyId2);
|
|
if(OK != st)
|
|
{
|
|
printf("failed read phy id! j=%d \r\n",j);
|
|
}
|
|
printf(" phyAddr[%02d] ID: 0x%04X 0x%04X \r\n", j, phyId1, phyId2);
|
|
}
|
|
printf(" \r\n");
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
STATUS ftGmacRxdecShow ()
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
GMAC_DRV_CTRL * pDrvCtrl;
|
|
int i, j;
|
|
for(i=0; i<1; i++)
|
|
{
|
|
pDev = vxbInstByNameFind("gmac", i);
|
|
pDrvCtrl = pDev->pDrvCtrl;
|
|
for(j=0; j<GMAC_RX_DESC_CNT; j++)
|
|
{
|
|
|
|
printf(" [%02d] des 0x%x status 0x%08X ctrl 0x%08X addr 0x%08X next 0x%08X\r\n"
|
|
, j, &pDrvCtrl->gmacRxDescMem[j], pDrvCtrl->gmacRxDescMem[j].status, pDrvCtrl->gmacRxDescMem[j].ctrl,pDrvCtrl->gmacRxDescMem[j].addr,
|
|
pDrvCtrl->gmacRxDescMem[j].next);
|
|
}
|
|
printf(" \r\n");
|
|
}
|
|
|
|
|
|
return OK;
|
|
}
|
|
|
|
|