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

📄 starfire.c

📁 Linux下各种网卡的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	unsigned int rx_done;	struct tx_done_report *tx_done_q __attribute__((aligned (L1_CACHE_BYTES)));	unsigned int tx_done;	struct net_device_stats stats;	struct timer_list timer;	/* Media monitoring timer. */	int msg_level;	int chip_id, drv_flags;	struct pci_dev *pci_dev;	/* Frequently used values: keep some adjacent for cache effect. */	int max_interrupt_work;	int intr_enable;	unsigned int restore_intr_enable:1;	/* Set if temporarily masked.  */	unsigned int polling:1;				/* Erk, IRQ err. */	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */	unsigned int rx_buf_sz;				/* Based on MTU+slack. */	int rx_copybreak;	unsigned int cur_tx, dirty_tx;	unsigned int tx_full:1;				/* The Tx queue is full. */	/* These values keep track of the transceiver/media in use. */	unsigned int full_duplex:1,			/* Full-duplex operation requested. */		medialock:1,					/* Xcvr set to fixed speed/duplex. */		rx_flowctrl:1,		tx_flowctrl:1;					/* Use 802.3x flow control. */	unsigned int default_port;			/* Last dev->if_port value. */	u32 tx_mode;	u8 tx_threshold;	u32 cur_rx_mode;	u16 mc_filter[32];	int multicast_filter_limit;	/* MII transceiver section. */	int mii_cnt;						/* MII device addresses. */	u16 advertising;					/* NWay media advertisement */	unsigned char phys[2];				/* MII device addresses. */};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 int  netdev_open(struct net_device *dev);static int  change_mtu(struct net_device *dev, int new_mtu);static void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static void init_ring(struct net_device *dev);static int  start_tx(struct sk_buff *skb, struct net_device *dev);static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);static void netdev_error(struct net_device *dev, int intr_status);static int  netdev_rx(struct net_device *dev);static void netdev_error(struct net_device *dev, int intr_status);static void set_rx_mode(struct net_device *dev);static struct net_device_stats *get_stats(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int  netdev_close(struct net_device *dev);/* A list of our installed devices, for removing the driver module. */static struct net_device *root_net_dev = NULL;#ifndef MODULEint starfire_probe(struct net_device *dev){	if (pci_drv_register(&starfire_drv_id, dev) < 0)		return -ENODEV;	printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);	return 0;}#endifstatic void *starfire_probe1(struct pci_dev *pdev, void *init_dev,							 long ioaddr, int irq, int chip_idx, int card_idx){	struct net_device *dev;	struct netdev_private *np;	void *priv_mem;	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;	dev = init_etherdev(init_dev, 0);	if (!dev)		return NULL;	printk(KERN_INFO "%s: %s at 0x%lx, ",		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);	/* Serial EEPROM reads are hidden by the hardware. */	for (i = 0; i < 6; i++)		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-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);	/* Make certain elements e.g. descriptor lists are aligned. */	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);	/* Check for the very unlikely case of no memory. */	if (priv_mem == NULL)		return NULL;	/* Reset the chip to erase previous misconfiguration. */	writel(ChipResetCmd, ioaddr + PCIDeviceConfig);	dev->base_addr = ioaddr;	dev->irq = irq;	dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);	memset(np, 0, sizeof(*np));	np->priv_addr = priv_mem;	np->next_module = root_net_dev;	root_net_dev = dev;	np->pci_dev = pdev;	np->chip_id = chip_idx;	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;	np->msg_level = (1 << debug) - 1;	np->rx_copybreak = rx_copybreak;	np->max_interrupt_work = max_interrupt_work;	np->multicast_filter_limit = multicast_filter_limit;	if (dev->mem_start)		option = dev->mem_start;	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)		np->full_duplex = 1;	if (np->full_duplex) {		if (np->msg_level & NETIF_MSG_PROBE)			printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"				   " disabled.\n", dev->name);		np->medialock = 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->change_mtu = &change_mtu;	if (np->drv_flags & CanHaveMII) {		int phy, phy_idx = 0;		for (phy = 0; 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);				if (np->msg_level & NETIF_MSG_PROBE)					printk(KERN_INFO "%s: MII PHY found at address %d, status "						   "0x%4.4x advertising %4.4x.\n",						   dev->name, phy, mii_status, np->advertising);			}		}		np->mii_cnt = phy_idx;	}	/* Force the media type after detecting the transceiver. */	if (option > 0) {		if (option & 0x220)			np->full_duplex = 1;		np->default_port = option & 0x3ff;		if (np->default_port & 0x330) {			np->medialock = 1;			if (np->msg_level & NETIF_MSG_PROBE)				printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",					   (option & 0x300 ? 100 : 10),					   (np->full_duplex ? "full" : "half"));			mdio_write(dev, np->phys[0], 0,					   ((option & 0x300) ? 0x2000 : 0) | 	/* 100mbps? */					   (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */		}	}	return dev;}/* Read the MII Management Data I/O (MDIO) interfaces. */static int mdio_read(struct net_device *dev, int phy_id, int location){	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);	int result, boguscnt=1000;	/* ??? Should we add a busy-wait here? */	do		result = readl(mdio_addr);	while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);	return result & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);	writel(value, mdio_addr);	/* The busy-wait will occur before a read. */	return;}static int netdev_open(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	MOD_INC_USE_COUNT;	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	/* We have no reports that indicate we need to reset the chip.	   But to be on the safe side... */	/* Disable the Rx and Tx, and reset the chip. */	writel(0, ioaddr + GenCtrl);	writel(ChipResetCmd, ioaddr + PCIDeviceConfig);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",			   dev->name, dev->irq);	/* Allocate the various queues, failing gracefully. */	if (np->tx_done_q == 0)		np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL);	if (np->rx_done_q == 0)		np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL);	if (np->tx_ring == 0)		np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL);	if (np->rx_ring == 0)		np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL);	if (np->tx_done_q == 0  ||  np->rx_done_q == 0		|| np->rx_ring == 0 ||  np->tx_ring == 0) {		/* Retain the pages to increase our chances next time. */		MOD_DEC_USE_COUNT;		return -ENOMEM;	}	init_ring(dev);	/* Set the size of the Rx buffers. */	writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);	/* Set Tx descriptor to type 1 and padding to 0 bytes. */	writel(0x02000401, ioaddr + TxDescCtrl);#if defined(STARFIRE_ADDR_64BITS)	writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr);	writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr);#else	writel(0, ioaddr + RxDescQHiAddr);	writel(0, ioaddr + TxRingHiAddr);	writel(0, ioaddr + CompletionHiAddr);#endif	writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr);	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);	writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr);	writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s:  Filling in the station address.\n", dev->name);	/* Fill both the unused Tx SA register and the Rx perfect filter. */	for (i = 0; i < 6; i++)		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);	for (i = 0; i < 16; i++) {		u16 *eaddrs = (u16 *)dev->dev_addr;		long setup_frm = ioaddr + 0x56000 + i*16;		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;		writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;		writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;	}	/* Initialize other registers. */	/* Configure the PCI bus bursts and FIFO thresholds. */	np->tx_mode = 0;			/* Initialized when TxMode set. */	np->tx_threshold = 4;	writel(np->tx_threshold, ioaddr + TxThreshold);	writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);	if (dev->if_port == 0)		dev->if_port = np->default_port;	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);	set_rx_mode(dev);	np->advertising = mdio_read(dev, np->phys[0], 4);	check_duplex(dev);	netif_start_tx_queue(dev);	/* Set the interrupt mask and enable PCI interrupts. */	np->intr_enable = IntrRxDone | IntrRxEmpty | IntrRxPCIErr |		IntrTxDone | IntrTxEmpty | IntrTxPCIErr |		StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary		| 0x0010;	writel(np->intr_enable, ioaddr + IntrEnable);	writel(PCIIntEnb | readl(ioaddr + PCIDeviceConfig),		   ioaddr + PCIDeviceConfig);	/* Enable the Rx and Tx units. */	writel(TxEnable|RxEnable, ioaddr + GenCtrl);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: Done netdev_open().\n",			   dev->name);	/* 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;}/* The starfire can handle frame sizes up to 64KB, but we arbitrarily * limit the size. */static int change_mtu(struct net_device *dev, int new_mtu){	if ((new_mtu < 68) || (new_mtu > 17268))		return -EINVAL;	if (netif_running(dev))		return -EBUSY;	dev->mtu = new_mtu;	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 new_tx_mode;	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0)		| (np->rx_flowctrl ? 0x0400:0);	if (np->medialock) {		if (np->full_duplex)			new_tx_mode |= 2;	} else {		int mii_reg5 = mdio_read(dev, np->phys[0], 5);		int negotiated = mii_reg5 & np->advertising;		int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;		if (duplex)			new_tx_mode |= 2;		if (np->full_duplex != duplex) {			np->full_duplex = duplex;			if (np->msg_level & NETIF_MSG_LINK)				printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"					   " negotiated capability %4.4x.\n", dev->name,					   duplex ? "full" : "half", np->phys[0], negotiated);		}	}	if (new_tx_mode != np->tx_mode) {		np->tx_mode = new_tx_mode;		writel(np->tx_mode | 0x8000, ioaddr + TxMode);		writel(np->tx_mode, ioaddr + TxMode);	}}/* Check for duplex changes, but mostly check for failures. */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 status = readl(ioaddr + IntrStatus);	static long last_msg = 0;	/* Normally we check only every few seconds. */	np->timer.expires = jiffies + 60*HZ;	if (np->msg_level & NETIF_MSG_TIMER) {		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",			   dev->name, status);	}	/* Check for a missing chip or failed interrupt line.	 * The latter may be falsely triggered, so we check twice. */	if (status == 0xffffffff) {

⌨️ 快捷键说明

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