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

📄 tulip.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned int csr6;					/* Current CSR6 control settings. */	unsigned char eeprom[128];			/* Serial EEPROM contents. */	u16 to_advertise;					/* NWay capabilities advertised.  */	u16 advertising[4];	signed char phys[4], mii_cnt;		/* MII device addresses. */	struct mediatable *mtable;	int cur_index;						/* Current media index. */	unsigned char pci_bus, pci_dev_fn;	int pad0, pad1;						/* Used for 8-byte alignment */};static struct device *tulip_probe1(int pci_bus, int pci_devfn,								   struct device *dev,								   int chip_id, int options);static void parse_eeprom(struct device *dev);static int read_eeprom(long ioaddr, int location);static int mdio_read(struct device *dev, int phy_id, int location);static void mdio_write(struct device *dev, int phy_id, int location, int value);static void select_media(struct device *dev, int startup);static int tulip_open(struct device *dev);static void tulip_timer(unsigned long data);static void tulip_tx_timeout(struct device *dev);static void tulip_init_ring(struct device *dev);static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);static int tulip_rx(struct device *dev);static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);static int tulip_close(struct device *dev);static struct enet_statistics *tulip_get_stats(struct device *dev);#ifdef HAVE_PRIVATE_IOCTLstatic int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);#endif#ifdef NEW_MULTICASTstatic void set_rx_mode(struct device *dev);#elsestatic void set_rx_mode(struct device *dev, int num_addrs, void *addrs);#endif/* A list of all installed Tulip devices, for removing the driver module. */static struct device *root_tulip_dev = NULL;/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,   but now receives directly into full-sized skbuffs that are allocated   at open() time.   This allows the probe routine to use the old driver initialization   interface. */int tulip_probe(struct device *dev){	int cards_found = 0;	static int pci_index = 0;	/* Static, for multiple probe calls. */	unsigned char pci_bus, pci_device_fn;	/* Ideally we would detect all network cards in slot order.  That would	   be best done a central PCI probe dispatch, which wouldn't work	   well with the current structure.  So instead we detect just the	   Tulip cards in slot order. */#if LINUX_VERSION_CODE >= 0x20155	if (! pci_present())		return -ENODEV;#else	if (! pcibios_present())		return -ENODEV;#endif	for (;pci_index < 0xff; pci_index++) {		u16 vendor, device, pci_command, new_command;		unsigned long pci_ioaddr = 0;		int chip_idx = 0;		if (pcibios_find_class			(PCI_CLASS_NETWORK_ETHERNET << 8,			 reverse_probe ? 0xfe - pci_index : pci_index,			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)			if (reverse_probe)				continue;			else				break;		pcibios_read_config_word(pci_bus, pci_device_fn,								 PCI_VENDOR_ID, &vendor);		pcibios_read_config_word(pci_bus, pci_device_fn,								 PCI_DEVICE_ID, &device);		for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)			if (vendor == tulip_tbl[chip_idx].vendor_id  &&				device == tulip_tbl[chip_idx].device_id)				break;		if (tulip_tbl[chip_idx].chip_name == 0) {			if (vendor == PCI_VENDOR_ID_DEC  ||				vendor == PCI_VENDOR_ID_LITEON)				printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"					   " %4.4x %4.4x"" detected: not configured.\n",					   vendor, device);			continue;		}#if LINUX_VERSION_CODE >= 0x20155		pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];#else		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,								  &pci_ioaddr);#endif		/* Remove I/O space marker in bit 0. */		pci_ioaddr &= ~3;		if (tulip_debug > 2)			printk(KERN_DEBUG "Found %s at I/O %#lx.\n",				   tulip_tbl[chip_idx].chip_name, pci_ioaddr);		if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))			continue;		pcibios_read_config_word(pci_bus, pci_device_fn,								 PCI_COMMAND, &pci_command);		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;		if (pci_command != new_command) {			printk(KERN_INFO "  The PCI BIOS has not enabled this"				   " device!  Updating PCI command %4.4x->%4.4x.\n",				   pci_command, new_command);			pcibios_write_config_word(pci_bus, pci_device_fn,									  PCI_COMMAND, new_command);		}		dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);		/* Get and check the bus-master and latency values. */		if (dev) {			unsigned char pci_latency;			pcibios_read_config_byte(pci_bus, pci_device_fn,									 PCI_LATENCY_TIMER, &pci_latency);			if (pci_latency < 10) {				printk(KERN_INFO "  PCI latency timer (CFLT) is "					   "unreasonably low at %d.  Setting to 64 clocks.\n",					   pci_latency);				pcibios_write_config_byte(pci_bus, pci_device_fn,										  PCI_LATENCY_TIMER, 64);			} else if (tulip_debug > 1)				printk(KERN_INFO "  PCI latency timer (CFLT) is %#x, "					   " PCI command is %4.4x.\n",					   pci_latency, new_command);			/* Bring the 21143 out power-down mode. */			if (device == PCI_DEVICE_ID_DEC_TULIP_21142)				pcibios_write_config_dword(pci_bus, pci_device_fn,										   0x40, 0x40000000);			dev = 0;			cards_found++;		}	}	return cards_found ? 0 : -ENODEV;}static struct device *tulip_probe1(int pci_bus, int pci_device_fn,								   struct device *dev,								   int chip_id, int board_idx){	static int did_version = 0;			/* Already printed version info. */	struct tulip_private *tp;	long ioaddr;	int irq;	/* See note below on the multiport cards. */	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};	static int last_irq = 0;	static int multiport_cnt = 0;		/* For four-port boards w/one EEPROM */	int i;	unsigned short sum;	if (tulip_debug > 0  &&  did_version++ == 0)		printk(KERN_INFO "%s", version);	dev = init_etherdev(dev, 0);#if LINUX_VERSION_CODE >= 0x20155	irq = pci_find_slot(pci_bus, pci_device_fn)->irq;	ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];#else	{		u8 pci_irq_line;		u32 pci_ioaddr;		pcibios_read_config_byte(pci_bus, pci_device_fn,								 PCI_INTERRUPT_LINE, &pci_irq_line);		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,								  &pci_ioaddr);		irq = pci_irq_line;		ioaddr = pci_ioaddr;	}#endif	/* Remove I/O space marker in bit 0. */	ioaddr &= ~3;	printk(KERN_INFO "%s: %s at %#3lx,",		   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);	/* Stop the chip's Tx and Rx processes. */	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);	/* Clear the missed-packet counter. */	(volatile int)inl(ioaddr + CSR8);	if (chip_id == DC21041) {		if (inl(ioaddr + CSR9) & 0x8000) {			printk(" 21040 compatible mode,");			chip_id = 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_id == 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_id == 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);			((u16*)dev->dev_addr)[i] = value;			sum += value & 0xffff;		}	} 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[128];		int sa_offset = 0;		for (i = 0; i < sizeof(ee_data)/2; i++)			((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);		/* 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[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__)		/* This BIOS bug doesn't exist on Alphas. */		irq = last_irq;#endif	}	for (i = 0; i < 6; i++)		printk(" %2.2x", 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_id].chip_name, but... */	request_region(ioaddr, TULIP_TOTAL_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->next_module = root_tulip_dev;	root_tulip_dev = dev;	tp->pci_bus = pci_bus;	tp->pci_dev_fn = pci_device_fn;	tp->chip_id = chip_id;#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_id].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 ((tp->mtable  &&  tp->mtable->has_mii) ||		( ! tp->mtable  &&  (tulip_tbl[tp->chip_id].flags & HAS_MII))) {		int phy, phy_idx;		/* 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 != 0xffff  &&  mii_status != 0x0000) {				int mii_reg0 = mdio_read(dev, phy, 0);				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 found at MDIO address "					   "%d, config %4.4x status %4.4x.\n",					   dev->name, phy, mii_reg0, mii_status);				if (1 || (media_cap[tp->default_port] & MediaIsMII)) {					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"						   " previously advertising %4.4x.\n",						   dev->name, reg4, phy, mdio_read(dev, phy, 4));					mdio_write(dev, phy, 4, reg4);				}				/* Enable autonegotiation: some boards default to off. */				mdio_write(dev, phy, 0, mii_reg0 |						   (tp->full_duplex ? 0x1100 : 0x1000) |						   (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));			}		}		tp->mii_cnt = phy_idx;		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",				   dev->name);			tp->phys[0] = 1;		}	}	/* The Tulip-specific entries in the device structure. */	dev->open = &tulip_open;	dev->hard_start_xmit = &tulip_start_xmit;	dev->stop = &tulip_close;	dev->get_stats = &tulip_get_stats;#ifdef HAVE_PRIVATE_IOCTL	dev->do_ioctl = &private_ioctl;#endif#ifdef HAVE_MULTICAST	dev->set_multicast_list = &set_rx_mode;#endif	/* Reset the xcvr interface and turn on heartbeat. */	switch (chip_id) {	case DC21041:		outl(0x00000000, ioaddr + CSR13);		outl(0xFFFFFFFF, ioaddr + CSR14);		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */

⌨️ 快捷键说明

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