changeset 1027:f0473e6bec8f

i82544 fix
author msalter
date Fri, 16 May 2003 13:55:19 +0000
parents e4cc97a76353
children 8a8d24f4000a
files packages/devs/eth/intel/i82544/current/ChangeLog packages/devs/eth/intel/i82544/current/include/i82544_info.h packages/devs/eth/intel/i82544/current/src/if_i82544.c
diffstat 3 files changed, 64 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/eth/intel/i82544/current/ChangeLog
+++ b/packages/devs/eth/intel/i82544/current/ChangeLog
@@ -1,3 +1,8 @@
+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.
+
 2003-03-19  Mark Salter  <msalter@redhat.com>
 
 	* src/if_i82544.c (i82544_setup): More 82546 EEPROM fixes (EE_PRES
--- a/packages/devs/eth/intel/i82544/current/include/i82544_info.h
+++ b/packages/devs/eth/intel/i82544/current/include/i82544_info.h
@@ -9,7 +9,7 @@
 //####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
@@ -138,7 +138,8 @@ typedef struct i82544 {
         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
--- a/packages/devs/eth/intel/i82544/current/src/if_i82544.c
+++ b/packages/devs/eth/intel/i82544/current/src/if_i82544.c
@@ -1358,6 +1358,9 @@ i82544_setup( struct i82544 *p_i82544 )
     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;
@@ -1448,17 +1451,22 @@ i82544_setup( struct i82544 *p_i82544 )
     {
         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    
@@ -1487,7 +1495,7 @@ i82544_setup( struct i82544 *p_i82544 )
     // 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 );
@@ -2146,6 +2154,43 @@ TxDone(struct i82544* p_i82544)
 }
 
 
+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
@@ -2172,11 +2217,15 @@ i82544_can_send(struct eth_drv_sc *sc)
     }
 
     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 );
 
@@ -2429,6 +2478,9 @@ i82544_poll(struct eth_drv_sc *sc)
         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 );