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

📄 dm9xs.c

📁 dm9k controller linux driver
💻 C
📖 第 1 页 / 共 4 页
字号:
	unregister_netdev(dev);
	kfree(dev);
err_out:
	return -ENODEV;
}


static void __exit dmfe_remove_one (struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct dmfe_board_info *db = dev->priv;

	DMFE_DBUG(0, "dmfe_remove_one()", 0);
	
 	if (dev) {
		pci_free_consistent(db->net_dev, sizeof(struct tx_desc) * 
					DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
 					db->desc_pool_dma_ptr);
		pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
					db->buf_pool_ptr, db->buf_pool_dma_ptr);
		unregister_netdev(dev);
		release_region(dev->base_addr, 
				CHK_IO_SIZE(pdev, db->chip_revision));
		kfree(dev);	/* free board information */
		pci_set_drvdata(pdev, NULL);
	}

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


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

static int dmfe_open(struct DEVICE *dev)
{
	int ret;
	struct dmfe_board_info *db = dev->priv;

	DMFE_DBUG(0, "dmfe_open", 0);

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

	/* 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;

	/* CR6 operation mode decision */
	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) || 
		(db->chip_revision >= 0x02000030) ) {
    		db->cr6_data |= DMFE_TXTH_256;
		db->cr0_data = CR0_DEFAULT;
		db->dm910x_chk_mode=4;		/* Enter the normal mode */
 	} else {
		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
		db->cr0_data = 0;
		db->dm910x_chk_mode = 1;	/* Enter the check mode */
	} 

	/* Initilize DM910X board */
	dmfe_init_dm910x(dev);
 
	/* Active System Interface */
	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);

	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;
	u32 ioaddr = db->ioaddr;

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

	/* Reset DM910x MAC controller */
	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
	udelay(100);
	outl(db->cr0_data, ioaddr + DCR0);
	DELAY_5US;

	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
	db->phy_addr = 1;
 
	/* Parser SROM and media mode */
	dmfe_parse_srom(db);
	db->media_mode = dmfe_media_mode;

	/* RESET Phyxcer Chip by GPR port bit 7 */
	outl(0x180, ioaddr + DCR12);		/* Let bit 7 output port */
	if (db->chip_id == PCI_DM9009_ID) {
		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */
		mdelay(300);			/* Delay 300 ms */
	}
	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */

	/* Process Phyxcer Media Mode */
	if ( !(db->media_mode & 0x10) )	/* Force 1M 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);

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

	/* Send setup frame */
	if (db->chip_id == PCI_DM9132_ID)
		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
	else
		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 tx_desc *txptr;

	DMFE_DBUG(0, "dmfe_start_xmit", 0);

	/* Resource flag check */
	netif_stop_queue(dev);

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

	/* No Tx resource check, it never happen nromally */
	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
		printk(KERN_ERR "<DM9XS>: No Tx resource %d\n", db->tx_queue_cnt);
		return 1;
	}

	/* Disable NIC interrupt */ 
	outl(0, dev->base_addr + DCR7);
	spin_lock_irq(&db->lock);

	/* transmit this packet */
	txptr = db->tx_insert_ptr;
	memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);

	/* Point to next transmit free descriptor */
	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;

	/* 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 */
	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_irq(&db->lock);
	outl(db->cr7_data, 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;
	u32 ioaddr = dev->base_addr; 

	DMFE_DBUG(0, "dmfe_stop", 0);

	/* disable system */
	netif_stop_queue(dev);

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

	/* Reset & stop DM910X board */
	outl(DM910X_RESET, ioaddr + DCR0);
	DELAY_5US;
	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("<DM9XS>: 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 void 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;
	u32 ioaddr = dev->base_addr;

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

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

	/* Got DM910X status */
	db->cr5_data = inl(ioaddr + DCR5);
	outl(db->cr5_data, ioaddr + DCR5);
	if ( !(db->cr5_data & 0xc1) )
		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 */
		outl(0, ioaddr + DCR7);	/* disable all interrupt */
		return;
	}

	 /* Received the coming packet */
	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
		dmfe_rx_packet(dev, db);

	/* reallocated rx descriptor buffer */
	if (db->rx_avail_cnt<RX_DESC_CNT)
		allocated_rx_buffer(db);

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

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

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


/*
 *	Free TX resource after TX complete
 */

static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
{
	struct tx_desc *txptr;
	u32 ioaddr = dev->base_addr; 

	txptr = db->tx_remove_ptr;
	while(db->tx_packet_cnt) {
		/* printk("<DM9XS>: tdes0=%x\n", txptr->tdes0); */
		if (txptr->tdes0 & 0x80000000)
			break;

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

		/* Transmit statistic counter */
		if ( txptr->tdes0 != 0x7fffffff ) {
			/* printk("<DM9XS>: tdes0=%x\n", txptr->tdes0); */
			db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
			db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
			if (txptr->tdes0 & TDES0_ERR_MASK) {
				db->stats.tx_errors++;
	
				if (txptr->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 (txptr->tdes0 & 0x0100)
					db->tx_excessive_collision++;
				if (txptr->tdes0 & 0x0200) 
					db->tx_late_collision++;
				if (txptr->tdes0 & 0x0400) 
					db->tx_no_carrier++;
				if (txptr->tdes0 & 0x0800) 
					db->tx_loss_carrier++;
				if (txptr->tdes0 & 0x4000) 
					db->tx_jabber_timeout++;
			}
		}

    		txptr = (struct tx_desc *) txptr->next_tx_desc;
	}/* End of while */
 
	/* Update TX remove pointer to next */
	db->tx_remove_ptr = (struct tx_desc *) 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 */
	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;
	int rxlen;

	rxptr = db->rx_ready_ptr;

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

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

		if ( (rxptr->rdes0 & 0x300) != 0x300) {
			/* A packet without First/Last flag */
			/* reused this SKB */
			DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
			dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
		} else {
			/* A packet with First/Last flag */
			rxlen = ( (rxptr->rdes0 >> 16) & 0x3fff) - 4;

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

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

				/* Received Packet CRC check need or not */
				if ( (db->dm910x_chk_mode & 1) && 
					(cal_CRC(skb->tail, rxlen, 1) != 
					(*(unsigned long *) (skb->tail+rxlen) )
					) ) {
					/* Found a error received packet */
					dmfe_reused_skb(db, (struct sk_buff *) 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, allocated a rxlen SKB */
						skb->dev = dev;
						skb_reserve(skb, 2); /* 16byte align */
						memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen);
						dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
					} else {
						skb->dev = dev;
						skb_put(skb, rxlen);
					}
					skb->protocol = eth_type_trans(skb, dev);
					netif_rx(skb);
					dev->last_rx = jiffies;
					db->stats.rx_packets++;
					db->stats.rx_bytes += rxlen;
				}
			} else {
				/* Reuse SKB buffer when the packet is error */
				DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
				dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
			}
		}

		rxptr = (struct rx_desc *) rxptr->next_rx_desc;
	}

	db->rx_ready_ptr = rxptr;
}


/*
 *	Get statistics from driver.
 */

static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
{
	struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;

	DMFE_DBUG(0, "dmfe_get_stats", 0);
	return &db->stats;
}


/*
 * Set DM910X multicast address
 */

static void dmfe_set_filter_mode(struct DEVICE * dev)
{
	struct dmfe_board_info *db = dev->priv;

	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);

	if (dev->flags & IFF_PROMISC) {
		DMFE_DBUG(0, "Enable PROM Mode", 0);
		db->cr6_data |= CR6_PM | CR6_PBF;
		update_cr6(db->cr6_data, db->ioaddr);
		return;
	}

	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
		db->cr6_data &= ~(CR6_PM | CR6_PBF);
		db->cr6_data |= CR6_PAM;
		return;
	}

⌨️ 快捷键说明

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