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

📄 3c359.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *   3c359.c (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved * *  Linux driver for 3Com 3c359 Tokenlink Velocity XL PCI NIC * *  Base Driver Olympic: *	Written 1999 Peter De Schrijver & Mike Phillips * *  This software may be used and distributed according to the terms *  of the GNU General Public License, incorporated herein by reference. *  *  7/17/00 - Clean up, version number 0.9.0. Ready to release to the world. * *  2/16/01 - Port up to kernel 2.4.2 ready for submission into the kernel. *  3/05/01 - Last clean up stuff before submission. *  2/15/01 - Finally, update to new pci api.  * *  To Do: *//*  *	Technical Card Details * *  All access to data is done with 16/8 bit transfers.  The transfer *  method really sucks. You can only read or write one location at a time. * *  Also, the microcode for the card must be uploaded if the card does not have *  the flashrom on board.  This is a 28K bloat in the driver when compiled *  as a module. * *  Rx is very simple, status into a ring of descriptors, dma data transfer, *  interrupts to tell us when a packet is received. * *  Tx is a little more interesting. Similar scenario, descriptor and dma data *  transfers, but we don't have to interrupt the card to tell it another packet *  is ready for transmission, we are just doing simple memory writes, not io or mmio *  writes.  The card can be set up to simply poll on the next *  descriptor pointer and when this value is non-zero will automatically download *  the next packet.  The card then interrupts us when the packet is done. * */#define XL_DEBUG 0#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/proc_fs.h>#include <linux/ptrace.h>#include <linux/skbuff.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/trdevice.h>#include <linux/stddef.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/bitops.h>#include <net/checksum.h>#include <asm/io.h>#include <asm/system.h>#include "3c359.h"static char version[] __devinitdata  = "3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ;/* Module paramters *//* Ring Speed 0,4,16  * 0 = Autosense    * 4,16 = Selected speed only, no autosense * This allows the card to be the first on the ring * and become the active monitor. * * WARNING: Some hubs will allow you to insert * at the wrong speed. *  * The adapter will _not_ fail to open if there are no * active monitors on the ring, it will simply open up in  * its last known ringspeed if no ringspeed is specified. */static int ringspeed[XL_MAX_ADAPTERS] = {0,} ;module_param_array(ringspeed, int, NULL, 0);MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; /* Packet buffer size */static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; module_param_array(pkt_buf_sz, int, NULL, 0) ;MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; /* Message Level */static int message_level[XL_MAX_ADAPTERS] = {0,} ; module_param_array(message_level, int, NULL, 0) ;MODULE_PARM_DESC(message_level, "3c359: Level of reported messages \n") ; /*  *	This is a real nasty way of doing this, but otherwise you *	will be stuck with 1555 lines of hex #'s in the code. */#include "3c359_microcode.h" static struct pci_device_id xl_pci_tbl[] ={	{PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, },	{ }			/* terminate list */};MODULE_DEVICE_TABLE(pci,xl_pci_tbl) ; static int xl_init(struct net_device *dev);static int xl_open(struct net_device *dev);static int xl_open_hw(struct net_device *dev) ;  static int xl_hw_reset(struct net_device *dev); static int xl_xmit(struct sk_buff *skb, struct net_device *dev);static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev);static void xl_set_rx_mode(struct net_device *dev);static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct net_device_stats * xl_get_stats(struct net_device *dev);static int xl_set_mac_address(struct net_device *dev, void *addr) ; static void xl_arb_cmd(struct net_device *dev);static void xl_asb_cmd(struct net_device *dev) ; static void xl_srb_cmd(struct net_device *dev, int srb_cmd) ; static void xl_wait_misr_flags(struct net_device *dev) ; static int xl_change_mtu(struct net_device *dev, int mtu);static void xl_srb_bh(struct net_device *dev) ; static void xl_asb_bh(struct net_device *dev) ; static void xl_reset(struct net_device *dev) ;  static void xl_freemem(struct net_device *dev) ;  /* EEProm Access Functions */static u16  xl_ee_read(struct net_device *dev, int ee_addr) ; static void  xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) ; /* Debugging functions */#if XL_DEBUGstatic void print_tx_state(struct net_device *dev) ; static void print_rx_state(struct net_device *dev) ; static void print_tx_state(struct net_device *dev){	struct xl_private *xl_priv = (struct xl_private *)dev->priv ; 	struct xl_tx_desc *txd ; 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 	int i ; 	printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d \n",xl_priv->tx_ring_head, 		xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; 	printk("Ring    , Address ,   FSH  , DnNextPtr, Buffer, Buffer_Len \n"); 	for (i = 0; i < 16; i++) {		txd = &(xl_priv->xl_tx_ring[i]) ; 		printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(txd), 			txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; 	}	printk("DNLISTPTR = %04x \n", readl(xl_mmio + MMIO_DNLISTPTR) ); 		printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); 	printk("Queue status = %0x \n",netif_running(dev) ) ; }static void print_rx_state(struct net_device *dev){	struct xl_private *xl_priv = (struct xl_private *)dev->priv ; 	struct xl_rx_desc *rxd ; 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 	int i ; 	printk("rx_ring_tail: %d \n", xl_priv->rx_ring_tail) ; 	printk("Ring    , Address ,   FrameState  , UPNextPtr, FragAddr, Frag_Len \n"); 	for (i = 0; i < 16; i++) { 		/* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */		rxd = &(xl_priv->xl_rx_ring[i]) ; 		printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(rxd), 			rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; 	}	printk("UPLISTPTR = %04x \n", readl(xl_mmio + MMIO_UPLISTPTR) ); 		printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); 	printk("Queue status = %0x \n",netif_running(dev) ) ;} #endif/* *	Read values from the on-board EEProm.  This looks very strange *	but you have to wait for the EEProm to get/set the value before  *	passing/getting the next value from the nic. As with all requests *	on this nic it has to be done in two stages, a) tell the nic which *	memory address you want to access and b) pass/get the value from the nic. *	With the EEProm, you have to wait before and inbetween access a) and b). *	As this is only read at initialization time and the wait period is very  *	small we shouldn't have to worry about scheduling issues. */static u16 xl_ee_read(struct net_device *dev, int ee_addr){     	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 	/* Wait for EEProm to not be busy */	writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ;	/* Tell EEProm what we want to do and where */	writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; 	/* Wait for EEProm to not be busy */	writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; 		/* Tell EEProm what we want to do and where */	writel(IO_WORD_WRITE | EECONTROL , xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; 	/* Finally read the value from the EEProm */	writel(IO_WORD_READ | EEDATA , xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	return readw(xl_mmio + MMIO_MACDATA) ; }/*  *	Write values to the onboard eeprom. As with eeprom read you need to  *	set which location to write, wait, value to write, wait, with the  *	added twist of having to enable eeprom writes as well. */static void  xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) {    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 	/* Wait for EEProm to not be busy */	writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ;		/* Enable write/erase */	writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writew(EE_ENABLE_WRITE, xl_mmio + MMIO_MACDATA) ; 	/* Wait for EEProm to not be busy */	writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ;	/* Put the value we want to write into EEDATA */ 	writel(IO_WORD_WRITE | EEDATA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writew(ee_value, xl_mmio + MMIO_MACDATA) ;	/* Tell EEProm to write eevalue into ee_addr */	writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writew(EEWRITE + ee_addr, xl_mmio + MMIO_MACDATA) ; 	/* Wait for EEProm to not be busy, to ensure write gets done */	writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ;		return ; } static int __devinit xl_probe(struct pci_dev *pdev,			      const struct pci_device_id *ent) {	struct net_device *dev ; 	struct xl_private *xl_priv ; 	static int card_no = -1 ;	int i ; 	card_no++ ; 	if (pci_enable_device(pdev)) { 		return -ENODEV ; 	} 	pci_set_master(pdev);	if ((i = pci_request_regions(pdev,"3c359"))) { 		return i ; 	} ; 	/* 	 * Allowing init_trdev to allocate the dev->priv structure will align xl_private   	 * on a 32 bytes boundary which we need for the rx/tx descriptors	 */	dev = alloc_trdev(sizeof(struct xl_private)) ; 	if (!dev) { 		pci_release_regions(pdev) ; 		return -ENOMEM ; 	} 	xl_priv = dev->priv ; #if XL_DEBUG  	printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", 		pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ;  #endif 	dev->irq=pdev->irq;	dev->base_addr=pci_resource_start(pdev,0) ; 	xl_priv->xl_card_name = pci_name(pdev);	xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE);	xl_priv->pdev = pdev ; 			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )		xl_priv->pkt_buf_sz = PKT_BUF_SZ ; 	else		xl_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 	dev->mtu = xl_priv->pkt_buf_sz - TR_HLEN ; 	xl_priv->xl_ring_speed = ringspeed[card_no] ; 	xl_priv->xl_message_level = message_level[card_no] ; 	xl_priv->xl_functional_addr[0] = xl_priv->xl_functional_addr[1] = xl_priv->xl_functional_addr[2] = xl_priv->xl_functional_addr[3] = 0 ; 	xl_priv->xl_copy_all_options = 0 ; 			if((i = xl_init(dev))) {		iounmap(xl_priv->xl_mmio) ; 		free_netdev(dev) ; 		pci_release_regions(pdev) ; 		return i ; 	}					dev->open=&xl_open;	dev->hard_start_xmit=&xl_xmit;	dev->change_mtu=&xl_change_mtu;	dev->stop=&xl_close;	dev->do_ioctl=NULL;	dev->set_multicast_list=&xl_set_rx_mode;	dev->get_stats=&xl_get_stats ;	dev->set_mac_address=&xl_set_mac_address ; 	SET_MODULE_OWNER(dev); 	SET_NETDEV_DEV(dev, &pdev->dev);	pci_set_drvdata(pdev,dev) ; 	if ((i = register_netdev(dev))) { 		printk(KERN_ERR "3C359, register netdev failed\n") ;  		pci_set_drvdata(pdev,NULL) ; 		iounmap(xl_priv->xl_mmio) ; 		free_netdev(dev) ; 		pci_release_regions(pdev) ; 		return i ; 	}   	printk(KERN_INFO "3C359: %s registered as: %s\n",xl_priv->xl_card_name,dev->name) ; 	return 0; }static int __init xl_init(struct net_device *dev) {    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;	printk(KERN_INFO "%s \n", version);	printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",		xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq);	spin_lock_init(&xl_priv->xl_lock) ; 	return xl_hw_reset(dev) ; }/*  *	Hardware reset.  This needs to be a separate entity as we need to reset the card *	when we change the EEProm settings. */static int xl_hw_reset(struct net_device *dev) {     	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 	unsigned long t ; 	u16 i ;     	u16 result_16 ; 	u8 result_8 ;	u16 start ; 	int j ;	/*	 *  Reset the card.  If the card has got the microcode on board, we have          *  missed the initialization interrupt, so we must always do this.	 */	writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; 	/* 	 * Must wait for cmdInProgress bit (12) to clear before continuing with	 * card configuration.	 */	t=jiffies;	while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { 		schedule();				if(jiffies-t > 40*HZ) {			printk(KERN_ERR "%s: 3COM 3C359 Velocity XL  card not responding to global reset.\n", dev->name);			return -ENODEV;		}	}	/*	 *  Enable pmbar by setting bit in CPAttention	 */	writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ;	result_8 = readb(xl_mmio + MMIO_MACDATA) ; 	result_8 = result_8 | CPA_PMBARVIS ; 	writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; 	writeb(result_8, xl_mmio + MMIO_MACDATA) ; 		/*	 * Read cpHold bit in pmbar, if cleared we have got Flashrom on board. 	 * If not, we need to upload the microcode to the card	 */	writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD);  #if XL_DEBUG	printk(KERN_INFO "Read from PMBAR = %04x \n", readw(xl_mmio + MMIO_MACDATA)) ; #endif	if ( readw( (xl_mmio + MMIO_MACDATA))  & PMB_CPHOLD ) { 		/* Set PmBar, privateMemoryBase bits (8:2) to 0 */		writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD);  		result_16 = readw(xl_mmio + MMIO_MACDATA) ; 		result_16 = result_16 & ~((0x7F) << 2) ; 		writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; 		writew(result_16,xl_mmio + MMIO_MACDATA) ; 			/* Set CPAttention, memWrEn bit */		writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; 		result_8 = readb(xl_mmio + MMIO_MACDATA) ; 		result_8 = result_8 | CPA_MEMWREN  ; 		writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; 		writeb(result_8, xl_mmio + MMIO_MACDATA) ; 		/* 

⌨️ 快捷键说明

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