r1000_n.c

来自「LINUX下面的RTL8169的驱动原码」· C语言 代码 · 共 2,072 行 · 第 1/4 页

C
2,072
字号
	else{
		if (netif_queue_stopped (dev)){
			netif_wake_queue (dev);
		}
	}

	return 0;
}







//======================================================================================================
static void r1000_tx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr)
{
	unsigned long dirty_tx, tx_left=0;
	int entry = priv->cur_tx % NUM_TX_DESC;
    	int txloop_cnt = 0;

	assert (dev != NULL);
	assert (priv != NULL);
	assert (ioaddr != NULL);


	dirty_tx = priv->dirty_tx;
	tx_left = priv->cur_tx - dirty_tx;

	while( (tx_left > 0) && (txloop_cnt < max_interrupt_work) ){
		if( (le32_to_cpu(priv->TxDescArray[entry].status) & OWNbit) == 0 ){

#ifdef R1000_DYNAMIC_CONTROL
			r1000_callback_tx(&(priv->rt), 1, priv->Tx_skbuff[dirty_tx % NUM_TX_DESC]->len);
#endif //end #ifdef R1000_DYNAMIC_CONTROL

			dev_kfree_skb_irq( priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] );
			priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
			priv->stats.tx_packets++;
			dirty_tx++;
			tx_left--;
			entry++;
		}
		txloop_cnt ++;
	}

	if (priv->dirty_tx != dirty_tx) {
		priv->dirty_tx = dirty_tx;
		if (netif_queue_stopped (dev))
			netif_wake_queue (dev);
	}
}






//======================================================================================================
static void r1000_rx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr)
{
	struct pci_dev *pdev = priv->pci_dev;
	int cur_rx;
	int pkt_size = 0 ;
	int rxdesc_cnt = 0;
	int ret;
	struct sk_buff *n_skb = NULL;
	struct sk_buff *cur_skb;
	struct sk_buff *rx_skb;
	struct	RxDesc	*rxdesc;

	assert (dev != NULL);
	assert (priv != NULL);
	assert (ioaddr != NULL);


	cur_rx = priv->cur_rx;

	rxdesc = &priv->RxDescArray[cur_rx];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif

	while ( ((le32_to_cpu(rxdesc->status) & OWNbit)== 0) && (rxdesc_cnt < max_interrupt_work) ){

	    rxdesc_cnt++;

	    if( le32_to_cpu(rxdesc->status) & RxRES ){
			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
			priv->stats.rx_errors++;
			if ( le32_to_cpu(rxdesc->status) & (RxRWT|RxRUNT) )
				priv->stats.rx_length_errors++;
			if ( le32_to_cpu(rxdesc->status) & RxCRC)
				priv->stats.rx_crc_errors++;
	    }
	    else{
			pkt_size=(int)(le32_to_cpu(rxdesc->status) & 0x00001FFF)-4;

			if( pkt_size > priv->rx_pkt_len ){
				printk("%s: Error -- Rx packet size(%d) > mtu(%d)+14\n", dev->name, pkt_size, dev->mtu);
				pkt_size = priv->rx_pkt_len;
			}

			DBG_PRINT("%s: RX pkt_size = %d\n", __FUNCTION__, pkt_size);

			{// -----------------------------------------------------
				rx_skb = priv->Rx_skbuff[cur_rx];
				n_skb = R1000_ALLOC_RXSKB(MAX_RX_SKBDATA_SIZE);
				if( n_skb != NULL ) {
					skb_reserve (n_skb, 8);	// 16 byte align the IP fields. //

					// Indicate rx_skb
					if( rx_skb != NULL ){
						rx_skb->dev = dev;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
						pci_dma_sync_single(pdev, priv->rx_skbuff_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif

						skb_put ( rx_skb, pkt_size );
						rx_skb->protocol = eth_type_trans ( rx_skb, dev );
						ret = R1000_NETIF_RX (rx_skb);

//						dev->last_rx = jiffies;
						priv->stats.rx_bytes += pkt_size;
						priv->stats.rx_packets++;

#ifdef R1000_DYNAMIC_CONTROL
						r1000_callback_rx( &(priv->rt), 1, pkt_size);
#endif //end #ifdef R1000_DYNAMIC_CONTROL

					}//end if( rx_skb != NULL )

					priv->Rx_skbuff[cur_rx] = n_skb;
				}
				else{
					DBG_PRINT("%s: Allocate n_skb failed!\n",__FUNCTION__ );
					priv->Rx_skbuff[cur_rx] = rx_skb;
				}


				// Update rx descriptor
				if( cur_rx == (NUM_RX_DESC-1) ){
					priv->RxDescArray[cur_rx].status  = cpu_to_le32((OWNbit | EORbit) | (unsigned long)priv->hw_rx_pkt_len);
				}
				else{
					priv->RxDescArray[cur_rx].status  = cpu_to_le32(OWNbit | (unsigned long)priv->hw_rx_pkt_len);
				}

				cur_skb = priv->Rx_skbuff[cur_rx];

				if( cur_skb != NULL ){
					priv->rx_skbuff_dma_addr[cur_rx] = pci_map_single(pdev, cur_skb->data, MAX_RX_SKBDATA_SIZE, PCI_DMA_FROMDEVICE);
					rxdesc->buf_addr = cpu_to_le32(priv->rx_skbuff_dma_addr[cur_rx]);
				}
				else{
					DBG_PRINT("%s: %s() cur_skb == NULL\n", dev->name, __FUNCTION__);
				}

			}//------------------------------------------------------------

	    }// end of if( priv->RxDescArray[cur_rx].status & RxRES )

	    cur_rx = (cur_rx +1) % NUM_RX_DESC;
	    rxdesc = &priv->RxDescArray[cur_rx];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	    pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif

	}// end of while ( (priv->RxDescArray[cur_rx].status & 0x80000000)== 0)

	if( rxdesc_cnt >= max_interrupt_work ){
		DBG_PRINT("%s: Too much work at Rx interrupt.\n", dev->name);
	}

	priv->cur_rx = cur_rx;
}








//======================================================================================================
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
#else
static irqreturn_t r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
#endif
{
	struct net_device *dev = (struct net_device *) dev_instance;
	struct r1000_private *priv = dev->priv;
	int boguscnt = max_interrupt_work;
	unsigned long ioaddr = priv->ioaddr;
	int status = 0;
//	irqreturn_int interrupt_handled = IRQ_NONE;
	int interrupt_handled = IRQ_NONE;

	RTL_W16 ( IntrMask, 0x0000);

	do {
		status = RTL_R16(IntrStatus);

		if (status == 0xFFFF)
			break;


		RTL_W16( IntrStatus, status );


		if ( (status & r1000_intr_mask ) == 0 )
			break;
		else
			interrupt_handled = IRQ_HANDLED;


		// Rx interrupt
//		if (status & (RxOK | RxErr /* | LinkChg | RxOverflow | RxFIFOOver*/)){
			r1000_rx_interrupt (dev, priv, ioaddr);
//		}

		// Tx interrupt
//		if (status & (TxOK | TxErr)) {
			spin_lock (&priv->lock);
			r1000_tx_interrupt (dev, priv, ioaddr);
			spin_unlock (&priv->lock);
//		}
		if ((status & TxOK)&&(status & TxDescUnavail)) 
			RTL_W8(TxPoll,0x40);

		boguscnt--;
	} while (boguscnt > 0);

	if (boguscnt <= 0) {
		DBG_PRINT("%s: Too much work at interrupt!\n", dev->name);
		RTL_W16( IntrStatus, 0xffff);	// Clear all interrupt sources
	}

	RTL_W16 ( IntrMask, r1000_intr_mask);

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
	return interrupt_handled;
#endif
}







//======================================================================================================
static int r1000_close (struct net_device *dev)
{
	struct r1000_private *priv = dev->priv;
	unsigned long ioaddr = priv->ioaddr;
	int i;

	// -----------------------------------------
	r1000_delete_timer( &(priv->r1000_timer) );


	netif_stop_queue (dev);

	spin_lock_irq (&priv->lock);

	/* Stop the chip's Tx and Rx processes. */
	RTL_W8 ( ChipCmd, 0x00);

	/* Disable interrupts by clearing the interrupt mask. */
	RTL_W16 ( IntrMask, 0x0000);

	/* Update the error counts. */
	priv->stats.rx_missed_errors += RTL_R32(RxMissed);
	RTL_W32( RxMissed, 0);

	spin_unlock_irq (&priv->lock);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
	synchronize_irq ();
#else
	synchronize_irq (dev->irq);
#endif
	free_irq (dev->irq, dev);

	r1000_tx_clear (priv);
	
	//2004-05-11
	if(priv->txdesc_space != NULL){
		pci_free_consistent(
				priv->pci_dev,
				priv->sizeof_txdesc_space,
				priv->txdesc_space,
				priv->txdesc_phy_dma_addr
		);
		priv->txdesc_space = NULL;
	}

	if(priv->rxdesc_space != NULL){
		pci_free_consistent(
				priv->pci_dev,
				priv->sizeof_rxdesc_space,
				priv->rxdesc_space,
				priv->rxdesc_phy_dma_addr
		);
		priv->rxdesc_space = NULL;
	}

	priv->TxDescArray = NULL;
	priv->RxDescArray = NULL;

	{//-----------------------------------------------------------------------------
		for(i=0;i<NUM_RX_DESC;i++){
			if( priv->Rx_skbuff[i] != NULL ) {
				R1000_FREE_RXSKB ( priv->Rx_skbuff[i] );
			}
		}
	}//-----------------------------------------------------------------------------

	DBG_PRINT("%s: %s() alloc_rxskb_cnt = %d\n", dev->name, __FUNCTION__, alloc_rxskb_cnt );

	return 0;
}







//======================================================================================================
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc (int length, unsigned char *data)
{
	int crc = -1;

	while (--length >= 0) {
		unsigned char current_octet = *data++;
		int bit;
		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
	}

	return crc;
}








//======================================================================================================
static void r1000_set_rx_mode (struct net_device *dev)
{
	struct r1000_private *priv = dev->priv;
	unsigned long ioaddr = priv->ioaddr;
	unsigned long flags;
	u32 mc_filter[2];	/* Multicast hash filter */
	int i, rx_mode;
	u32 tmp=0;
	

	if (dev->flags & IFF_PROMISC) {
		/* Unconditionally log net taps. */
		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys;
		mc_filter[1] = mc_filter[0] = 0xffffffff;
	} else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) {
		/* Too many to filter perfectly -- accept all multicasts. */
		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
		mc_filter[1] = mc_filter[0] = 0xffffffff;
	} else {
		struct dev_mc_list *mclist;
		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
		mc_filter[1] = mc_filter[0] = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next)
		{
			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
		}			
#else
		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next)
		{
			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
			                                                                                                     
			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
			rx_mode |= AcceptMulticast;
		}
