📄 tlan.c
字号:
/*********************************************************************************************************************************************************** ThunderLAN Driver Adapter Related Routines***********************************************************************************************************************************************************/ /*************************************************************** * TLan_ResetLists * * Returns: * Nothing * Parms: * dev The device structure with the list * stuctures to be reset. * * This routine sets the variables associated with managing * the TLAN lists to their initial values. * **************************************************************/void TLan_ResetLists( struct net_device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; int i; TLanList *list; struct sk_buff *skb; void *t = NULL; priv->txHead = 0; priv->txTail = 0; for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; if ( bbuf ) { list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); } else { list->buffer[0].address = 0; } list->buffer[2].count = 0; list->buffer[2].address = 0; } priv->rxHead = 0; priv->rxTail = TLAN_NUM_RX_LISTS - 1; for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { list = priv->rxList + i; list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; if ( bbuf ) { list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); } else { skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); if ( skb == NULL ) { printk( "TLAN: Couldn't allocate memory for received data.\n" ); /* If this ever happened it would be a problem */ } else { skb->dev = dev; skb_reserve( skb, 2 ); t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); } list->buffer[0].address = virt_to_bus( t ); list->buffer[9].address = (u32) skb; } list->buffer[1].count = 0; list->buffer[1].address = 0; if ( i < TLAN_NUM_RX_LISTS - 1 ) list->forward = virt_to_bus( list + 1 ); else list->forward = 0; }} /* TLan_ResetLists */void TLan_FreeLists( struct net_device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; int i; TLanList *list; struct sk_buff *skb; if ( ! bbuf ) { for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } } for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { list = priv->rxList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } } }} /* TLan_FreeLists */ /*************************************************************** * TLan_PrintDio * * Returns: * Nothing * Parms: * io_base Base IO port of the device of * which to print DIO registers. * * This function prints out all the the internal (DIO) * registers of a TLAN chip. * **************************************************************/void TLan_PrintDio( u16 io_base ){ u32 data0, data1; int i; printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); printk( "TLAN: Off. +0 +4\n" ); for ( i = 0; i < 0x4C; i+= 8 ) { data0 = TLan_DioRead32( io_base, i ); data1 = TLan_DioRead32( io_base, i + 0x4 ); printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); }} /* TLan_PrintDio */ /*************************************************************** * TLan_PrintList * * Returns: * Nothing * Parms: * list A pointer to the TLanList structure to * be printed. * type A string to designate type of list, * "Rx" or "Tx". * num The index of the list. * * This function prints out the contents of the list * pointed to by the list parameter. * **************************************************************/void TLan_PrintList( TLanList *list, char *type, int num){ int i; printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); printk( "TLAN: Forward = 0x%08x\n", list->forward ); printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); /* for ( i = 0; i < 10; i++ ) { */ for ( i = 0; i < 2; i++ ) { printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); }} /* TLan_PrintList */ /*************************************************************** * TLan_ReadAndClearStats * * Returns: * Nothing * Parms: * dev Pointer to device structure of adapter * to which to read stats. * record Flag indicating whether to add * * This functions reads all the internal status registers * of the TLAN chip, which clears them as a side effect. * It then either adds the values to the device's status * struct, or discards them, depending on whether record * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). * **************************************************************/void TLan_ReadAndClearStats( struct net_device *dev, int record ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u32 tx_good, tx_under; u32 rx_good, rx_over; u32 def_tx, crc, code; u32 multi_col, single_col; u32 excess_col, late_col, loss; outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); if ( record ) { priv->stats.rx_packets += rx_good; priv->stats.rx_errors += rx_over + crc + code; priv->stats.tx_packets += tx_good; priv->stats.tx_errors += tx_under + loss; priv->stats.collisions += multi_col + single_col + excess_col + late_col; priv->stats.rx_over_errors += rx_over; priv->stats.rx_crc_errors += crc; priv->stats.rx_frame_errors += code; priv->stats.tx_aborted_errors += tx_under; priv->stats.tx_carrier_errors += loss; } } /* TLan_ReadAndClearStats */ /*************************************************************** * TLan_Reset * * Returns: * 0 * Parms: * dev Pointer to device structure of adapter * to be reset. * * This function resets the adapter and it's physical * device. See Chap. 3, pp. 9-10 of the "ThunderLAN * Programmer's Guide" for details. The routine tries to * implement what is detailed there, though adjustments * have been made. * **************************************************************/voidTLan_ResetAdapter( struct net_device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; int i; u32 addr; u32 data; u8 data8; priv->tlanFullDuplex = FALSE; priv->phyOnline=0;/* 1. Assert reset bit. */ data = inl(dev->base_addr + TLAN_HOST_CMD); data |= TLAN_HC_AD_RST; outl(data, dev->base_addr + TLAN_HOST_CMD); udelay(1000);/* 2. Turn off interrupts. ( Probably isn't necessary ) */ data = inl(dev->base_addr + TLAN_HOST_CMD); data |= TLAN_HC_INT_OFF; outl(data, dev->base_addr + TLAN_HOST_CMD);/* 3. Clear AREGs and HASHs. */ for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) { TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); }/* 4. Setup NetConfig register. */ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );/* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD );/* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; TLan_SetBit( TLAN_NET_SIO_NMRST, addr );/* 7. Setup the remaining registers. */ if ( priv->tlanRev >= 0x30 ) { data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 ); } TLan_PhyDetect( dev ); data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) { data |= TLAN_NET_CFG_BIT; if ( priv->aui == 1 ) { TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a ); } else if ( priv->duplex == TLAN_DUPLEX_FULL ) { TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 ); priv->tlanFullDuplex = TRUE; } else { TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); } } if ( priv->phyNum == 0 ) { data |= TLAN_NET_CFG_PHY_EN; } TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { TLan_FinishReset( dev ); } else { TLan_PhyPowerDown( dev ); }} /* TLan_ResetAdapter */voidTLan_FinishReset( struct net_device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u8 data; u32 phy; u8 sio; u16 status; u16 partner; u16 tlphy_ctl; u16 tlphy_par; u16 tlphy_id1, tlphy_id2; int i; phy = priv->phy[priv->phyNum]; data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; if ( priv->tlanFullDuplex ) { data |= TLAN_NET_CMD_DUPLEX; } TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data ); data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; if ( priv->phyNum == 0 ) { data |= TLAN_NET_MASK_MASK7; } TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) { status = MII_GS_LINK; printk( "TLAN: %s: Link forced.\n", dev->name ); } else { TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */ (tlphy_id1 == NAT_SEM_ID1) && (tlphy_id2 == NAT_SEM_ID2) ) { TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par ); printk( "TLAN: %s: Link active with ", dev->name ); if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { printk( "forced 10%sMbps %s-Duplex\n", tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); } else { printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); printk("TLAN: Partner capability: "); for (i = 5; i <= 10; i++) if (partner & (1<<i)) printk("%s", media[i-5]); printk("\n"); } TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );#ifdef MONITOR /* We have link beat..for now anyway */ priv->link = 1; /*Enabling link beat monitoring */ TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT );#endif } else if (status & MII_GS_LINK) { printk( "TLAN: %s: Link active\n", dev->name ); TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); } } if ( priv->phyNum == 0 ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); tlphy_ctl |= TLAN_TC_INTEN; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl ); sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); sio |= TLAN_NET_SIO_MINTEN; TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); } if ( status & MII_GS_LINK ) { TLan_SetMac( dev, 0, dev->dev_addr ); priv->phyOnline = 1; outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) { outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); } outl( virt_to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -