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

📄 via-rhine.c

📁 Linux下各种网卡的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* The Rx and Tx buffer descriptors. */struct rx_desc {	s32 rx_status;	u32 desc_length;	u32 addr;	u32 next_desc;};struct tx_desc {	s32 tx_status;	u32 desc_length;	u32 addr;	u32 next_desc;};/* Bits in *_desc.status */enum rx_status_bits {	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};enum desc_status_bits {	DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,};/* Bits in rx.desc_length for extended status. */enum rx_info_bits {	RxTypeTag=0x00010000,	RxTypeUDP=0x00020000, RxTypeTCP=0x00040000, RxTypeIP=0x00080000,	RxTypeUTChksumOK=0x00100000, RxTypeIPChksumOK=0x00200000,	/* Summarized. */	RxTypeCsumMask=0x003E0000,	RxTypeUDPSumOK=0x003A0000, RxTypeTCPSumOK=0x003C0000, };/* Bits in ChipCmd. */enum chip_cmd_bits {	CmdInit=0x0001, CmdStart=0x0002, CmdStop=0x0004, CmdRxOn=0x0008,	CmdTxOn=0x0010, CmdTxDemand=0x0020, CmdRxDemand=0x0040,	CmdEarlyRx=0x0100, CmdEarlyTx=0x0200, CmdFDuplex=0x0400,	CmdNoTxPoll=0x0800, CmdReset=0x8000,};#define PRIV_ALIGN	15	/* Required alignment mask *//* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment   within the structure. */struct netdev_private {	/* Descriptor rings first for alignment. */	struct rx_desc rx_ring[RX_RING_SIZE];	struct tx_desc tx_ring[TX_RING_SIZE];	/* 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];	unsigned char *tx_buf[TX_RING_SIZE];	/* Tx bounce buffers */	unsigned char *tx_bufs;				/* Tx bounce buffer region. */	struct net_device *next_module;		/* Link for devices of this type. */	void *priv_addr;					/* Unaligned address for kfree */	struct net_device_stats stats;	struct timer_list timer;	/* Media monitoring timer. */	int msg_level;	int max_interrupt_work;	int intr_enable;	int chip_id, drv_flags;	struct pci_dev *pci_dev;	/* Frequently used values: keep some adjacent for cache effect. */	struct rx_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;	u16 chip_cmd;						/* Current setting for ChipCmd */	int multicast_filter_limit;	u32 mc_filter[2];	int rx_mode;	unsigned int tx_full:1;				/* The Tx queue is full. */	/* These values are 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. */	u8 tx_thresh, rx_thresh;	/* 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 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 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 via_rhine_probe(struct net_device *dev){	printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);	return pci_drv_register(&via_rhine_drv_id, dev);}#endifstatic void *via_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_tbl[chip_idx].name, ioaddr);	/* We would prefer to directly read the EEPROM but access may be locked. */	for (i = 0; i < 6; i++)		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);	if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {		/* Reload the station address from the EEPROM. */		writeb(0x20, ioaddr + MACRegEEcsr); 		/* Typically 2 cycles to reload. */		for (i = 0; i < 150; i++)			if (! (readb(ioaddr + MACRegEEcsr) & 0x20))				break;		for (i = 0; i < 6; i++)			dev->dev_addr[i] = readb(ioaddr + StationAddr + i);		if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {			printk(" (MISSING EEPROM ADDRESS)");			/* Fill a temp addr with the "locally administered" bit set. */			memcpy(dev->dev_addr, ">Linux", 6);		}	}	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 the descriptor lists are cache-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;#ifdef USE_IO_OPS	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);#endif	/* Reset the chip to erase previous misconfiguration. */	writew(CmdReset, ioaddr + ChipCmd);	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_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 & 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) {		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;	if (np->drv_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;	}	/* 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;			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",				   (option & 0x300 ? 100 : 10),				   (np->full_duplex ? "full" : "half"));			if (np->mii_cnt)				mdio_write(dev, np->phys[0], 0,						   ((option & 0x300) ? 0x2000 : 0) | 	/* 100mbps? */						   (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */		}	}	return dev;}/* Read and write over the MII Management Data I/O (MDIO) interface. */static int mdio_read(struct net_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 net_device *dev, int phy_id, int regnum, int value){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int boguscnt = 1024;	if (phy_id == np->phys[0]) {		switch (regnum) {		case 0:					/* Is user forcing speed/duplex? */			if (value & 0x9000)	/* Autonegotiation. */				np->duplex_lock = 0;			else				np->full_duplex = (value & 0x0100) ? 1 : 0;			break;		case 4: np->advertising = value; break;		}	}	/* 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 net_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);	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++)		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);	/* Initialize other registers. */	writew(0x0006, ioaddr + PCIBusConfig);	/* 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;	set_rx_mode(dev);	netif_start_tx_queue(dev);	np->intr_enable = IntrRxDone | IntrRxErr | IntrRxEmpty |		IntrRxOverflow| IntrRxDropped| IntrTxDone | IntrTxAbort |		IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange |		IntrMIIChange;	/* Enable interrupts by setting the interrupt mask. */	writew(np->intr_enable, ioaddr + IntrEnable);	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;	if (np->duplex_lock)		np->chip_cmd |= CmdFDuplex;	writew(np->chip_cmd, ioaddr + ChipCmd);	check_duplex(dev);	/* The LED outputs of various MII xcvrs should be configured.  */	/* For NS or Mison phys, turn on bit 1 in register 0x17 */

⌨️ 快捷键说明

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