if_i82544.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页

C
2,128
字号
#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",                  p_i82544->index );#endif        return;    }    if ( p_i82544->active )        i82544_stop( sc );    // Enable device    p_i82544->active = 1;    /* Enable promiscuous mode if requested, reception of oversized frames always.     * The latter is needed for VLAN support and shouldn't hurt even if we're not     * using VLANs.     */    i82544_configure(p_i82544, 0#ifdef CYGPKG_NET                     || !!(ifp->if_flags & IFF_PROMISC)#endif#ifdef ETH_DRV_FLAGS_PROMISC_MODE                     || !!(flags & ETH_DRV_FLAGS_PROMISC_MODE)#endif                     , 1);    // enable receiver    rxctl = INL( ioaddr + I82544_RCTL );    rxctl |= I82544_RCTL_EN;    OUTL( rxctl, ioaddr + I82544_RCTL );    // Enable transmitter    txctl = INL( ioaddr + I82544_TCTL );    txctl |= I82544_TCTL_EN;    OUTL( txctl, ioaddr + I82544_TCTL );    }// ------------------------------------------------------------------------////  Function : i82544_status//// ------------------------------------------------------------------------inti82544_status( struct eth_drv_sc *sc ){    int status;    struct i82544 *p_i82544;    cyg_uint32 ioaddr;#ifdef DEBUG    db_printf("i82544_status\n");#endif        p_i82544 = (struct i82544 *)sc->driver_private;        IF_BAD_82544( p_i82544 ) {#ifdef DEBUG        os_printf( "i82544_status: Bad device pointer %x\n", p_i82544 );#endif        return 0;    }

⌨️ 快捷键说明

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