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

📄 dm9xs.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:


static int __init dmfe_init_one (struct pci_dev *pdev,

				 const struct pci_device_id *ent)

{

	unsigned long pci_iobase;

	u8 pci_irqline;

	struct dmfe_board_info *db;	/* board information structure */

	int i;

	struct net_device *dev;

	u32 dev_rev, pci_pmr;



	DMFE_DBUG(0, "dmfe_init_one()", 0);



	pci_iobase = pci_resource_start(pdev, 0);

	pci_irqline = pdev->irq;



	/* iobase check */

	if (pci_iobase == 0) {

		printk(KERN_ERR "<DM9XS>: I/O base is zero\n");

		goto err_out;

	}



#if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */



	/* Set Latency Timer 80h */

	/* FIXME: setting values > 32 breaks some SiS 559x stuff.

	   Need a PCI quirk.. */



	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);

#endif



	/* Read Chip revision */

	pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);



	/* Init network device */

	dev = init_etherdev(NULL, sizeof(*db));

	if (dev == NULL)

		goto err_out;

	SET_MODULE_OWNER(dev);



	/* IO range check */

	if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {

		printk(KERN_ERR "<DM9XS>: Allocated I/O size too small\n");

		goto err_out_netdev;

	}



	if (!request_region(pci_iobase, 

			    pci_resource_len (pdev, 0), 

			    dev->name)) {

		printk(KERN_ERR "<DM9XS>: I/O conflict : IO=%lx Range=%x\n",

		       pci_iobase, CHK_IO_SIZE(pdev, dev_rev));

		goto err_out_netdev;

	}



	/* Enable Master/IO access, Disable memory access */

	if (pci_enable_device(pdev))

		goto err_out_netdev;

	pci_set_master(pdev);



	/* Init system & device */

	db = dev->priv;



	/* Allocated Tx/Rx descriptor memory */

	db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);

	db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);



	db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr;

	db->first_tx_desc_dma = db->desc_pool_dma_ptr;

	db->buf_pool_start = db->buf_pool_ptr;

	db->buf_pool_dma_start = db->buf_pool_dma_ptr;

	

	pdev->driver_data = dev;



	db->chip_id = ent->driver_data;

	db->ioaddr = pci_iobase;

	db->chip_revision = dev_rev;



	db->net_dev = pdev;



	dev->base_addr = pci_iobase;

	dev->irq = pci_irqline;

	pci_set_drvdata(pdev, dev);

	dev->open = &dmfe_open;

	dev->hard_start_xmit = &dmfe_start_xmit;

	dev->stop = &dmfe_stop;

	dev->get_stats = &dmfe_get_stats;

	dev->set_multicast_list = &dmfe_set_filter_mode;

	dev->do_ioctl = &dmfe_do_ioctl;

	spin_lock_init(&db->lock);



	pci_read_config_dword(pdev, 0x50, &pci_pmr);

	pci_pmr &= 0x70000;

	if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) ) 

		db->chip_type = 1;	/* DM9102A E3 */

	else 

		db->chip_type = 0;



	/* read 64 word srom data */

	for (i = 0; i < 64; i++)

		((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i);



	/* Set Node address */

	for (i = 0; i < 6; i++)

		dev->dev_addr[i] = db->srom[20 + i];



	return 0;



err_out_netdev:

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

⌨️ 快捷键说明

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