702 lines
16 KiB
C
702 lines
16 KiB
C
/*+
|
|
* file: mactophy.c
|
|
*
|
|
* Copyright (C) 1992-1995 by
|
|
* Digital Equipment Corporation, Maynard, Massachusetts.
|
|
* All rights reserved.
|
|
*
|
|
* This software is furnished under a license and may be used and copied
|
|
* only in accordance of the terms of such license and with the
|
|
* inclusion of the above copyright notice. This software or any other
|
|
* copies thereof may not be provided or otherwise made available to any
|
|
* other person. No title to and ownership of the software is hereby
|
|
* transferred.
|
|
*
|
|
* The information in this software is subject to change without notice
|
|
* and should not be construed as a commitment by digital equipment
|
|
* corporation.
|
|
*
|
|
* Digital assumes no responsibility for the use or reliability of its
|
|
* software on equipment which is not supplied by digital.
|
|
*
|
|
*
|
|
* Abstract: This file contains the code to access the MII PHY device
|
|
* (initialization, set the connections, and sensing of the
|
|
* link.
|
|
*
|
|
* Author: Claudio Hazan
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 15-Oct-95 ch Creation
|
|
* 20-Dec-95 phk Cleanup, add support for DC21142
|
|
*
|
|
-*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define LINK_PASS_MAX_LOOP 350
|
|
#define LINK_PASS_DELAY (10*MILLISECOND)
|
|
|
|
#if MII_DBG
|
|
PUCHAR MiiMediumString[] = {
|
|
"","","","","","","","","",
|
|
"Mii10BaseT",
|
|
"Mii10BaseT_FD",
|
|
"Mii10Base2",
|
|
"Mii10Base5",
|
|
"Mii100BaseTx",
|
|
"Mii100BaseTx_FD",
|
|
"Mii100BaseT4",
|
|
"Mii100BaseFx",
|
|
"Mii100BaseFx_FD"
|
|
};
|
|
#endif
|
|
|
|
/*+
|
|
* DC21X4PhyInit
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This routine initializes each PHY present in the SROM; Reset each Phy
|
|
* if there is a Reset sequence specified there, Initializes the Phys and
|
|
* updates the Capabilities tables from the values contained in the SROM
|
|
* with the values supported by the Phys.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* True if any PHY was succesfully initialized.
|
|
*
|
|
-*/
|
|
extern
|
|
BOOLEAN
|
|
DC21X4PhyInit(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
{
|
|
BOOLEAN PhyPresent;
|
|
BOOLEAN ConnectionPresent=FALSE;
|
|
USHORT Capabilities;
|
|
INT PhyNumber;
|
|
INT Seq;
|
|
|
|
ULONG Data;
|
|
|
|
#if MII_DBG
|
|
DbgPrint("DC21X4PhyInit\n");
|
|
#endif
|
|
// Reset all the phys using its reset sequence.
|
|
|
|
if (!Adapter->PhyMediumInSrom) {
|
|
#if __DBG
|
|
DbgPrint("No PHY Media in SROM\n");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
#if __DBG
|
|
DbgPrint("PHY Reset\n");
|
|
#endif
|
|
|
|
Adapter->Force10 = FALSE;
|
|
|
|
for (PhyNumber=0; PhyNumber < MAX_PHY_TABLE; PhyNumber++) {
|
|
|
|
if (Adapter->Phy[Adapter->PhyNumber].ResetSequenceLength != 0) {
|
|
|
|
DC21X4WriteGepRegister(
|
|
Adapter,
|
|
(ULONG)Adapter->Phy[Adapter->PhyNumber].GeneralPurposeCtrl
|
|
);
|
|
|
|
for (Seq=0; Seq < Adapter->Phy[Adapter->PhyNumber].ResetSequenceLength; Seq++) {
|
|
#if MII_DBG
|
|
DbgPrint("Sequence[%d]=%04x\n", Seq, Adapter->Phy[PhyNumber].ResetSequence[Seq]);
|
|
#endif
|
|
DELAY (5); // 5 microseconds
|
|
|
|
DC21X4WriteGepRegister(
|
|
Adapter,
|
|
(ULONG)Adapter->Phy[Adapter->PhyNumber].ResetSequence[Seq]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Adapter->PhyNumber = 0;
|
|
PhyPresent = MiiGenInit(Adapter);
|
|
|
|
if (PhyPresent) {
|
|
#if __DBG
|
|
DbgPrint("Phy: Initialization OK\n");
|
|
#endif
|
|
|
|
Capabilities = MiiGenGetCapabilities(Adapter);
|
|
|
|
// Convert the MediaType to the MiiMediaType values
|
|
|
|
Adapter->MiiMediaType =
|
|
ConvertMediaTypeToMiiType[Adapter->MediaType & MEDIA_MASK]
|
|
| (Adapter->MediaType & CONTROL_MASK);
|
|
|
|
#if MII_DBG
|
|
DbgPrint("Translate MediaType %x to MiiMediaType %x\n",
|
|
Adapter->MediaType,Adapter->MiiMediaType);
|
|
#endif
|
|
|
|
Adapter->PhyNwayCapable = ( ((Adapter->MiiMediaType & MEDIA_NWAY) != 0)
|
|
&& ((Capabilities & MiiPhyNwayCapable) != 0)
|
|
);
|
|
|
|
// Merge the PHY Capabilities with the medium stored in SROM
|
|
|
|
for (PhyNumber=0; PhyNumber < MAX_PHY_TABLE; PhyNumber++) {
|
|
|
|
Adapter->Phy[PhyNumber].MediaCapabilities &= Capabilities;
|
|
|
|
|
|
Adapter->Phy[PhyNumber].MediaCapabilities |= (Capabilities & MiiPhyNwayCapable);
|
|
#if MII_DBG
|
|
DbgPrint("Merged Capabilities (SROM&PHY)= %04x\n", Adapter->Phy[PhyNumber].MediaCapabilities);
|
|
#endif
|
|
Adapter->MiiGen.Phys[PhyNumber]->PhyCapabilities = Adapter->Phy[PhyNumber].MediaCapabilities;
|
|
}
|
|
}
|
|
if (PhyPresent) {
|
|
#if MII_DBG
|
|
DbgPrint("Check if Connection is supported\n");
|
|
#endif
|
|
// Now check the Connection.
|
|
ConnectionPresent = MiiGenCheckConnection(
|
|
Adapter,
|
|
(USHORT)Adapter->MiiMediaType
|
|
);
|
|
|
|
if (!ConnectionPresent) {
|
|
//Force the Phy to 10
|
|
DC21X4SetPhyControl(
|
|
Adapter,
|
|
MiiGenAdminForce10
|
|
);
|
|
}
|
|
}
|
|
|
|
return (PhyPresent && ConnectionPresent);
|
|
}
|
|
|
|
|
|
/*+
|
|
* DC21X4SetPhyConnection
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function first resets the MAC (which could reset the PHY) and
|
|
* initialize CSR6 and CSR12 registers. Then sets the PHY to
|
|
* the required medium.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* True if the requested Medium is supported by the Phy.
|
|
*
|
|
-*/
|
|
extern
|
|
BOOLEAN
|
|
DC21X4SetPhyConnection(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
{
|
|
BOOLEAN MediaSupported;
|
|
|
|
// First set Mac Connection.
|
|
#if MII_DBG
|
|
DbgPrint("DC21X4SetPhyConnection\n");
|
|
#endif
|
|
SetMacConnection(Adapter);
|
|
|
|
// Now set the PHY Connection.
|
|
MediaSupported = MiiGenSetConnection(
|
|
Adapter,
|
|
Adapter->MiiMediaType,
|
|
Adapter->Phy[Adapter->PhyNumber].NwayAdvertisement
|
|
);
|
|
return MediaSupported;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*+
|
|
* SetMacConnection
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function initialize the CSR6 and CSR12 registers according to the
|
|
* values present in the SROM for the Selected Medium.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
*
|
|
-*/
|
|
|
|
void
|
|
SetMacConnection(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
{
|
|
|
|
USHORT MediaPositionMask;
|
|
ULONG OperationMode;
|
|
|
|
#if MII_DBG
|
|
DbgPrint("SetMacConnection\n");
|
|
#endif
|
|
// First of all find the media type.
|
|
|
|
MediaPositionMask = MediaBitTable[(Adapter->MiiMediaType & MEDIA_MASK)];
|
|
#if MII_DBG
|
|
DbgPrint(" MiiMediaType %04x Bitmap %04x\n",
|
|
Adapter->MiiMediaType,MediaPositionMask);
|
|
#endif
|
|
|
|
// If unknown media, just return.
|
|
if (MediaPositionMask == 0) {
|
|
#if __DBG
|
|
DbgPrint("UNKNOWN Phy Medium %x!!!\n",Adapter->MiiMediaType);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// select Port_Select MII (disable HEARTBEAT in MII mode).
|
|
OperationMode = Adapter->OperationMode | (DC21X4_PORT_SELECT | DC21X4_HEARTBEAT_DISABLE);
|
|
|
|
if (Adapter->Phy[Adapter->PhyNumber].MediaCapabilities & MediaPositionMask) {
|
|
|
|
if (Adapter->Phy[Adapter->PhyNumber].FullDuplexBits & MediaPositionMask) {
|
|
// Set FullDuplex bit
|
|
OperationMode |= DC21X4_FULL_DUPLEX_MODE;
|
|
}
|
|
else {
|
|
//Reset FullDuplex bit
|
|
OperationMode &= ~DC21X4_FULL_DUPLEX_MODE;
|
|
}
|
|
if (Adapter->Phy[Adapter->PhyNumber].TxThresholdModeBits & MediaPositionMask) {
|
|
// Set TTM bit
|
|
OperationMode &= ~(Adapter->Threshold100Mbps);
|
|
OperationMode |= (DC21X4_TXM_THRESHOLD_MODE | Adapter->Threshold10Mbps);
|
|
}
|
|
else {
|
|
// Reset TTM bit
|
|
OperationMode &= ~(DC21X4_TXM_THRESHOLD_MODE | Adapter->Threshold10Mbps);
|
|
OperationMode |= Adapter->Threshold100Mbps;
|
|
}
|
|
|
|
#if __DBG
|
|
DbgPrint("SetMacConnection:%s FullDuplex & %s TTM bits in CSR6\n",
|
|
OperationMode & DC21X4_FULL_DUPLEX_MODE ? "Set" : "Reset",
|
|
OperationMode & DC21X4_TXM_THRESHOLD_MODE ? "Set" : "Reset");
|
|
#endif
|
|
|
|
}
|
|
|
|
// Switch Medium:
|
|
|
|
DC21X4IndicateMediaStatus(
|
|
Adapter,
|
|
LinkFail
|
|
);
|
|
|
|
// if TTM or FDX setting has changed, stop the TXM and RCV process before modifying
|
|
// these modes
|
|
|
|
if ((OperationMode & DC21X4_MODE_MASK) != (Adapter->OperationMode & DC21X4_MODE_MASK) ) {
|
|
#if MII_DBG
|
|
DbgPrint("FDX or TTM setting has changed: stop RCV and TXM\n");
|
|
#endif
|
|
DC21X4StopReceiverAndTransmitter(Adapter);
|
|
}
|
|
|
|
switch (Adapter->DeviceId) {
|
|
|
|
case DC21142_CFID:
|
|
|
|
//Initialize the Sia Registers for MII operation
|
|
// Reset Sia (CSR13)
|
|
// Turn off the BNC transceiver (CSR15)
|
|
// Disable Autonegotiation (CSR14)
|
|
|
|
DC21X4_WRITE_PORT(
|
|
DC21X4_SIA_MODE_0,
|
|
DC21X4_RESET_SIA
|
|
);
|
|
|
|
Adapter->Gep_Sia2 =
|
|
(DC21142_SIA2_10BT & DC21142_SIA2_MASK)
|
|
| (Adapter->Gep_Sia2 & DC21142_GEP_MASK);
|
|
|
|
DC21X4_WRITE_PORT(
|
|
DC21X4_SIA_MODE_2,
|
|
Adapter->Gep_Sia2
|
|
);
|
|
|
|
DC21X4_WRITE_PORT(
|
|
DC21X4_SIA_MODE_1,
|
|
0
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
// Init the Command Register.
|
|
|
|
Adapter->OperationMode = OperationMode;
|
|
|
|
#if __DBG
|
|
DbgPrint("SetMacConnection: Write CSR6=%08x\n", OperationMode);
|
|
#endif
|
|
DC21X4_WRITE_PORT(
|
|
DC21X4_OPERATION_MODE,
|
|
Adapter->OperationMode
|
|
);
|
|
DELAY(5);
|
|
|
|
DC21X4InitializeGepRegisters(Adapter,TRUE);
|
|
|
|
}
|
|
|
|
/*+
|
|
* DC21X4MiiAutoDetect
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function contains the power up autosensing for PHYs.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Link status
|
|
*
|
|
-*/
|
|
extern
|
|
BOOLEAN
|
|
DC21X4MiiAutoDetect(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
{
|
|
ULONG OperationMode;
|
|
INT Loop;
|
|
USHORT ConnectionStatus;
|
|
USHORT TmpMedia;
|
|
BOOLEAN Link;
|
|
#if MII_DBG
|
|
ULONG Status;
|
|
#endif
|
|
|
|
Link = MiiGenGetConnectionStatus(
|
|
Adapter,
|
|
&ConnectionStatus
|
|
);
|
|
DC21X4IndicateMediaStatus(
|
|
Adapter,
|
|
Link ? MiiLinkPass : LinkFail
|
|
);
|
|
|
|
// If no link available while still negotiating, continue to
|
|
// check the link up to 3s.
|
|
|
|
if (!Link) {
|
|
#if MII_DBG
|
|
Loop = 30;
|
|
#else
|
|
Loop = LINK_PASS_MAX_LOOP;
|
|
#endif
|
|
while (!Link && Loop--) {
|
|
#if MII_DBG
|
|
DbgPrint("LinkPass=FALSE: wait up to 3 seconds %d\n", Loop);
|
|
#endif
|
|
DELAY(LINK_PASS_DELAY);
|
|
Link = MiiGenGetConnectionStatus(
|
|
Adapter,
|
|
&ConnectionStatus
|
|
);
|
|
}
|
|
DC21X4IndicateMediaStatus(
|
|
Adapter,
|
|
Link ? MiiLinkPass : LinkFail
|
|
);
|
|
}
|
|
|
|
#if MII_DBG
|
|
DC21X4_READ_PORT(
|
|
DC21X4_OPERATION_MODE,
|
|
&Status
|
|
);
|
|
DbgPrint("CSR6= %08x, OperationMode=%08x\n", Status, Adapter->OperationMode);
|
|
#endif
|
|
|
|
// In AutoSense mode, we must know which media has been chosen to set the MAC.
|
|
// otherwise the MAC has been already set.
|
|
|
|
if (Adapter->MiiMediaType & MEDIA_AUTOSENSE){
|
|
#if MII_DBG
|
|
DbgPrint("AutoSense to check which Medium was chosen\n");
|
|
#endif
|
|
Link = MiiGenGetConnection(
|
|
Adapter,
|
|
&TmpMedia
|
|
);
|
|
DC21X4IndicateMediaStatus(
|
|
Adapter,
|
|
Link ? MiiLinkPass : LinkFail
|
|
);
|
|
|
|
if (Link){
|
|
#if MII_DBG
|
|
DbgPrint("LinkPass= TRUE; Medium = %s\n",
|
|
MiiMediumString[TmpMedia&MEDIA_MASK]);
|
|
#endif
|
|
Adapter->MiiMediaType = (TmpMedia | MEDIA_AUTOSENSE);
|
|
SetMacConnection(Adapter);
|
|
}
|
|
}
|
|
|
|
if ( !Link
|
|
&& (Adapter->MediaCapable)
|
|
&& (Adapter->MiiMediaType & MEDIA_AUTOSENSE)
|
|
) {
|
|
|
|
//Switch back to the non_MII port
|
|
|
|
SelectNonMiiPort(Adapter);
|
|
|
|
}
|
|
|
|
return Link;
|
|
|
|
}
|
|
|
|
|
|
/*+
|
|
* DC21X4DynamicMiiAutoSense
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function performs the PHY Dynamic Autosense
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Link status
|
|
*
|
|
-*/
|
|
extern
|
|
BOOLEAN
|
|
DC21X4MiiAutoSense(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
|
|
{
|
|
ULONG OperationMode;
|
|
USHORT CurrentMedia;
|
|
USHORT ConnectionStatus;
|
|
BOOLEAN Link;
|
|
BOOLEAN SwitchPort=FALSE;
|
|
|
|
#if MII_DBG
|
|
DbgPrint("DC21X4MiiAutoSense\n");
|
|
#endif
|
|
|
|
Link = MiiGenGetConnectionStatus(
|
|
Adapter,
|
|
&ConnectionStatus
|
|
);
|
|
|
|
#if MII_DBG
|
|
DbgPrint("MiiMediaType = %04x, ConnectionStatus = %04x\n",
|
|
Adapter->MiiMediaType, ConnectionStatus);
|
|
#endif
|
|
|
|
if (Adapter->MiiMediaType & MEDIA_AUTOSENSE) {
|
|
|
|
if (Link &&
|
|
((ConnectionStatus & MEDIA_STATUS_MASK) == MEDIA_LINK_PASS_WITH_PF)){
|
|
|
|
// There was a link failure
|
|
// Check the current medium
|
|
|
|
Link = MiiGenGetConnection(
|
|
Adapter,
|
|
&CurrentMedia
|
|
);
|
|
|
|
if ( Link
|
|
&& ( (Adapter->MiiMediaType != CurrentMedia)
|
|
|| (Adapter->LinkStatus != MiiLinkPass)
|
|
)
|
|
){
|
|
|
|
//The link is up but the medium has changed
|
|
#if MII_DBG
|
|
DbgPrint("Mii Medium has changed: New Mii Medium = %s \n",
|
|
MiiMediumString[CurrentMedia&MEDIA_MASK]);
|
|
#endif
|
|
Adapter->MiiMediaType = (CurrentMedia | MEDIA_AUTOSENSE);
|
|
SetMacConnection(Adapter);
|
|
}
|
|
}
|
|
}
|
|
|
|
// do not indicate the Mii Link down transition
|
|
// if the non_Mii link is up.
|
|
// In any other case indicate the transition
|
|
|
|
if (Link || (Adapter->LinkStatus != LinkPass)) {
|
|
|
|
DC21X4IndicateMediaStatus(
|
|
Adapter,
|
|
Link ? MiiLinkPass : LinkFail
|
|
);
|
|
}
|
|
|
|
if ( !Link
|
|
&& (Adapter->MediaCapable)
|
|
&& (Adapter->MiiMediaType & MEDIA_AUTOSENSE)
|
|
) {
|
|
|
|
if ((ConnectionStatus & MEDIA_STATUS_MASK) == MEDIA_READ_REGISTER_FAILED){
|
|
|
|
//PHY is not connected anymore
|
|
|
|
Adapter->PhyPresent=FALSE;
|
|
|
|
if (Adapter->MediaType & MEDIA_NWAY) {
|
|
|
|
//Enable Nway Negotiation
|
|
DC21X4EnableNway (Adapter);
|
|
|
|
SwitchPort=TRUE;
|
|
}
|
|
}
|
|
else if (Adapter->OperationMode & DC21X4_PORT_SELECT){
|
|
|
|
// Mii link is down,current port is Mii,
|
|
// at least one non Mii port is populated:
|
|
//Switch Port_Select to enable the non MII ports
|
|
SwitchPort = TRUE;
|
|
}
|
|
|
|
if (SwitchPort) {
|
|
|
|
SelectNonMiiPort(Adapter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Link;
|
|
|
|
}
|
|
|
|
/*+
|
|
* SelectNonMiiPort
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function selects the DC21X4 non_MII port
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
-*/
|
|
extern
|
|
VOID
|
|
SelectNonMiiPort(
|
|
IN PDC21X4_ADAPTER Adapter
|
|
)
|
|
|
|
{
|
|
|
|
ULONG OperationMode;
|
|
|
|
OperationMode = Adapter->OperationMode & ~(DC21X4_MEDIUM_MASK);
|
|
OperationMode |= Adapter->Media[Adapter->SelectedMedium].Mode;
|
|
|
|
if ((OperationMode & DC21X4_MODE_MASK) != (Adapter->OperationMode & DC21X4_MODE_MASK)) {
|
|
DC21X4StopReceiverAndTransmitter(Adapter);
|
|
}
|
|
|
|
Adapter->OperationMode = OperationMode;
|
|
|
|
DC21X4_WRITE_PORT(
|
|
DC21X4_OPERATION_MODE,
|
|
Adapter->OperationMode
|
|
);
|
|
|
|
DC21X4InitializeMediaRegisters(Adapter,FALSE);
|
|
|
|
switch (Adapter->SelectedMedium) {
|
|
|
|
case Medium10Base2:
|
|
case Medium10Base5:
|
|
|
|
DC21X4IndicateMediaStatus(Adapter,LinkPass);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*+
|
|
* DC21X4SetPhyControl
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This function modifies the PHY Control register.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Adapter - Pointer to the Data Structure
|
|
* Control - The Control to perform
|
|
*
|
|
* Return Value:
|
|
*
|
|
* none
|
|
-*/
|
|
extern
|
|
VOID
|
|
DC21X4SetPhyControl(
|
|
PDC21X4_ADAPTER Adapter,
|
|
USHORT AdminControl
|
|
)
|
|
{
|
|
|
|
MiiGenAdminControl(Adapter, AdminControl);
|
|
return;
|
|
|
|
}
|
|
|
|
|