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 + -
显示快捷键?