⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8139too.c

📁 2.4内核下8139芯片网卡驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* disable magic packet scanning, which is enabled		 * when PM is enabled above (Config1) */		RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));	}	RTL_W32 ( CPlusTxStartAddr, virt_to_bus(tp->TxDescArray) );	//C+ mode only	RTL_W32 ( CPlusRxStartAddr, virt_to_bus(tp->RxDescArray) );	//C+ mode only		/* Lock Config[01234] and BMCR register writes */	RTL_W8_F (Cfg9346, Cfg9346_Lock);	udelay (10);	RTL_W32_F (RxMissed, 0);	rtl8139_set_rx_mode (dev);	/* no early-rx interrupts */	RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);	/* Enable all known interrupts by setting the interrupt mask. */	RTL_W16_F (IntrMask, rtl8139_intr_mask);	netif_start_queue (dev);	DPRINTK ("EXIT\n");}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rtl8139CP_init_ring (struct net_device *dev){	struct rtl8139_private *tp = dev->priv;	int i;	DPRINTK ("ENTER\n");	//////////////////////////////////////////////////////////////////////////////	tp->CP_cur_rx = 0;	tp->CP_cur_tx = 0;	tp->CP_dirty_tx = 0;	memset(tp->TxDescArray, 0x0, NUM_CP_TX_DESC*sizeof(struct CPlusTxDesc));	memset(tp->RxDescArray, 0x0, NUM_CP_RX_DESC*sizeof(struct CPlusRxDesc));	for (i=0 ; i<NUM_CP_TX_DESC ; i++){		tp->Tx_skbuff[i]=NULL;	}	for (i=0; i <NUM_CP_RX_DESC; i++) {		if(i==(NUM_CP_RX_DESC-1))			tp->RxDescArray[i].status = 0xC0000000+CP_RX_BUF_SIZE;		else			tp->RxDescArray[i].status = 0x80000000+CP_RX_BUF_SIZE;		tp->RxBufferRing[i]= &(tp->RxBufferRings[i*CP_RX_BUF_SIZE]);		tp->RxDescArray[i].buf_addr=virt_to_bus(tp->RxBufferRing[i]);	}	//////////////////////////////////////////////////////////////////////////////	DPRINTK ("EXIT\n");}static void rtl8139_tx_clear (struct rtl8139_private *tp){	int i;	tp->cur_tx = 0;	tp->dirty_tx = 0;	/* Dump the unsent Tx packets. */	for (i = 0; i < NUM_TX_DESC; i++) {		struct ring_info *rp = &tp->tx_info[i];		if (rp->mapping != 0) {			pci_unmap_single (tp->pci_dev, rp->mapping,					  rp->skb->len, PCI_DMA_TODEVICE);			rp->mapping = 0;		}		if (rp->skb) {			dev_kfree_skb (rp->skb);			rp->skb = NULL;			tp->stats.tx_dropped++;		}	}}static void rtl8139CP_tx_clear (struct rtl8139_private *tp){	int i;	tp->CP_cur_tx=0;	for (i=0 ; i<NUM_CP_TX_DESC ; i++){		if ( tp->Tx_skbuff[i]!=NULL ) {			dev_kfree_skb (tp->Tx_skbuff[i]);			tp->Tx_skbuff[i] = NULL;			tp->stats.tx_dropped++;		}	}}static void rtl8139_tx_timeout (struct net_device *dev){	struct rtl8139_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	u8 tmp8;	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "		 "media %2.2x.\n", dev->name,		 RTL_R8 (ChipCmd),		 RTL_R16 (IntrStatus),		 RTL_R8 (MediaStatus));	/* disable Tx ASAP, if not already */	tmp8 = RTL_R8 (ChipCmd);	if (tmp8 & CmdTxEnb)		RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb);	/* Disable interrupts by clearing the interrupt mask. */	RTL_W16 (IntrMask, 0x0000);	/* Stop a shared interrupt from scavenging while we are. */	spin_lock_irq (&tp->lock);	rtl8139_tx_clear (tp);	spin_unlock_irq (&tp->lock);	/* ...and finally, reset everything */	rtl8139_hw_start (dev);		netif_wake_queue (dev);}static void rtl8139CP_tx_timeout (struct net_device *dev){	struct rtl8139_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	u8 tmp8;	printk ("%s: %s - Transmit timeout, status %2.2x %4.4x "		 "media %2.2x.\n", dev->name, __FUNCTION__,		 RTL_R8 (ChipCmd),		 RTL_R16 (IntrStatus),		 RTL_R8 (MediaStatus));	/* disable Tx ASAP, if not already */	tmp8 = RTL_R8 (ChipCmd);	if (tmp8 & CmdTxEnb)		RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb);	/* Disable interrupts by clearing the interrupt mask. */	RTL_W16 (IntrMask, 0x0000);	/* Stop a shared interrupt from scavenging while we are. */	spin_lock_irq (&tp->lock);	rtl8139CP_tx_clear (tp);	spin_unlock_irq (&tp->lock);	/* ...and finally, reset everything */	rtl8139CP_hw_start (dev);	netif_wake_queue (dev);}static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev){	struct rtl8139_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	int entry;	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % NUM_TX_DESC;	assert (tp->tx_info[entry].skb == NULL);	assert (tp->tx_info[entry].mapping == 0);	// ----------------------------------------------	// For skb->len < 60, padding payload with 0x20.	// ----------------------------------------------	if( skb->len < ETH_ZLEN ){							//if data_len < 60		if( (skb->data + ETH_ZLEN) <= skb->end ){				//	if data_buf is greater than 60 bytes			//printk("%s:memset( skb->data + %d, 0x20, %d )\n", __FUNCTION__, skb->len, ETH_ZLEN - skb->len);			memset( skb->data + skb->len, 0x20, (ETH_ZLEN - skb->len) );	//		padding data payload with 0x20			skb->len = (skb->len >= ETH_ZLEN) ? skb->len : ETH_ZLEN;	//		data_len = 60		}		else{			printk("%s:(skb->data+ETH_ZLEN) > skb->end\n",__FUNCTION__);	//	data_buf is less than or equal to 60 bytes		}																//		do nothing	}	tp->tx_info[entry].skb = skb;	if ((long) skb->data & 3) {	/* Must use alignment buffer. */		/* tp->tx_info[entry].mapping = 0; */		memcpy (tp->tx_buf[entry], skb->data, skb->len);		RTL_W32 (TxAddr0 + (entry * 4),			 tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));	} else {		tp->tx_info[entry].mapping =		    pci_map_single (tp->pci_dev, skb->data, skb->len,				    PCI_DMA_TODEVICE);		RTL_W32 (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping);	}	/* Note: the chip doesn't have auto-pad! */	RTL_W32 (TxStatus0 + (entry * sizeof (u32)),		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));	dev->trans_start = jiffies;	spin_lock_irq (&tp->lock);	tp->cur_tx++;	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)		netif_stop_queue (dev);	spin_unlock_irq (&tp->lock);	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",		 dev->name, skb->data, skb->len, entry);	return 0;}static int rtl8139CP_start_xmit (struct sk_buff *skb, struct net_device *dev){	struct rtl8139_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	int CP_entry;	struct ethernet_ii_header *eIIHeader;    	ip_v4_header   *IPPacket = NULL;	mb();	CP_entry = tp->CP_cur_tx % NUM_CP_TX_DESC;			//C+ mode only	spin_lock_irq (&tp->lock);	if( (tp->TxDescArray[CP_entry].status & 0x80000000)==0 ){		tp->Tx_skbuff[CP_entry] = skb;								//C+ mode only		tp->TxDescArray[CP_entry].buf_addr=virt_to_bus(skb->data);	//C+ mode only		if( CP_entry != (NUM_CP_TX_DESC-1) )		  tp->TxDescArray[CP_entry].status= 0xB0000000 |( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);	        else		  tp->TxDescArray[CP_entry].status= 0xF0000000 |( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);			//////////////////////////////////////////////////////////////////////////////		if( skb->ip_summed == CHECKSUM_HW ){			eIIHeader = (struct ethernet_ii_header *) skb->data;    			// Check for Ethernet_II IP encapsulation //    			if (eIIHeader->TypeLength == IP_PROTOCOL) {        			// We need to point the IPPacket past the Ethernet_II header. //        			IPPacket = (ip_v4_header *) ((uint8_t *) eIIHeader + sizeof(struct ethernet_ii_header));		        			if (IPPacket->ProtocolCarried == TCP_PROTOCOL) {					tp->TxDescArray[CP_entry].status |= (CPlusTxIPchecksumOffload | CPlusTxTCPchecksumOffload);        			}        			else if (IPPacket->ProtocolCarried == UDP_PROTOCOL) {					tp->TxDescArray[CP_entry].status |= (CPlusTxIPchecksumOffload | CPlusTxUDPchecksumOffload);        			}    			}		}//end of if( skb->ip_summed == CHECKSUM_HW )		//////////////////////////////////////////////////////////////////////////////		RTL_W8 (CPlusTxPoll, 0x40);		//set polling bit		dev->trans_start = jiffies;		tp->CP_cur_tx++;						//C+ mode only		if ( (tp->CP_cur_tx - NUM_CP_TX_DESC) == tp->CP_dirty_tx )			netif_stop_queue (dev);	}//end of if( (tp->TxDescArray[CP_entry].status & 0x80000000)==0 )	spin_unlock_irq (&tp->lock);	mb();//	if ( (tp->CP_cur_tx - NUM_CP_TX_DESC) == tp->CP_dirty_tx )//		netif_stop_queue (dev);	return 0;}static void rtl8139_tx_interrupt (struct net_device *dev,				  struct rtl8139_private *tp,				  void *ioaddr){	unsigned long dirty_tx, tx_left;	assert (dev != NULL);	assert (tp != NULL);	assert (ioaddr != NULL);	dirty_tx = tp->dirty_tx;	tx_left = tp->cur_tx - dirty_tx;	while (tx_left > 0) {		int entry = dirty_tx % NUM_TX_DESC;		int txstatus;		txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))			break;	/* It still hasn't been Txed */		/* Note: TxCarrierLost is always asserted at 100mbps. */		if (txstatus & (TxOutOfWindow | TxAborted)) {			/* There was an major error, log it. */			DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",				 dev->name, txstatus);			tp->stats.tx_errors++;			if (txstatus & TxAborted) {				tp->stats.tx_aborted_errors++;				RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));			}			if (txstatus & TxCarrierLost)				tp->stats.tx_carrier_errors++;			if (txstatus & TxOutOfWindow)				tp->stats.tx_window_errors++;#ifdef ETHER_STATS			if ((txstatus & 0x0f000000) == 0x0f000000)				tp->stats.collisions16++;#endif		} else {			if (txstatus & TxUnderrun) {				/* Add 64 to the Tx FIFO threshold. */				if (tp->tx_flag < 0x00300000)					tp->tx_flag += 0x00020000;				tp->stats.tx_fifo_errors++;			}			tp->stats.collisions += (txstatus >> 24) & 15;			tp->stats.tx_bytes += txstatus & 0x7ff;			tp->stats.tx_packets++;		}		/* Free the original skb. */		if (tp->tx_info[entry].mapping != 0) {			pci_unmap_single(tp->pci_dev,					 tp->tx_info[entry].mapping,					 tp->tx_info[entry].skb->len,					 PCI_DMA_TODEVICE);			tp->tx_info[entry].mapping = 0;		}		dev_kfree_skb_irq (tp->tx_info[entry].skb);		tp->tx_info[entry].skb = NULL;		dirty_tx++;		tx_left--;	}#ifndef RTL8139_NDEBUG	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",		        dev->name, dirty_tx, tp->cur_tx);		dirty_tx += NUM_TX_DESC;	}#endif /* RTL8139_NDEBUG */	/* only wake the queue if we did work, and the queue is stopped */	if (tp->dirty_tx != dirty_tx) {		tp->dirty_tx = dirty_tx;		if (netif_queue_stopped (dev))			netif_wake_queue (dev);	}}/* TODO: clean this up!  Rx reset need not be this intensive */static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,			    struct rtl8139_private *tp, void *ioaddr){	u8 tmp8;	int tmp_work = 1000;	DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",	         dev->name, rx_status);	if (rx_status & RxTooLong) {		DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",			 dev->name, rx_status);		/* A.C.: The chip hangs here. */	}	tp->stats.rx_errors++;	if (rx_status & (RxBadSymbol | RxBadAlign))		tp->stats.rx_frame_errors++;	if (rx_status & (RxRunt | RxTooLong))		tp->stats.rx_length_errors++;	if (rx_status & RxCRCErr)		tp->stats.rx_crc_errors++;	/* Reset the receiver, based on RealTek recommendation. (Bug?) */	tp->cur_rx = 0;	/* disable receive */	tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;	RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb);	/* A.C.: Reset the multicast list. */	rtl8139_set_rx_mode (dev);	/* XXX potentially temporary hack to	 * restart hung receiver */	while (--tmp_work > 0) {		tmp8 = RTL_R8 (ChipCmd);		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))			break;		RTL_W8_F (ChipCmd,			  (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);	}	/* G.S.: Re-enable receiver */	/* XXX temporary hack to work around receiver hang */	rtl8139_set_rx_mode (dev);	if (tmp_work <= 0)		printk (KERN_WARNING PFX "tx/rx enable wait too long\n");}/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the   field alignments and semantics. */static void rtl8139_rx_interrupt (struct net_device *dev,				  struct rtl8139_private *tp, void *ioaddr){	unsigned char *rx_ring;	u16 cur_rx;	assert (dev != NULL);	assert (tp != NULL);	assert (ioaddr != NULL);	rx_ring = tp->rx_ring;	cur_rx = tp->cur_rx;	DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,		 RTL_R16 (RxBufAddr),		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));	while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {		int ring_offset = cur_rx % RX_BUF_LEN;		u32 rx_status;		unsigned int rx_size;		unsigned int pkt_size;		struct sk_buff *skb;		/* read size+status of next frame from DMA ring buffer */		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));		rx_size = rx_status >> 16;		pkt_size = rx_size - 4;		DPRINTK ("%s:  rtl8139_rx() status %4.4x, size %4.4x,"			 " cur %4.4x.\n", dev->name, rx_status,			 rx_size, cur_rx);#if RTL8139_DEBUG > 2

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -