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

📄 ethernet driver for linux.txt

📁 Linux下的以太网驱动
💻 TXT
📖 第 1 页 / 共 4 页
字号:
//		kfree(dev);	/* free board information */
    free_netdev(dev); 
	}

	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
}


/*
 *	Open the interface.
 *	The interface is opened whenever "ifconfig" actives it.
 */

//#define request_irq myrequest_irq
//#define free_irq myfree_irq

static int dmfe_open(struct DEVICE *dev)
{
	int ret;
//	struct dmfe_board_info *db = dev->priv;
    struct dmfe_board_info *db = netdev_priv(dev);
	DMFE_DBUG(0, "dmfe_open", 0);

	/* system variable init */
	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
	db->tx_packet_cnt = 0;
	db->tx_queue_cnt = 0;
	db->rx_avail_cnt = 0;
	db->link_failed = 1;
	db->wait_reset = 0;

	db->first_in_callback = 0;
	db->NIC_capability = 0xf;	/* All capability*/
	db->PHY_reg4 = 0x1e0;

	db->dm910x_chk_mode=4;		/* Enter the normal mode */
	db->cr0_data = 0;
	db->cr6_data = 0x32002002;

	/* Initilize DM910X board */
    dmfe_init_dm910x(dev);
    
	/* Active System Interface */
// add by tfl	
	netif_wake_queue(dev);

	/* set and active a timer process */
	init_timer(&db->timer);
	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
	db->timer.data = (unsigned long)dev;
	db->timer.function = &dmfe_timer;
	add_timer(&db->timer);

	ret = request_irq(dev->irq, dmfe_interrupt, SA_SHIRQ, dev->name, dev);
	if (ret)
		return ret;

	return 0;
}


/*	Initilize DM910X board
 *	Reset DM910X board
 *	Initilize TX/Rx descriptor chain structure
 *	Send the set-up frame
 *	Enable Tx/Rx machine
 */

static void dmfe_init_dm910x(struct DEVICE *dev)
{
//	struct dmfe_board_info *db = dev->priv;
    struct dmfe_board_info *db = netdev_priv(dev);
	unsigned long ioaddr = db->ioaddr;
	int tmp;

	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);

	/* Reset DM910x MAC controller */
	tmp = inl(ioaddr + DCR0);
	outl(DM910X_RESET|tmp, ioaddr + DCR0);	/* RESET MAC */
	udelay(1000);
	outl(db->cr0_data, ioaddr + DCR0);
	udelay(5);

	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
	db->phy_addr = IRQ2PHYADDR(dev->irq);
	if (ioaddr == 0x1F005200) {
//		db->phy_addr = 5;
      db->phy_addr = 0x13;
	} else if (ioaddr == 0x1F005300) {
		db->phy_addr = 4;
	}

	/* Parser media mode */
	db->media_mode = dmfe_media_mode;

	dmfe_set_phyxcer(db);

	/* Media Mode Process */
	if ( !(db->media_mode & DMFE_AUTO) )
		db->op_mode = db->media_mode; 	/* Force Mode */

	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
	dmfe_descriptor_init(db, ioaddr);
	db->cr5_data = inl(ioaddr + DCR5);
	outl(db->cr5_data, ioaddr + DCR5);

	/* Init CR6 to program DM910x operation */
	update_cr6(db->cr6_data, ioaddr);

	send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */

	/* Init CR7, interrupt active bit */
	db->cr7_data = CR7_DEFAULT;
	outl(db->cr7_data, ioaddr + DCR7);

	/* Init CR15, Tx jabber and Rx watchdog timer */
	outl(db->cr15_data, ioaddr + DCR15);

	/* Enable DM910X Tx/Rx function */
	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
	update_cr6(db->cr6_data, ioaddr);
}


/*
 *	Hardware start transmission.
 *	Send a packet to media from the upper layer.
 */

static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
{
//	struct dmfe_board_info *db = dev->priv;
    struct dmfe_board_info *db = netdev_priv(dev);
	struct tx_desc *txptr;
	unsigned long flags;

	DMFE_DBUG(0, "dmfe_start_xmit", 0);
	/* Resource flag check */
// add by tfl  	
	netif_stop_queue(dev);

	/* Too large packet check */
	if (skb->len > MAX_PACKET_SIZE) {
		printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
		dev_kfree_skb(skb);
		return 0;
	}

	spin_lock_irqsave(&db->lock, flags);

	/* No Tx resource check, it never happen nromally */
	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
		spin_unlock_irqrestore(&db->lock, flags);
		printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);
		return 1;
	}

	/* Disable NIC interrupt */ //yyyyy
	//outl(0, dev->base_addr + DCR7);

	outl(db->cr7_data | 0x1, dev->base_addr + DCR7);
	/* transmit this packet */
	txptr = db->tx_insert_ptr;
	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
	//txptr->tdes1 = cpu_to_le32(0x61000000 | skb->len);

	/* Point to next transmit free descriptor */
	db->tx_insert_ptr = txptr->next_tx_desc;
