if_i82544.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 2,053 行 · 第 1/5 页
C
2,053 行
#else // ! CYGHWR_DEVS_ETH_INTEL_I82544_GET_ESA
#ifndef CYGHWR_DEVS_ETH_INTEL_I82544_HAS_NO_EEPROM
int addr_length, i;
cyg_uint16 checksum;
// read eeprom and get 82544's mac address
addr_length = get_eeprom_size(p_i82544);
// (this is the length of the *EEPROM*s address, not MAC address)
// If length is 1, it _probably_ means there's no EEPROM
// present. Couldn't find an explicit mention of this in the
// docs, but length=1 appears to be the behaviour in that case.
if (1 == addr_length) {
#ifdef DEBUG_EE
os_printf("Error: No EEPROM present for device %d\n",
p_i82544->index);
#endif
} else {
for (checksum = 0, i = 0, count = 0; count < 64; count++) {
cyg_uint16 value;
// read word from eeprom
value = read_eeprom_word(p_i82544, addr_length, count);
#ifdef DEBUG_EE
os_printf( "%02x: %04x\n", count, value );
#endif
checksum += value;
if (count < 3) {
mac_address[i++] = value & 0xFF;
mac_address[i++] = (value >> 8) & 0xFF;
}
}
#ifndef CYGHWR_DEVS_ETH_INTEL_I82544_HAS_ONE_EEPROM_WITHOUT_CRC
// If the EEPROM checksum is wrong, the MAC address read
// from the EEPROM is probably wrong as well. In that
// case, we don't set mac_addr_ok, but continue the
// initialization. If then somebody calls i82544_start
// without calling eth_set_mac_address() first, we refuse
// to bring up the interface, because running with an
// invalid MAC address is not a very brilliant idea.
if ((checksum & 0xFFFF) != 0xBABA) {
// selftest verified checksum, verify again
#ifdef DEBUG_EE
os_printf("Warning: Invalid EEPROM checksum %04X for device %d\n",
checksum, p_i82544->index);
#endif
} else // trailing block
#endif
{
p_i82544->mac_addr_ok = 1;
#ifdef DEBUG_EE
os_printf("Valid EEPROM checksum\n");
#endif
// Second port of dual-port 82546 uses EEPROM ESA | 1
if (p_i82544->device == 0x1010 ||
p_i82544->device == 0x100e) {
cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(p_i82544->devid);
if (CYG_PCI_DEV_GET_FN(devfn) == 1)
mac_address[5] |= 1;
}
eth_set_mac_address(p_i82544, mac_address, 0);
}
}
// record the MAC address in the device structure
p_i82544->mac_address[0] = mac_address[0];
p_i82544->mac_address[1] = mac_address[1];
p_i82544->mac_address[2] = mac_address[2];
p_i82544->mac_address[3] = mac_address[3];
p_i82544->mac_address[4] = mac_address[4];
p_i82544->mac_address[5] = mac_address[5];
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82544_HAS_NO_EEPROM
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82544_GET_ESA
}
#ifdef DEBUG
os_printf("i82544_init: MAC Address = %02X %02X %02X %02X %02X %02X\n",
p_i82544->mac_address[0], p_i82544->mac_address[1],
p_i82544->mac_address[2], p_i82544->mac_address[3],
p_i82544->mac_address[4], p_i82544->mac_address[5]);
#endif
// and record the net dev pointer
p_i82544->ndp = (void *)ndp;
p_i82544->within_send = 0; // init recursion level
// Initialize upper level driver
if ( p_i82544->mac_addr_ok )
(sc->funs->eth_drv->init)(sc, &(p_i82544->mac_address[0]) );
else
{
(sc->funs->eth_drv->init)(sc, NULL );
}
#ifdef DEBUG
os_printf("CTRL %08x\n",INL( ioaddr + I82544_CTRL ));
os_printf("STATUS %08x\n",INL( ioaddr + I82544_STATUS ));
#endif
return (1);
}
// ------------------------------------------------------------------------
//
// Function : i82544_setup
//
// ------------------------------------------------------------------------
static void
i82544_setup( struct i82544 *p_i82544 )
{
cyg_uint32 ioaddr;
cyg_uint32 ctrl;
#ifndef CYGHWR_DEVS_ETH_INTEL_I82544_USE_ASD
cyg_uint32 ctrl_ext;
#endif
ioaddr = p_i82544->io_address; // get 82544's I/O address
#ifdef CYGHWR_DEVS_ETH_INTEL_I82544_USE_ASD
// Use Auto-negotiation
ctrl = INL( ioaddr + I82544_CTRL );
// Set link up bit
ctrl |= I82544_CTRL_SLU | I82544_CTRL_ASDE;
ctrl &= ~(I82544_CTRL_ILOS | I82544_CTRL_FRCSPD | I82544_CTRL_FRCDPLX);
OUTL( ctrl, ioaddr + I82544_CTRL );
udelay(20);
// we can assume link is up with autonegotiation
p_i82544->link = 1;
// wait up to 5 seconds for link to come up
{
int delay_cnt = 500;
while ((mii_read_register( p_i82544, PHY_ADDRESS, 1 ) & 0x4) == 0) {
udelay(10000);
if (--delay_cnt <= 0)
break;
}
}
#else
// The following sequence of resets and bit twiddling seem to be
// necessary to get the 82543 working. Not sure what is necessary
// for the 82544.
ctrl = INL( ioaddr + I82544_CTRL );
// Set link up bit
ctrl |= I82544_CTRL_SLU;
ctrl &= ~I82544_CTRL_ILOS;
OUTL( ctrl, ioaddr + I82544_CTRL );
udelay(20);
// Force PHY physical reset
// We can only access the PHY after we have done this.
ctrl_ext = INL( ioaddr + I82544_CTRL_EXT );
ctrl_ext |= I82544_CTRL_EXT_PHY_RESET_DIR4;
OUTL( ctrl_ext, ioaddr + I82544_CTRL_EXT );
udelay( 20000 );
ctrl_ext = INL( ioaddr + I82544_CTRL_EXT );
ctrl_ext &= ~I82544_CTRL_EXT_PHY_RESET4;
OUTL( ctrl_ext, ioaddr + I82544_CTRL_EXT );
udelay( 20000 );
ctrl_ext = INL( ioaddr + I82544_CTRL_EXT );
ctrl_ext |= I82544_CTRL_EXT_PHY_RESET4;
OUTL( ctrl_ext, ioaddr + I82544_CTRL_EXT );
udelay( 20000 );
#ifdef DEBUG
show_phy( p_i82544, PHY_ADDRESS );
#endif
#if 0
// Reset PHY
// Does not appear to be necessary.
{
cyg_uint16 phy_ctrl;
phy_ctrl = mii_read_register( p_i82544, PHY_ADDRESS, 0 );
phy_ctrl = 0x9000;
// os_printf("PHY ctrl %04x\n",phy_ctrl);
mii_write_register( p_i82544, PHY_ADDRESS, 0, phy_ctrl );
do {
phy_ctrl = mii_read_register( p_i82544, PHY_ADDRESS, 0 );
// os_printf("PHY ctrl %04x\n",phy_ctrl);
} while( phy_ctrl & 0x8000 );
}
show_phy( p_i82544, PHY_ADDRESS );
#endif
#if 0
// Tinker with PHY configuration.
// Only on 82543? May not be necessary at all, since disabling
// this does not see to make any difference.
{
cyg_uint16 data;
// Set CRS on Tx bit in PHY specific CR
data = mii_read_register( p_i82544, PHY_ADDRESS, 16 );
os_printf("PSCR %04x\n",data);
data |= 0x0800;
mii_write_register( p_i82544, PHY_ADDRESS, 16, data );
// Set TX clock to 25MHz in PHY extended CR
data = mii_read_register( p_i82544, PHY_ADDRESS, 20 );
os_printf("PSECR %04x\n",data);
data |= 0x0070;
mii_write_register( p_i82544, PHY_ADDRESS, 20, data );
}
show_phy( p_i82544, PHY_ADDRESS );
#endif
#if 1
// Force speed renegotiation.
{
cyg_uint16 phy_ctrl;
cyg_uint16 phy_stat;
int delay_cnt = 100 * 5; // wait five seconds, then give up
p_i82544->link = 0;
phy_ctrl = mii_read_register( p_i82544, PHY_ADDRESS, 0 );
phy_ctrl |= 0x1200;
// os_printf("PHY ctrl %04x\n",phy_ctrl);
mii_write_register( p_i82544, PHY_ADDRESS, 0, phy_ctrl );
// Wait for it to complete
do {
udelay(10000);
phy_stat = mii_read_register( p_i82544, PHY_ADDRESS, 1 );
phy_stat = mii_read_register( p_i82544, PHY_ADDRESS, 1 );
} while( (phy_stat & 0x0020) == 0 && (delay_cnt-- > 0) );
if (phy_stat & 0x0020)
p_i82544->link = 1;
}
#ifdef DEBUG
show_phy( p_i82544, PHY_ADDRESS );
#endif
#endif
#if 0
// Reset link
OUTL( ctrl | I82544_CTRL_LRST, ioaddr + I82544_CTRL );
udelay(20);
OUTL( ctrl, ioaddr + I82544_CTRL );
udelay(20);
show_phy( p_i82544, PHY_ADDRESS );
#endif
// Transfer speed and duplicity settings from PHY to MAC
// In theory the MAC is supposed to auto-configure from what the
// PHY has autonegotiated. In practice this does not seem to work
// (on the 82543 at least, it always thinks it is 1000MHz full
// duplex) and we have to transfer the settings from the PHY by
// hand. Additionally, the settings in the PHY ctrl register seem
// bogus, so we read the values out of the PHY specific status
// register instead.
if (p_i82544->link) {
cyg_uint16 phy_pssr;
phy_pssr = mii_read_register( p_i82544, PHY_ADDRESS, 17 );
ctrl = INL( ioaddr + I82544_CTRL );
// os_printf("CTRL %08x\n",ctrl);
ctrl &= ~(I82544_CTRL_SPEED | I82544_CTRL_FD);
if( phy_pssr & (1<<13) )
ctrl |= I82544_CTRL_FD;
// Transfer speed
ctrl |= ((phy_pssr>>14)&3)<<8;
ctrl |= I82544_CTRL_FRCDPLX | I82544_CTRL_FRCSPD;
OUTL( ctrl, ioaddr + I82544_CTRL );
// os_printf("CTRL %08x\n",ctrl);
}
#if 0
#ifdef DEBUG
{
int status = i82544_status( sc );
static int speed[4] = { 10, 100, 1000, 1000 };
os_printf("i82544_start %d flg %x Link = %s, %d Mbps, %s Duplex\n",
p_i82544->index,
*(int *)p_i82544,
status & GEN_STATUS_LINK ? "Up" : "Down",
speed[(status & GEN_STATUS_BPS)>>GEN_STATUS_BPS_SHIFT],
status & GEN_STATUS_FDX ? "Full" : "Half");
}
#endif
#endif
// Hang around here for a bit to let the device settle down. We
// don't seem to get away without this.
udelay( 1000000 );
#if 0
// Having done all that, the interface still does not work
// properly, UNLESS I now wait >= 45 seconds here. After that it
// seems happy. I cannot find any difference in the state of the
// PHY or the 82543 to explain this.
show_phy( p_i82544, PHY_ADDRESS );
os_printf("CTRL %08x\n",INL( ioaddr + I82544_CTRL ));
os_printf("STATUS %08x\n",INL( ioaddr + I82544_STATUS ));
os_printf("ICR %08x\n",INL( ioaddr + I82544_ICR ));
os_printf("RCTL %08x\n",INL( ioaddr + I82544_RCTL ));
os_printf("TCTL %08x\n",INL( ioaddr + I82544_TCTL ));
os_printf("Waiting 45 seconds\n");
{
int i;
cyg_uint32 status = INL( ioaddr + I82544_STATUS );
// for( i = 0; i < 60; i++ ) // works
// for( i = 0; i < 45; i++ ) // works
// for( i = 0; i < 40; i++ ) // fails
// for( i = 0; i < 35; i++ ) // fails
// for( i = 0; i < 30; i++ ) // fails
{
cyg_uint32 s;
PC_WRITE_SCREEN_32( 60, i );
udelay(1000000);
s = INL( ioaddr + I82544_STATUS );
if( s != status )
{
os_printf("%d STATUS change %08x\n",i,s);
status = s;
}
}
}
show_phy( p_i82544, PHY_ADDRESS );
os_printf("CTRL %08x\n",INL( ioaddr + I82544_CTRL ));
os_printf("STATUS %08x\n",INL( ioaddr + I82544_STATUS ));
os_printf("ICR %08x\n",INL( ioaddr + I82544_ICR ));
os_printf("RCTL %08x\n",INL( ioaddr + I82544_RCTL ));
os_printf("TCTL %08x\n",INL( ioaddr + I82544_TCTL ));
#endif
#endif // CYGHWR_DEVS_ETH_INTEL_I82544_USE_ASD
// Set up interrupts
// Clear any pending interrupts
ctrl = INL( ioaddr + I82544_ICR );
// clear all mask bits
OUTL( 0xFFFFFFFF, ioaddr + I82544_IMC );
// Set interrupt bits for:
// 1 = Transmit queue empty
// 7 = Receiver timeout interrupt
OUTL( (1<<1)|(1<<7), ioaddr + I82544_IMS );
}
// ------------------------------------------------------------------------
//
// Function : i82544_start
//
// ------------------------------------------------------------------------
static void
i82544_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
{
struct i82544 *p_i82544;
cyg_uint32 ioaddr;
cyg_uint32 txctl, rxctl;
#ifdef CYGPKG_NET
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
#ifdef DEBUG
db_printf("i82544_start\n");
#endif
p_i82544 = (struct i82544 *)sc->driver_private;
ioaddr = p_i82544->io_address; // get 82544's I/O address
IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
os_printf( "i82544_start: Bad device pointer %x\n", p_i82544 );
#endif
return;
}
if ( ! p_i82544->mac_addr_ok ) {
#ifdef DEBUG
os_printf("i82544_start %d: invalid MAC address, "
"can't bring up interface\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?