ipg.c
来自「linux 内核源代码」· C语言 代码 · 共 2,341 行 · 第 1/5 页
C
2,341 行
for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { /* Reading the TXSTATUS register clears the * TX_COMPLETE interrupt. */ u32 txstatusdword = ipg_r32(TX_STATUS); IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword); /* Check for Transmit errors. Error bits only valid if * TX_COMPLETE bit in the TXSTATUS register is a 1. */ if (!(txstatusdword & IPG_TS_TX_COMPLETE)) break; /* If in 10Mbps mode, indicate transmit is ready. */ if (sp->tenmbpsmode) { netif_wake_queue(dev); } /* Transmit error, increment stat counters. */ if (txstatusdword & IPG_TS_TX_ERROR) { IPG_DEBUG_MSG("Transmit error.\n"); sp->stats.tx_errors++; } /* Late collision, re-enable transmitter. */ if (txstatusdword & IPG_TS_LATE_COLLISION) { IPG_DEBUG_MSG("Late collision on transmit.\n"); ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, MAC_CTRL); } /* Maximum collisions, re-enable transmitter. */ if (txstatusdword & IPG_TS_TX_MAX_COLL) { IPG_DEBUG_MSG("Maximum collisions on transmit.\n"); ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, MAC_CTRL); } /* Transmit underrun, reset and re-enable * transmitter. */ if (txstatusdword & IPG_TS_TX_UNDERRUN) { IPG_DEBUG_MSG("Transmitter underrun.\n"); sp->stats.tx_fifo_errors++; ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK | IPG_AC_FIFO); /* Re-configure after DMA reset. */ if (ipg_io_config(dev) < 0) { printk(KERN_INFO "%s: Error during re-configuration.\n", dev->name); } init_tfdlist(dev); ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, MAC_CTRL); } } ipg_nic_txfree(dev);}/* Provides statistical information about the IPG NIC. */static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; u16 temp1; u16 temp2; IPG_DEBUG_MSG("_nic_get_stats\n"); /* Check to see if the NIC has been initialized via nic_open, * before trying to read statistic registers. */ if (!test_bit(__LINK_STATE_START, &dev->state)) return &sp->stats; sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK); sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK); sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK); sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK); temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS); sp->stats.rx_errors += temp1; sp->stats.rx_missed_errors += temp1; temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) + ipg_r32(IPG_LATECOLLISIONS); temp2 = ipg_r16(IPG_CARRIERSENSEERRORS); sp->stats.collisions += temp1; sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS); sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) + ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2; sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK); /* detailed tx_errors */ sp->stats.tx_carrier_errors += temp2; /* detailed rx_errors */ sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) + ipg_r16(IPG_FRAMETOOLONGERRRORS); sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS); /* Unutilized IPG statistic registers. */ ipg_r32(IPG_MCSTFRAMESRCVDOK); return &sp->stats;}/* Restore used receive buffers. */static int ipg_nic_rxrestore(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); const unsigned int curr = sp->rx_current; unsigned int dirty = sp->rx_dirty; IPG_DEBUG_MSG("_nic_rxrestore\n"); for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) { unsigned int entry = dirty % IPG_RFDLIST_LENGTH; /* rx_copybreak may poke hole here and there. */ if (sp->RxBuff[entry]) continue; /* Generate a new receive buffer to replace the * current buffer (which will be released by the * Linux system). */ if (ipg_get_rxbuff(dev, entry) < 0) { IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n"); break; } /* Reset the RFS field. */ sp->rxd[entry].rfs = 0x0000000000000000; } sp->rx_dirty = dirty; return 0;}#ifdef JUMBO_FRAME/* use jumboindex and jumbosize to control jumbo frame status initial status is jumboindex=-1 and jumbosize=0 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump previous receiving and need to continue dumping the current one*/enum { NormalPacket, ErrorPacket};enum { Frame_NoStart_NoEnd = 0, Frame_WithStart = 1, Frame_WithEnd = 10, Frame_WithStart_WithEnd = 11};inline void ipg_nic_rx_free_skb(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; if (sp->RxBuff[entry]) { struct ipg_rx *rxfd = sp->rxd + entry; pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); sp->RxBuff[entry] = NULL; }}inline int ipg_nic_rx_check_frame_type(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); int type = Frame_NoStart_NoEnd; if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) type += Frame_WithStart; if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) type += Frame_WithEnd; return type;}inline int ipg_nic_rx_check_error(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; struct ipg_rx *rxfd = sp->rxd + entry; if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) { IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", (unsigned long) rxfd->rfs); /* Increment general receive error statistic. */ sp->stats.rx_errors++; /* Increment detailed receive error statistics. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); sp->stats.rx_fifo_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { IPG_DEBUG_MSG("RX runt occured.\n"); sp->stats.rx_length_errors++; } /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME, * error count handled by a IPG statistic register. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { IPG_DEBUG_MSG("RX alignment error occured.\n"); sp->stats.rx_frame_errors++; } /* Do nothing for IPG_RFS_RXFCSERROR, error count * handled by a IPG statistic register. */ /* Free the memory associated with the RX * buffer since it is erroneous and we will * not pass it to higher layer processes. */ if (sp->RxBuff[entry]) { pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); sp->RxBuff[entry] = NULL; } return ErrorPacket; } return NormalPacket;}static void ipg_nic_rx_with_start_and_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry){ struct SJumbo *jumbo = &sp->Jumbo; struct sk_buff *skb; int framelen; if (jumbo->FoundStart) { IPG_DEV_KFREE_SKB(jumbo->skb); jumbo->FoundStart = 0; jumbo->CurrentSize = 0; jumbo->skb = NULL; } // 1: found error, 0 no error if (ipg_nic_rx_check_error(dev) != NormalPacket) return; skb = sp->RxBuff[entry]; if (!skb) return; // accept this frame and send to upper layer framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; if (framelen > IPG_RXFRAG_SIZE) framelen = IPG_RXFRAG_SIZE; skb_put(skb, framelen); skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); dev->last_rx = jiffies; sp->RxBuff[entry] = NULL;}static void ipg_nic_rx_with_start(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry){ struct SJumbo *jumbo = &sp->Jumbo; struct pci_dev *pdev = sp->pdev; struct sk_buff *skb; // 1: found error, 0 no error if (ipg_nic_rx_check_error(dev) != NormalPacket) return; // accept this frame and send to upper layer skb = sp->RxBuff[entry]; if (!skb) return; if (jumbo->FoundStart) IPG_DEV_KFREE_SKB(jumbo->skb); pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb, IPG_RXFRAG_SIZE); jumbo->FoundStart = 1; jumbo->CurrentSize = IPG_RXFRAG_SIZE; jumbo->skb = skb; sp->RxBuff[entry] = NULL; dev->last_rx = jiffies;}static void ipg_nic_rx_with_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry){ struct SJumbo *jumbo = &sp->Jumbo; //1: found error, 0 no error if (ipg_nic_rx_check_error(dev) == NormalPacket) { struct sk_buff *skb = sp->RxBuff[entry]; if (!skb) return; if (jumbo->FoundStart) { int framelen, endframelen; framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; endframeLen = framelen - jumbo->CurrentSize; /* if (framelen > IPG_RXFRAG_SIZE) framelen=IPG_RXFRAG_SIZE; */ if (framelen > IPG_RXSUPPORT_SIZE) IPG_DEV_KFREE_SKB(jumbo->skb); else { memcpy(skb_put(jumbo->skb, endframeLen), skb->data, endframeLen); jumbo->skb->protocol = eth_type_trans(jumbo->skb, dev); jumbo->skb->ip_summed = CHECKSUM_NONE; netif_rx(jumbo->skb); } } dev->last_rx = jiffies; jumbo->FoundStart = 0; jumbo->CurrentSize = 0; jumbo->skb = NULL; ipg_nic_rx_free_skb(dev); } else { IPG_DEV_KFREE_SKB(jumbo->skb); jumbo->FoundStart = 0; jumbo->CurrentSize = 0; jumbo->skb = NULL; }}static void ipg_nic_rx_no_start_no_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry){ struct SJumbo *jumbo = &sp->Jumbo; //1: found error, 0 no error if (ipg_nic_rx_check_error(dev) == NormalPacket) { struct sk_buff *skb = sp->RxBuff[entry]; if (skb) { if (jumbo->FoundStart) { jumbo->CurrentSize += IPG_RXFRAG_SIZE; if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) { memcpy(skb_put(jumbo->skb, IPG_RXFRAG_SIZE), skb->data, IPG_RXFRAG_SIZE); } } dev->last_rx = jiffies; ipg_nic_rx_free_skb(dev); } } else { IPG_DEV_KFREE_SKB(jumbo->skb); jumbo->FoundStart = 0; jumbo->CurrentSize = 0; jumbo->skb = NULL; }}static int ipg_nic_rx(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); unsigned int curr = sp->rx_current; void __iomem *ioaddr = sp->ioaddr; unsigned int i; IPG_DEBUG_MSG("_nic_rx\n"); for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { unsigned int entry = curr % IPG_RFDLIST_LENGTH; struct ipg_rx *rxfd = sp->rxd + entry; if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE))) break; switch (ipg_nic_rx_check_frame_type(dev)) { case Frame_WithStart_WithEnd: ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry); break; case Frame_WithStart: ipg_nic_rx_with_start(dev, tp, rxfd, entry); break; case Frame_WithEnd: ipg_nic_rx_with_end(dev, tp, rxfd, entry); break; case Frame_NoStart_NoEnd: ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry); break; } } sp->rx_current = curr; if (i == IPG_MAXRFDPROCESS_COUNT) { /* There are more RFDs to process, however the * allocated amount of RFD processing time has * expired. Assert Interrupt Requested to make * sure we come back to process the remaining RFDs. */ ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); } ipg_nic_rxrestore(dev); return 0;}#elsestatic int ipg_nic_rx(struct net_device *dev){ /* Transfer received Ethernet frames to higher network layers. */ struct ipg_nic_private *sp = netdev_priv(dev); unsigned int curr = sp->rx_current; void __iomem *ioaddr = sp->ioaddr; struct ipg_rx *rxfd; unsigned int i; IPG_DEBUG_MSG("_nic_rx\n");#define __RFS_MASK \ cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND) for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { unsigned int entry = curr % IPG_RFDLIST_LENGTH; struct sk_buff *skb = sp->RxBuff[entry]; unsigned int framelen;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?