📄 tlan.c
字号:
head_list = priv->txList + priv->txHead; while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { ack++; if ( ! bbuf ) { dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address ); head_list->buffer[9].address = 0; } if ( tmpCStat & TLAN_CSTAT_EOC ) eoc = 1; priv->stats.tx_bytes += head_list->frameSize; head_list->cStat = TLAN_CSTAT_UNUSED; netif_start_queue(dev); CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); head_list = priv->txList + priv->txHead; } if (!ack) printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { priv->txInProgress = 0; } } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; priv->timerSetAt = jiffies; priv->timerType = TLAN_TIMER_ACTIVITY; add_timer(&priv->timer); } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { priv->timerSetAt = jiffies; } } return ack;} /* TLan_HandleTxEOF */ /*************************************************************** * TLan_HandleStatOverflow * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Statistics Overflow interrupt * which means that one or more of the TLAN statistics * registers has reached 1/2 capacity and needs to be read. * **************************************************************/u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ){ TLan_ReadAndClearStats( dev, TLAN_RECORD ); return 1;} /* TLan_HandleStatOverflow */ /*************************************************************** * TLan_HandleRxEOF * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Rx EOF interrupt which * indicates a frame has been received by the adapter from * the net and the frame has been transferred to memory. * The function determines the bounce buffer the frame has * been loaded into, creates a new sk_buff big enough to * hold the frame, and sends it to protocol stack. It * then resets the used buffer and appends it to the end * of the list. If the frame was the last in the Rx * channel (EOC), the function restarts the receive channel * by sending an Rx Go command to the adapter. Then it * activates/continues the activity LED. * **************************************************************/u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ){ TLanPrivateInfo *priv = dev->priv; u32 ack = 0; int eoc = 0; u8 *head_buffer; TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; void *t; u32 frameSize; u16 tmpCStat; TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { frameSize = head_list->frameSize; ack++; if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; if (bbuf) { skb = dev_alloc_skb(frameSize + 7); if (skb == NULL) printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); else { head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); skb->dev = dev; skb_reserve(skb, 2); t = (void *) skb_put(skb, frameSize); priv->stats.rx_bytes += head_list->frameSize; memcpy( t, head_buffer, frameSize ); skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); } } else { struct sk_buff *new_skb; /* * I changed the algorithm here. What we now do * is allocate the new frame. If this fails we * simply recycle the frame. */ new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); if ( new_skb != NULL ) { /* If this ever happened it would be a problem */ /* not any more - ac */ skb = (struct sk_buff *) head_list->buffer[9].address; skb_trim( skb, frameSize ); priv->stats.rx_bytes += frameSize; skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); new_skb->dev = dev; skb_reserve( new_skb, 2 ); t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); head_list->buffer[0].address = virt_to_bus( t ); head_list->buffer[8].address = (u32) t; head_list->buffer[9].address = (u32) new_skb; } else printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); } head_list->forward = 0; head_list->cStat = 0; tail_list = priv->rxList + priv->rxTail; tail_list->forward = virt_to_bus( head_list ); CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); head_list = priv->rxList + priv->rxHead; } if (!ack) printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; priv->rxEocCount++; } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; priv->timerSetAt = jiffies; priv->timerType = TLAN_TIMER_ACTIVITY; add_timer(&priv->timer); } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { priv->timerSetAt = jiffies; } } dev->last_rx = jiffies; return ack;} /* TLan_HandleRxEOF */ /*************************************************************** * TLan_HandleDummy * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Dummy interrupt, which is * raised whenever a test interrupt is generated by setting * the Req_Int bit of HOST_CMD to 1. * **************************************************************/u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ){ printk( "TLAN: Test interrupt on %s.\n", dev->name ); return 1;} /* TLan_HandleDummy */ /*************************************************************** * TLan_HandleTxEOC * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This driver is structured to determine EOC occurances by * reading the CSTAT member of the list structure. Tx EOC * interrupts are disabled via the DIO INTDIS register. * However, TLAN chips before revision 3.0 didn't have this * functionality, so process EOC events if this is the * case. * **************************************************************/u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ){ TLanPrivateInfo *priv = dev->priv; TLanList *head_list; u32 ack = 1; host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { netif_stop_queue(dev); outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { priv->txInProgress = 0; } } return ack;} /* TLan_HandleTxEOC */ /*************************************************************** * TLan_HandleStatusCheck * * Returns: * 0 if Adapter check, 1 if Network Status check. * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles Adapter Check/Network Status * interrupts generated by the adapter. It checks the * vector in the HOST_INT register to determine if it is * an Adapter Check interrupt. If so, it resets the * adapter. Otherwise it clears the status registers * and services the PHY. * **************************************************************/u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ){ TLanPrivateInfo *priv = dev->priv; u32 ack; u32 error; u8 net_sts; u32 phy; u16 tlphy_ctl; u16 tlphy_sts; ack = 1; if ( host_int & TLAN_HI_IV_MASK ) { netif_stop_queue( dev ); error = inl( dev->base_addr + TLAN_CH_PARM ); printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error ); TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); queue_task(&priv->tlan_tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); netif_wake_queue(dev); ack = 0; } else { TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); phy = priv->phy[priv->phyNum]; net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); if ( net_sts ) { TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); } if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl |= TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl &= ~TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); } if (debug) { TLan_PhyPrint( dev ); } } } return ack;} /* TLan_HandleStatusCheck */ /*************************************************************** * TLan_HandleRxEOC * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This driver is structured to determine EOC occurances by * reading the CSTAT member of the list structure. Rx EOC * interrupts are disabled via the DIO INTDIS register. * However, TLAN chips before revision 3.0 didn't have this * CSTAT member or a INTDIS register, so if this chip is * pre-3.0, process EOC interrupts normally. * **************************************************************/u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ){ TLanPrivateInfo *priv = dev->priv; TLanList *head_list; u32 ack = 1; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; priv->rxEocCount++; } return ack;} /* TLan_HandleRxEOC *//*********************************************************************************************************************************************************** ThunderLAN Driver Timer Function***********************************************************************************************************************************************************/ /*************************************************************** * TLan_Timer * * Returns: * Nothing * Parms: * data A value given to add timer when * add_timer was called. * * This function handles timed functionality for the * TLAN driver. The two current timer uses are for * delaying for autonegotionation and driving the ACT LED. * - Autonegotiation requires being allowed about * 2 1/2 seconds before attempting to transmit a * packet. It would be a very bad thing to hang * the kernel this long, so the driver doesn't * allow transmission 'til after this time, for * certain PHYs. It would be much nicer if all * PHYs were interrupt-capable like the internal * PHY. * - The ACT LED, which shows adapter activity, is * driven by the driver, and so must be left on * for a short period to power up the LED so it * can be seen. This delay can be changed by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -