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

📄 sunbmac.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	return res;}static int bigmac_close(struct 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;}/* Put a packet on the wire. */static int bigmac_start_xmit(struct sk_buff *skb, struct device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	int len, entry;	if(dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;	    		if (tickssofar < 40) {			return 1;		} else {			printk ("%s: transmit timed out, resetting\n", dev->name);			bp->enet_stats.tx_errors++;			bigmac_init(bp, 0);			dev->tbusy = 0;			dev->trans_start = jiffies;			dev_kfree_skb(skb);			return 0;		}	}	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {		printk("%s: Transmitter access conflict.\n", dev->name);		return 1;	}	if(!TX_BUFFS_AVAIL(bp))		return 1;#ifdef NEED_DMA_SYNCHRONIZATION#ifdef __sparc_v9__	if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {		struct sk_buff *new_skb = skb_copy(skb, GFP_DMA | GFP_ATOMIC);		if(!new_skb)			return 1;		dev_kfree_skb(skb);		skb = new_skb;	}#endif	mmu_sync_dma(sbus_dvma_addr(skb->data),		     skb->len, bp->bigmac_sbus_dev->my_bus);#endif	len = skb->len;	entry = bp->tx_new;	DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry));	/* Avoid a race... */	bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE;	bp->tx_skbs[entry] = skb;	bp->bmac_block->be_txd[entry].tx_addr = sbus_dvma_addr(skb->data);	bp->bmac_block->be_txd[entry].tx_flags =		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));	dev->trans_start = jiffies;	bp->tx_new = NEXT_TX(entry);	/* Get it going. */	bp->creg->ctrl = CREG_CTRL_TWAKEUP;	if(TX_BUFFS_AVAIL(bp))		dev->tbusy = 0;	return 0;}#ifndef __sparc_v9__static int sun4c_bigmac_start_xmit(struct sk_buff *skb, struct device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	struct bigmac_buffers *bbufs = bp->sun4c_buffers;	__u32 txbuf_dvma, bbufs_dvma = bp->s4c_buf_dvma;	unsigned char *txbuf;	int len, entry;	if(dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;	    		if (tickssofar < 40) {			return 1;		} else {			printk ("%s: transmit timed out, resetting\n", dev->name);			bp->enet_stats.tx_errors++;			bigmac_init(bp, 0);			dev->tbusy = 0;			dev->trans_start = jiffies;			return 0;		}	}	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {		printk("%s: Transmitter access conflict.\n", dev->name);		return 1;	}	if(!SUN4C_TX_BUFFS_AVAIL(bp))		return 1;	len = skb->len;	entry = bp->tx_new;	txbuf = &bbufs->tx_buf[entry][0];	txbuf_dvma = bbufs_dvma + bbuf_offset(tx_buf, entry);	memcpy(txbuf, skb->data, len);	/* Avoid a race... */	bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE;	bp->bmac_block->be_txd[entry].tx_addr = txbuf_dvma;	bp->bmac_block->be_txd[entry].tx_flags =		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));	bp->tx_new = NEXT_TX(entry);	/* Get it going. */	dev->trans_start = jiffies;	bp->creg->ctrl = CREG_CTRL_TWAKEUP;	dev_kfree_skb(skb);	if(SUN4C_TX_BUFFS_AVAIL(bp))		dev->tbusy = 0;	return 0;}#endifstatic struct enet_statistics *bigmac_get_stats(struct 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 device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	struct BIG_MAC_regs *bregs = bp->bregs;	struct dev_mc_list *dmi = dev->mc_list;	char *addrs;	int i, j, bit, byte;	u32 crc, poly = CRC_POLYNOMIAL_LE;	/* Disable the receiver.  The bit self-clears when	 * the operation is complete.	 */	bregs->rx_cfg &= ~(BIGMAC_RXCFG_ENABLE);	while((bregs->rx_cfg & BIGMAC_RXCFG_ENABLE) != 0)		udelay(20);	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {		bregs->htable0 = 0xffff;		bregs->htable1 = 0xffff;		bregs->htable2 = 0xffff;		bregs->htable3 = 0xffff;	} else if(dev->flags & IFF_PROMISC) {		bregs->rx_cfg |= BIGMAC_RXCFG_PMISC;	} 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);		}		bregs->htable0 = hash_table[0];		bregs->htable1 = hash_table[1];		bregs->htable2 = hash_table[2];		bregs->htable3 = hash_table[3];	}	/* Re-enable the receiver. */	bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE;}__initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev)){	static unsigned version_printed = 0;	struct bigmac *bp = 0;	unsigned char bsizes, bsizes_more;	int i, j, num_qranges, res = ENOMEM;	struct linux_prom_ranges qranges[8];	/* Get a new device struct for this interface. */	dev = init_etherdev(0, sizeof(struct bigmac));	if(version_printed++ == 0)		printk(version);	/* Report what we have found to the user. */	printk("%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_sbus_dev = qec_sdev;	bp->bigmac_sbus_dev = qec_sdev->child;	/* All further failures we find return this. */	res = ENODEV;	/* Verify the registers we expect, are actually there. */	if((bp->bigmac_sbus_dev->num_registers != 3) ||	   (bp->qec_sbus_dev->num_registers != 2)) {		printk("BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",		       bp->qec_sbus_dev->num_registers,		       bp->bigmac_sbus_dev->num_registers);		printk("BIGMAC: Would you like that for here or to go?\n");		goto fail_and_cleanup;	}	/* Fun with QEC ranges... */	if(bp->bigmac_sbus_dev->ranges_applied == 0) {		i = prom_getproperty(bp->qec_sbus_dev->prom_node, "ranges",				     (char *)&qranges[0], sizeof(qranges));		num_qranges = (i / sizeof(struct linux_prom_ranges));		/* Now, apply all the ranges for the BigMAC. */		for(j = 0; j < bp->bigmac_sbus_dev->num_registers; j++) {			int k;			for(k = 0; k < num_qranges; k++)				if(bp->bigmac_sbus_dev->reg_addrs[j].which_io ==				   qranges[k].ot_child_space)					break;			if(k >= num_qranges) {				printk("BigMAC: Aieee, bogus QEC range for space %08x\n",				       bp->bigmac_sbus_dev->reg_addrs[j].which_io);				goto fail_and_cleanup;			}			bp->bigmac_sbus_dev->reg_addrs[j].which_io = qranges[k].ot_parent_space;			bp->bigmac_sbus_dev->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;		}		/* Next, apply SBUS ranges on top of what we just changed. */		prom_apply_sbus_ranges(bp->bigmac_sbus_dev->my_bus,				       &bp->bigmac_sbus_dev->reg_addrs[0],				       bp->bigmac_sbus_dev->num_registers,				       bp->bigmac_sbus_dev);	}	/* Apply SBUS ranges for the QEC parent. */	prom_apply_sbus_ranges(bp->qec_sbus_dev->my_bus,			       &bp->qec_sbus_dev->reg_addrs[0],			       bp->qec_sbus_dev->num_registers,			       bp->qec_sbus_dev);	/* Map in QEC global control registers. */	bp->gregs = sparc_alloc_io(bp->qec_sbus_dev->reg_addrs[0].phys_addr,				   0,				   sizeof(struct qe_globreg),				   "BigMAC QEC Global Regs",				   bp->qec_sbus_dev->reg_addrs[0].which_io,				   0);	if(!bp->gregs) {		printk("BIGMAC: Cannot map QEC global registers.\n");		goto fail_and_cleanup;	}	/* Make sure QEC is in BigMAC mode. */	if((bp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_BMODE) {		printk("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_sbus_dev->prom_node,				    "burst-sizes",				    0xff);	bsizes_more = prom_getintdefault(bp->qec_sbus_dev->my_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 = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[0].phys_addr,				  0,				  sizeof(struct qe_creg),				  "BigMAC QEC Channel Regs",				  bp->bigmac_sbus_dev->reg_addrs[0].which_io,				  0);	if(!bp->creg) {		printk("BIGMAC: Cannot map QEC channel registers.\n");		goto fail_and_cleanup;	}	/* Map in the BigMAC control registers. */	bp->bregs = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[1].phys_addr,				   0,				   sizeof(struct BIG_MAC_regs),				   "BigMAC Primary Regs",				   bp->bigmac_sbus_dev->reg_addrs[1].which_io,				   0);	if(!bp->bregs) {		printk("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 = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[2].phys_addr,				   0,				   sizeof(struct bmac_tcvr),				   "BigMAC Transceiver Regs",				   bp->bigmac_sbus_dev->reg_addrs[2].which_io,				   0);	if(!bp->tregs) {		printk("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 = (struct bmac_init_block *)		sparc_dvma_malloc(PAGE_SIZE, "BigMAC Init Block",				  &bp->bblock_dvma);	/* Get the board revision of this BigMAC. */	bp->board_rev = prom_getintdefault(bp->bigmac_sbus_dev->prom_node,					   "board-version", 1);	/* If on sun4c, we use a static buffer pool, on sun4m we DMA directly	 * in and out of sk_buffs instead for speed and one copy to userspace.	 */#ifndef __sparc_v9__	if(sparc_cpu_model == sun4c)		bp->sun4c_buffers = (struct bigmac_buffers *)			sparc_dvma_malloc(sizeof(struct bigmac_buffers),					  "BigMAC Bufs",					  &bp->s4c_buf_dvma);	else#endif		bp->sun4c_buffers = 0;	/* 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;	/* Choose transmit routine based upon buffering scheme. */#ifndef __sparc_v9__	if(sparc_cpu_model == sun4c)		dev->hard_start_xmit = &sun4c_bigmac_start_xmit;	else#endif		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;	/* Finish net device registration. */	dev->irq = bp->bigmac_sbus_dev->irqs[0];	dev->dma = 0;	ether_setup(dev);#ifdef MODULE	/* Put us into the list of instances attached for later module unloading. */	bp->next_module = root_bigmac_dev;	root_bigmac_dev = bp;#endif	return 0;fail_and_cleanup:	/* Something went wrong, undo whatever we did so far. */	if(bp) {		/* Free register mappings if any. */		if(bp->gregs)			sparc_free_io(bp->gregs, sizeof(struct qe_globreg));		if(bp->creg)			sparc_free_io(bp->creg, sizeof(struct qe_creg));		if(bp->bregs)			sparc_free_io(bp->bregs, sizeof(struct BIG_MAC_regs));		if(bp->tregs)			sparc_free_io(bp->tregs, sizeof(struct bmac_tcvr));		/* XXX todo, bmac_block and sun4c_buffers */		/* Free the BigMAC softc. */		kfree(bp);		dev->priv = 0;	}	return res;	/* Return error code. */}__initfunc(int bigmac_probe(struct device *dev)){	struct linux_sbus *bus;	struct linux_sbus_device *sdev = 0;	static int called = 0;	int cards = 0, v;	if(called)		return ENODEV;	called++;	for_each_sbus(bus) {		for_each_sbusdev(sdev, bus) {			if(cards) dev = NULL;			/* QEC can be the parent of either QuadEthernet or			 * a BigMAC.  We want the latter.			 */			if(!strcmp(sdev->prom_name, "qec") && sdev->child &&			   !strcmp(sdev->child->prom_name, "be")) {				cards++;				if((v = bigmac_ether_init(dev, sdev)))				   return v;			}		}	}	if(!cards)		return ENODEV;	return 0;}#ifdef MODULEintinit_module(void){	root_bigmac_dev = NULL;	return bigmac_probe(NULL);}voidcleanup_module(void){	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_bigmac_dev) {		struct bigmac *bp = root_bigmac_dev;		struct bigmac *bp_nxt = root_bigmac_dev->next_module;		sparc_free_io(bp->gregs, sizeof(struct qe_globreg));		sparc_free_io(bp->creg, sizeof(struct qe_creg));		sparc_free_io(bp->bregs, sizeof(struct BIG_MAC_regs));		sparc_free_io(bp->tregs, sizeof(struct bmac_tcvr));		/* XXX todo, bmac_block and sun4c_buffers */		unregister_netdev(bp->dev);		kfree(bp->dev);		root_bigmac_dev = bp_nxt;	}}#endif /* MODULE */

⌨️ 快捷键说明

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