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

📄 ns820.c

📁 Linux下各种网卡的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	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. */	unsigned int duplex_lock:1;	unsigned int medialock:1;			/* Do not sense media. */	unsigned int default_port;			/* Last dev->if_port value. */	/* Rx filter. */	u32 cur_rx_mode;	u32 rx_filter[16];	int multicast_filter_limit;	/* FIFO and PCI burst thresholds. */	int tx_config, rx_config;	/* MII transceiver section. */	u16 advertising;					/* NWay media advertisement */};static int  eeprom_read(long ioaddr, int location);static void mdio_sync(long mdio_addr);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 void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static int  rx_ring_fill(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 ns820_probe(struct net_device *dev){	if (pci_drv_register(&natsemi_drv_id, dev) < 0)		return -ENODEV;	printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);	return 0;}#endifstatic void *ns820_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;	/* Perhaps NETIF_MSG_PROBE */	printk(KERN_INFO "%s: %s at 0x%lx, ",		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);	for (i = 0; i < 3; i++)		((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, 12 - 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);	/* Reset the chip to erase previous misconfiguration. */	writel(ChipReset, ioaddr + ChipCmd);	/* Power up Xcvr. */	writel(~CfgXcrOff & readl(ioaddr + ChipConfig), ioaddr + ChipConfig);	/* 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;	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;	/* The lower four bits are the media type. */	if (option > 0) {		if (option & 0x220)			np->full_duplex = 1;		np->default_port = option & 0x33ff;		if (np->default_port & 0x330)			np->medialock = 1;	}	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->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;#ifdef HAVE_CHANGE_MTU	dev->change_mtu = change_mtu;#endif	/* Allow forcing the media type. */	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, 1, 0,					   ((option & 0x300) ? 0x2000 : 0) | 	/* 100mbps? */					   (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */		}	}	return dev;}/* 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.   Update to the code in other drivers for 8/10 bit addresses.*//* Delay between EEPROM clock transitions.   This "delay" forces out buffered PCI writes, which is sufficient to meet   the timing requirements of most EEPROMs.*/#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 01 preamble. */enum EEPROM_Cmds {	EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7,};static int eeprom_read(long addr, int location){	long eeprom_addr = addr + EECtrl;	int read_cmd = (EE_ReadCmd << 6) | location;	int retval = 0;	int i;	writel(EE_Write0, eeprom_addr);	/* Shift the read command bits out. */	for (i = 10; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;		writel(dataval, eeprom_addr);		eeprom_delay(eeprom_addr);		writel(dataval | EE_ShiftClk, eeprom_addr);		eeprom_delay(eeprom_addr);	}	writel(EE_ChipSelect, eeprom_addr);	eeprom_delay(eeprom_addr);	for (i = 15; i >= 0; i--) {		writel(EE_ChipSelect | EE_ShiftClk, eeprom_addr);		eeprom_delay(eeprom_addr);		retval |= (readl(eeprom_addr) & EE_DataOut) ? 1 << i : 0;		writel(EE_ChipSelect, eeprom_addr);		eeprom_delay(eeprom_addr);	}	/* Terminate the EEPROM access. */	writel(EE_Write0, eeprom_addr);	writel(0, eeprom_addr);	return retval;}/*  MII transceiver control section.	Read and write MII registers using software-generated serial MDIO	protocol.  See the MII specifications or DP83840A data sheet for details.	The maximum data clock rate is 2.5 Mhz.  To meet minimum timing we	must flush writes to the PCI bus with a PCI read. */#define mdio_delay(mdio_addr) readl(mdio_addr)/* Set iff a MII transceiver on any interface requires mdio preamble.   This only set with older tranceivers, so the extra   code size of a per-interface flag is not worthwhile. */static char mii_preamble_required = 0;enum mii_reg_bits {	MDIO_ShiftClk=0x0040, MDIO_Data=0x0010, MDIO_EnbOutput=0x0020,};#define MDIO_EnbIn  (0)#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and   a few older transceivers. */static void mdio_sync(long mdio_addr){	int bits = 32;	/* Establish sync by sending at least 32 logic ones. */	while (--bits >= 0) {		writel(MDIO_WRITE1, mdio_addr);		mdio_delay(mdio_addr);		writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}}static int mdio_read(struct net_device *dev, int phy_id, int location){	long mdio_addr = dev->base_addr + EECtrl;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int i, retval = 0;	if (mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		writel(dataval, mdio_addr);		mdio_delay(mdio_addr);		writel(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		writel(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		retval = (retval << 1) | ((readl(mdio_addr) & MDIO_Data) ? 1 : 0);		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	long mdio_addr = dev->base_addr + EECtrl;	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;	int i;	if (mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		writel(dataval, mdio_addr);		mdio_delay(mdio_addr);		writel(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		writel(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	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;	u32 intr_status = readl(ioaddr + IntrStatus);	/* We have not yet encountered a case where we need to reset the chip. */	MOD_INC_USE_COUNT;	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	/* Power up Xcvr. */	writel((~CfgXcrOff & readl(ioaddr + ChipConfig)) | 0x00400000,		   ioaddr + ChipConfig);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: netdev_open() irq %d intr_status %8.8x.\n",			   dev->name, dev->irq, intr_status);	init_ring(dev);#if defined(ADDR_64BITS) && defined(__alpha__)	writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxRingPtrHi);	writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingPtrHi);#else	writel(0, ioaddr + RxRingPtrHi);	writel(0, ioaddr + TxRingPtrHi);#endif	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);	for (i = 0; i < 6; i += 2) {		writel(i, ioaddr + RxFilterAddr);		writel(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. */	if (np->full_duplex  ||		((readl(ioaddr + ChipConfig) & CfgFDX) == 0) ^		((np->drv_flags & FDXActiveLow) != 0)) {		np->tx_config = 0xD0801002;		np->rx_config = 0x10000020;	} else {		np->tx_config = 0x10801002;		np->rx_config = 0x0020;	}	if (dev->mtu > 1500)		np->rx_config |= 0x08000000;	writel(np->tx_config, ioaddr + TxConfig);	writel(np->rx_config, ioaddr + RxConfig);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: Setting TxConfig to %8.8x.\n",			   dev->name, (int)readl(ioaddr + TxConfig));	if (dev->if_port == 0)		dev->if_port = np->default_port;	np->in_interrupt = 0;	check_duplex(dev);	set_rx_mode(dev);	netif_start_tx_queue(dev);	/* Enable interrupts by setting the interrupt mask. */	np->intr_enable = IntrNormalSummary | IntrAbnormalSummary | 0x1f;	writel(np->intr_enable, ioaddr + IntrMask);	writel(1, ioaddr + IntrEnable);	writel(RxOn | TxOn, ioaddr + ChipCmd);	writel(4, ioaddr + StatsCtrl);					/* Clear Stats */	if (np->msg_level & NETIF_MSG_IFUP)		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);	/* Call an external test function, if provided. */

⌨️ 快捷键说明

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