#if 0
	printk("xmit use descriptor %d\n", db->tx_insert_ptr -db->first_tx_desc);
#endif
	/* Transmit Packet Process */
	//if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
		db->tx_packet_cnt++;			/* Ready to send */
		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
		dev->trans_start = jiffies;		/* saved time stamp */
	//} else {
	//	db->tx_queue_cnt++;			/* queue TX packet */
	//	outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
	//}

	/* Tx resource check */
// add by tfl	
	
	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
		netif_wake_queue(dev);

	/* free this SKB */
	dev_kfree_skb(skb);

	/* Restore CR7 to enable interrupt */
	spin_unlock_irqrestore(&db->lock, flags);
	//outl(db->cr7_data | 0x1, dev->base_addr + DCR7);

	return 0;
}


/*
 *	Stop the interface.
 *	The interface is stopped when it is brought.
 */

static int dmfe_stop(struct DEVICE *dev)
{
//	struct dmfe_board_info *db = dev->priv;
    struct dmfe_board_info *db = netdev_priv(dev);
	unsigned long ioaddr = dev->base_addr;

	DMFE_DBUG(0, "dmfe_stop", 0);

	/* disable system */
// add by tfl	
	netif_stop_queue(dev);

	/* deleted timer */
	del_timer_sync(&db->timer);

	/* Reset & stop DM910X board */
	outl(DM910X_RESET, ioaddr + DCR0);
	udelay(5);
	phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);

	/* free interrupt */
	free_irq(dev->irq, dev);

	/* free allocated rx buffer */
	dmfe_free_rxbuffer(db);

#if 0
	/* show statistic counter */
	printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
		db->tx_fifo_underrun, db->tx_excessive_collision,
		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
		db->reset_fatal, db->reset_TXtimeout);
#endif

	return 0;
}


/*
 *	DM9102 insterrupt handler
 *	receive the packet to upper layer, free the transmitted packet
 */

static int count = 0;
static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct DEVICE *dev = dev_id;
//	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
    struct dmfe_board_info *db = netdev_priv(dev);
	unsigned long ioaddr = dev->base_addr;
	unsigned long flags;

	DMFE_DBUG(0, "dmfe_interrupt()", 0);

	if (!dev) {
		DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
		return;
	}

	spin_lock_irqsave(&db->lock, flags);

	/* Got DM910X status */
	db->cr5_data = inl(ioaddr + DCR5);
//	printk("cr5 %x\n", db->cr5_data);
	outl(db->cr5_data, ioaddr + DCR5);
	if ( !(db->cr5_data & 0xc1) ) {
		spin_unlock_irqrestore(&db->lock, flags);
		return;
	}

	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
//	outl(0, ioaddr + DCR7);

	/* Check system status */
	if (db->cr5_data & 0x2000) {
		/* system bus error happen */
		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
		db->reset_fatal++;
		db->wait_reset = 1;	/* Need to RESET */
		spin_unlock_irqrestore(&db->lock, flags);
		return;
	}

	 /* Received the coming packet */
	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) {
		count++;
		if (count == 8000) {
			count = 0;
			int j = 0;
			int i;
		/*	do {
				if (t->rdes0 & 0x80000000) {
					j++;
				} 
				t = t->next_rx_desc;
			} while (t != db->first_rx_desc);
			printk("io base = 0x%X, rx_avail_cnt = 0x%x, scan_cnt = 0x%x\n", db->ioaddr, db->rx_avail_cnt, j);
                */
		}

		dmfe_rx_packet(dev, db);
	}

	/* reallocate rx descriptor buffer */
	if (db->rx_avail_cnt<RX_DESC_CNT)
		allocate_rx_buffer(db);

	/* Free the transmitted descriptor */
	if ( db->cr5_data & 0x01)
		dmfe_free_tx_pkt(dev, db);
	

#if 0
	/* Mode Check */
	if (db->dm910x_chk_mode & 0x2) {
		db->dm910x_chk_mode = 0x4;
		db->cr6_data |= 0x100;
		update_cr6(db->cr6_data, db->ioaddr);
	}
#endif

	/* Restore CR7 to enable interrupt mask */
