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

📄 sunbmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		this = &rxbase[elem];	}	bp->rx_new = elem;	if (drops)		printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);}static void bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct bigmac *bp = (struct bigmac *) dev_id;	u32 qec_status, bmac_status;	DIRQ(("bigmac_interrupt: "));	/* Latch status registers now. */	bmac_status = sbus_readl(bp->creg + CREG_STAT);	qec_status = sbus_readl(bp->gregs + GLOB_STAT);	DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status));	if ((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) ||	   (bmac_status & CREG_STAT_ERRORS))		bigmac_is_medium_rare(bp, qec_status, bmac_status);	if (bmac_status & CREG_STAT_TXIRQ)		bigmac_tx(bp);	if (bmac_status & CREG_STAT_RXIRQ)		bigmac_rx(bp);}static int bigmac_open(struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	int res;	if (request_irq(dev->irq, &bigmac_interrupt,			SA_SHIRQ, "BIG MAC", (void *) bp)) {		printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);		return -EAGAIN;	}	init_timer(&bp->bigmac_timer);	res = bigmac_init(bp, 0);	if (!res) {		MOD_INC_USE_COUNT;	}	return res;}static int bigmac_close(struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	del_timer(&bp->bigmac_timer);	bp->timer_state = asleep;	bp->timer_ticks = 0;	bigmac_stop(bp);	bigmac_clean_rings(bp);	free_irq(dev->irq, (void *)bp);	MOD_DEC_USE_COUNT;	return 0;}static void bigmac_tx_timeout(struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	bigmac_init(bp, 0);	netif_wake_queue(dev);}/* Put a packet on the wire. */static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	int len, entry;	u32 mapping;	len = skb->len;	mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);	/* Avoid a race... */	spin_lock_irq(&bp->lock);	entry = bp->tx_new;	DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry));	bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE;	bp->tx_skbs[entry] = skb;	bp->bmac_block->be_txd[entry].tx_addr = mapping;	bp->bmac_block->be_txd[entry].tx_flags =		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));	bp->tx_new = NEXT_TX(entry);	if (TX_BUFFS_AVAIL(bp) <= 0)		netif_stop_queue(dev);	spin_unlock_irq(&bp->lock);	/* Get it going. */	sbus_writel(CREG_CTRL_TWAKEUP, bp->creg + CREG_CTRL);	dev->trans_start = jiffies;	return 0;}static struct net_device_stats *bigmac_get_stats(struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	bigmac_get_counters(bp, bp->bregs);	return &bp->enet_stats;}#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */static void bigmac_set_multicast(struct net_device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	unsigned long bregs = bp->bregs;	struct dev_mc_list *dmi = dev->mc_list;	char *addrs;	int i, j, bit, byte;	u32 tmp, crc, poly = CRC_POLYNOMIAL_LE;	/* Disable the receiver.  The bit self-clears when	 * the operation is complete.	 */	tmp = sbus_readl(bregs + BMAC_RXCFG);	tmp &= ~(BIGMAC_RXCFG_ENABLE);	sbus_writel(tmp, bregs + BMAC_RXCFG);	while ((sbus_readl(bregs + BMAC_RXCFG) & BIGMAC_RXCFG_ENABLE) != 0)		udelay(20);	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {		sbus_writel(0xffff, bregs + BMAC_HTABLE0);		sbus_writel(0xffff, bregs + BMAC_HTABLE1);		sbus_writel(0xffff, bregs + BMAC_HTABLE2);		sbus_writel(0xffff, bregs + BMAC_HTABLE3);	} else if (dev->flags & IFF_PROMISC) {		tmp = sbus_readl(bregs + BMAC_RXCFG);		tmp |= BIGMAC_RXCFG_PMISC;		sbus_writel(tmp, bregs + BMAC_RXCFG);	} else {		u16 hash_table[4];		for (i = 0; i < 4; i++)			hash_table[i] = 0;		for (i = 0; i < dev->mc_count; i++) {			addrs = dmi->dmi_addr;			dmi = dmi->next;			if (!(*addrs & 1))				continue;			crc = 0xffffffffU;			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 >>= 26;			hash_table[crc >> 4] |= 1 << (crc & 0xf);		}		sbus_writel(hash_table[0], bregs + BMAC_HTABLE0);		sbus_writel(hash_table[1], bregs + BMAC_HTABLE1);		sbus_writel(hash_table[2], bregs + BMAC_HTABLE2);		sbus_writel(hash_table[3], bregs + BMAC_HTABLE3);	}	/* Re-enable the receiver. */	tmp = sbus_readl(bregs + BMAC_RXCFG);	tmp |= BIGMAC_RXCFG_ENABLE;	sbus_writel(tmp, bregs + BMAC_RXCFG);}static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec_sdev){	static int version_printed = 0;	struct bigmac *bp = 0;	u8 bsizes, bsizes_more;	int i, res = ENOMEM;	/* Get a new device struct for this interface. */	dev = init_etherdev(0, sizeof(struct bigmac));	if (version_printed++ == 0)		printk(KERN_INFO "%s", version);	/* Report what we have found to the user. */	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);	dev->base_addr = (long) qec_sdev;	for (i = 0; i < 6; i++)		printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i],		       i == 5 ? ' ' : ':');	printk("\n");	/* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */	bp = (struct bigmac *) dev->priv;	bp->qec_sdev = qec_sdev;	bp->bigmac_sdev = qec_sdev->child;	spin_lock_init(&bp->lock);	/* All further failures we find return this. */	res = ENODEV;	/* Verify the registers we expect, are actually there. */	if ((bp->bigmac_sdev->num_registers != 3) ||	   (bp->qec_sdev->num_registers != 2)) {		printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",		       bp->qec_sdev->num_registers,		       bp->bigmac_sdev->num_registers);		printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");		goto fail_and_cleanup;	}	/* Map in QEC global control registers. */	bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0,				 GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");	if (!bp->gregs) {		printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");		goto fail_and_cleanup;	}	/* Make sure QEC is in BigMAC mode. */	if ((sbus_readl(bp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_BMODE) {		printk(KERN_ERR "BigMAC: AIEEE, QEC is not in BigMAC mode!\n");		goto fail_and_cleanup;	}	/* Reset the QEC. */	if (qec_global_reset(bp->gregs))		goto fail_and_cleanup;	/* Get supported SBUS burst sizes. */	bsizes = prom_getintdefault(bp->qec_sdev->prom_node,				    "burst-sizes",				    0xff);	bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node,					 "burst-sizes",					 0xff);	bsizes &= 0xff;	if (bsizes_more != 0xff)		bsizes &= bsizes_more;	if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||	    (bsizes & DMA_BURST32) == 0)		bsizes = (DMA_BURST32 - 1);	bp->bigmac_bursts = bsizes;	/* Perform QEC initialization. */	qec_init(bp);	/* Map in the BigMAC channel registers. */	bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,				CREG_REG_SIZE, "BigMAC QEC Channel Regs");	if (!bp->creg) {		printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");		goto fail_and_cleanup;	}	/* Map in the BigMAC control registers. */	bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,				 BMAC_REG_SIZE, "BigMAC Primary Regs");	if (!bp->bregs) {		printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");		goto fail_and_cleanup;	}	/* Map in the BigMAC transceiver registers, this is how you poke at	 * the BigMAC's PHY.	 */	bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,				 TCVR_REG_SIZE, "BigMAC Transceiver Regs");	if (!bp->tregs) {		printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");		goto fail_and_cleanup;	}	/* Stop the BigMAC. */	bigmac_stop(bp);	/* Allocate transmit/receive descriptor DVMA block. */	bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,					       PAGE_SIZE,					       &bp->bblock_dvma);	if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {		printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");		goto fail_and_cleanup;	}	/* Get the board revision of this BigMAC. */	bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node,					   "board-version", 1);	/* Init auto-negotiation timer state. */	init_timer(&bp->bigmac_timer);	bp->timer_state = asleep;	bp->timer_ticks = 0;	/* Backlink to generic net device struct. */	bp->dev = dev;	/* Set links to our BigMAC open and close routines. */	dev->open = &bigmac_open;	dev->stop = &bigmac_close;	dev->hard_start_xmit = &bigmac_start_xmit;	/* Set links to BigMAC statistic and multi-cast loading code. */	dev->get_stats = &bigmac_get_stats;	dev->set_multicast_list = &bigmac_set_multicast;	dev->tx_timeout = &bigmac_tx_timeout;	dev->watchdog_timeo = 5*HZ;	/* Finish net device registration. */	dev->irq = bp->bigmac_sdev->irqs[0];	dev->dma = 0;	ether_setup(dev);	/* Put us into the list of instances attached for later driver	 * exit.	 */	bp->next_module = root_bigmac_dev;	root_bigmac_dev = bp;	return 0;fail_and_cleanup:	/* Something went wrong, undo whatever we did so far. */	if (bp) {		/* Free register mappings if any. */		if (bp->gregs)			sbus_iounmap(bp->gregs, GLOB_REG_SIZE);		if (bp->creg)			sbus_iounmap(bp->creg, CREG_REG_SIZE);		if (bp->bregs)			sbus_iounmap(bp->bregs, BMAC_REG_SIZE);		if (bp->tregs)			sbus_iounmap(bp->tregs, TCVR_REG_SIZE);		if (bp->bmac_block)			sbus_free_consistent(bp->bigmac_sdev,					     PAGE_SIZE,					     bp->bmac_block,					     bp->bblock_dvma);		/* Free the BigMAC softc. */		kfree(bp);		dev->priv = 0;	}	return res;	/* Return error code. */}/* QEC can be the parent of either QuadEthernet or * a BigMAC.  We want the latter. */static int __init bigmac_match(struct sbus_dev *sdev){	struct sbus_dev *child = sdev->child;	if (strcmp(sdev->prom_name, "qec") != 0)		return 0;	if (child == NULL)		return 0;	if (strcmp(child->prom_name, "be") != 0)		return 0;	return 1;}static int __init bigmac_probe(void){	struct net_device *dev = NULL;	struct sbus_bus *sbus;	struct sbus_dev *sdev = 0;	static int called = 0;	int cards = 0, v;	root_bigmac_dev = NULL;	if (called)		return -ENODEV;	called++;	for_each_sbus(sbus) {		for_each_sbusdev(sdev, sbus) {			if (cards)				dev = NULL;			if (bigmac_match(sdev)) {				cards++;				if ((v = bigmac_ether_init(dev, sdev)))					return v;			}		}	}	if (!cards)		return -ENODEV;	return 0;}static void __exit bigmac_cleanup(void){	while (root_bigmac_dev) {		struct bigmac *bp = root_bigmac_dev;		struct bigmac *bp_nxt = root_bigmac_dev->next_module;		sbus_iounmap(bp->gregs, GLOB_REG_SIZE);		sbus_iounmap(bp->creg, CREG_REG_SIZE);		sbus_iounmap(bp->bregs, BMAC_REG_SIZE);		sbus_iounmap(bp->tregs, TCVR_REG_SIZE);		sbus_free_consistent(bp->bigmac_sdev,				     PAGE_SIZE,				     bp->bmac_block,				     bp->bblock_dvma);		unregister_netdev(bp->dev);		kfree(bp->dev);		root_bigmac_dev = bp_nxt;	}}module_init(bigmac_probe);module_exit(bigmac_cleanup);

⌨️ 快捷键说明

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