📄 rhine_main.c
字号:
static void rhine_rx_srv(PRHINE_INFO pInfo, int status) { PRX_DESC pRD=pInfo->pCurrRD; struct net_device_stats* pStats=&pInfo->stats; PMAC_REGS pMacRegs=pInfo->pMacRegs; for (pRD=pInfo->pCurrRD; pRD->rdesc0.f1Owner==OWNED_BY_HOST;pRD=pRD->next) { if (pRD->rdesc0.byRSR1 & RSR1_RXOK) { if (rhine_receive_frame(pInfo, pRD)) { if (!rhine_alloc_rx_buf(pInfo,pRD)) { RHINE_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", pInfo->dev->name); break; } } else { pStats->rx_errors++; pStats->rx_dropped++; } } else { pStats->rx_errors++; if (pRD->rdesc0.byRSR0 & RSR0_CRC) pStats->rx_crc_errors++; if (pRD->rdesc0.byRSR0 & RSR0_FAE) pStats->rx_frame_errors++; if (pRD->rdesc0.byRSR0 & RSR0_FOV) pStats->rx_fifo_errors++; pStats->rx_dropped++; } pRD->rdesc0.f1Owner=OWNED_BY_NIC; if (pInfo->flags & RHINE_FLAGS_FLOW_CTRL) writeb(1,&pMacRegs->byFlowCR0); pInfo->dev->last_rx=jiffies; } pInfo->pCurrRD=pRD;}#ifdef VMNSstatic void inlinerhine_attach_vmns_info(PRX_DESC pRD,struct sk_buff* skb,U16 wTag) { PVMNS_ATTACH_INFO pAttch = GET_VMNS_ATTACH_INFO(skb); pAttch->type = ATT_INFO_TYPE_NONE; if (pRD->rdesc1.byPQSTS & PQSTS_TAG) { pAttch->type |=ATT_INFO_TYPE_TAG; if (pRD->rdesc0.byRSR1 & RSR1_VIDHIT) pAttch->type |=ATT_INFO_TYPE_VIDHIT; pAttch->vlan=wTag & 0xfff; pAttch->priority=(wTag>>12) & 0x7; } if (pRD->rdesc1.byIPKT) { pAttch->type |= ATT_INFO_TYPE_INST; pAttch->InstNo = pRD->rdesc1.byIPKT; } pAttch->protocol=skb->protocol; skb->protocol=VMNS_FRAME_TYPE;}#endifstatic inline void rhine_rx_csum(PRX_DESC pRD, struct sk_buff* skb) { skb->ip_summed=CHECKSUM_NONE; if (pRD->rdesc0.byRSR0 & RSR0_FRAG) return; if (pRD->rdesc1.byPQSTS & PQSTS_IPKT) { if (pRD->rdesc1.byPQSTS & PQSTS_IPOK) { if ((pRD->rdesc1.byPQSTS & PQSTS_TCPKT) ||(pRD->rdesc1.byPQSTS & PQSTS_UDPKT)) { if (!(pRD->rdesc1.byPQSTS & PQSTS_TUOK)) { return; } } skb->ip_summed=CHECKSUM_UNNECESSARY; } }}static BOOL rhine_receive_frame(PRHINE_INFO pInfo, PRX_DESC pRD) { PRHINE_RD_INFO pRDInfo=pRD->pInfo; struct net_device_stats* pStats=&pInfo->stats; struct sk_buff* skb; U16 wTag; if ((pRD->rdesc0.byRSR1 & (RSR1_STP|RSR1_EDP)) !=(RSR1_STP|RSR1_EDP)) { RHINE_PRT(MSG_LEVEL_VERBOSE, KERN_NOTICE " %s : the received frame span multple RDs\n", pInfo->dev->name); pStats->rx_length_errors++; return FALSE; } if ((pRD->rdesc1.byPQSTS & PQSTS_TAG) && (!(pInfo->flags & (RHINE_FLAGS_VMNS_COMMITTED|RHINE_FLAGS_TAGGING) ))) { pStats->rx_dropped++; return FALSE; } if (pRD->rdesc0.byRSR0 & (RSR0_RUNT|RSR0_LONG)) { if (pRD->rdesc1.byPQSTS & PQSTS_TAG) { if (pRD->rdesc0.f15Length<60) { pStats->rx_length_errors++; return FALSE; } } else { pStats->rx_length_errors++; return FALSE; } } skb=pRDInfo->skb; skb->dev=pInfo->dev; pci_unmap_single(pInfo->pcid,pRDInfo->skb_dma, pInfo->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pInfo->flags & RHINE_FLAGS_IP_ALIGN) { int i; for (i = pRD->rdesc0.f15Length+4; i >= 0 ; i--) *(skb->data + i + 2) = *(skb->data + i); skb->data += 2; skb->tail += 2; } //Get Tag wTag=htons(*(PU16)((PU8)skb->data+((pRD->rdesc0.f15Length+3) & ~3)+2)); skb_put(skb,(pRD->rdesc0.f15Length-4)); skb->protocol=eth_type_trans(skb, skb->dev); //drop frame not met IEEE 802.3 if (pInfo->flags & RHINE_FLAGS_VAL_PKT_LEN) { if ((skb->protocol==ETH_P_802_3) && ((skb->len-14)!=skb->mac.ethernet->h_proto)) { pStats->rx_length_errors++; return FALSE; } } skb->ip_summed=CHECKSUM_NONE; if (pInfo->flags & RHINE_FLAGS_RX_CSUM) rhine_rx_csum(pRD,skb);#ifdef VMNS if (pInfo->flags & RHINE_FLAGS_VMNS_COMMITTED) rhine_attach_vmns_info(pRD, skb, wTag);#endif if (pRD->rdesc0.byRSR0 & RSR0_FRAG) skb->ip_summed=CHECKSUM_NONE; pStats->rx_bytes+=skb->len; pStats->rx_packets++; netif_rx(skb); return TRUE;}static BOOL rhine_alloc_rx_buf(PRHINE_INFO pInfo, PRX_DESC pRD) { PRHINE_RD_INFO pRDInfo=pRD->pInfo; pRDInfo->skb=dev_alloc_skb(pInfo->rx_buf_sz); if (pRDInfo->skb==NULL) return FALSE; ASSERT(pRDInfo->skb); pRDInfo->skb->dev=pInfo->dev; pRDInfo->skb_dma= pci_map_single(pInfo->pcid, pRDInfo->skb->tail, pInfo->rx_buf_sz, PCI_DMA_FROMDEVICE); *((PU32) &(pRD->rdesc0)) = 0; pRD->rdesc1.f15BufLen=cpu_to_le32(pInfo->rx_buf_sz); pRD->rdesc0.f1Owner=OWNED_BY_NIC; pRD->buff_addr=cpu_to_le32(pRDInfo->skb_dma); return TRUE; }//// Re-transmited the frame//static void rhine_tx_srv_resend(PRHINE_INFO pInfo, PTX_DESC pTD, int iQNo) { PMAC_REGS pMacRegs=pInfo->pMacRegs; WAIT_MAC_TX_OFF(pMacRegs); pTD->tdesc0.f1Owner=OWNED_BY_NIC; writel(cpu_to_le32(pTD->pInfo->curr_desc), &pMacRegs->adwCurrTxDescAddr[iQNo]); BYTE_REG_BITS_ON(CR0_TXON,&pMacRegs->byCR0); if( pInfo->flags & RHINE_FLAGS_TAGGING) BYTE_REG_BITS_ON(1 << (7-iQNo), &pMacRegs->byTXQWAK); BYTE_REG_BITS_ON(CR1_TDMD1,&pMacRegs->byCR1); }//// Drop the frame//static void rhine_tx_srv_drop(PRHINE_INFO pInfo, PTX_DESC pTD, int iQNo) { PMAC_REGS pMacRegs=pInfo->pMacRegs; WAIT_MAC_TX_OFF(pMacRegs); pTD=pTD->next; writel(cpu_to_le32(pTD->pInfo->curr_desc), &pMacRegs->adwCurrTxDescAddr[iQNo]); BYTE_REG_BITS_ON(CR0_TXON,&pMacRegs->byCR0); if( pInfo->flags & RHINE_FLAGS_TAGGING) BYTE_REG_BITS_ON(1 << (7-iQNo), &pMacRegs->byTXQWAK); BYTE_REG_BITS_ON(CR1_TDMD1,&pMacRegs->byCR1); }//// Drop all frame on the TX Queue//static void rhine_tx_srv_drop_all(PRHINE_INFO pInfo) { PMAC_REGS pMacRegs=pInfo->pMacRegs; PTX_DESC pTD; int iQNo; struct net_device_stats* pStats=&pInfo->stats; WAIT_MAC_TX_OFF(pMacRegs); //Drop all transmited packets in the TD queue, because //The TD write back status may be incorrect. for (iQNo=0;iQNo<pInfo->nTxQueues;iQNo++) { for (pTD=pInfo->apTailTD[iQNo];pInfo->iTDUsed[iQNo]>0; pTD=pTD->next) { if (pTD->tdesc0.f1Owner==OWNED_BY_NIC) break; rhine_free_tx_buf(pInfo,pTD); pInfo->iTDUsed[iQNo]--; pStats->tx_dropped++; } pInfo->apTailTD[iQNo]=pTD; writel(cpu_to_le32(pTD->pInfo->curr_desc), &(pMacRegs->adwCurrTxDescAddr[iQNo])); if (pInfo->flags & RHINE_FLAGS_TAGGING) BYTE_REG_BITS_ON(1<<(7-iQNo), &pMacRegs->byTXQWAK); } BYTE_REG_BITS_ON(CR0_TXON,&pMacRegs->byCR0); BYTE_REG_BITS_ON(CR1_TDMD1,&pMacRegs->byCR1);}static void rhine_tx_srv(PRHINE_INFO pInfo, int status) { PTX_DESC pTD; int iQNo; BOOL bFull=FALSE; struct net_device_stats* pStats=&pInfo->stats; for (iQNo=0;iQNo<pInfo->nTxQueues;iQNo++) { for (pTD=pInfo->apTailTD[iQNo];pInfo->iTDUsed[iQNo]>0; pTD=pTD->next) { if (pTD->tdesc0.f1Owner==OWNED_BY_NIC) { break; } //Only the status of first TD in the chain is correct if (pTD->tdesc1.byTCR & TCR_STP) { if (pTD->tdesc0.byTSR1 & TSR1_TERR) { RHINE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s : td error %x,%x\n",pInfo->dev->name, pTD->tdesc0.byTSR1,pTD->tdesc0.byTSR0); pStats->tx_errors++; if (pTD->tdesc0.byTSR1 & TSR1_UDF) { if (pInfo->sOpts.tx_thresh<4) { pInfo->sOpts.tx_thresh++; RHINE_PRT(MSG_LEVEL_VERBOSE, KERN_INFO "%s : transmitter fifo underrun occurred, increase fifo threshold to %d\n", pInfo->dev->name, pInfo->sOpts.tx_thresh); rhine_set_tx_thresh(pInfo,pInfo->sOpts.tx_thresh); } rhine_tx_srv_resend(pInfo,pTD,iQNo); pStats->tx_fifo_errors++; break; } if (pTD->tdesc0.byTSR1 & TSR1_ABT) { RHINE_PRT(MSG_LEVEL_VERBOSE, KERN_INFO "%s : transmitter fifo abort occurred\n",pInfo->dev->name); rhine_tx_srv_drop(pInfo,pTD,iQNo); pStats->tx_aborted_errors++; } pStats->tx_dropped++; if (pTD->tdesc0.byTSR1 & TSR1_CRS) pStats->tx_carrier_errors++; if (pTD->tdesc0.byTSR1 & TSR1_OWC) pStats->tx_window_errors++; if (pTD->tdesc0.byTSR0 & TSR0_CDH) pStats->tx_heartbeat_errors++; } else { pStats->collisions+=(pTD->tdesc0.byTSR0 & 0xF); pStats->tx_packets++; pStats->tx_bytes+=pTD->pInfo->skb->len; } rhine_free_tx_buf(pInfo,pTD); pInfo->iTDUsed[iQNo]--; } } pInfo->apTailTD[iQNo]=pTD; if (pInfo->iTDUsed[iQNo]>pInfo->sOpts.nTxDescs-4) { bFull=TRUE; } } if (netif_queue_stopped(pInfo->dev) && (bFull==FALSE)) { netif_wake_queue(pInfo->dev); } }static void rhine_print_link_status(PRHINE_INFO pInfo) { if (pInfo->mii_status & RHINE_LINK_FAIL) { RHINE_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n",pInfo->dev->name); } else { if (pInfo->mii_status & RHINE_AUTONEG_ENABLE) RHINE_PRT(MSG_LEVEL_INFO, "%s: Link autonegation",pInfo->dev->name) else RHINE_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced",pInfo->dev->name); if (pInfo->mii_status & RHINE_SPEED_100) RHINE_PRT(MSG_LEVEL_INFO," speed 100M bps") else RHINE_PRT(MSG_LEVEL_INFO," speed 10M bps"); if (pInfo->mii_status & RHINE_DUPLEX_FULL) RHINE_PRT(MSG_LEVEL_INFO, " full duplex\n") else RHINE_PRT(MSG_LEVEL_INFO, " half duplex\n"); }}static void rhine_error(PRHINE_INFO pInfo, int status) { if (status & ISR_SRCI) { pInfo->mii_status=rhine_check_media_mode(pInfo); rhine_print_link_status(pInfo); if (pInfo->byRevId>=REV_ID_VT6102_A) enable_flow_control_ability(pInfo); #ifdef VMNS if (pInfo->flags & RHINE_FLAGS_VMNS_COMMITTED) { PVMNS_DRV_PRIVATE pvmns_priv = pInfo->vmns_priv; if ((pInfo->flags & RHINE_FLAGS_VMNS_COMMITTED) && pvmns_priv->notify) { if (pInfo->mii_status & RHINE_LINK_FAIL) pvmns_priv->notify(pInfo->dev->name, VMNS_EVENT_LINK_FAIL); else pvmns_priv->notify(pInfo->dev->name, VMNS_EVENT_LINK_UP); } }#endif }; if (status & ISR_TDWBRAI) { RHINE_PRT(MSG_LEVEL_VERBOSE, KERN_INFO "%s: Tx descriptor status write back race occurred.\n", pInfo->dev->name); rhine_tx_srv_drop_all(pInfo); } if (status & ISR_BE) { RHINE_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: Hardware fatal error.\n", pInfo->dev->name); rhine_shutdown(pInfo); } if (status & ~(ISR_BE|ISR_TDWBRAI|ISR_SRCI)) { RHINE_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: status %hx unhandled\n", pInfo->dev->name, status); }}static void rhine_free_tx_buf(PRHINE_INFO pInfo, PTX_DESC pDesc) { PRHINE_TD_INFO pTDInfo=pDesc->pInfo; struct sk_buff* skb=pTDInfo->skb; if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) { #ifdef RHINE_ZERO_COPY_SUPPORT pci_unmap_single(pInfo->pcid,pTDInfo->skb_dma, pDesc->tdesc1.f15BufLen,PCI_DMA_TODEVICE);#else pci_unmap_single(pInfo->pcid,pTDInfo->skb_dma,skb->len, PCI_DMA_TODEVICE);#endif } dev_kfree_skb_irq(skb); pTDInfo->skb_dma=0; pTDInfo->skb=0;}static int rhine_open(struct net_device *dev) { PRHINE_INFO pInfo=(PRHINE_INFO) dev->priv; int i; #ifdef VMNS if (pInfo->flags & RHINE_FLAGS_OPENED) return -EBUSY;#endif i=request_irq(pInfo->pcid->irq, &rhine_intr, SA_SHIRQ, dev->name, dev); if (i) return i; pInfo->rx_buf_sz=(dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32); if (!rhine_init_rings(pInfo)) { return -ENOMEM; } rhine_init_rd_ring(pInfo); rhine_init_td_ring(pInfo); rhine_init_registers(pInfo); rhine_enable_int(pInfo); netif_start_queue(dev); pInfo->flags |=RHINE_FLAGS_OPENED; MOD_INC_USE_COUNT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -