📄 ks8695end.c
字号:
}
/*
* SetDefaults
* This function is used to set initial defaults before Parse routine.
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE structure.
*
* Return(s)
* NONE.
*/
LOCAL void SetDefaults(PEND_DEVICE pDrvCtrl)
{
DRV_LOG(DRV_DEBUG_LOAD, "SetDefaults\n", 1, 2, 3, 4, 5, 6);
/* Transmit Descriptor Count */
DI.nTxDescTotal = TXDESC_DEFAULT; /* 128 | 32 | 32(d) */
/* Receive Descriptor Count */
DI.nRxDescTotal = RXDESC_DEFAULT; /* 128 | 32 | 32(d) */
/* Transmit Checksum Offload Enable configuration */
DI.bTxChecksum = TXCHECKSUM_DEFAULT; /* enabled */
/* Receive Checksum Offload Enable */
DI.bRxChecksum = RXCHECKSUM_DEFAULT; /* enabled */
/* Flow Control */
DI.bRxFlowCtrl = FLOWCONTROL_DEFAULT; /* enabled */
/* currently Tx control flow shares the setting of Rx control flow */
DI.bTxFlowCtrl = DI.bRxFlowCtrl;
/* Programmable Burst Length */
DI.byTxPBL = PBL_DEFAULT; /* Tx PBL size */
DI.byRxPBL = PBL_DEFAULT; /* Rx PBL size */
/* Perform PHY PowerDown Reset instead of soft reset, the Option function can
be overwritten by user later */
DI.bPowerDownReset = TRUE;
#ifdef PACKET_DUMP
/* for debug only */
DI.uDebugDumpTxPkt = 0xff;
DI.uDebugDumpRxPkt = 0xff;
#endif
pDrvCtrl->nWatchdogDelay = sysClkRateGet() * 5; /* every 5 secs */
pDrvCtrl->offset = 2; /* 2 bytes to make IP header dword aligned */
}
/*
* CheckConfigurations
* This function checks all command line paramters for valid user
* input. If an invalid value is given, or if no user specified
* value exists, a default value is used.
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE structure.
*
* Return(s)
* NONE.
*/
LOCAL void CheckConfigurations(PEND_DEVICE pDrvCtrl)
{
int i;
DRV_LOG(DRV_DEBUG_LOAD, "CheckConfigurations\n", 1, 2, 3, 4, 5, 6);
/* Tx coalescing, currently can only be used if buffer unavailable bit is set */
DI.nTransmitCoalescing = (DI.nTxDescTotal >> 3);
/* User speed and/or duplex options */
DI.usCType[0] = SW_PHY_DEFAULT;
if (DMA_LAN == DI.usDMAId) {
/*TEMP, currently assume all other ports share same configuration with
first one, will add more options for LAN ports later */
for (i = 1; i < SW_MAX_LAN_PORTS; i++) {
DI.usCType[i] = DI.usCType[0];
}
/* initialize some variables which do not have user configurable options */
for (i = 0; i <= SW_MAX_LAN_PORTS; i++) {
DPI[i].byCrossTalkMask = 0x1f;
DPI[i].bySpanningTree = SW_SPANNINGTREE_ALL;
DPI[i].byDisableSpanningTreeLearn = FALSE;
}
/* set default as direct mode for port 5, so no lookup table is checking */
DI.bRxDirectMode = FALSE;
DI.bTxRreTagMode = FALSE;
DI.bPort5FlowCtrl = DI.bRxFlowCtrl;
DI.bPortsFlowCtrl = DI.bRxFlowCtrl;
}
}
/*
* gpioConfigure
* This function is use to configure GPIO pins required for extra LEDs
* as speed indicators.
*
* Argument(s)
* pDrvCtrl pionter to END_DEVICE data structure.
*
* Return(s)
* NONE
*/
void gpioConfigure(PEND_DEVICE pDrvCtrl)
{
UINT32 uReg;
uReg = KS8695_READ_REG(REG_GPIO_MODE);
switch (DI.usDMAId) {
#ifdef KS8695
case DMA_HPNA:
return;
#endif
case DMA_LAN:
uReg |= 0xf0; /* GPIO 4-7 for port 1 - 4, configure them as output */
break;
default:
case DMA_WAN:
uReg |= 0x08; /* GPIO 3 for WAN port */
break;
}
KS8695_WRITE_REG(REG_GPIO_MODE, uReg);
}
/*
* gpioSet
* This function is use to set/reset given GPIO pin corresponding to the port.
*
* Argument(s)
* pDrvCtrl pionter to END_DEVICE data structure.
* uPort port for the tag to insert
* bSet enable/disable LED
*
* Return(s)
* NONE
*/
void gpioSet(PEND_DEVICE pDrvCtrl, UINT uPort, UINT bSet)
{
UINT32 uReg;
DRV_LOG(DRV_DEBUG_LOAD, "gpioSet\n", 1, 2, 3, 4, 5, 6);
uReg = KS8695_READ_REG(REG_GPIO_DATA);
switch (DI.usDMAId) {
#ifdef KS8695
case DMA_HPNA:
return;
#endif
case DMA_LAN:
if (bSet)
uReg &= ~(1 << (uPort + 4)); /* low for LED on */
else
uReg |= (1 << (uPort + 4)); /* high for LED off */
break;
default:
case DMA_WAN:
if (bSet)
uReg &= ~0x08; /* low for LED on */
else
uReg |= 0x08; /* high for LED off */
break;
}
KS8695_WRITE_REG(REG_GPIO_DATA, uReg);
}
/*
* swGetPhyStatus
* This function is used to get the status of auto negotiation.
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE structure.
* uPort port to query
*
* Return(s)
* TRUE if connected
* FALSE otherwise
*/
int swGetPhyStatus(PEND_DEVICE pDrvCtrl, UINT uPort)
{
UINT uReg, uOff, uShift = 0;
DRV_LOG(DRV_DEBUG_LOG_PHY, "swGetPhyStatus\n", 1, 2, 3, 4, 5, 6);
switch (DI.usDMAId) {
#ifdef KS8695
case DMA_HPNA:
/* temp */
uReg = KS8695_READ_REG(KS8695_HPNA_CONTROL);
DI.usLinkSpeed[uPort] = (uReg & 0x00000002) ? SPEED_100 : SPEED_10;
DI.bHalfDuplex[uPort] = (uReg & 0x00000001) ? FULL_DUPLEX : HALF_DUPLEX;
/* note that there is no register bit corresponding to HPNA's link status
therefore don't report it */
DI.bLinkActive[uPort] = TRUE;
return TRUE;
#endif
case DMA_WAN:
uOff = REG_WAN_CONTROL;
uShift = 16;
break;
default:
case DMA_LAN:
switch (uPort) {
case SW_PORT_4:
uOff = REG_SWITCH_AUTO1;
break;
break;
case SW_PORT_3:
uOff = REG_SWITCH_AUTO1;
break;
uShift = 16;
break;
case SW_PORT_2:
uOff = REG_SWITCH_AUTO0;
break;
case SW_PORT_1:
default:
uOff = REG_SWITCH_AUTO0;
uShift = 16;
break;
}
}
uReg = KS8695_READ_REG(uOff);
/* if not linked yet */
if (!(uReg & ((UINT)SW_AUTONEGO_STAT_LINK << uShift))) {
DI.bLinkActive[uPort] = FALSE;
DI.usLinkSpeed[uPort] = SPEED_UNKNOWN;
DI.bHalfDuplex[uPort] = 0;
gpioSet(pDrvCtrl, uPort, FALSE);
return FALSE;
}
DI.bLinkActive[uPort] = TRUE;
if (SW_PHY_AUTO == DI.usCType[uPort]) {
/* if auto nego complete */
if ((UINT)SW_AUTONEGO_COMPLETE << uShift) {
/* clear auto nego restart bit */
uReg &= ~((UINT)SW_AUTONEGO_RESTART << uShift);
KS8695_WRITE_REG(uOff, uReg);
SW_WRITE_DELAY();
DI.usLinkSpeed[uPort] = (uReg & ((UINT)SW_AUTONEGO_STAT_SPEED << uShift)) ? SPEED_100 : SPEED_10;
DI.bHalfDuplex[uPort] = (uReg & ((UINT)SW_AUTONEGO_STAT_DUPLEX << uShift)) ? FULL_DUPLEX : HALF_DUPLEX;
DI.bAutoNegoInProgress[uPort] = FALSE;
gpioSet(pDrvCtrl, uPort, SPEED_100 == DI.usLinkSpeed[uPort]);
/*RLQ, need to verify real duplex mode instead report it correct here */
/* duplex bit may not right if partner doesn't support all mode, do further detection */
if ((uReg & (SW_AUTONEGO_PART_100FD | SW_AUTONEGO_PART_100HD | SW_AUTONEGO_PART_10FD | SW_AUTONEGO_PART_10HD) << uShift)
!= (SW_AUTONEGO_PART_100FD | SW_AUTONEGO_PART_100HD | SW_AUTONEGO_PART_10FD | SW_AUTONEGO_PART_10HD)) {
if (SPEED_100 == DI.usLinkSpeed[uPort]) {
if ((uReg & (SW_AUTONEGO_PART_100FD << uShift))) {
DI.bHalfDuplexDetected[uPort] = FULL_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, TRUE);
backPressureEnable(pDrvCtrl, uPort, FALSE);
#endif
} else {
DI.bHalfDuplexDetected[uPort] = HALF_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, FALSE);
backPressureEnable(pDrvCtrl, uPort, TRUE);
#endif
}
}
else {
if ((uReg & (SW_AUTONEGO_PART_10FD << uShift))) {
DI.bHalfDuplexDetected[uPort] = FULL_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, TRUE);
backPressureEnable(pDrvCtrl, uPort, FALSE);
#endif
}
else {
DI.bHalfDuplexDetected[uPort] = HALF_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, FALSE);
backPressureEnable(pDrvCtrl, uPort, TRUE);
#endif
}
}
}
/* software workaround for flow control, need to know partner's flow control */
if (DMA_WAN == DI.usDMAId) { /* currently do it to WAN only, there is no problem to LAN, will do HPNA later */
uint8_t bFlowCtrl;
/* we need to check partner's control flow setting for the matching, if not, changes ours */
bFlowCtrl = ((SW_AUTONEGO_PART_PAUSE << uShift) & uReg) ? TRUE : FALSE;
if (bFlowCtrl != DI.bRxFlowCtrl) { /* Tx same as Rx, so test Rx should be enough */
/* need to change ours accordingly, which will overwrite current one */
macConfigureFlow(pDrvCtrl, bFlowCtrl);
}
}
DRV_LOG(DRV_DEBUG_LOG_PHY, "Auto Nego completed\n", 1, 2, 3, 4, 5, 6);
}
else {
/* auto nego in progress */
DRV_LOG(DRV_DEBUG_LOG_PHY, "Auto Nego in progress...\n", 1, 2, 3, 4, 5, 6);
/* wait for next timer */
DI.bLinkActive[uPort] = FALSE;
DI.usLinkSpeed[uPort] = SPEED_UNKNOWN;
DI.bHalfDuplex[uPort] = 0;
}
}
else {
/* manually connection */
if (SW_PHY_10BASE_T_FD == DI.usCType[uPort] || SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) {
DI.bHalfDuplex[uPort] = FULL_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, TRUE);
backPressureEnable(pDrvCtrl, uPort, FALSE);
#endif
}
else {
DI.bHalfDuplex[uPort] = HALF_DUPLEX;
#if !defined(KS8695) && !defined(KS8695X)
forceFlowControl(pDrvCtrl, uPort, FALSE);
backPressureEnable(pDrvCtrl, uPort, TRUE);
#endif
}
if (SW_PHY_100BASE_TX_FD == DI.usCType[uPort] || SW_PHY_100BASE_TX == DI.usCType[uPort]) {
DI.usLinkSpeed[uPort] = SPEED_100;
gpioSet(pDrvCtrl, uPort, TRUE);
}
else {
DI.usLinkSpeed[uPort] = SPEED_10;
gpioSet(pDrvCtrl, uPort, FALSE);
}
/* software workaround for flow control, need to know partner's flow control */
if (DMA_WAN == DI.usDMAId) { /* currently do it to WAN only, there is no problem to LAN, will do HPNA later */
macConfigureFlow(pDrvCtrl, FULL_DUPLEX == DI.bHalfDuplex[uPort] ? TRUE : FALSE);
}
}
return TRUE;
}
/*
* swDetectPhyConnection
* This function is used to start auto negotiation
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE struct
* uPort port to start
*
* Return(s)
* NONE.
*/
LOCAL void swDetectPhyConnection(PEND_DEVICE pDrvCtrl, UINT uPort)
{
if (LINK_SELECTION_FORCED != DI.byDisableAutoNego[uPort] && !DI.bAutoNegoInProgress[uPort] && DI.bLinkChanged[uPort]) {
swAutoNegoStart(pDrvCtrl, uPort);
DI.bLinkChanged[uPort] = FALSE;
DI.bLinkActive[uPort] = FALSE;
}
swGetPhyStatus(pDrvCtrl, uPort);
}
/*
* swPhyReset
* This function is used to reset phy chipset (powerdown or soft reset).
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE structure.
* uPort port to start
*
* Return(s)
* NONE
*/
void swPhyReset(PEND_DEVICE pDrvCtrl, UINT uPort)
{
UINT uReg, uShift = 0;
UINT uPowerReg;
UINT uReg1;
DRV_LOG(DRV_DEBUG_LOG_PHY, "swPhyReset\n", 1, 2, 3, 4, 5, 6);
/* IEEE spec. of auto nego bit */
uReg1 = BIT(7);
switch (DI.usDMAId) {
#ifdef KS8695
case DMA_HPNA:
return;
#endif
case DMA_WAN:
uPowerReg = REG_WAN_POWERMAGR;
break;
default:
case DMA_LAN:
switch (uPort) {
case SW_PORT_4:
uPowerReg = REG_LAN34_POWERMAGR;
break;
case SW_PORT_3:
uPowerReg = REG_LAN34_POWERMAGR;
uShift = 16;
break;
case SW_PORT_2:
uPowerReg = REG_LAN12_POWERMAGR;
break;
case SW_PORT_1:
default:
uPowerReg = REG_LAN12_POWERMAGR;
uShift = 16;
break;
}
}
if (DI.bPowerDownReset) {
uReg = KS8695_READ_REG(uPowerReg);
KS8695_WRITE_REG(uPowerReg, uReg | ((UINT)POWER_POWERDOWN << uShift));
#ifndef NO_TASK_DELAY
taskDelay(5);
#else
delayEx(500000);
#endif
uReg &= ~((UINT)POWER_POWERDOWN << uShift);
/* turn off IEEE auto nego */
uReg &= ~(uReg1 << uShift);
KS8695_WRITE_REG(uPowerReg, uReg);
/* need 20 cpu clock delay for switch related registers */
SW_WRITE_DELAY();
}
else {
uReg = KS8695_READ_REG(uPowerReg);
/* turn off IEEE auto nego */
uReg &= ~(uReg1 << uShift);
KS8695_WRITE_REG(uPowerReg, uReg);
/* need 20 cpu clock delay for switch related registers */
SW_WRITE_DELAY();
}
}
/*
* macReset
* This function will execute a soft reset the chipset.
*
* Argument(s)
* pDrvCtrl pointer to END_DEVICE structure.
*
* Return(s)
* OK if success
* ERROR otherwise
*/
int macReset(PEND_DEVICE pDrvCtrl)
{
int nTimeOut = 200;
UINT32 uReg;
DRV_LOG(DRV_DEBUG_LOAD, "macReset\n", 1, 2, 3, 4, 5, 6);
/* disable IER if any */
uReg = KS8695_READ_REG(REG_INT_ENABLE);
switch (DI.usDMAId) {
#ifdef KS8695
case DMA_HPNA:
uReg &= ~INT_HPNA_MASK;
break;
#endif
case DMA_LAN:
uReg &= ~INT_LAN_MASK;
break;
default:
case DMA_WAN:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -