📄 tlan.c
字号:
* changing the TLAN_TIMER_ACT_DELAY in tlan.h, * if desired. 100 ms produces a slightly * sluggish response. * **************************************************************/void TLan_Timer( unsigned long data ){ struct net_device *dev = (struct net_device *) data; TLanPrivateInfo *priv = dev->priv; u32 elapsed; unsigned long flags = 0; priv->timer.function = NULL; switch ( priv->timerType ) {#ifdef MONITOR case TLAN_TIMER_LINK_BEAT: TLan_PhyMonitor( dev ); break;#endif case TLAN_TIMER_PHY_PDOWN: TLan_PhyPowerDown( dev ); break; case TLAN_TIMER_PHY_PUP: TLan_PhyPowerUp( dev ); break; case TLAN_TIMER_PHY_RESET: TLan_PhyReset( dev ); break; case TLAN_TIMER_PHY_START_LINK: TLan_PhyStartLink( dev ); break; case TLAN_TIMER_PHY_FINISH_AN: TLan_PhyFinishAutoNeg( dev ); break; case TLAN_TIMER_FINISH_RESET: TLan_FinishReset( dev ); break; case TLAN_TIMER_ACTIVITY: spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function == NULL ) { elapsed = jiffies - priv->timerSetAt; if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); } else { priv->timer.function = &TLan_Timer; priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; spin_unlock_irqrestore(&priv->lock, flags); add_timer( &priv->timer ); break; } } spin_unlock_irqrestore(&priv->lock, flags); break; default: break; }} /* TLan_Timer *//*********************************************************************************************************************************************************** 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 = 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; list->buffer[9].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[8].address = (u32) 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 = 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 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 = 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 = 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 | 0x3f, dev->base_addr + TLAN_HOST_CMD ); outl( TLAN_HC_LD_THR | 0x9, 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 = 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, ((1536)+7)&~7 ); TLan
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -