if_i82544.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 2,053 行 · 第 1/5 页

C
2,053
字号

    if( p_i82544->device == 0x1004 )
    {
        // An 82543, write MII register via software defined pins in
        // CTRL register.
        
        MII_INIT();
        MII_WRITE_PREAMBLE();
        MII_WRITE_START();
        MII_WRITE_WRITE_CMD();
        MII_WRITE_PHY_ADDR(phy);
        MII_WRITE_REGNUM( regnum );
        MII_WRITE_TURNAROUND();
        MII_WRITE_REGVAL( value );
        MII_IDLE();
    }
    else
    {
        // Others, write MII register via MDIC register.

        cyg_uint32 mdic = (1<<26) | (phy<<21) | (regnum<<16) | (value&0xFFFF);

        OUTL( mdic, ioaddr + I82544_MDIC );

        // Wait for ready
        do
        {
            mdic = INL( ioaddr + I82544_MDIC );
        } while( (mdic & (1<<28)) == 0 );
    }
}
#endif

#ifdef DEBUG
// dump out the PHY registers
static void show_phy( struct i82544 *p_i82544, int phy )
{
    int i;

    os_printf("PHY %d regs:",phy);
    for( i = 0; i < 32; i++ )
    {
        cyg_uint32 mdic;
        
        mdic = mii_read_register( p_i82544, phy, i );

        if( (i%8)==0 ) os_printf("\n");

        os_printf("%04x ",mdic);
    }
    os_printf("\n");        
}
#endif

// ------------------------------------------------------------------------
//
//                       GET EEPROM SIZE
//
// ------------------------------------------------------------------------

// ------------------------------------------------------------------------
//
// Serial EEPROM access  - much like the other Intel ethernet
//

// CYGACC_CALL_IF_DELAY_US() drags in huge amounts of scheduler locking and
// the like 'cos it's a VV call!  Waste of time, mostly.

#define EE_DELAY() do { int z; for ( z = 0; z < 10000; z++ ) ; } while (0)

#if 0
# define EE_PRINTF diag_printf
# define EE_STUFF "%4s | %4s | %4s | %4s [%08x]\n",     \
    (l & EE_SHIFT_CLK) ? "CLK"  : "clk",                      \
    (l & EE_CS) ? "eeCS" : "--",                       \
    (l & EE_DATA_WRITE) ? "eeDW" : "---",                      \
    (l & EE_DATA_READ) ? "eeDR" : "---",                      \
    l & 0xfffff
#else
# define EE_PRINTF( foo )
# define EE_STUFF
#endif


static inline void ee_select( int ioaddr, struct i82544 *p_i82544 )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD );
    if (p_i82544->device == 0x1010 ||
        p_i82544->device == 0x100e) {
	// i82546 requires REQ/GNT before EEPROM access
	l |= EE_REQ;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();
	while ((l & EE_GNT) == 0)
	    l = INL( ioaddr + I82544_EECD );
    }
    l &= ~0x3f;
    l |= EE_ENB;
    OUTL( l, ioaddr + I82544_EECD );
    EE_DELAY();
    l |= EE_CS;
    OUTL( l, ioaddr + I82544_EECD );
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_select       : " EE_STUFF  );
    EE_DELAY();
}

static inline void ee_deselect( int ioaddr )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD ) & ~0x3f;
    l |= EE_ENB;
    OUTL( l, ioaddr + I82544_EECD );
    EE_PRINTF( "ee_deselect 1   : " EE_STUFF  );
    EE_DELAY();
    EE_DELAY();
    EE_DELAY();
    l &= ~EE_CS;
    OUTL( l, ioaddr + I82544_EECD );
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_deselect 2   : " EE_STUFF  );
    EE_DELAY();
    EE_DELAY();
    EE_DELAY();
    if (l & EE_REQ) {
	l &= ~EE_REQ;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();
    }
}

static inline void ee_clock_up( int ioaddr )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD );
    l |= EE_SHIFT_CLK;
    OUTL( l, ioaddr + I82544_EECD );
    EE_DELAY();
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_clock_up     : " EE_STUFF  );
    EE_DELAY();
}