//	outl(db->cr7_data, ioaddr + DCR7);

	spin_unlock_irqrestore(&db->lock, flags);
}


/*
 *	Free TX resource after TX complete
 */

static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
{
	struct tx_desc *txptr;
	unsigned long ioaddr = dev->base_addr;
	u32 tdes0;
//	netif_stop_queue(dev);
	txptr = db->tx_remove_ptr;
	while(db->tx_packet_cnt) {
		tdes0 = le32_to_cpu(txptr->tdes0);
		/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
		//printk("free tx_ptr %d tdes0 %x\n", txptr - db->first_tx_desc, tdes0);
		if (tdes0 & 0x80000000)
			break;

		/* A packet sent completed */
		db->tx_packet_cnt--;
		db->stats.tx_packets++;

		/* Transmit statistic counter */
		if ( tdes0 != 0x7fffffff ) {
			/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
			db->stats.collisions += (tdes0 >> 3) & 0xf;
			db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
			if (tdes0 & TDES0_ERR_MASK) {
				db->stats.tx_errors++;

				if (tdes0 & 0x0002) {	/* UnderRun */
					db->tx_fifo_underrun++;
					if ( !(db->cr6_data & CR6_SFT) ) {
						db->cr6_data = db->cr6_data | CR6_SFT;
						update_cr6(db->cr6_data, db->ioaddr);
					}
				}
				if (tdes0 & 0x0100)
					db->tx_excessive_collision++;
				if (tdes0 & 0x0200)
					db->tx_late_collision++;
				if (tdes0 & 0x0400)
					db->tx_no_carrier++;
				if (tdes0 & 0x0800)
					db->tx_loss_carrier++;
				if (tdes0 & 0x4000)
					db->tx_jabber_timeout++;
			}
		}

    		txptr = txptr->next_tx_desc;
	}/* End of while */

	/* Update TX remove pointer to next */
	db->tx_remove_ptr = txptr;

	/* Send the Tx packet in queue */
	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
		db->tx_packet_cnt++;			/* Ready to send */
		db->tx_queue_cnt--;
		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */
		dev->trans_start = jiffies;		/* saved time stamp */
	}

	/* Resource available check */
// add by tfl 	
	
	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
		netif_wake_queue(dev);	/* Active upper layer, send again */

}


/*
 *	Receive the come packet and pass to upper layer
 */

static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
{
	struct rx_desc *rxptr;
	struct sk_buff *skb = NULL;
	int rxlen;
	u32 rdes0;

	rxptr = db->rx_ready_ptr;

	while(db->rx_avail_cnt) {
		rdes0 = le32_to_cpu(rxptr->rdes0);
		if (rdes0 & 0x80000000)	/* packet owner check */
			break;

		db->rx_avail_cnt--;
		db->interval_rx_cnt++;

		pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
		if ( (rdes0 & 0x300) != 0x300) {
			/* A packet without First/Last flag */
			/* reuse this SKB */
			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
		} else {
			/* A packet with First/Last flag */
			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;

			/* error summary bit check */
			if (rdes0 & 0x8000) {
				/* This is a error packet */
				//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
				db->stats.rx_errors++;
				if (rdes0 & 1)
					db->stats.rx_fifo_errors++;
				if (rdes0 & 2)
					db->stats.rx_crc_errors++;
				if (rdes0 & 0x80)
					db->stats.rx_length_errors++;
			}

			if ( !(rdes0 & 0x8000) ||
				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
				skb = rxptr->rx_skb_ptr;

				/* Received Packet CRC check need or not */
				if ( (db->dm910x_chk_mode & 1) &&
					(cal_CRC(skb->tail, rxlen, 1) !=
					(*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
					/* Found a error received packet */
					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
					db->dm910x_chk_mode = 3;
				} else {
					/* Good packet, send to upper layer */
					/* Shorst packet used new SKB */
					if ( (rxlen < RX_COPY_SIZE) &&
						( (skb = dev_alloc_skb(rxlen + 2) )
						!= NULL) ) {
						/* size less than COPY_SIZE, allocate a rxlen SKB */
						skb->dev = dev;
						skb_reserve(skb, 2); /* 16byte align */
						memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
#if 0
						{
							int i;
							printk("Received :\n");	
							for(i=0; i<rxlen; i++){
								printk("%02x", (u8)rxptr->rx_skb_ptr->tail[i]);
								if((i+1)%16==0)
									printk("\n");
								else
									printk(" ");	
							}
							printk("\n");
						}
#endif
						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);

⌨️ 快捷键说明

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