This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
i82544 fix
- From: Mark Salter <msalter at redhat dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: Fri, 16 May 2003 09:57:39 -0400 (EDT)
- Subject: i82544 fix
2003-05-16 Mark Salter <msalter@redhat.com>
* include/i82544_info.h: Add link flag.
* src/if_i82544.c: Allow booting when not using ASD and link is down.
Index: devs/eth/intel/i82544/current/include/i82544_info.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/intel/i82544/current/include/i82544_info.h,v
retrieving revision 1.2
diff -u -p -5 -r1.2 i82544_info.h
--- devs/eth/intel/i82544/current/include/i82544_info.h 23 May 2002 23:00:43 -0000 1.2
+++ devs/eth/intel/i82544/current/include/i82544_info.h 16 May 2003 13:51:23 -0000
@@ -7,11 +7,11 @@
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
@@ -136,11 +136,12 @@ typedef struct i82544 {
cyg_uint8 // (split up for atomic byte access)
found:1, // was hardware discovered?
mac_addr_ok:1, // can we bring up?
active:1, // has this if been brung up?
hardwired_esa:1, // set if ESA is hardwired via CDL
- spare1:4;
+ link:1, // set if link is up
+ spare1:3;
cyg_uint8 // Count nested sends to reject
within_send:8; // nested requests to send
cyg_uint8
tx_in_progress:1, // transmit in progress flag
tx_queue_full:1, // all Tx descriptors used flag
Index: devs/eth/intel/i82544/current/src/if_i82544.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/intel/i82544/current/src/if_i82544.c,v
retrieving revision 1.8
diff -u -p -5 -r1.8 if_i82544.c
--- devs/eth/intel/i82544/current/src/if_i82544.c 19 Mar 2003 19:55:36 -0000 1.8
+++ devs/eth/intel/i82544/current/src/if_i82544.c 16 May 2003 13:52:11 -0000
@@ -1356,10 +1356,13 @@ i82544_setup( struct i82544 *p_i82544 )
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);
@@ -1446,21 +1449,26 @@ i82544_setup( struct i82544 *p_i82544 )
// 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(100);
+ 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 );
+ } 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
@@ -1485,11 +1493,11 @@ i82544_setup( struct i82544 *p_i82544 )
// 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 );
@@ -2144,10 +2152,47 @@ TxDone(struct i82544* p_i82544)
p_i82544->tx_pointer = txp;
}
+static cyg_bool
+check_link(struct i82544 *p_i82544)
+{
+ if ( p_i82544->link == 0 )
+ {
+ cyg_uint16 phy_pssr;
+ cyg_uint16 phy_stat;
+
+ phy_stat = mii_read_register( p_i82544, PHY_ADDRESS, 1 );
+ if (phy_stat & 0x20)
+ {
+ cyg_uint32 ioaddr;
+ cyg_uint32 ctrl;
+
+ p_i82544->link = 1;
+
+ ioaddr = p_i82544->io_address; // get device I/O address
+
+ phy_pssr = mii_read_register( p_i82544, PHY_ADDRESS, 17 );
+
+ ctrl = INL( ioaddr + I82544_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 );
+ }
+ }
+
+ return p_i82544->link == 1;
+}
+
+
// ------------------------------------------------------------------------
//
// Function : i82544_can_send
//
// ------------------------------------------------------------------------
@@ -2170,15 +2215,19 @@ i82544_can_send(struct eth_drv_sc *sc)
#endif
return 0;
}
ioaddr = p_i82544->io_address; // get device I/O address
-
+
if ( p_i82544->active )
{
cyg_int32 txh, txt, diff;
+
+ if (!check_link(p_i82544))
+ return 0;
+
// Poll for Tx completion
TxDone( p_i82544 );
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
// We are not prepared to receive a packet now if we are in a polled
@@ -2426,10 +2475,13 @@ i82544_poll(struct eth_drv_sc *sc)
#ifdef DEBUG
os_printf( "i82544_poll: Bad device pointer %x\n", p_i82544 );
#endif
return;
}
+
+ if (!check_link(p_i82544))
+ return;
// As it happens, this driver always requests the DSR to be called:
(void)eth_isr( p_i82544->vector, (cyg_addrword_t)p_i82544 );
// (no harm in calling this ints-off also, when polled)