static inline void ee_clock_down( int ioaddr )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD );
    l &=~ EE_SHIFT_CLK;
    OUTL( l, ioaddr + I82544_EECD );
    EE_DELAY();
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_clock_down   : " EE_STUFF  );
    EE_DELAY();
}

static inline int ee_read_data_bit( int ioaddr )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_read_data    : " EE_STUFF  );
    return EE_DATA_READ == (EE_DATA_READ & l);
}

static inline void ee_write_data_bit( int ioaddr, int databit )
{
    cyg_uint32 l;
    l = INL( ioaddr + I82544_EECD );
    if ( databit )
        l |= EE_DATA_WRITE;
    else
        l &= ~EE_DATA_WRITE;
    OUTL( l, ioaddr + I82544_EECD );
    l = INL( ioaddr + I82544_EECD );
    EE_PRINTF( "ee_write_data   : " EE_STUFF  );
    EE_DELAY();
}

// Pass ioaddr around "invisibly"
#define EE_SELECT()              ee_select(ioaddr, p_i82544)
#define EE_DESELECT()            ee_deselect(ioaddr)
#define EE_CLOCK_UP()            ee_clock_up(ioaddr)
#define EE_CLOCK_DOWN()          ee_clock_down(ioaddr)
#define EE_READ_DATA_BIT()       ee_read_data_bit(ioaddr)
#define EE_WRITE_DATA_BIT( _d_ ) ee_write_data_bit(ioaddr,(_d_))

// ------------------------------------------------------------------------

static int
get_eeprom_size( struct i82544 *p_i82544 )
{
    cyg_uint32 l, ioaddr = p_i82544->io_address;
    int i, tmp, addrbits;

    l = INL( ioaddr + I82544_EECD );

#ifdef DEBUG_EE
    diag_printf( "get_eeprom_size\n" );
#endif

    if (p_i82544->device == 0x1010 ||
        p_i82544->device == 0x100e) {
	
	l |= EE_REQ;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();
	while ((l & EE_GNT) == 0)
	    l = INL( ioaddr + I82544_EECD );
	l &= ~0x3f;
	l |= EE_ENB;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();
	l |= EE_CS;
	OUTL( l, ioaddr + I82544_EECD );
	l = INL( ioaddr + I82544_EECD );
	EE_DELAY();

	for (i = 3; i >= 0; i--) { // Doc says to shift out a zero then:
	    tmp = (6 & (1 << i)) ? 1 : 0; // "6" is the "read" command.
	    EE_WRITE_DATA_BIT(tmp);
	    EE_CLOCK_UP();
	    EE_CLOCK_DOWN();
	}
	// Now clock out address zero, looking for the dummy 0 data bit
	for ( i = 1; i <= 10; i++ ) {
	    EE_WRITE_DATA_BIT(0);
	    EE_CLOCK_UP();
	    EE_CLOCK_DOWN();
	    if (EE_READ_DATA_BIT() == 0)
		break; // The dummy zero est arrive'
	}

	if (6 != i && 8 != i)
	    diag_printf("no EEPROM found\n");

	addrbits = i;
        
	tmp = 0;
	for (i = 15; i >= 0; i--) {
	    EE_CLOCK_UP();
	    if (EE_READ_DATA_BIT())
		tmp |= (1<<i);
	    EE_CLOCK_DOWN();
	}

	l = INL( ioaddr + I82544_EECD ) & ~0x3f;
	l |= EE_ENB;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();
	EE_DELAY();
	EE_DELAY();
	l &= ~EE_CS;
	OUTL( l, ioaddr + I82544_EECD );
	l = INL( ioaddr + I82544_EECD );
	EE_DELAY();
	EE_DELAY();
	EE_DELAY();

	l &= ~EE_REQ;
	OUTL( l, ioaddr + I82544_EECD );
	EE_DELAY();

	return addrbits;
    }

    return 6;
}

