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 + -
显示快捷键?