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

📄 via-rhine.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);#ifdef VIA_USE_IO			pciaddr = pdev->base_address[0];#else			pciaddr = pdev->base_address[1];#endif			irq = pdev->irq;#else			u32 pci_memaddr;			u8 pci_irq_line;			pcibios_read_config_byte(pci_bus, pci_device_fn,									 PCI_INTERRUPT_LINE, &pci_irq_line);#ifdef VIA_USE_IO			pcibios_read_config_dword(pci_bus, pci_device_fn,									  PCI_BASE_ADDRESS_0, &pci_memaddr);			pciaddr = pci_memaddr;#else			pcibios_read_config_dword(pci_bus, pci_device_fn,									  PCI_BASE_ADDRESS_1, &pci_memaddr);			pciaddr = pci_memaddr;#endif			irq = pci_irq_line;#endif		}		if (debug > 2)			printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",				   pci_tbl[chip_idx].name, pciaddr, irq);		if (pci_tbl[chip_idx].flags & PCI_USES_IO) {			if (check_region(pciaddr, pci_tbl[chip_idx].io_size))				continue;			ioaddr = pciaddr & ~3;		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xf,										 pci_tbl[chip_idx].io_size)) == 0) {			printk(KERN_INFO "Failed to map PCI address %#lx.\n",				   pciaddr);			continue;		}		pcibios_read_config_word(pci_bus, pci_device_fn,								 PCI_COMMAND, &pci_command);		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);		if (pci_command != new_command) {			printk(KERN_INFO "  The PCI BIOS has not enabled the"				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",				   pci_bus, pci_device_fn, pci_command, new_command);			pcibios_write_config_word(pci_bus, pci_device_fn,									  PCI_COMMAND, new_command);		}		dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,									   irq, chip_idx, cards_found);		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {			u8 pci_latency;			pcibios_read_config_byte(pci_bus, pci_device_fn,									 PCI_LATENCY_TIMER, &pci_latency);			if (pci_latency < min_pci_latency) {				printk(KERN_INFO "  PCI latency timer (CFLT) is "					   "unreasonably low at %d.  Setting to %d clocks.\n",					   pci_latency, min_pci_latency);				pcibios_write_config_byte(pci_bus, pci_device_fn,										  PCI_LATENCY_TIMER, min_pci_latency);			}		}		dev = 0;		cards_found++;	}	return cards_found ? 0 : -ENODEV;}#ifndef MODULEint via_rhine_probe(struct device *dev){	return pci_etherdev_probe(dev, pci_tbl);}#endifstatic struct device *via_probe1(int pci_bus, int pci_devfn,								 struct device *dev, long ioaddr, int irq,								 int chip_id, int card_idx){	static int did_version = 0;		/* Already printed version info */	struct netdev_private *np;	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;	if (debug > 0 && did_version++ == 0)		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);	dev = init_etherdev(dev, 0);	printk(KERN_INFO "%s: %s at 0x%lx, ",		   dev->name, pci_tbl[chip_id].name, ioaddr);	/* Ideally we would be read the EEPROM but access may be locked. */	for (i = 0; i <6; i++)		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);	for (i = 0; i < 5; i++)			printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);#ifdef VIA_USE_IO	request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name);#endif	/* Reset the chip to erase previous misconfiguration. */	writew(CmdReset, ioaddr + ChipCmd);	dev->base_addr = ioaddr;	dev->irq = irq;	/* Make certain the descriptor lists are cache-aligned. */	np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);	memset(np, 0, sizeof(*np));	dev->priv = np;	np->next_module = root_net_dev;	root_net_dev = dev;	np->pci_bus = pci_bus;	np->pci_devfn = pci_devfn;	np->chip_id = chip_id;	if (dev->mem_start)		option = dev->mem_start;	/* The lower four bits are the media type. */	if (option > 0) {		if (option & 0x200)			np->full_duplex = 1;		np->default_port = option & 15;		if (np->default_port)			np->medialock = 1;	}	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)		np->full_duplex = 1;	if (np->full_duplex)		np->duplex_lock = 1;	/* The chip-specific entries in the device structure. */	dev->open = &netdev_open;	dev->hard_start_xmit = &start_tx;	dev->stop = &netdev_close;	dev->get_stats = &get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &mii_ioctl;	if (cap_tbl[np->chip_id].flags & CanHaveMII) {		int phy, phy_idx = 0;		np->phys[0] = 1;		/* Standard for this chip. */		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(dev, phy, 1);			if (mii_status != 0xffff  &&  mii_status != 0x0000) {				np->phys[phy_idx++] = phy;				np->advertising = mdio_read(dev, phy, 4);				printk(KERN_INFO "%s: MII PHY found at address %d, status "					   "0x%4.4x advertising %4.4x Link %4.4x.\n",					   dev->name, phy, mii_status, np->advertising,					   mdio_read(dev, phy, 5));			}		}		np->mii_cnt = phy_idx;	}	return dev;}/* Read and write over the MII Management Data I/O (MDIO) interface. */static int mdio_read(struct device *dev, int phy_id, int regnum){	long ioaddr = dev->base_addr;	int boguscnt = 1024;	/* Wait for a previous command to complete. */	while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)		;	writeb(0x00, ioaddr + MIICmd);	writeb(phy_id, ioaddr + MIIPhyAddr);	writeb(regnum, ioaddr + MIIRegAddr);	writeb(0x40, ioaddr + MIICmd);			/* Trigger read */	boguscnt = 1024;	while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0)		;	return readw(ioaddr + MIIData);}static void mdio_write(struct device *dev, int phy_id, int regnum, int value){	long ioaddr = dev->base_addr;	int boguscnt = 1024;	/* Wait for a previous command to complete. */	while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)		;	writeb(0x00, ioaddr + MIICmd);	writeb(phy_id, ioaddr + MIIPhyAddr);	writeb(regnum, ioaddr + MIIRegAddr);	writew(value, ioaddr + MIIData);	writeb(0x20, ioaddr + MIICmd);			/* Trigger write. */	return;}static int netdev_open(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	/* Reset the chip. */	writew(CmdReset, ioaddr + ChipCmd);	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))		return -EAGAIN;	if (debug > 1)		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",			   dev->name, dev->irq);	MOD_INC_USE_COUNT;	init_ring(dev);	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);	for (i = 0; i < 6; i++)		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);	/* Initialize other registers. */	writew(0x0006, ioaddr + PCIConfig);	/* Tune configuration??? */	/* Configure the FIFO thresholds. */	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */	np->tx_thresh = 0x20;	np->rx_thresh = 0x60;				/* Written in set_rx_mode(). */	if (dev->if_port == 0)		dev->if_port = np->default_port;	dev->tbusy = 0;	dev->interrupt = 0;	np->in_interrupt = 0;	set_rx_mode(dev);	dev->start = 1;	/* Enable interrupts by setting the interrupt mask. */	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,		   ioaddr + IntrEnable);	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;	writew(np->chip_cmd, ioaddr + ChipCmd);	check_duplex(dev);	if (debug > 2)		printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "			   "MII status: %4.4x.\n",			   dev->name, readw(ioaddr + ChipCmd),			   mdio_read(dev, np->phys[0], 1));	/* Set the timer to check for link beat. */	init_timer(&np->timer);	np->timer.expires = RUN_AT(1);	np->timer.data = (unsigned long)dev;	np->timer.function = &netdev_timer;				/* timer handler */	add_timer(&np->timer);	return 0;}static void check_duplex(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int mii_reg5 = mdio_read(dev, np->phys[0], 5);	int duplex;	if (np->duplex_lock  ||  mii_reg5 == 0xffff)		return;	duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;	if (np->full_duplex != duplex) {		np->full_duplex = duplex;		if (debug)			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"				   " partner capability of %4.4x.\n", dev->name,				   duplex ? "full" : "half", np->phys[0], mii_reg5);		if (duplex)			np->chip_cmd |= CmdFDuplex;		else			np->chip_cmd &= ~CmdFDuplex;		writew(np->chip_cmd, ioaddr + ChipCmd);	}}static void netdev_timer(unsigned long data){	struct device *dev = (struct device *)data;	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int next_tick = 10*HZ;	if (debug > 3) {		printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",			   dev->name, readw(ioaddr + IntrStatus));	}	check_duplex(dev);	np->timer.expires = RUN_AT(next_tick);	add_timer(&np->timer);}static void tx_timeout(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "		   "%4.4x, resetting...\n",		   dev->name, readw(ioaddr + IntrStatus),		   mdio_read(dev, np->phys[0], 1));  /* Perhaps we should reinitialize the hardware here. */  dev->if_port = 0;  /* Stop and restart the chip's Tx processes . */  /* Trigger an immediate transmit demand. */  dev->trans_start = jiffies;  np->stats.tx_errors++;  return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void init_ring(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int i;	np->tx_full = 0;	np->cur_rx = np->cur_tx = 0;	np->dirty_rx = np->dirty_tx = 0;	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);	np->rx_head_desc = &np->rx_ring[0];	for (i = 0; i < RX_RING_SIZE; i++) {		np->rx_ring[i].rx_status = 0;		np->rx_ring[i].rx_length = 0;		np->rx_ring[i].desc_length = np->rx_buf_sz;		np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);		np->rx_skbuff[i] = 0;	}	/* Mark the last entry as wrapping the ring. */	np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);	/* Fill in the Rx buffers. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);		np->rx_skbuff[i] = skb;		if (skb == NULL)			break;		skb->dev = dev;			/* Mark as being used by this device. */		np->rx_ring[i].addr = virt_to_bus(skb->tail);		np->rx_ring[i].rx_status = 0;		np->rx_ring[i].rx_length = DescOwn;	}	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);	for (i = 0; i < TX_RING_SIZE; i++) {		np->tx_skbuff[i] = 0;		np->tx_ring[i].tx_own = 0;		np->tx_ring[i].desc_length = 0x00e08000;		np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);		np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);	}	np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);	return;}static int start_tx(struct sk_buff *skb, struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	unsigned entry;	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		if (jiffies - dev->trans_start < TX_TIMEOUT)			return 1;		tx_timeout(dev);		return 1;	}	/* Caution: the write order is important here, set the field	   with the "ownership" bits last. */	/* Calculate the next Tx descriptor entry. */	entry = np->cur_tx % TX_RING_SIZE;	np->tx_skbuff[entry] = skb;	if ((long)skb->data & 3) {			/* Must use alignment buffer. */		if (np->tx_buf[entry] == NULL &&			(np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)			return 1;		memcpy(np->tx_buf[entry], skb->data, skb->len);		np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);	} else		np->tx_ring[entry].addr = virt_to_bus(skb->data);	np->tx_ring[entry].desc_length = 0x00E08000 |		(skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);	np->tx_ring[entry].tx_own = DescOwn;	np->cur_tx++;	/* Non-x86 Todo: explicitly flush cache lines here. */	/* Wake the potentially-idle transmit channel. */	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)		clear_bit(0, (void*)&dev->tbusy);		/* Typical path */	else		np->tx_full = 1;	dev->trans_start = jiffies;	if (debug > 4) {		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",

⌨️ 快捷键说明

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