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

📄 xircom_tulip_cb.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	const char *product_name;	struct tulip_rx_desc rx_ring[RX_RING_SIZE];	struct tulip_tx_desc tx_ring[TX_RING_SIZE];	/* The saved address of a sent-in-place packet/buffer, for skfree(). */	struct sk_buff* tx_skbuff[TX_RING_SIZE];#ifdef CARDBUS	/* The X3201-3 requires double word aligned tx bufs */	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];#endif	/* The addresses of receive-in-place skbuffs. */	struct sk_buff* rx_skbuff[RX_RING_SIZE];	char *rx_buffs;				/* Address of temporary Rx buffers. */	u8 setup_buf[96*sizeof(u16) + 7];	u16 *setup_frame;		/* Pseudo-Tx frame to init address table. */	int chip_id;	int revision;	struct net_device_stats stats;	struct timer_list timer;	/* Media selection timer. */	int interrupt;				/* In-interrupt flag. */	unsigned int cur_rx, cur_tx;		/* The next free ring entry */	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */	unsigned int tx_full:1;				/* The Tx queue is full. */	unsigned int full_duplex:1;			/* Full-duplex operation requested. */	unsigned int full_duplex_lock:1;	unsigned int fake_addr:1;			/* Multiport board faked address. */	unsigned int default_port:4;		/* Last dev->if_port value. */	unsigned int media2:4;				/* Secondary monitored media port. */	unsigned int medialock:1;			/* Don't sense media type. */	unsigned int mediasense:1;			/* Media sensing in progress. */	unsigned int nway:1, nwayset:1;		/* 21143 internal NWay. */	unsigned int open:1;	unsigned int csr0;					/* CSR0 setting. */	unsigned int csr6;					/* Current CSR6 control settings. */	unsigned char eeprom[EEPROM_SIZE];	/* Serial EEPROM contents. */	u16 to_advertise;					/* NWay capabilities advertised.  */	u16 lpar;							/* 21143 Link partner ability. */	u16 advertising[4];	signed char phys[4], mii_cnt;		/* MII device addresses. */	struct mediatable *mtable;	int cur_index;						/* Current media index. */	int saved_if_port;	struct pci_dev *pdev;	spinlock_t lock;	int pad0, pad1;						/* Used for 8-byte alignment */};static void parse_eeprom(struct net_device *dev);static int read_eeprom(long ioaddr, int location, int addr_len);static int mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static void select_media(struct net_device *dev, int startup);static void tulip_up(struct net_device *dev);static void tulip_down(struct net_device *dev);static int tulip_open(struct net_device *dev);static void tulip_timer(unsigned long data);static void t21142_start_nway(struct net_device *dev);static void tulip_tx_timeout(struct net_device *dev);static void tulip_init_ring(struct net_device *dev);static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);static int tulip_rx(struct net_device *dev);static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int tulip_close(struct net_device *dev);static struct net_device_stats *tulip_get_stats(struct net_device *dev);#ifdef HAVE_PRIVATE_IOCTLstatic int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);#endifstatic void set_rx_mode(struct net_device *dev);/* The Xircom cards are picky about when certain bits in CSR6 can be   manipulated.  Keith Owens <kaos@ocs.com.au>. */static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx){	const int strict_bits = 0x0060e202;    int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;    long flags;    save_flags(flags);    cli();    if (chip_idx != X3201_3) {		outl(newcsr6, ioaddr + CSR6);		restore_flags(flags);		return;    }    newcsr6 &= 0x726cfecb; /* mask out the reserved CSR6 bits that always */			   /* read 0 on the Xircom cards */    newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */    currcsr6 = inl(ioaddr + CSR6);    if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||	((currcsr6 & ~0x2002) == 0)) {		outl(newcsr6, ioaddr + CSR6);	/* safe */		restore_flags(flags);		return;    }    /* make sure the transmitter and receiver are stopped first */    currcsr6 &= ~0x2002;    while (1) {		csr5 = inl(ioaddr + CSR5);		if (csr5 == 0xffffffff)			break;  /* cannot read csr5, card removed? */		csr5_22_20 = csr5 & 0x700000;		csr5_19_17 = csr5 & 0x0e0000;		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&			(csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))			break;  /* both are stopped or suspended */		if (!--attempts) {			printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts,"				   "csr5=0x%08x\n", csr5);			outl(newcsr6, ioaddr + CSR6);  /* unsafe but do it anyway */			restore_flags(flags);			return;		}		outl(currcsr6, ioaddr + CSR6);		udelay(1);    }    /* now it is safe to change csr6 */    outl(newcsr6, ioaddr + CSR6);    restore_flags(flags);}static struct net_device *tulip_probe1(struct pci_dev *pdev,				       struct net_device *dev, long ioaddr, int irq,				       int chip_idx, int board_idx){	static int did_version;			/* Already printed version info. */	struct tulip_private *tp;	/* See note below on the multiport cards. */	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};	static int last_irq;	static int multiport_cnt;		/* For four-port boards w/one EEPROM */	u8 chip_rev;	int i;	unsigned short sum;	if (tulip_debug > 0  &&  did_version++ == 0)		printk(KERN_INFO "%s", version);	dev = init_etherdev(dev, 0);	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);	/* Bring the 21143 out of sleep mode.	   Caution: Snooze mode does not work with some boards! */	if (tulip_tbl[chip_idx].flags & HAS_ACPI)		pci_write_config_dword(pdev, 0x40, 0x00000000);	printk(KERN_INFO "%s: %s rev %d at %#3lx,",		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);	/* Stop the chip's Tx and Rx processes. */	outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx);	/* Clear the missed-packet counter. */	(volatile int)inl(ioaddr + CSR8);	if (chip_idx == DC21041) {		if (inl(ioaddr + CSR9) & 0x8000) {			printk(" 21040 compatible mode,");			chip_idx = DC21040;		} else {			printk(" 21041 mode,");		}	}	/* The station address ROM is read byte serially.  The register must	   be polled, waiting for the value to be read bit serially from the	   EEPROM.	   */	sum = 0;	if (chip_idx == DC21040) {		outl(0, ioaddr + CSR9);		/* Reset the pointer with a dummy write. */		for (i = 0; i < 6; i++) {			int value, boguscnt = 100000;			do				value = inl(ioaddr + CSR9);			while (value < 0  && --boguscnt > 0);			dev->dev_addr[i] = value;			sum += value & 0xff;		}	} else if (chip_idx == LC82C168) {		for (i = 0; i < 3; i++) {			int value, boguscnt = 100000;			outl(0x600 | i, ioaddr + 0x98);			do				value = inl(ioaddr + CSR9);			while (value < 0  && --boguscnt > 0);			put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);			sum += value & 0xffff;		}	} else if (chip_idx == COMET) {		/* No need to read the EEPROM. */		put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);		put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));		for (i = 0; i < 6; i ++)			sum += dev->dev_addr[i];	} else if (chip_idx == X3201_3) {		/* Xircom has its address stored in the CIS		 * we access it through the boot rom interface for now		 * this might not work, as the CIS is not parsed but I		 * (danilo) use the offset I found on my card's CIS !!!		 * 		 * Doug Ledford: I changed this routine around so that it		 * walks the CIS memory space, parsing the config items, and		 * finds the proper lan_node_id tuple and uses the data		 * stored there.		 */		unsigned char j, tuple, link, data_id, data_count;		outl(1<<12, ioaddr + CSR9); /* enable boot rom access */		for (i = 0x100; i < 0x1f7; i += link+2) {			outl(i, ioaddr + CSR10);			tuple = inl(ioaddr + CSR9) & 0xff;			outl(i + 1, ioaddr + CSR10);			link = inl(ioaddr + CSR9) & 0xff;			outl(i + 2, ioaddr + CSR10);			data_id = inl(ioaddr + CSR9) & 0xff;			outl(i + 3, ioaddr + CSR10);			data_count = inl(ioaddr + CSR9) & 0xff;			if ( (tuple == 0x22) &&				 (data_id == 0x04) && (data_count == 0x06) ) {				/*				 * This is it.  We have the data we want.				 */				for (j = 0; j < 6; j++) {					outl(i + j + 4, ioaddr + CSR10);					dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;				}				break;			} else if (link == 0) {				break;			}		}		sum = 1; // to make check below fail!	} else {	/* Must be a new chip, with a serial EEPROM interface. */		/* We read the whole EEPROM, and sort it out later.  DEC has a		   specification _Digital Semiconductor 21X4 Serial ROM Format_		   but early vendor boards just put the address in the first six		   EEPROM locations. */		unsigned char ee_data[EEPROM_SIZE];		int sa_offset = 0;		for (i = 0; i < sizeof(ee_data)/2; i++)			((u16 *)ee_data)[i] =				le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));		/* Detect the simple EEPROM format by the duplicated station addr. */		for (i = 0; i < 8; i ++)			if (ee_data[i] != ee_data[16+i])				sa_offset = 20;		if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {			sa_offset = 2;		/* Grrr, damn Matrox boards. */			multiport_cnt = 4;		}		for (i = 0; i < 6; i ++) {			dev->dev_addr[i] = ee_data[i + sa_offset];			sum += ee_data[i + sa_offset];		}	}	/* Lite-On boards have the address byte-swapped. */	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)		&&  dev->dev_addr[1] == 0x00)		for (i = 0; i < 6; i+=2) {			char tmp = dev->dev_addr[i];			dev->dev_addr[i] = dev->dev_addr[i+1];			dev->dev_addr[i+1] = tmp;		}	/* On the Zynx 315 Etherarray and other multiport boards only the	   first Tulip has an EEPROM.	   The addresses of the subsequent ports are derived from the first.	   Many PCI BIOSes also incorrectly report the IRQ line, so we correct	   that here as well. */	if (sum == 0  || sum == 6*0xff) {		printk(" EEPROM not present,");		for (i = 0; i < 5; i++)			dev->dev_addr[i] = last_phys_addr[i];		dev->dev_addr[i] = last_phys_addr[i] + 1;#if defined(__i386__)		/* Patch up x86 BIOS bug. */		if (last_irq)			irq = last_irq;#endif	}	for (i = 0; i < 6; i++)		printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);	printk(", IRQ %d.\n", irq);	last_irq = irq;	/* We do a request_region() only to register /proc/ioports info. */	/* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */	request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);	dev->base_addr = ioaddr;	dev->irq = irq;	/* Make certain the data structures are quadword aligned. */	tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);	memset(tp, 0, sizeof(*tp));	dev->priv = tp;	tp->lock = SPIN_LOCK_UNLOCKED;	tp->pdev = pdev;	tp->chip_id = chip_idx;	tp->revision = chip_rev;	tp->csr0 = csr0;	tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7);	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.	   And the ASIX must have a burst limit or horrible things happen. */	if ( (chip_idx == DC21143  &&  chip_rev == 65) ||	     (chip_idx == X3201_3) )		tp->csr0 &= ~0x01000000;	else if (chip_idx == AX88140)		tp->csr0 |= 0x2000;#ifdef TULIP_FULL_DUPLEX	tp->full_duplex = 1;	tp->full_duplex_lock = 1;#endif#ifdef TULIP_DEFAULT_MEDIA	tp->default_port = TULIP_DEFAULT_MEDIA;#endif#ifdef TULIP_NO_MEDIA_SWITCH	tp->medialock = 1;#endif	/* The lower four bits are the media type. */	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {		tp->default_port = options[board_idx] & 15;		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)			tp->full_duplex = 1;		if (mtu[board_idx] > 0)			dev->mtu = mtu[board_idx];	}	if (dev->mem_start)		tp->default_port = dev->mem_start;	if (tp->default_port) {		tp->medialock = 1;		if (media_cap[tp->default_port] & MediaAlwaysFD)			tp->full_duplex = 1;	}	if (tp->full_duplex)		tp->full_duplex_lock = 1;	/* This is logically part of probe1(), but too complex to write inline. */	if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE)		parse_eeprom(dev);	if (media_cap[tp->default_port] & MediaIsMII) {		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };		tp->to_advertise = media2advert[tp->default_port - 9];	} else		tp->to_advertise = 0x03e1;	if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) ||		(tp->mtable  &&  tp->mtable->has_mii) ||		( ! tp->mtable  &&  (tulip_tbl[chip_idx].flags & HAS_MII))) {		int phy, phy_idx;		if (tp->mtable  &&  tp->mtable->has_mii) {			for (i = 0; i < tp->mtable->leafcount; i++)				if (tp->mtable->mleaf[i].media == 11) {					tp->cur_index = i;					tp->saved_if_port = dev->if_port;					select_media(dev, 1);					dev->if_port = tp->saved_if_port;					break;				}		}		/* Find the connected MII xcvrs.		   Doing this in open() would allow detecting external xcvrs later,		   but takes much time. */		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);			 phy++) {			int mii_status = mdio_read(dev, phy, 1);			if ((mii_status & 0x8301) == 0x8001 ||				((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {				int mii_reg0 = mdio_read(dev, phy, 0);				int mii_advert = mdio_read(dev, phy, 4);				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;				tp->phys[phy_idx] = phy;				tp->advertising[phy_idx++] = reg4;				printk(KERN_INFO "%s:  MII transceiver #%d "					   "config %4.4x status %4.4x advertising %4.4x.\n",					   dev->name, phy, mii_reg0, mii_status, mii_advert);				/* Fixup for DLink with miswired PHY. */				if (mii_advert != reg4) {					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"						   " previously advertising %4.4x.\n",						   dev->name, reg4, phy, mii_advert);					mdio_write(dev, phy, 4, reg4);

⌨️ 快捷键说明

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