#endif		
	}

	spin_lock_irqsave (&priv->lock, flags);

	tmp = r1000_rx_config | rx_mode | (RTL_R32(RxConfig) & rtl_chip_info[priv->chipset].RxConfigMask);

	RTL_W32 ( RxConfig, tmp);
	if((priv->mcfg==MCFG_METHOD_11)||(priv->mcfg==MCFG_METHOD_12)||
	   (priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)||
	   (priv->mcfg==MCFG_METHOD_15)){
		RTL_W32 ( MAR0 + 0, 0xFFFFFFFF);
		RTL_W32 ( MAR0 + 4, 0xFFFFFFFF);
	}else{
		RTL_W32 ( MAR0 + 0, mc_filter[0]);
		RTL_W32 ( MAR0 + 4, mc_filter[1]);
	}

	spin_unlock_irqrestore (&priv->lock, flags);

}//end of r1000_set_rx_mode (struct net_device *dev)







//================================================================================
struct net_device_stats *r1000_get_stats(struct net_device *dev)

{
	struct r1000_private *priv = dev->priv;

    return &priv->stats;
}








//================================================================================
static struct pci_driver r1000_pci_driver = {
	name:		MODULENAME,
	id_table:	r1000_pci_tbl,
	probe:		r1000_init_one,
	remove:		r1000_remove_one,
	suspend:	NULL,
	resume:		NULL,
};





//======================================================================================================
static int __init r1000_init_module (void)
{
	return pci_module_init (&r1000_pci_driver);	// pci_register_driver (drv)
}




//======================================================================================================
static void __exit r1000_cleanup_module (void)
{
	pci_unregister_driver (&r1000_pci_driver);
}


#ifdef R1000_JUMBO_FRAME_SUPPORT
static int r1000_change_mtu(struct net_device *dev, int new_mtu)
{
	struct r1000_private *priv = dev->priv;
	unsigned long ioaddr = priv->ioaddr;

	if( new_mtu > MAX_JUMBO_FRAME_MTU ){
		printk("%s: Error -- new_mtu(%d) > MAX_JUMBO_FRAME_MTU(%d).\n", dev->name, new_mtu, MAX_JUMBO_FRAME_MTU);
		return -1;
	}

	dev->mtu = new_mtu;

	priv->curr_mtu_size = new_mtu;
	priv->tx_pkt_len = new_mtu + ETH_HDR_LEN;
	priv->rx_pkt_len = new_mtu + ETH_HDR_LEN;
	priv->hw_rx_pkt_len = priv->rx_pkt_len + 8;

	RTL_W8 ( Cfg9346, Cfg9346_Unlock);
	RTL_W16	( RxMaxSize, (unsigned short)priv->hw_rx_pkt_len );
	RTL_W8 ( Cfg9346, Cfg9346_Lock);

	DBG_PRINT("-------------------------- \n");
	DBG_PRINT("dev->mtu = %d \n", dev->mtu);
	DBG_PRINT("priv->curr_mtu_size = %d \n", priv->curr_mtu_size);
	DBG_PRINT("priv->rx_pkt_len = %d \n", priv->rx_pkt_len);
	DBG_PRINT("priv->tx_pkt_len = %d \n", priv->tx_pkt_len);
	DBG_PRINT("RTL_W16( RxMaxSize, %d )\n", priv->hw_rx_pkt_len);
	DBG_PRINT("-------------------------- \n");

	r1000_close (dev);
	r1000_open (dev);

	return 0;
}
#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT











//======================================================================================================
module_init(r1000_init_module);
module_exit(r1000_cleanup_module);

⌨️ 快捷键说明

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