📄 nicmiiwork.c
字号:
/*******************************************************************************
*** Note: Copy rights resevered to Beijing Pacific Linkair Communications Co.
***
*** File Name: NICMii.c
*** Purpose : Operations about MII
***
*** Author : Guangzhao Tian
*** Modified : By Guangzhao Tian at 2000/9/11
***
**/
#include "NICMacro.h"
#include "NICWinReg.h"
#include "NICCommand.h"
#include "NICEeprom.h"
#include "NICData.h"
#include "NICHelper.h"
#include "NICMii.h"
#include "NICExport.h"
/***********************************************************************
*** Used to detect if 10Base-T, 100Base-TX, or external MII is available.
**/
BOOLEAN NIC_MIITryIt(IN PNIC_INFORMATION pAdapter,IN USHORT MediaOptions )
{
BOOLEAN bHandles100Mbit = FALSE;
USHORT wPhyStatus=0;
/* First see if there's anything connected to the MII */
if (!NIC_MIIFindPhy(pAdapter) )
{
DebugMsg("Cannot find MII!\n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
DebugMsg(" We find the MII available ! \n");
/* Nowhere is it written that the register must be latched, and since reset is the last bit out,
the contents might not be valid. read it one more time.*/
/* Now we can read the status and try to figure out what's out there. */
if (! NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &wPhyStatus) )
{
DebugMsg("Error: PHY not responding when getting status ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
if ( (wPhyStatus & MII_STATUS_AUTO) && (wPhyStatus & MII_STATUS_EXTENDED) )
{
/* If it is capable of auto negotiation, see if it has been done already. */
DebugMsg(" MII Capable of Autonegotiation ! \n");
/* Check the current MII auto-negotiation state and see if we need to start auto-neg over. */
if ( !NIC_MIICheckConfg(pAdapter, MediaOptions) )
{
DebugMsg(" We cannot config the MII Phy ! \n");
return FALSE;
}
DebugMsg(" MII auto-negotiation state -- OK ! \n");
/* See if link is up... */
if (! NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &wPhyStatus) )
{
DebugMsg("Error: PHY not responding when getting status ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
if (wPhyStatus & MII_STATUS_LINK_UP)
{
if (!NIC_MIILinkSpeedGet(pAdapter, &bHandles100Mbit))
{
DebugMsg(" Unknown link speed! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
if (bHandles100Mbit)
{ pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_100; }
else
{ pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_10; }
return TRUE;
}
else
{
DebugMsg(" Auto Negotiations not completed, or even not be executed at all, use default! \n");
/* Assume 10Mbit if no link*/
if (wPhyStatus & MII_STATUS_100MB_MASK)
{ pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_100; }
else
{ pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_10; }
return TRUE;
}
}
return FALSE;
}
/*************************************************************************************************
*** Sets up the tranceiver through MII registers. This will first check on the current connection
*** state as shown by the MII registers. If the current state matches what the media options support,
*** then the link is kept. If not, the registers will be configured in the proper manner and auto-negotiation
*** will be restarted.
*** Since this function is called for forced xcvr configurations, it assumes that the xcvr type has
*** been verified as supported by the NIC.
**/
BOOLEAN NIC_MIICheckConfg(IN PNIC_INFORMATION pAdapter, IN USHORT pMediaOptions )
{
BOOLEAN PhyResponding;
USHORT PhyControl;
USHORT PhyStatus;
USHORT PhyAnar;
USHORT tempAnar;
/* Check to see if auto-negotiation has completed. Check the results in the control and status registers. */
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_CONTROL, &PhyControl);
if (!PhyResponding)
{
DebugMsg(" Error: Phy not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
if (!PhyResponding)
{
DebugMsg(" Error: Phy not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
if ( ! ( (PhyControl & MII_CONTROL_ENABLE_AUTO) && (PhyStatus & MII_STATUS_AUTO_DONE) ) )
{
/* Auto-negotiation did not complete, so start it over using the new settings. */
if ( !NIC_MIIConfig(pAdapter,pMediaOptions) ) return FALSE;
}
/* Auto-negotiation has completed. Check the results against the ANAR and ANLPAR
registers to see if we need to restart auto-neg. */
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
if (!PhyResponding)
{
DebugMsg(" Error: Phy not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
/* Check to see what we negotiated with the link partner. First, let's make
sure that the ANAR is set properly based on the media options defined. */
tempAnar = 0;
if (pMediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE)
{
if (pAdapter->LinkInfo.AutoSelect) tempAnar |= MII_ANAR_100TXFD | MII_ANAR_100TX;
else
{
if (pAdapter->LinkInfo.FullDuplexEnable) tempAnar |= MII_ANAR_100TXFD;
else tempAnar |= MII_ANAR_100TX;
}
}
if (pMediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
{
if (pAdapter->LinkInfo.AutoSelect) tempAnar |= MII_ANAR_10TFD | MII_ANAR_10T;
else
{
if (pAdapter->LinkInfo.FullDuplexEnable) tempAnar |= MII_ANAR_10TFD;
else tempAnar |= MII_ANAR_10T;
}
}
if ( pAdapter->LinkInfo.FullDuplexEnable && pAdapter->LinkInfo.FlowControlSupported )
tempAnar |= MII_ANAR_FLOWCONTROL;
if ( (PhyAnar & MII_ANAR_MEDIA_MASK) == tempAnar)
{
/*The negotiated configuration hasn't changed. So, return and don't restart auto-negotiation.*/
return TRUE;
}
/* Check the media settings. */
if (pMediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE)
{
/* Check 100BaseTX settings. */
if ( (PhyAnar & MII_ANAR_MEDIA_100_MASK) != (tempAnar & MII_ANAR_MEDIA_100_MASK) )
{
DebugMsg(" Now We Re-Initiating autonegotiation...\n") ;
return NIC_MIIConfig(pAdapter,pMediaOptions);
}
}
if (pMediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
{
/* Check 10BaseT settings. */
if ( (PhyAnar & MII_ANAR_MEDIA_10_MASK) != (tempAnar & MII_ANAR_MEDIA_10_MASK) )
{
DebugMsg(" Now We Re-Initiating autonegotiation...\n") ;
return NIC_MIIConfig(pAdapter,pMediaOptions);
}
}
return TRUE;
}
/**************************************************************************************************
*** Used to setup the configuration for 10Base-T and 100Base-TX.
**/
BOOLEAN NIC_MIIConfig(IN PNIC_INFORMATION pAdapter,IN USHORT MediaOptions)
{
BOOLEAN PhyResponding;
USHORT PhyControl;
USHORT PhyAnar;
USHORT PhyStatusReset;
ULONG TimeOutCount;
/* Nowhere is it written that the register must be latched, and since reset is
the last bit out, the contents might not be valid. read it one more time.*/
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_CONTROL, &PhyControl);
if (!PhyResponding)
{
DebugMsg(" Error: PHY not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
/* Also, read the ANAR register and clear out it's current settings. */
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
if (!PhyResponding)
{
DebugMsg(" Error: PHY not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
/* Set up speed and duplex settings in MII Control and ANAR register. */
PhyAnar &= ~( MII_ANAR_100TXFD| MII_ANAR_100TX |MII_ANAR_10TFD |MII_ANAR_10T);
/* Set up duplex. */
if (pAdapter->LinkInfo.FullDuplexEnable) PhyControl |= MII_CONTROL_FULL_DUPLEX;
else PhyControl &= ~(MII_CONTROL_FULL_DUPLEX);
/* Set up flow control.
NOTE: On some NICs, such as Tornado, this will be hardwired to be set.
Clearing it will have no effect. */
if (pAdapter->LinkInfo.FlowControlSupported) PhyAnar |= MII_ANAR_FLOWCONTROL;
else PhyAnar &= ~(MII_ANAR_FLOWCONTROL);
/* Set up the media options. For duplex settings, if we're set to auto-select
then enable both half and full-duplex settings. Otherwise, go by what's
been enabled for duplex mode. */
if (MediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE)
{
if (pAdapter->LinkInfo.AutoSelect) PhyAnar |= (MII_ANAR_100TXFD | MII_ANAR_100TX);
else
{
if (pAdapter->LinkInfo.FullDuplexEnable) PhyAnar |= MII_ANAR_100TXFD;
else PhyAnar |= MII_ANAR_100TX;
}
}
if (MediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
{
if (pAdapter->LinkInfo.AutoSelect) PhyAnar |= (MII_ANAR_10TFD | MII_ANAR_10T);
else
{
if (pAdapter->LinkInfo.FullDuplexEnable) PhyAnar |= MII_ANAR_10TFD;
else PhyAnar |= MII_ANAR_10T;
}
}
/* Enable and start auto-negotiation */
PhyControl |= (MII_CONTROL_ENABLE_AUTO | MII_CONTROL_START_AUTO);
/* Write the MII registers back. */
NIC_MIIWritePhy(pAdapter, MII_PHY_ANAR, PhyAnar);
NIC_MIIWritePhy(pAdapter, MII_PHY_CONTROL, PhyControl);
/* Wait for auto-negotiation to finish. */
NIC_DELAY(MII_RESETWAITTIMEs);
PhyResponding = NIC_MIIReadPhy(pAdapter,MII_PHY_STATUS, &PhyStatusReset);
if (!PhyResponding)
{
DebugMsg(" Error: PHY not responding ! \n");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return FALSE;
}
if (! (PhyStatusReset & MII_STATUS_AUTO_DONE) )
{
DebugMsg(" Error: Auto Negotionation not done ! \n");
pAdapter->LinkInfo.LinkState = LINK_DOWN_AT_INIT;
return FALSE;
}
pAdapter->LinkInfo.LinkState = LINK_UP;
return TRUE;
}
/**********************************************************************************************
**** Since this function is called for forced xcvr configurations, it assumes that the xcvr type has
**** been verified as supported by the NIC.
**/
VOID NIC_MIICheckErrorReason( IN PNIC_INFORMATION pAdapter )
{
BOOLEAN PhyResponding;
USHORT PhyStatus;
USHORT PhyAnar;
USHORT PhyAnlpar;
/* Check to see if auto-negotiation has completed. Check the results in the status registers. */
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
if (!PhyResponding)
{
DebugMsg(" Error: the MII Phy not responding ! \n ");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return;
}
if (PhyStatus & MII_STATUS_LINK_UP) return; /*We have a valid link, so get out! */
/* Check to see why auto-negotiation or parallel detection has failed. We'll do this
by comparing the advertisement registers between the NIC and the link partner. */
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
if (!PhyResponding)
{
DebugMsg(" Error: the MII Phy not responding ! \n ");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return;
}
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANLPAR, &PhyAnlpar);
if (!PhyResponding)
{
DebugMsg(" Error: the MII Phy not responding ! \n ");
pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
return;
}
/* Now, compare what was advertised between the NIC and it's link partner.
If the media bits don't match, then write an error log entry. */
if ( (PhyAnar & MII_ANAR_MEDIA_MASK) != (PhyAnlpar & MII_ANAR_MEDIA_MASK) )
DebugMsg(" Error Reason: Incompatible configuration between Link peer !\n" );
else
DebugMsg(" Error Reason: Unknown ! \n ");
return;
}
/************************************************************************************
*** Determine from the MII AutoNegotiationAdvertisement and AutoNegotiationPartnerAbility
*** registers whether the current linkspeed is 10Mbits or 100Mbits.
**/
BOOLEAN NIC_MIILinkSpeedGet(IN PNIC_INFORMATION pAdapter,OUT BOOLEAN * handles100Mbitptr )
{
BOOLEAN PhyResponding;
USHORT PhyAnlpar;
USHORT PhyAner;
USHORT PhyAnar;
USHORT PhyStatus;
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANER, &PhyAner);
if (!PhyResponding) return FALSE;
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANLPAR, &PhyAnlpar);
if (!PhyResponding) return FALSE;
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
if (!PhyResponding) return FALSE;
PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
if (!PhyResponding) return FALSE;
/* Check to see if we've completed auto-negotiation.*/
if (!(PhyStatus & MII_STATUS_AUTO_DONE)) return FALSE;
if ((PhyAnar & MII_ANAR_100TXFD) && (PhyAnlpar & MII_ANLPAR_100TXFD) )
{
pAdapter->LinkInfo.MIIPhyUsed = MII_100TXFD;
*handles100Mbitptr = TRUE;
pAdapter->LinkInfo.FullDuplexEnable = TRUE;
}
else if ((PhyAnar & MII_ANAR_100TX) && (PhyAnlpar & MII_ANLPAR_100TX))
{
pAdapter->LinkInfo.MIIPhyUsed = MII_100TX ;
*handles100Mbitptr = TRUE;
pAdapter->LinkInfo.FullDuplexEnable = FALSE;
}
else if ((PhyAnar & MII_ANAR_10TFD) && (PhyAnlpar & MII_ANLPAR_10TFD))
{
pAdapter->LinkInfo.MIIPhyUsed = MII_10TFD ;
pAdapter->LinkInfo.FullDuplexEnable = TRUE;
*handles100Mbitptr = FALSE;
}
else if ((PhyAnar & MII_ANAR_10T) && (PhyAnlpar & MII_ANLPAR_10T))
{
pAdapter->LinkInfo.MIIPhyUsed = MII_10T ;
pAdapter->LinkInfo.FullDuplexEnable = FALSE;
*handles100Mbitptr = FALSE;
}
else if (!(PhyAner & MII_ANER_LPANABLE))
{
/* Link partner is not capable of auto-negotiation. Fall back to 10HD. */
pAdapter->LinkInfo.MIIPhyUsed = MII_10T ;
pAdapter->LinkInfo.FullDuplexEnable = FALSE;
*handles100Mbitptr = FALSE;
}
else
return FALSE;
return TRUE;
}
/** Above are routines about MII
*** End of NICMII.c
*****************************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -