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

📄 sunlance.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	unsigned long piobuf = (unsigned long) dest;	if (piobuf & 1) {		sbus_writeb(0, piobuf);		piobuf += 1;		len -= 1;		if (len == 0)			return;	}	if (len == 1) {		sbus_writeb(0, piobuf);		return;	}	if (piobuf & 2) {		sbus_writew(0, piobuf);		piobuf += 2;		len -= 2;		if (len == 0)			return;	}	while (len >= 4) {		sbus_writel(0, piobuf);		piobuf += 4;		len -= 4;	}	if (len >= 2) {		sbus_writew(0, piobuf);		piobuf += 2;		len -= 2;	}	if (len >= 1)		sbus_writeb(0, piobuf);}static void lance_tx_timeout(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",	       dev->name, sbus_readw(lp->lregs + RDP));	lance_reset(dev);	netif_wake_queue(dev);}static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	int entry, skblen, len;	skblen = skb->len;	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;	spin_lock_irq(&lp->lock);	lp->stats.tx_bytes += len;	entry = lp->tx_new & TX_RING_MOD_MASK;	if (lp->pio_buffer) {		sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length);		sbus_writew(0, &ib->btx_ring[entry].misc);		lance_piocopy_from_skb(&ib->tx_buf[entry][0], skb->data, skblen);		if (len != skblen)			lance_piozero(&ib->tx_buf[entry][skblen], len - skblen);		sbus_writeb(LE_T1_POK | LE_T1_OWN, &ib->btx_ring[entry].tmd1_bits);	} else {		ib->btx_ring [entry].length = (-len) | 0xf000;		ib->btx_ring [entry].misc = 0;		memcpy((char *)&ib->tx_buf [entry][0], skb->data, skblen);		if (len != skblen)			memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);		ib->btx_ring [entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);	}	lp->tx_new = TX_NEXT(entry);	if (TX_BUFFS_AVAIL <= 0)		netif_stop_queue(dev);	/* Kick the lance: transmit now */	sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP);	/* Read back CSR to invalidate the E-Cache.	 * This is needed, because DMA_DSBL_WR_INV is set.	 */	if (lp->dregs)		sbus_readw(lp->lregs + RDP);	spin_unlock_irq(&lp->lock);	dev->trans_start = jiffies;	dev_kfree_skb(skb);    	return 0;}static struct net_device_stats *lance_get_stats(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	return &lp->stats;}/* taken from the depca driver */static void lance_load_multicast(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	volatile u16 *mcast_table = (u16 *) &ib->filter;	struct dev_mc_list *dmi = dev->mc_list;	char *addrs;	int i, j, bit, byte;	u32 crc, poly = CRC_POLYNOMIAL_LE;		/* set all multicast bits */	if (dev->flags & IFF_ALLMULTI) {		if (lp->pio_buffer) {			sbus_writel(0xffffffff, &ib->filter[0]);			sbus_writel(0xffffffff, &ib->filter[1]);		} else {			ib->filter [0] = 0xffffffff;			ib->filter [1] = 0xffffffff;		}		return;	}	/* clear the multicast filter */	if (lp->pio_buffer) {		sbus_writel(0, &ib->filter[0]);		sbus_writel(0, &ib->filter[1]);	} else {		ib->filter [0] = 0;		ib->filter [1] = 0;	}	/* Add addresses */	for (i = 0; i < dev->mc_count; i++) {		addrs = dmi->dmi_addr;		dmi   = dmi->next;		/* multicast address? */		if (!(*addrs & 1))			continue;		crc = 0xffffffff;		for (byte = 0; byte < 6; byte++) {			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {				int test;				test = ((bit ^ crc) & 0x01);				crc >>= 1;				if (test)					crc = crc ^ poly;			}		}		crc = crc >> 26;		if (lp->pio_buffer) {			u16 tmp = sbus_readw(&mcast_table[crc>>4]);			tmp |= 1 << (crc & 0xf);			sbus_writew(tmp, &mcast_table[crc>>4]);		} else {			mcast_table [crc >> 4] |= 1 << (crc & 0xf);		}	}}static void lance_set_multicast(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	u16 mode;	if (!netif_running(dev))		return;	if (lp->tx_old != lp->tx_new) {		mod_timer(&lp->multicast_timer, jiffies + 4);		netif_wake_queue(dev);		return;	}	netif_stop_queue(dev);	STOP_LANCE(lp);	lp->init_ring(dev);	if (lp->pio_buffer)		mode = sbus_readw(&ib->mode);	else		mode = ib->mode;	if (dev->flags & IFF_PROMISC) {		mode |= LE_MO_PROM;		if (lp->pio_buffer)			sbus_writew(mode, &ib->mode);		else			ib->mode = mode;	} else {		mode &= ~LE_MO_PROM;		if (lp->pio_buffer)			sbus_writew(mode, &ib->mode);		else			ib->mode = mode;		lance_load_multicast(dev);	}	load_csrs(lp);	init_restart_lance(lp);	netif_wake_queue(dev);}static void lance_set_multicast_retry(unsigned long _opaque){	struct net_device *dev = (struct net_device *) _opaque;	lance_set_multicast(dev);}static void lance_free_hwresources(struct lance_private *lp){	if (lp->lregs)		sbus_iounmap(lp->lregs, LANCE_REG_SIZE);	if (lp->init_block != NULL) {		if (lp->pio_buffer) {			sbus_iounmap((unsigned long)lp->init_block,				     sizeof(struct lance_init_block));		} else {			sbus_free_consistent(lp->sdev,					     sizeof(struct lance_init_block),					     (void *)lp->init_block,					     lp->init_block_dvma);		}	}}static int __init sparc_lance_init(struct net_device *dev,				   struct sbus_dev *sdev,				   struct sbus_dma *ledma,				   struct sbus_dev *lebuffer){	static unsigned version_printed = 0;	struct lance_private *lp = NULL;	int    i;	if (dev == NULL) {		dev = init_etherdev (0, sizeof (struct lance_private) + 8);	} else {		dev->priv = kmalloc(sizeof (struct lance_private) + 8,				    GFP_KERNEL);		if (dev->priv == NULL)			return -ENOMEM;		memset(dev->priv, 0, sizeof (struct lance_private) + 8);	}	if (sparc_lance_debug && version_printed++ == 0)		printk (KERN_INFO "%s", version);	printk(KERN_INFO "%s: LANCE ", dev->name);	/* Make certain the data structures used by the LANCE are aligned. */	dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7);	lp = (struct lance_private *) dev->priv;	spin_lock_init(&lp->lock);	/* Copy the IDPROM ethernet address to the device structure, later we	 * will copy the address in the device structure to the lance	 * initialization block.	 */	for (i = 0; i < 6; i++)		printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i],		       i == 5 ? ' ': ':');	printk("\n");	/* Get the IO region */	lp->lregs = sbus_ioremap(&sdev->resource[0], 0,				 LANCE_REG_SIZE, lancestr);	if (lp->lregs == 0UL) {		printk(KERN_ERR "%s: Cannot map SunLance registers.\n",		       dev->name);		goto fail;	}	lp->sdev = sdev;	if (lebuffer) {		lp->init_block = (volatile struct lance_init_block *)			sbus_ioremap(&lebuffer->resource[0], 0,				     sizeof(struct lance_init_block), "lebuffer");		if (lp->init_block == NULL) {			printk(KERN_ERR "%s: Cannot map SunLance PIO buffer.\n",			       dev->name);			goto fail;		}		lp->init_block_dvma = 0;		lp->pio_buffer = 1;		lp->init_ring = lance_init_ring_pio;		lp->rx = lance_rx_pio;		lp->tx = lance_tx_pio;	} else {		lp->init_block = (volatile struct lance_init_block *)			sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),					      &lp->init_block_dvma);		if (lp->init_block == NULL ||		    lp->init_block_dvma == 0) {			printk(KERN_ERR "%s: Cannot allocate consistent DMA memory.\n",			       dev->name);			goto fail;		}		lp->pio_buffer = 0;		lp->init_ring = lance_init_ring_dvma;		lp->rx = lance_rx_dvma;		lp->tx = lance_tx_dvma;	}	lp->busmaster_regval = prom_getintdefault(sdev->prom_node,						  "busmaster-regval",						  (LE_C3_BSWP | LE_C3_ACON |						   LE_C3_BCON));	lp->name = lancestr;	lp->ledma = ledma;	lp->burst_sizes = 0;	if (lp->ledma) {		char prop[6];		unsigned int sbmask;		u32 csr;		/* Find burst-size property for ledma */		lp->burst_sizes = prom_getintdefault(ledma->sdev->prom_node,						     "burst-sizes", 0);		/* ledma may be capable of fast bursts, but sbus may not. */		sbmask = prom_getintdefault(ledma->sdev->bus->prom_node,					    "burst-sizes", DMA_BURSTBITS);		lp->burst_sizes &= sbmask;		/* Get the cable-selection property */		memset(prop, 0, sizeof(prop));		prom_getstring(ledma->sdev->prom_node, "cable-selection",			       prop, sizeof(prop));		if (prop[0] == 0) {			int topnd, nd;			printk(KERN_INFO "%s: using auto-carrier-detection.\n",			       dev->name);			/* Is this found at /options .attributes in all			 * Prom versions? XXX			 */			topnd = prom_getchild(prom_root_node);			nd = prom_searchsiblings(topnd, "options");			if (!nd)				goto no_link_test;			if (!prom_node_has_property(nd, "tpe-link-test?"))				goto no_link_test;			memset(prop, 0, sizeof(prop));			prom_getstring(nd, "tpe-link-test?", prop,				       sizeof(prop));			if (strcmp(prop, "true")) {				printk(KERN_NOTICE "%s: warning: overriding option "				       "'tpe-link-test?'\n", dev->name);				printk(KERN_NOTICE "%s: warning: mail any problems "				       "to ecd@skynet.be\n", dev->name);				set_auxio(AUXIO_LINK_TEST, 0);			}no_link_test:			lp->auto_select = 1;			lp->tpe = 0;		} else if (!strcmp(prop, "aui")) {			lp->auto_select = 0;			lp->tpe = 0;		} else {			lp->auto_select = 0;			lp->tpe = 1;		}		lp->dregs = ledma->regs;		/* Reset ledma */		csr = sbus_readl(lp->dregs + DMA_CSR);		sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR);		udelay(200);		sbus_writel(csr & ~DMA_RST_ENET, lp->dregs + DMA_CSR);	} else		lp->dregs = 0;	/* This should never happen. */	if ((unsigned long)(lp->init_block->brx_ring) & 0x07) {		printk(KERN_ERR "%s: ERROR: Rx and Tx rings not on even boundary.\n",		       dev->name);		goto fail;	}	lp->dev = dev;	dev->open = &lance_open;	dev->stop = &lance_close;	dev->hard_start_xmit = &lance_start_xmit;	dev->tx_timeout = &lance_tx_timeout;	dev->watchdog_timeo = 5*HZ;	dev->get_stats = &lance_get_stats;	dev->set_multicast_list = &lance_set_multicast;	dev->irq = sdev->irqs[0];	dev->dma = 0;	ether_setup(dev);	/* We cannot sleep if the chip is busy during a	 * multicast list update event, because such events	 * can occur from interrupts (ex. IPv6).  So we	 * use a timer to try again later when necessary. -DaveM	 */	init_timer(&lp->multicast_timer);	lp->multicast_timer.data = (unsigned long) dev;	lp->multicast_timer.function = &lance_set_multicast_retry;	dev->ifindex = dev_new_index();	lp->next_module = root_lance_dev;	root_lance_dev = lp;	return 0;fail:	if (lp != NULL)		lance_free_hwresources(lp);	return -ENODEV;}/* On 4m, find the associated dma for the lance chip */static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev){	struct sbus_dma *p;	for_each_dvma(p) {		if (p->sdev == sdev)			return p;	}	return NULL;}#ifdef CONFIG_SUN4#include <asm/sun4paddr.h>/* Find all the lance cards on the system and initialize them */static int __init sparc_lance_probe(void){	static struct sbus_dev sdev;	static int called = 0;	root_lance_dev = NULL;	if (called)		return -ENODEV;	called++;	if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||	    (idprom->id_machtype == (SM_SUN4|SM_4_470))) {		memset(&sdev, 0, sizeof(sdev));		sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;		sdev.irqs[0] = 6;		return sparc_lance_init(NULL, &sdev, 0, 0);	}	return -ENODEV;}#else /* !CONFIG_SUN4 *//* Find all the lance cards on the system and initialize them */static int __init sparc_lance_probe(void){	struct sbus_bus *bus;	struct sbus_dev *sdev = 0;	struct net_device *dev = NULL;	struct sbus_dma *ledma = 0;	static int called = 0;	int cards = 0, v;	root_lance_dev = NULL;	if (called)		return -ENODEV;	called++;	for_each_sbus (bus) {		for_each_sbusdev (sdev, bus) {			if (cards)				dev = NULL;			if (strcmp(sdev->prom_name, "le") == 0) {				cards++;				if ((v = sparc_lance_init(dev, sdev, 0, 0)))					return v;				continue;			}			if (strcmp(sdev->prom_name, "ledma") == 0) {				cards++;				ledma = find_ledma(sdev);				if ((v = sparc_lance_init(dev, sdev->child,							  ledma, 0)))					return v;				continue;			}			if (strcmp(sdev->prom_name, "lebuffer") == 0){				cards++;				if ((v = sparc_lance_init(dev, sdev->child,							  0, sdev)))					return v;				continue;			}		} /* for each sbusdev */	} /* for each sbus */	if (!cards)		return -ENODEV;	return 0;}#endif /* !CONFIG_SUN4 */static void __exit sparc_lance_cleanup(void){	struct lance_private *lp;	while (root_lance_dev) {		lp = root_lance_dev->next_module;		unregister_netdev(root_lance_dev->dev);		lance_free_hwresources(root_lance_dev);		kfree(root_lance_dev->dev);		root_lance_dev = lp;	}}module_init(sparc_lance_probe);module_exit(sparc_lance_cleanup);

⌨️ 快捷键说明

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