static int
read_eeprom_word( struct i82544 *p_i82544, int addrbits, int address )
{
    int i, tmp;
    cyg_uint32 ioaddr = p_i82544->io_address;

    // Should already be not-selected, but anyway:
    EE_SELECT();

    // Shift the read command bits out.
    for (i = 3; i >= 0; i--) { // Doc says to shift out a zero then:
        tmp = (6 & (1 << i)) ? 1 : 0; // "6" is the "read" command.
        EE_WRITE_DATA_BIT(tmp);
        EE_CLOCK_UP();
        EE_CLOCK_DOWN();
    }

    // Now clock out address
    for ( i = addrbits - 1; i >= 0 ; i-- ) {
        tmp = (address & (1<<i)) ? 1 : 0;
        EE_WRITE_DATA_BIT(tmp);
        EE_CLOCK_UP();
        tmp = EE_READ_DATA_BIT();
        EE_CLOCK_DOWN();

//        CYG_ASSERT( (0 == tmp) == (0 == i), "Looking for zero handshake bit" );
    }

    // read in the data
    tmp = 0;
    for (i = 15; i >= 0; i--) {
        EE_CLOCK_UP();
        if ( EE_READ_DATA_BIT() )
            tmp |= (1<<i);
        EE_CLOCK_DOWN();
    }

    // Terminate the EEPROM access.
    EE_DESELECT();
 
#ifdef DEBUG_EE
//    diag_printf( "eeprom address %4x: data %4x\n", address, tmp );
#endif

    return tmp;
}

// ------------------------------------------------------------------------

// ------------------------------------------------------------------------
//
//                NETWORK INTERFACE INITIALIZATION
//
//  Function : Init82544
//
//  Description :
//       This routine resets, configures, and initializes the chip.
//       It also clears the ethernet statistics structure, and selects
//       which statistics are supported by this driver.
//
// ------------------------------------------------------------------------

static bool
i82544_init(struct cyg_netdevtab_entry * ndp)
{
    static int initialized = 0; // only probe PCI et al *once*

    struct eth_drv_sc *sc;
    cyg_uint32 ioaddr;
    int count;
    struct i82544 *p_i82544;
    cyg_uint8 mac_address[ETHER_ADDR_LEN];

#ifdef DEBUG
    db_printf("i82544_init\n");
#endif

    sc = (struct eth_drv_sc *)(ndp->device_instance);
    p_i82544 = (struct i82544 *)(sc->driver_private);

    IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
        os_printf( "Bad device private pointer %x\n", sc->driver_private );
#endif
        return 0;
    }

    CHECK_NDP_SC_LINK();

    if ( 0 == initialized++ ) {
        // then this is the first time ever:
        if ( ! pci_init_find_82544s() ) {
#ifdef DEBUG
            os_printf( "pci_init_find_82544s failed\n" );
#endif
            return 0;
        }
    }

    // If this device is not present, exit
    if (0 == p_i82544->found)
        return 0;

    p_i82544->mac_addr_ok = 0;

    ioaddr = p_i82544->io_address; // get I/O address for 82544

#ifdef DEBUG
    os_printf("Init82544 %d @ %x\n", p_i82544->index, (int)ndp);
#endif

    // Reset device
    i82544_reset(p_i82544);

    i82544_setup(p_i82544);
        
    InitRxRing(p_i82544);
    InitTxRing(p_i82544);

    
    if (p_i82544->hardwired_esa) {
        // Hardwire the address without consulting the EEPROM.
        // When this flag is set, the p_i82544 will already contain
        // the ESA. Copy it to a mac_address for call to set_mac_addr
        mac_address[0] = p_i82544->mac_address[0];
        mac_address[1] = p_i82544->mac_address[1];
        mac_address[2] = p_i82544->mac_address[2];
        mac_address[3] = p_i82544->mac_address[3];
        mac_address[4] = p_i82544->mac_address[4];
        mac_address[5] = p_i82544->mac_address[5];

        eth_set_mac_address(p_i82544, mac_address, 0);

    } else {

        // Acquire the ESA either from extenal means (probably RedBoot
        // variables) or from the attached EEPROM - if there is one.

#ifdef CYGHWR_DEVS_ETH_INTEL_I82544_GET_ESA
        int ok = false;
        CYGHWR_DEVS_ETH_INTEL_I82544_GET_ESA( p_i82544, mac_address, ok );
        if ( ok )
            eth_set_mac_address(p_i82544, mac_address, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?