DevE1000Phy.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/** $Id$ */
/** @file
* DevE1000Phy - Intel 82540EM Ethernet Controller Internal PHY Emulation.
*
* Implemented in accordance with the specification:
*
* 317453-002 Revision 3.5
*/
/*
* Copyright (C) 2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#define LOG_GROUP LOG_GROUP_DEV_E1000
/** @todo Remove me! For now I want asserts to work in release code. */
// #ifndef RT_STRICT
// #define RT_STRICT
// #undef RT_STRICT
// #endif
#include "DevE1000Phy.h"
/* Little helpers ************************************************************/
#ifdef PHY_UNIT_TEST
# define SSMR3PutMem(a,b,c)
# define SSMR3GetMem(a,b,c)
#include <stdio.h>
#else /* PHY_UNIT_TEST */
#endif /* PHY_UNIT_TEST */
/* Internals */
namespace Phy {
/** Retrieves state name by id */
/** Look up register index by address. */
/** Software-triggered reset. */
/* Generic handlers ******************************************************/
/* Register-specific handlers ********************************************/
/**
* PHY register map table.
*
* Override pfnRead and pfnWrite to implement register-specific behavior.
*/
static struct RegMap_st
{
/** PHY register address. */
/** Read callback. */
/** Write callback. */
/** Abbreviated name. */
const char *szAbbrev;
/** Full name. */
const char *szName;
} s_regMap[NUM_OF_PHY_REGS] =
{
/*ra read callback write callback abbrev full name */
/*-- ------------------------- -------------------------- ---------- ------------------------------*/
{ 20, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON1" , "Extended PHY Specific Control 1" },
{ 26, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON2" , "Extended PHY Specific Control 2" },
{ 29, Phy::regReadForbidden , Phy::regWriteUnimplemented, "R30PS" , "MDI Register 30 Page Select" },
{ 30, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "R30AW" , "MDI Register 30 Access Window" }
};
}
/**
* Default read handler.
*
* Fetches register value from the state structure.
*
* @returns Register value
*
* @param index Register index in register array.
*/
{
}
/**
* Default write handler.
*
* Writes the specified register value to the state structure.
*
* @param index Register index in register array.
* @param value The value to store (ignored).
*/
{
}
/**
* Read handler for write-only registers.
*
* Merely reports reads from write-only registers.
*
* @returns Register value (always 0)
*
* @param index Register index in register array.
*/
{
PhyLog(("PHY#%d At %02d read attempted from write-only '%s'\n",
return 0;
}
/**
* Write handler for read-only registers.
*
* Merely reports writes to read-only registers.
*
* @param index Register index in register array.
* @param value The value to store (ignored).
*/
{
PhyLog(("PHY#%d At %02d write attempted to read-only '%s'\n",
}
/**
* Read handler for unimplemented registers.
*
* Merely reports reads from unimplemented registers.
*
* @returns Register value (always 0)
*
* @param index Register index in register array.
*/
{
PhyLog(("PHY#%d At %02d read attempted from unimplemented '%s'\n",
return 0;
}
/**
* Write handler for unimplemented registers.
*
* Merely reports writes to unimplemented registers.
*
* @param index Register index in register array.
* @param value The value to store (ignored).
*/
{
PhyLog(("PHY#%d At %02d write attempted to unimplemented '%s'\n",
}
/**
* Search PHY register table for register with matching address.
*
* @returns Index in the register table or -1 if not found.
*
* @param u32Address Register address.
*/
{
unsigned int index;
{
{
return index;
}
}
return -1;
}
/**
* Read PHY register.
*
* @returns Value of specified PHY register.
*
* @param u32Address Register address.
*/
{
if (index != -1)
{
PhyLog(("PHY#%d At %02d read %04X from %s (%s)\n",
}
else
{
PhyLog(("PHY#%d read attempted from non-existing register %08x\n",
}
return u16;
}
/**
* Write to PHY register.
*
* @param u32Address Register address.
* @param u16Value Value to store.
*/
{
if (index != -1)
{
PhyLog(("PHY#%d At %02d write %04X to %s (%s)\n",
}
else
{
PhyLog(("PHY#%d write attempted to non-existing register %08x\n",
}
}
/**
* PHY contructor.
*
* Stores E1000 instance internally. Triggers PHY hard reset.
*
* @param iNICInstance Number of network controller instance this PHY is
* attached to.
* @param u16EPid Extended PHY Id.
*/
{
/* Make sure the link is down */
/* The PHY identifier composed of bits 3 through 18 of the OUI */
/* (Organizationally Unique Identifier). OUI is 0x05043. */
/* Extended PHY identifier */
}
/**
* Hardware PHY reset.
*
* Sets all PHY registers to their initial values.
*/
{
/*
* AUTO NEG AB, EXT CAP
*/
/* No flow control by our link partner, all speeds */
}
/**
* Software PHY reset.
*/
{
}
/**
* Get the current state of the link.
*
* @returns true if link is up.
*/
{
}
/**
* Set the current state of the link.
*
* @remarks Link Status bit in PHY Status register is latched-low and does
* not change the state when the link goes up.
*
* @param fLinkIsUp New state of the link.
*/
{
if (fLinkIsUp)
else
{
}
}
#ifdef IN_RING3
/**
* Save PHY state.
*
* @remarks Since PHY is agregated into E1K it does not currently supports
* versioning of its own.
*
* @returns VBox status code.
* @param pSSMHandle The handle to save the state to.
* @param pPhy The pointer to this instance.
*/
{
return VINF_SUCCESS;
}
/**
* Restore previously saved PHY state.
*
* @remarks Since PHY is agregated into E1K it does not currently supports
* versioning of its own.
*
* @returns VBox status code.
* @param pSSMHandle The handle to save the state to.
* @param pPhy The pointer to this instance.
*/
{
}
#endif /* IN_RING3 */
/* Register-specific handlers ************************************************/
/**
* Write handler for PHY Control register.
*
* Handles reset.
*
* @param index Register index in register array.
* @param value The value to store (ignored).
*/
{
if (u16Value & PCTRL_RESET)
else
}
/**
* Read handler for PHY Status register.
*
* Handles Latched-Low Link Status bit.
*
* @returns Register value
*
* @param index Register index in register array.
*/
{
/* Read latched value */
else
return u16;
}
/**
* Read handler for 1000BASE-T Status register.
*
* @returns Register value
*
* @param index Register index in register array.
*/
{
/*
* - Link partner is capable of 1000BASE-T half duplex
* - Link partner is capable of 1000BASE-T full duplex
* - Remote receiver OK
* - Local receiver OK
* - Local PHY config resolved to SLAVE
*/
return 0x3C00;
}
{
static const char *pcszState[] =
{
"MDIO_IDLE",
"MDIO_ST",
"MDIO_OP_ADR",
"MDIO_TA_RD",
"MDIO_TA_WR",
"MDIO_READ",
"MDIO_WRITE"
};
}
{
bool fPin = false;
{
case MDIO_TA_RD:
fPin = false;
break;
case MDIO_READ:
/* Bits are shifted out in MSB to LSB order */
break;
default:
PhyLog(("PHY#%d WARNING! MDIO pin read in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
}
return fPin;
}
/** Set the value of MDIO pin. */
{
{
case MDIO_IDLE:
if (!fPin)
break;
case MDIO_ST:
if (fPin)
{
}
break;
case MDIO_OP_ADR:
/* Shift in 'u16Cnt' bits into accumulator */
if (fPin)
{
/* Got OP(2) + PHYADR(5) + REGADR(5) */
/* Note: A single PHY is supported, ignore PHYADR */
{
case MDIO_READ_OP:
break;
case MDIO_WRITE_OP:
break;
default:
break;
}
}
break;
case MDIO_TA_WR:
{
}
break;
case MDIO_WRITE:
if (fPin)
{
}
break;
default:
PhyLog(("PHY#%d ERROR! MDIO pin write in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
break;
}
}