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

📄 natsemi.c

📁 Linux下各种网卡的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct netdev_desc rx_ring[RX_RING_SIZE];	struct netdev_desc tx_ring[TX_RING_SIZE];	struct net_device *next_module;		/* Link for devices of this type. */	void *priv_addr;					/* Unaligned address for kfree */	const char *product_name;	/* The addresses of receive-in-place skbuffs. */	struct sk_buff* rx_skbuff[RX_RING_SIZE];	/* The saved address of a sent-in-place packet/buffer, for later free(). */	struct sk_buff* tx_skbuff[TX_RING_SIZE];	struct net_device_stats stats;	struct timer_list timer;	/* Media monitoring timer. */	/* Frequently used values: keep some adjacent for cache effect. */	int msg_level;	int chip_id, drv_flags;	struct pci_dev *pci_dev;	long in_interrupt;			/* Word-long for SMP locks. */	int max_interrupt_work;	int intr_enable;	unsigned int restore_intr_enable:1;	/* Set if temporarily masked.  */	unsigned int rx_q_empty:1;			/* Set out-of-skbuffs.  */	struct netdev_desc *rx_head_desc;	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. */	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;	u16 rx_filter[32];	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 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 natsemi_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 *natsemi_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;	int prev_eedata;	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);	/* Work around the dropped serial bit. */	prev_eedata = eeprom_read(ioaddr, 6);	for (i = 0; i < 3; i++) {		int eedata = eeprom_read(ioaddr, i + 7);		dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);		dev->dev_addr[i*2+1] = eedata >> 7;		prev_eedata = eedata;	}	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);	/* 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;	/* 0x10/0x20/0x100/0x200 set forced speed&duplex modes. */	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"));			writew(((option & 0x300) ? 0x2000 : 0) |	/* 100mbps? */				   (np->full_duplex ? 0x0100 : 0), /* Full duplex? */				   ioaddr + NS_MII_BMCR);		}	}	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;	/* Override the PME enable from the EEPROM. */	writel(0x8000, ioaddr + ClkRunCtrl);	if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) {		u32 chip_config = readl(ioaddr + ChipConfig);		if (np->msg_level & NETIF_MSG_PROBE)			printk(KERN_INFO "%s: Transceiver default autonegotiation %s "				   "10%s %s duplex.\n",				   dev->name, chip_config & 0x2000 ? "enabled, advertise"				   : "disabled, force", chip_config & 0x4000 ? "0" : "",				   chip_config & 0x8000 ? "full" : "half");	}	if (np->msg_level & NETIF_MSG_PROBE)		printk(KERN_INFO "%s: Transceiver status 0x%4.4x partner %4.4x.\n",			   dev->name, (int)readl(ioaddr + NS_MII_BMSR),			   (int)readl(ioaddr + NS_MIILinkPartner));	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 preamble. */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;	long 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);	eeprom_delay(ee_addr);	for (i = 0; i < 16; i++) {		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);		eeprom_delay(ee_addr);		retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 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, directly accessable transceiver.	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 readw(dev->base_addr + NS_Xcvr_Mgmt + (location<<2));	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 + NS_Xcvr_Mgmt + (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;	/* We do not need to reset the '815 chip. */	MOD_INC_USE_COUNT;	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	if (np->msg_level & NETIF_MSG_IFUP)		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 < 6; i += 2) {		writel(i, ioaddr + RxFilterAddr);		writel(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),			   ioaddr + RxFilterData);	}	/* Initialize other registers. */	/* See the datasheet for this correction. */	if (readl(ioaddr + ChipRevReg) == 0x0203) {		writew(0x0001, ioaddr + 0xCC);		writew(0x189C, ioaddr + 0xE4);		writew(0x0000, ioaddr + 0xFC);		writew(0x5040, ioaddr + 0xF4);		writew(0x008C, ioaddr + 0xF8);	}	/* Configure the PCI bus bursts and FIFO thresholds. */	/* Configure for standard, in-spec Ethernet. */	if (readl(ioaddr + ChipConfig) & CfgFDX) {	/* Full duplex */		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 (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);	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) {

⌨️ 快捷键说明

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