📄 physet.c
字号:
// driver will skip the speed and duplex over-ride code, and
// assume the adapter is automatically setting the line speed, and
// the duplex mode. At the end of this routine, any truly Phy
// specific code will be executed (each Phy has its own quirks,
// and some require that certain special bits are set).
//
// NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
// same time. If FORCEDPX is set without speed being set, the driver
// will encouter a fatal error and log a message into the event viewer.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Result:
// Returns:
// TRUE - If the phy could be configured correctly
// FALSE - If the phy couldn't be configured correctly, because an
// unsupported over-ride option was used
//-----------------------------------------------------------------------------
BOOLEAN
SetupPhy(
IN PD100_ADAPTER Adapter
)
{
USHORT MdiControlReg, MdiStatusReg, MdiIdLowReg, MdiIdHighReg;
USHORT MdiMiscReg;
USHORT LastMdiMiscReg;
UINT PhyId;
BOOLEAN ForcePhySetting = FALSE;
UINT i;
DEBUGFUNC("SetupPhy");
INITSTR(("\n"));
// If we are NOT forcing a setting for line speed or full duplex, then
// we won't force a link setting, and we'll jump down to the phy
// specific code.
if (((Adapter->AiTempSpeed) || (Adapter->AiForceDpx)))
{
// Find out what kind of technology this Phy is capable of.
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
// Read the MDI control register at our phy
MdiRead(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, &MdiControlReg);
// Now check the validity of our forced option. If the force option is
// valid, then force the setting. If the force option is not valid,
// we'll set a flag indicating that we should error out.
// If speed is forced to 10mb
if (Adapter->AiTempSpeed == 10)
{
// If half duplex is forced
if (Adapter->AiForceDpx == 1)
{
if (MdiStatusReg & MDI_SR_10T_HALF_DPX)
{
INITSTR(("Forcing 10mb 1/2 duplex\n"));
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
}
}
// If full duplex is forced
else if (Adapter->AiForceDpx == 2)
{
if (MdiStatusReg & MDI_SR_10T_FULL_DPX)
{
INITSTR(("Forcing 10mb full duplex\n"));
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
MdiControlReg |= MDI_CR_FULL_HALF;
ForcePhySetting = TRUE;
}
}
// If auto duplex (we actually set phy to 1/2)
else
{
if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX))
{
INITSTR(("Forcing 10mb auto duplex\n"));
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
Adapter->AiForceDpx = 1;
}
}
}
// If speed is forced to 100mb
else if (Adapter->AiTempSpeed == 100)
{
// If half duplex is forced
if (Adapter->AiForceDpx == 1)
{
if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
{
INITSTR(("Forcing 100mb half duplex\n"));
MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
MdiControlReg |= MDI_CR_10_100;
ForcePhySetting = TRUE;
}
}
// If full duplex is forced
else if (Adapter->AiForceDpx == 2)
{
if (MdiStatusReg & MDI_SR_TX_FULL_DPX)
{
INITSTR(("Forcing 100mb full duplex\n"));
MdiControlReg &= ~MDI_CR_AUTO_SELECT;
MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
}
}
// If auto duplex (we set phy to 1/2)
else
{
if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
{
INITSTR(("Forcing 100mb auto duplex\n"));
MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
MdiControlReg |= MDI_CR_10_100;
ForcePhySetting = TRUE;
Adapter->AiForceDpx = 1;
}
}
}
if (ForcePhySetting == FALSE)
{
INITSTR(("Can't force speed=%d, duplex=%d\n",Adapter->AiTempSpeed, Adapter->AiForceDpx));
D100LogError(Adapter, EVENT_9, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 0);
return (FALSE);
}
// Write the MDI control register with our new Phy configuration
MdiWrite(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, MdiControlReg);
// wait 100 milliseconds for auto-negotiation to complete
D100StallExecution(100);
}
// Find out specifically what Phy this is. We do this because for certain
// phys there are specific bits that must be set so that the phy and the
// 82557 work together properly.
MdiRead(Adapter, PHY_ID_REG_1, Adapter->PhyAddress, &MdiIdLowReg);
MdiRead(Adapter, PHY_ID_REG_2, Adapter->PhyAddress, &MdiIdHighReg);
PhyId = ((UINT) MdiIdLowReg | ((UINT) MdiIdHighReg << 16));
Adapter->PhyId = PhyId;
INITSTR(("Phy ID is %x\n", PhyId));
// And out the revsion field of the Phy ID so that we'll be able to detect
// future revs of the same Phy.
PhyId &= PHY_MODEL_REV_ID_MASK;
// Handle the National TX
if (PhyId == PHY_NSC_TX)
{
INITSTR(("Found a NSC TX Phy\n"));
MdiRead(Adapter, NSC_CONG_CONTROL_REG, Adapter->PhyAddress, &MdiMiscReg);
MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);
// If we are configured to do congestion control, then enable the
// congestion control bit in the National Phy
if (Adapter->Congest)
MdiMiscReg |= NSC_TX_CONG_ENABLE;
else
MdiMiscReg &= ~NSC_TX_CONG_ENABLE;
MdiWrite(Adapter, NSC_CONG_CONTROL_REG, Adapter->PhyAddress, MdiMiscReg);
}
FindPhySpeedAndDpx(Adapter, PhyId);
INITSTR(("Current speed=%d, Current Duplex=%d\n",Adapter->AiLineSpeedCur, Adapter->AiDuplexCur));
return (TRUE);
}
//-----------------------------------------------------------------------------
// Procedure: FindPhySpeedAndDpx
//
// Description: This routine will figure out what line speed and duplex mode
// the PHY is currently using.
//
// Arguments:
// Adapter - ptr to Adapter object instance
// PhyId - The ID of the PHY in question.
//
// Returns:
// NOTHING
//-----------------------------------------------------------------------------
VOID
FindPhySpeedAndDpx(
IN PD100_ADAPTER Adapter,
IN UINT PhyId
)
{
USHORT MdiStatusReg, MdiMiscReg, MdiOwnAdReg, MdiLinkPartnerAdReg;
DEBUGFUNC("FindPhySpeedAndDpx");
INITSTR(("\n"));
// If there was a speed and/or duplex override, then set our current
// value accordingly
Adapter->AiLineSpeedCur = Adapter->AiTempSpeed;
Adapter->AiDuplexCur = (USHORT) Adapter->AiForceDpx;
// If speed and duplex were forced, then we know our current settings, so
// we'll just return. Otherwise, we'll need to figure out what NWAY set
// us to.
if (Adapter->AiLineSpeedCur && Adapter->AiDuplexCur)
return;
// If we didn't have a valid link, then we'll assume that our current
// speed is 10mb half-duplex.
// Read the status register twice because of sticky bits
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
// If there wasn't a valid link then use default speed & duplex
if (!(MdiStatusReg & MDI_SR_LINK_STATUS))
{
INITSTR(("Link Not found for speed detection!!! Using defaults.\n"));
Adapter->AiLineSpeedCur = 10;
Adapter->AiDuplexCur = 1;
return;
}
// If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
// 1 and 0 of extended register 0, to get the current speed and duplex
// settings.
if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID))
{
INITSTR(("Detecting Speed/Dpx for an Intel PHY\n"));
// Read extended register 0
MdiRead(Adapter, EXTENDED_REG_0, Adapter->PhyAddress, &MdiMiscReg);
// Get current speed setting
if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC)
Adapter->AiLineSpeedCur = 100;
else
Adapter->AiLineSpeedCur = 10;
// Get current duplex setting -- if bit is set then FDX is enabled
if (MdiMiscReg & PHY_100_ER0_FDX_INDIC)
Adapter->AiDuplexCur = 2;
else
Adapter->AiDuplexCur = 1;
return;
}
// Read our link partner's advertisement register
MdiRead(Adapter, AUTO_NEG_LINK_PARTNER_REG, Adapter->PhyAddress, &MdiLinkPartnerAdReg);
// See if Auto-Negotiation was complete (bit 5, reg 1)
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
// If a True NWAY connection was made, then we can detect speed/duplex by
// ANDing our adapter's advertised abilities with our link partner's
// advertised ablilities, and then assuming that the highest common
// denominator was chosed by NWAY.
if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
(MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE))
{
INITSTR(("Detecting Speed/Dpx from NWAY connection\n"));
// Read our advertisement register
MdiRead(Adapter, AUTO_NEG_ADVERTISE_REG, Adapter->PhyAddress, &MdiOwnAdReg);
// AND the two advertisement registers together, and get rid of any
// extraneous bits.
MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY);
// Get speed setting
if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE))
Adapter->AiLineSpeedCur = 100;
else
Adapter->AiLineSpeedCur = 10;
// Get duplex setting -- use priority resolution algorithm
if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE))
{
Adapter->AiDuplexCur = 1;
return;
}
else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX))
{
Adapter->AiDuplexCur = 2;
return;
}
else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX))
{
Adapter->AiDuplexCur = 1;
return;
}
else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX))
{
Adapter->AiDuplexCur = 2;
return;
}
else
{
Adapter->AiDuplexCur = 1;
return;
}
}
// If we are connected to a non-NWAY repeater or hub, and the line
// speed was determined automatically by parallel detection, then we have
// no way of knowing exactly what speed the PHY is set to unless that PHY
// has a propietary register which indicates speed in this situation. The
// NSC TX PHY does have such a register. Also, since NWAY didn't establish
// the connection, the duplex setting should HALF duplex.
Adapter->AiDuplexCur = 1;
if (PhyId == PHY_NSC_TX)
{
INITSTR(("Detecting Speed/Dpx from non-NWAY NSC connection\n"));
// Read register 25 to get the SPEED_10 bit
MdiRead(Adapter, NSC_SPEED_IND_REG, Adapter->PhyAddress, &MdiMiscReg);
// If bit 6 was set then we're at 10mb
if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED)
Adapter->AiLineSpeedCur = 10;
else
Adapter->AiLineSpeedCur = 100;
}
// If we don't know what line speed we are set at, then we'll default to
// 10mbs
else
Adapter->AiLineSpeedCur = 10;
}
//-----------------------------------------------------------------------------
// Procedure: ResetPhy
//
// Description: This routine will reset the PHY that the adapter is currently
// configured to use.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Returns:
// NOTHING
//-----------------------------------------------------------------------------
VOID
ResetPhy(
IN PD100_ADAPTER Adapter
)
{
USHORT MdiControlReg;
DEBUGFUNC("ResetPhy");
INITSTR(("\n"));
DEBUGCHAR(Adapter,'P');
// Reset the Phy, enable auto-negotiation, and restart auto-negotiation.
MdiControlReg = (MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | MDI_CR_RESET);
// Write the MDI control register with our new Phy configuration
MdiWrite(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, MdiControlReg);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -