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

📄 natsemi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	printk(KERN_INFO "%s: %s at 0x%lx, ",		   dev->name, natsemi_pci_info[chip_idx].name, ioaddr);	for (i = 0; i < ETH_ALEN/2; i++) {		/* weird organization */		unsigned short a;		a = (le16_to_cpu(eeprom_read(ioaddr, i + 6)) >> 15) + 		    (le16_to_cpu(eeprom_read(ioaddr, i + 7)) << 1);		((u16 *)dev->dev_addr)[i] = a;	}	for (i = 0; i < ETH_ALEN-1; i++)			printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);#if ! defined(final_version) /* Dump the EEPROM contents during development. */	if (debug > 4)		for (i = 0; i < 64; i++)			printk("%4.4x%s",				   eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n");#endif	/* Reset the chip to erase previous misconfiguration. */	writel(ChipReset, ioaddr + ChipCmd);	dev->base_addr = ioaddr;	dev->irq = irq;	np = dev->priv;	np->pci_dev = pdev;	pdev->driver_data = dev;	np->iosize = iosize;	spin_lock_init(&np->lock);	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 (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 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;	dev->tx_timeout = &tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	if (mtu)		dev->mtu = mtu;	np->advertising = readl(ioaddr + 0x90);	printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n",		   dev->name, (int)readl(ioaddr + 0x84), np->advertising);	return 0;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.   The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. *//* Delay between EEPROM clock transitions.   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that   made udelay() unreliable.   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is   depricated.*/#define eeprom_delay(ee_addr)	readl(ee_addr)enum EEPROM_Ctrl_Bits {	EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,};#define EE_Write0 (EE_ChipSelect)#define EE_Write1 (EE_ChipSelect | EE_DataIn)/* The EEPROM commands include the alway-set leading bit. */enum EEPROM_Cmds {	EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),};static int eeprom_read(long addr, int location){	int i;	int retval = 0;	int ee_addr = addr + EECtrl;	int read_cmd = location | EE_ReadCmd;	writel(EE_Write0, ee_addr);	/* Shift the read command bits out. */	for (i = 10; i >= 0; i--) {		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;		writel(dataval, ee_addr);		eeprom_delay(ee_addr);		writel(dataval | EE_ShiftClk, ee_addr);		eeprom_delay(ee_addr);	}	writel(EE_ChipSelect, ee_addr);	for (i = 16; i > 0; i--) {		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);		eeprom_delay(ee_addr);		/* data bits are LSB first */		retval = (retval >> 1) | ((readl(ee_addr) & EE_DataOut) ? 0x8000 : 0);		writel(EE_ChipSelect, ee_addr);		eeprom_delay(ee_addr);	}	/* Terminate the EEPROM access. */	writel(EE_Write0, ee_addr);	writel(0, ee_addr);	return retval;}/*  MII transceiver control section.	The 83815 series has an internal transceiver, and we present the	management registers as if they were MII connected. */static int mdio_read(struct net_device *dev, int phy_id, int location){	if (phy_id == 1 && location < 32)		return readl(dev->base_addr + 0x80 + (location<<2)) & 0xffff;	else		return 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	if (phy_id == 1 && location < 32)		writew(value, dev->base_addr + 0x80 + (location<<2));}static int netdev_open(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	/* Do we need to reset the chip??? */	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);	if (i) return i;	if (debug > 1)		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",			   dev->name, dev->irq);	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 < ETH_ALEN; i += 2) {		writel(i, ioaddr + RxFilterAddr);		writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),			   ioaddr + RxFilterData);	}	/* Initialize other registers. */	/* Configure the PCI bus bursts and FIFO thresholds. */	/* Configure for standard, in-spec Ethernet. */	np->tx_config = (1<<28) +	/* Automatic transmit padding */			(1<<23) +	/* Excessive collision retry */			(0x0<<20) +	/* Max DMA burst = 512 byte */			(8<<8) +	/* fill threshold = 256 byte */			2;		/* drain threshold = 64 byte */	writel(np->tx_config, ioaddr + TxConfig);	np->rx_config = (0x0<<20)	/* Max DMA burst = 512 byte */ +			(0x8<<1);	/* Drain Threshold = 64 byte */	writel(np->rx_config, ioaddr + RxConfig);	if (dev->if_port == 0)		dev->if_port = np->default_port;	/* Disable PME */	np->SavedClkRun = readl(ioaddr + ClkRun);	writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun);	netif_start_queue(dev);	check_duplex(dev);	set_rx_mode(dev);	/* Enable interrupts by setting the interrupt mask.	 * We don't listen for TxDone interrupts and rely on TxIdle. */	writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone,		ioaddr + IntrMask);	writel(1, ioaddr + IntrEnable);	writel(RxOn | TxOn, ioaddr + ChipCmd);	writel(4, ioaddr + StatsCtrl); 					/* Clear Stats */	if (debug > 2)		printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n",			   dev->name, (int)readl(ioaddr + ChipCmd));	/* Set the timer to check for link beat. */	init_timer(&np->timer);	np->timer.expires = jiffies + 3*HZ;	np->timer.data = (unsigned long)dev;	np->timer.function = &netdev_timer;				/* timer handler */	add_timer(&np->timer);	return 0;}static void check_duplex(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int duplex;	if (np->duplex_lock)		return;	duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;	if (np->full_duplex != duplex) {		np->full_duplex = duplex;		if (debug)			printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link"				   " capability.\n", dev->name,				   duplex ? "full" : "half");		if (duplex) {			np->rx_config |= 0x10000000;			np->tx_config |= 0xC0000000;		} else {			np->rx_config &= ~0x10000000;			np->tx_config &= ~0xC0000000;		}		writel(np->tx_config, ioaddr + TxConfig);		writel(np->rx_config, ioaddr + RxConfig);	}}static void netdev_timer(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int next_tick = 60*HZ;	if (debug > 3)		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",			   dev->name, (int)readl(ioaddr + IntrStatus));	check_duplex(dev);	np->timer.expires = jiffies + next_tick;	add_timer(&np->timer);}static void tx_timeout(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"		   " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));#ifndef __alpha__	{		int i;		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);		for (i = 0; i < RX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);		printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);		for (i = 0; i < TX_RING_SIZE; i++)			printk(" %4.4x", np->tx_ring[i].cmd_status);		printk("\n");	}#endif	/* 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 net_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];	/* Initialize all Rx descriptors. */	for (i = 0; i < RX_RING_SIZE; i++) {		np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);		np->rx_ring[i].cmd_status = DescOwn;		np->rx_skbuff[i] = 0;	}	/* Mark the last entry as wrapping the ring. */	np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */	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_le32desc(skb->tail);		np->rx_ring[i].cmd_status =			cpu_to_le32(np->rx_buf_sz);	}	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].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);		np->tx_ring[i].cmd_status = 0;	}	np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);	return;}static int start_tx(struct sk_buff *skb, struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	unsigned entry;	/* Note: Ordering is important here, set the field with the	   "ownership" bit last, and only then increment cur_tx. */	/* Calculate the next Tx descriptor entry. */	entry = np->cur_tx % TX_RING_SIZE;	np->tx_skbuff[entry] = skb;	np->tx_ring[entry].addr = virt_to_le32desc(skb->data);	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);	np->cur_tx++;	/* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */	if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {		np->tx_full = 1;		netif_stop_queue(dev);	}	/* Wake the potentially-idle transmit channel. */	writel(TxOn, dev->base_addr + ChipCmd);	dev->trans_start = jiffies;	if (debug > 4) {		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",			   dev->name, np->cur_tx, entry);	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs){	struct net_device *dev = (struct net_device *)dev_instance;	struct netdev_private *np;	long ioaddr;	int boguscnt = max_interrupt_work;#ifndef final_version			/* Can never occur. */	if (dev == NULL) {		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "				"device.\n", irq);		return;	}#endif	ioaddr = dev->base_addr;	np = (struct netdev_private *)dev->priv;	spin_lock(&np->lock);	do {		u32 intr_status = readl(ioaddr + IntrStatus);		/* Acknowledge all of the current interrupt sources ASAP. */		writel(intr_status & 0x000ffff, ioaddr + IntrStatus);		if (debug > 4)			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",				   dev->name, intr_status);

⌨️ 快捷键说明

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