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

📄 bmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (status & TxUnderrun) bp->stats.tx_fifo_errors++;	if (status & TxNormalCollExp) bp->stats.collisions++;}/* * Procedure for reading EEPROM */#define SROMAddressLength	5#define DataInOn		0x0008#define DataInOff		0x0000#define Clk			0x0002#define ChipSelect		0x0001#define SDIShiftCount		3#define SD0ShiftCount		2#define	DelayValue		1000	/* number of microseconds */#define SROMStartOffset		10	/* this is in words */#define SROMReadCount		3	/* number of words to read from SROM */#define SROMAddressBits		6#define EnetAddressOffset	20static unsigned charbmac_clock_out_bit(struct net_device *dev){	unsigned short         data;	unsigned short         val;	bmwrite(dev, SROMCSR, ChipSelect | Clk);	udelay(DelayValue);	data = bmread(dev, SROMCSR);	udelay(DelayValue);	val = (data >> SD0ShiftCount) & 1;	bmwrite(dev, SROMCSR, ChipSelect);	udelay(DelayValue);	return val;}static voidbmac_clock_in_bit(struct net_device *dev, unsigned int val){	unsigned short data;	if (val != 0 && val != 1) return;	data = (val << SDIShiftCount);	bmwrite(dev, SROMCSR, data | ChipSelect  );	udelay(DelayValue);	bmwrite(dev, SROMCSR, data | ChipSelect | Clk );	udelay(DelayValue);	bmwrite(dev, SROMCSR, data | ChipSelect);	udelay(DelayValue);}static voidreset_and_select_srom(struct net_device *dev){	/* first reset */	bmwrite(dev, SROMCSR, 0);	udelay(DelayValue);	/* send it the read command (110) */	bmac_clock_in_bit(dev, 1);	bmac_clock_in_bit(dev, 1);	bmac_clock_in_bit(dev, 0);}static unsigned shortread_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len){	unsigned short data, val;	int i;	/* send out the address we want to read from */	for (i = 0; i < addr_len; i++)	{		val = addr >> (addr_len-i-1);		bmac_clock_in_bit(dev, val & 1);	}	/* Now read in the 16-bit data */	data = 0;	for (i = 0; i < 16; i++)	{		val = bmac_clock_out_bit(dev);		data <<= 1;		data |= val;	}	bmwrite(dev, SROMCSR, 0);	return data;}/* * It looks like Cogent and SMC use different methods for calculating * checksums. What a pain.. */static intbmac_verify_checksum(struct net_device *dev){	unsigned short data, storedCS;	reset_and_select_srom(dev);	data = read_srom(dev, 3, SROMAddressBits);	storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);	return 0;}static voidbmac_get_station_address(struct net_device *dev, unsigned char *ea){	int i;	unsigned short data;	for (i = 0; i < 6; i++)			{			reset_and_select_srom(dev);			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);			ea[2*i]   = bitrev(data & 0x0ff);			ea[2*i+1] = bitrev((data >> 8) & 0x0ff);		}}static int bmac_reset_and_enable(struct net_device *dev, int enable){	struct bmac_data *bp = dev->priv;	unsigned long flags;	struct sk_buff *skb;	unsigned char *data;	save_flags(flags); cli();	bp->reset_and_enabled = 0;	bmac_reset_chip(dev);	if (enable) {		if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp))			return 0;		if (!bmac_init_chip(dev))			return 0;		bmac_start_chip(dev);		bmwrite(dev, INTDISABLE, EnableNormal);		bp->reset_and_enabled = 1;		/*		 * It seems that the bmac can't receive until it's transmitted		 * a packet.  So we give it a dummy packet to transmit.		 */		skb = dev_alloc_skb(ETHERMINPACKET);		data = skb_put(skb, ETHERMINPACKET);		memset(data, 0, ETHERMINPACKET);		memcpy(data, dev->dev_addr, 6);		memcpy(data+6, dev->dev_addr, 6);		bmac_transmit_packet(skb, dev);	}	restore_flags(flags);	return 1;}static int __init bmac_probe(void){	struct device_node *bmac;	for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next)		bmac_probe1(bmac, 0);	for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0;	     bmac = bmac->next)		bmac_probe1(bmac, 1);	if (bmac_devs != 0) {		proc_net_create ("bmac", 0, bmac_proc_info);#ifdef CONFIG_PMAC_PBOOK		pmu_register_sleep_notifier(&bmac_sleep_notifier);#endif	}	return 0;}static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus){	int j, rev, ret;	struct bmac_data *bp;	unsigned char *addr;	struct net_device *dev;	if (bmac->n_addrs != 3 || bmac->n_intrs != 3) {		printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n",		       bmac->full_name);		return;	}	addr = get_property(bmac, "mac-address", NULL);	if (addr == NULL) {		addr = get_property(bmac, "local-mac-address", NULL);		if (addr == NULL) {			printk(KERN_ERR "Can't get mac-address for BMAC %s\n",			       bmac->full_name);			return;		}	}	dev = init_etherdev(NULL, PRIV_BYTES);	if (!dev) {		printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n",		       bmac->full_name);		return;	}	SET_MODULE_OWNER(dev);	dev->base_addr = (unsigned long)		ioremap(bmac->addrs[0].address, bmac->addrs[0].size);	if (!dev->base_addr)		goto err_out;	dev->irq = bmac->intrs[0].line;	bmwrite(dev, INTDISABLE, DisableAll);	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));	rev = addr[0] == 0 && addr[1] == 0xA0;	for (j = 0; j < 6; ++j) {		dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);	}	XXDEBUG((", base_addr=%#0lx", dev->base_addr));	printk("\n");	dev->open = bmac_open;	dev->stop = bmac_close;	dev->hard_start_xmit = bmac_output;	dev->get_stats = bmac_stats;	dev->set_multicast_list = bmac_set_multicast;	dev->set_mac_address = bmac_set_address;	bmac_get_station_address(dev, addr);	if (bmac_verify_checksum(dev) != 0)		goto err_out_iounmap;	bp = (struct bmac_data *) dev->priv;	bp->is_bmac_plus = is_bmac_plus;	bp->tx_dma = (volatile struct dbdma_regs *)		ioremap(bmac->addrs[1].address, bmac->addrs[1].size);	if (!bp->tx_dma)		goto err_out_iounmap;	bp->tx_dma_intr = bmac->intrs[1].line;	bp->rx_dma = (volatile struct dbdma_regs *)		ioremap(bmac->addrs[2].address, bmac->addrs[2].size);	if (!bp->rx_dma)		goto err_out_iounmap_tx;	bp->rx_dma_intr = bmac->intrs[2].line;	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);	skb_queue_head_init(bp->queue);	bp->node = bmac;	memset((char *) bp->tx_cmds, 0,	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));	/*     init_timer(&bp->tx_timeout); */	/*     bp->timeout_active = 0; */	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);	if (ret) {		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);		goto err_out_iounmap_rx;	}	ret = request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev);	if (ret) {		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line);		goto err_out_irq0;	}	ret = request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);	if (ret) {		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line);		goto err_out_irq1;	}	bp->next_bmac = bmac_devs;	bmac_devs = dev;	return;err_out_irq1:	free_irq(bmac->intrs[1].line, dev);err_out_irq0:	free_irq(dev->irq, dev);err_out_iounmap_rx:	iounmap((void *)bp->rx_dma);err_out_iounmap_tx:	iounmap((void *)bp->tx_dma);err_out_iounmap:	iounmap((void *)dev->base_addr);err_out:	unregister_netdev(dev);	kfree(dev);}static int bmac_open(struct net_device *dev){	/* XXDEBUG(("bmac: enter open\n")); */	/* reset the chip */	if (!bmac_reset_and_enable(dev, 1))		return -ENOMEM;	dev->flags |= IFF_RUNNING;	return 0;}static int bmac_close(struct net_device *dev){	struct bmac_data *bp = (struct bmac_data *) dev->priv;	volatile struct dbdma_regs *rd = bp->rx_dma;	volatile struct dbdma_regs *td = bp->tx_dma;	unsigned short config;	int i;	dev->flags &= ~(IFF_UP | IFF_RUNNING);	/* disable rx and tx */	config = bmread(dev, RXCFG);	bmwrite(dev, RXCFG, (config & ~RxMACEnable));	config = bmread(dev, TXCFG);	bmwrite(dev, TXCFG, (config & ~TxMACEnable));	bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */	/* disable rx and tx dma */	st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */	st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */	/* free some skb's */	XXDEBUG(("bmac: free rx bufs\n"));	for (i=0; i<N_RX_RING; i++) {		if (bp->rx_bufs[i] != NULL) {			dev_kfree_skb(bp->rx_bufs[i]);			bp->rx_bufs[i] = NULL;		}	}	bp->rx_allocated = 0;	XXDEBUG(("bmac: free tx bufs\n"));	for (i = 0; i<N_TX_RING; i++) {		if (bp->tx_bufs[i] != NULL) {			dev_kfree_skb(bp->tx_bufs[i]);			bp->tx_bufs[i] = NULL;		}	}	bp->reset_and_enabled = 0;	XXDEBUG(("bmac: all bufs freed\n"));	return 0;}static voidbmac_start(struct net_device *dev){	struct bmac_data *bp = dev->priv;	int i;	struct sk_buff *skb;	unsigned long flags;	save_flags(flags); cli();	while (1) {		i = bp->tx_fill + 1;		if (i >= N_TX_RING)			i = 0;		if (i == bp->tx_empty)			break;		skb = skb_dequeue(bp->queue);		if (skb == NULL)			break;		bmac_transmit_packet(skb, dev);	}	restore_flags(flags);}static intbmac_output(struct sk_buff *skb, struct net_device *dev){	struct bmac_data *bp = dev->priv;	skb_queue_tail(bp->queue, skb);	bmac_start(dev);	return 0;}static void bmac_tx_timeout(unsigned long data){	struct net_device *dev = (struct net_device *) data;	struct bmac_data *bp = (struct bmac_data *) dev->priv;	volatile struct dbdma_regs *td = bp->tx_dma;	volatile struct dbdma_regs *rd = bp->rx_dma;	volatile struct dbdma_cmd *cp;	unsigned long flags;	unsigned short config, oldConfig;	int i;	XXDEBUG(("bmac: tx_timeout called\n"));	save_flags(flags); cli();	bp->timeout_active = 0;	/* update various counters *//*     	bmac_handle_misc_intrs(bp, 0); */	cp = &bp->tx_cmds[bp->tx_empty];/*	XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", *//* 	   ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, *//* 	   mb->pr, mb->xmtfs, mb->fifofc)); */	/* turn off both tx and rx and reset the chip */	config = bmread(dev, RXCFG);	bmwrite(dev, RXCFG, (config & ~RxMACEnable));	config = bmread(dev, TXCFG);	bmwrite(dev, TXCFG, (config & ~TxMACEnable));	out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));	printk(KERN_ERR "bmac: transmit timeout - resetting\n");	bmac_reset_chip(dev);	/* restart rx dma */	cp = bus_to_virt(ld_le32(&rd->cmdptr));	out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));	out_le16(&cp->xfer_status, 0);	out_le32(&rd->cmdptr, virt_to_bus(cp));	out_le32(&rd->control, DBDMA_SET(RUN|WAKE));	/* fix up the transmit side */	XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",		 bp->tx_empty, bp->tx_fill, bp->tx_fullup));	i = bp->tx_empty;	++bp->stats.tx_errors;	if (i != bp->tx_fill) {		dev_kfree_skb(bp->tx_bufs[i]);		bp->tx_bufs[i] = NULL;		if (++i >= N_TX_RING) i = 0;		bp->tx_empty = i;	}	bp->tx_fullup = 0;	netif_wake_queue(dev);	if (i != bp->tx_fill) {		cp = &bp->tx_cmds[i];		out_le16(&cp->xfer_status, 0);		out_le16(&cp->command, OUTPUT_LAST);		out_le32(&td->cmdptr, virt_to_bus(cp));		out_le32(&td->control, DBDMA_SET(RUN));		/* 	bmac_set_timeout(dev); */		XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));	}	/* turn it back on */	oldConfig = bmread(dev, RXCFG);			bmwrite(dev, RXCFG, oldConfig | RxMACEnable );	oldConfig = bmread(dev, TXCFG);			bmwrite(dev, TXCFG, oldConfig | TxMACEnable );	restore_flags(flags);}#if 0static void dump_dbdma(volatile struct dbdma_cmd *cp,int count){	int i,*ip;		for (i=0;i< count;i++) {		ip = (int*)(cp+i);			printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",		       ld_le32(ip+0),		       ld_le32(ip+1),		       ld_le32(ip+2),		       ld_le32(ip+3));	}}#endifstatic intbmac_proc_info(char *buffer, char **start, off_t offset, int length){	int len = 0;	off_t pos   = 0;	off_t begin = 0;	int i;	if (bmac_devs == NULL)		return (-ENOSYS);	len += sprintf(buffer, "BMAC counters & registers\n");	for (i = 0; i<N_REG_ENTRIES; i++) {		len += sprintf(buffer + len, "%s: %#08x\n",			       reg_entries[i].name,			       bmread(bmac_devs, reg_entries[i].reg_offset));		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > offset+length) break;	}	*start = buffer + (offset - begin);	len -= (offset - begin);	if (len > length) len = length;	return len;}MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");static void __exit bmac_cleanup (void){	struct bmac_data *bp;	struct net_device *dev;	if (bmac_devs == 0)		return;#ifdef CONFIG_PMAC_PBOOK	pmu_unregister_sleep_notifier(&bmac_sleep_notifier);#endif	proc_net_remove("bmac");	do {		dev = bmac_devs;		bp = (struct bmac_data *) dev->priv;		bmac_devs = bp->next_bmac;		free_irq(dev->irq, dev);		free_irq(bp->tx_dma_intr, dev);		free_irq(bp->rx_dma_intr, dev);		unregister_netdev(dev);		kfree(dev);	} while (bmac_devs != NULL);}module_init(bmac_probe);module_exit(bmac_cleanup);

⌨️ 快捷键说明

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