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

📄 z85230.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	 *	DMA interrupts	 */	 	/*	 *	Set up the DMA configuration	 */		 	flags=claim_dma_lock();	 	disable_dma(c->rxdma);	clear_dma_ff(c->rxdma);	set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);	set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));	set_dma_count(c->rxdma, c->mtu);	enable_dma(c->rxdma);	disable_dma(c->txdma);	clear_dma_ff(c->txdma);	set_dma_mode(c->txdma, DMA_MODE_WRITE);	disable_dma(c->txdma);		release_dma_lock(flags);		/*	 *	Select the DMA interrupt handlers	 */	c->rxdma_on = 1;	c->txdma_on = 1;	c->tx_dma_used = 1;	 	c->irqs = &z8530_dma_sync;	z8530_rtsdtr(c,1);	write_zsreg(c, R3, c->regs[R3]|RxENABLE);	return 0;}EXPORT_SYMBOL(z8530_sync_dma_open);int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c){	u8 chk;	unsigned long flags;		c->irqs = &z8530_nop;	c->max = 0;	c->sync = 0;		/*	 *	Disable the PC DMA channels	 */		flags=claim_dma_lock(); 	disable_dma(c->rxdma);	clear_dma_ff(c->rxdma);		c->rxdma_on = 0;		disable_dma(c->txdma);	clear_dma_ff(c->txdma);	release_dma_lock(flags);		c->txdma_on = 0;	c->tx_dma_used = 0;	/*	 *	Disable DMA control mode	 */	 	c->regs[R1]&= ~WT_RDY_ENAB;	write_zsreg(c, R1, c->regs[R1]);            	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);	c->regs[R1]|= INT_ALL_Rx;	write_zsreg(c, R1, c->regs[R1]);	c->regs[R14]&= ~DTRREQ;	write_zsreg(c, R14, c->regs[R14]);   		if(c->rx_buf[0])	{		kfree(c->rx_buf[0]);		c->rx_buf[0]=NULL;	}	if(c->rx_buf[1])	{		kfree(c->rx_buf[1]);		c->rx_buf[1]=NULL;	}	if(c->tx_dma_buf[0])	{		kfree(c->tx_dma_buf[0]);		c->tx_dma_buf[0]=NULL;	}	if(c->tx_dma_buf[1])	{		kfree(c->tx_dma_buf[1]);		c->tx_dma_buf[1]=NULL;	}	chk=read_zsreg(c,R0);	write_zsreg(c, R3, c->regs[R3]);	z8530_rtsdtr(c,0);	return 0;}EXPORT_SYMBOL(z8530_sync_dma_close);int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c){	printk("Opening sync interface for TX-DMA\n");	c->sync = 1;	c->mtu = dev->mtu+64;	c->count = 0;	c->skb = NULL;	c->skb2 = NULL;		/*	 *	Load the PIO receive ring	 */	z8530_rx_done(c);	z8530_rx_done(c); 	/*	 *	Load the DMA interfaces up	 */	c->rxdma_on = 0;	c->txdma_on = 0;		c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);	if(c->tx_dma_buf[0]==NULL)	{		kfree(c->rx_buf[0]);		kfree(c->rx_buf[1]);		c->rx_buf[0]=NULL;		return -ENOBUFS;	}	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);	if(c->tx_dma_buf[1]==NULL)	{		kfree(c->tx_dma_buf[0]);		kfree(c->rx_buf[0]);		kfree(c->rx_buf[1]);		c->rx_buf[0]=NULL;		c->rx_buf[1]=NULL;		c->tx_dma_buf[0]=NULL;		return -ENOBUFS;	}	c->tx_dma_used=0;	c->dma_num=0;	c->dma_ready=1;	c->dma_tx = 1; 	/*	 *	Enable DMA control mode	 */ 	/*	 *	TX DMA via DIR/REQ 	 */	c->regs[R14]|= DTRREQ;	write_zsreg(c, R14, c->regs[R14]);     		/*	 *	Set up the DMA configuration	 */		 	disable_dma(c->txdma);	clear_dma_ff(c->txdma);	set_dma_mode(c->txdma, DMA_MODE_WRITE);	disable_dma(c->txdma);		/*	 *	Select the DMA interrupt handlers	 */	c->rxdma_on = 0;	c->txdma_on = 1;	c->tx_dma_used = 1;	 	c->irqs = &z8530_txdma_sync;	printk("Loading RX\n");	z8530_rtsdtr(c,1);	printk("Rx interrupts ON\n");		write_zsreg(c, R3, c->regs[R3]|RxENABLE);	return 0;}EXPORT_SYMBOL(z8530_sync_txdma_open);	int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c){	u8 chk;	c->irqs = &z8530_nop;	c->max = 0;	c->sync = 0;		/*	 *	Disable the PC DMA channels	 */	 	disable_dma(c->txdma);	clear_dma_ff(c->txdma);	c->txdma_on = 0;	c->tx_dma_used = 0;	/*	 *	Disable DMA control mode	 */	 	c->regs[R1]&= ~WT_RDY_ENAB;	write_zsreg(c, R1, c->regs[R1]);            	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);	c->regs[R1]|= INT_ALL_Rx;	write_zsreg(c, R1, c->regs[R1]);	c->regs[R14]&= ~DTRREQ;	write_zsreg(c, R14, c->regs[R14]);   		if(c->tx_dma_buf[0])	{		kfree(c->tx_dma_buf[0]);		c->tx_dma_buf[0]=NULL;	}	if(c->tx_dma_buf[1])	{		kfree(c->tx_dma_buf[1]);		c->tx_dma_buf[1]=NULL;	}	chk=read_zsreg(c,R0);	write_zsreg(c, R3, c->regs[R3]);	z8530_rtsdtr(c,0);	return 0;}EXPORT_SYMBOL(z8530_sync_txdma_close);/* *	Describe a Z8530 in a standard format. We must pass the I/O as *	the port offset isnt predictable. The main reason for this function *	is to try and get a common format of report. */static char *z8530_type_name[]={	"Z8530",	"Z85C30",	"Z85230"};void z8530_describe(struct z8530_dev *dev, char *mapping, int io){	printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",		dev->name, 		z8530_type_name[dev->type],		mapping,		Z8530_PORT_OF(io),		dev->irq);}EXPORT_SYMBOL(z8530_describe);/* *	Configure up a Z8530 */ int z8530_init(struct z8530_dev *dev){	/* NOP the interrupt handlers first - we might get a	   floating IRQ transition when we reset the chip */	dev->chanA.irqs=&z8530_nop;	dev->chanB.irqs=&z8530_nop;	/* Reset the chip */	write_zsreg(&dev->chanA, R9, 0xC0);	udelay(200);	/* Now check its valid */	write_zsreg(&dev->chanA, R12, 0xAA);	if(read_zsreg(&dev->chanA, R12)!=0xAA)		return -ENODEV;	write_zsreg(&dev->chanA, R12, 0x55);	if(read_zsreg(&dev->chanA, R12)!=0x55)		return -ENODEV;			dev->type=Z8530;		/*	 *	See the application note.	 */	 	write_zsreg(&dev->chanA, R15, 0x01);		/*	 *	If we can set the low bit of R15 then	 *	the chip is enhanced.	 */	 	if(read_zsreg(&dev->chanA, R15)==0x01)	{		/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */		/* Put a char in the fifo */		write_zsreg(&dev->chanA, R8, 0);		if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)			dev->type = Z85230;	/* Has a FIFO */		else			dev->type = Z85C30;	/* Z85C30, 1 byte FIFO */	}			/*	 *	The code assumes R7' and friends are	 *	off. Use write_zsext() for these and keep	 *	this bit clear.	 */	 	write_zsreg(&dev->chanA, R15, 0);			/*	 *	At this point it looks like the chip is behaving	 */	 	memcpy(dev->chanA.regs, reg_init, 16);	memcpy(dev->chanB.regs, reg_init ,16);		return 0;}EXPORT_SYMBOL(z8530_init);int z8530_shutdown(struct z8530_dev *dev){	/* Reset the chip */	dev->chanA.irqs=&z8530_nop;	dev->chanB.irqs=&z8530_nop;	write_zsreg(&dev->chanA, R9, 0xC0);	udelay(100);	return 0;}EXPORT_SYMBOL(z8530_shutdown);/* *	Load a Z8530 channel up from the system data *	We use +16 to indicate the 'prime' registers */int z8530_channel_load(struct z8530_channel *c, u8 *rtable){	while(*rtable!=255)	{		int reg=*rtable++;		if(reg>0x0F)			write_zsreg(c, R15, c->regs[15]|1);		write_zsreg(c, reg&0x0F, *rtable);		if(reg>0x0F)			write_zsreg(c, R15, c->regs[15]&~1);		c->regs[reg]=*rtable++;	}	c->rx_function=z8530_null_rx;	c->skb=NULL;	c->tx_skb=NULL;	c->tx_next_skb=NULL;	c->mtu=1500;	c->max=0;	c->count=0;	c->status=0;	/* Fixme - check DCD now */	c->sync=1;	write_zsreg(c, R3, c->regs[R3]|RxENABLE);	return 0;}EXPORT_SYMBOL(z8530_channel_load);/* *	Higher level shovelling - transmit chains */static void z8530_tx_begin(struct z8530_channel *c){	unsigned long flags;	if(c->tx_skb)		return;			c->tx_skb=c->tx_next_skb;	c->tx_next_skb=NULL;	c->tx_ptr=c->tx_next_ptr;		mark_bh(NET_BH);	if(c->tx_skb==NULL)	{		/* Idle on */		if(c->dma_tx)		{			flags=claim_dma_lock();			disable_dma(c->txdma);			/*			 *	Check if we crapped out.			 */			if(get_dma_residue(c->txdma))			{				c->stats.tx_dropped++;				c->stats.tx_fifo_errors++;			}			release_dma_lock(flags);		}		c->txcount=0;	}	else	{		c->txcount=c->tx_skb->len;						if(c->dma_tx)		{			/*			 *	FIXME. DMA is broken for the original 8530,			 *	on the older parts we need to set a flag and			 *	wait for a further TX interrupt to fire this			 *	stage off				 */			 			flags=claim_dma_lock();			disable_dma(c->txdma);			/*			 *	These two are needed by the 8530/85C30			 *	and must be issued when idling.			 */			 			if(c->dev->type!=Z85230)			{				write_zsctrl(c, RES_Tx_CRC);				write_zsctrl(c, RES_EOM_L);			}				write_zsreg(c, R10, c->regs[10]&~ABUNDER);			clear_dma_ff(c->txdma);			set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));			set_dma_count(c->txdma, c->txcount);			enable_dma(c->txdma);			release_dma_lock(flags);			write_zsctrl(c, RES_EOM_L);			write_zsreg(c, R5, c->regs[R5]|TxENAB);		}		else		{			save_flags(flags);			cli();			/* ABUNDER off */			write_zsreg(c, R10, c->regs[10]);			write_zsctrl(c, RES_Tx_CRC);//???			write_zsctrl(c, RES_EOM_L);				while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))			{						write_zsreg(c, R8, *c->tx_ptr++);				c->txcount--;			}			restore_flags(flags);		}	}}  static void z8530_tx_done(struct z8530_channel *c){	unsigned long flags;	struct sk_buff *skb;	spin_lock_irqsave(&z8530_buffer_lock, flags);	c->netdevice->tbusy=0;	/* Actually this can happen.*/	if(c->tx_skb==NULL)	{		spin_unlock_irqrestore(&z8530_buffer_lock, flags);		return;	}	skb=c->tx_skb;	c->tx_skb=NULL;	z8530_tx_begin(c);	spin_unlock_irqrestore(&z8530_buffer_lock, flags);	c->stats.tx_packets++;	c->stats.tx_bytes+=skb->len;	dev_kfree_skb(skb);}/* *	Higher level shovelling - receive chains */ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb){	kfree_skb(skb);}EXPORT_SYMBOL(z8530_null_rx);static void z8530_rx_done(struct z8530_channel *c){	struct sk_buff *skb;	int ct;		/*	 *	Is our receive engine in DMA mode	 */	 	if(c->rxdma_on)	{		/*		 *	Save the ready state and the buffer currently		 *	being used as the DMA target		 */		int ready=c->dma_ready;		unsigned char *rxb=c->rx_buf[c->dma_num];		unsigned long flags;				/*		 *	Complete this DMA. Neccessary to find the length		 */				 		flags=claim_dma_lock();				disable_dma(c->rxdma);		clear_dma_ff(c->rxdma);		c->rxdma_on=0;		ct=c->mtu-get_dma_residue(c->rxdma);		if(ct<0)			ct=2;	/* Shit happens.. */		c->dma_ready=0;				/*		 *	Normal case: the other slot is free, start the next DMA		 *	into it immediately.		 */		 		if(ready)		{			c->dma_num^=1;			set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);			set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));			set_dma_count(c->rxdma, c->mtu);			c->rxdma_on = 1;			enable_dma(c->rxdma);			/* Stop any frames that we missed the head of 			   from passing */			write_zsreg(c, R0, RES_Rx_CRC);		}		else			/* Can't occur as we dont reenable the DMA irq until			   after the flip is done */			printk("DMA flip overrun!\n");					release_dma_lock(flags);				/*		 *	Shove the old buffer into an sk_buff. We can't DMA		 *	directly into one on a PC - it might be above the 16Mb		 *	boundary. Optimisation - we could check to see if we		 *	can avoid the copy. Optimisation 2 - make the memcpy		 *	a copychecksum.		 */		 		skb=dev_alloc_skb(ct);		if(skb==NULL)		{			c->stats.rx_dropped++;			printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name);		}		else		{			skb_put(skb, ct);			memcpy(skb->data, rxb, ct);			c->stats.rx_packets++;			c->stats.rx_bytes+=ct;		}		c->dma_ready=1;	}	else	{		RT_LOCK;			skb=c->skb;				/*		 *	The game we play for non DMA is similar. We want to		 *	get the controller set up for the next packet as fast		 *	as possible. We potentially only have one byte + the		 *	fifo length for this. Thus we want to flip to the new		 *	buffer and then mess around copying and allocating		 *	things. For the current case it doesn't matter but		 *	if you build a system where the sync irq isnt blocked		 *	by the kernel IRQ disable then you need only block the		 *	sync IRQ for the RT_LOCK area.		 *			 */		ct=c->count;				c->skb = c->skb2;		c->count = 0;		c->max = c->mtu;		if(c->skb)		{			c->dptr = c->skb->data;			c->max = c->mtu;		}		else		{			c->count= 0;			c->max = 0;		}		RT_UNLOCK;		c->skb2 = dev_alloc_skb(c->mtu);		if(c->skb2==NULL)			printk(KERN_WARNING "%s: memory squeeze.\n",				c->netdevice->name);		else		{			skb_put(c->skb2,c->mtu);		}		c->stats.rx_packets++;		c->stats.rx_bytes+=ct;			}	/*	 *	If we received a frame we must now process it.	 */	if(skb)	{		skb_trim(skb, ct);		c->rx_function(c,skb);	}	else	{		c->stats.rx_dropped++;		printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name);	}}/* *	Cannot DMA over a 64K boundary on a PC */ extern inline int spans_boundary(struct sk_buff *skb){	unsigned long a=(unsigned long)skb->data;	a^=(a+skb->len);	if(a&0x00010000)	/* If the 64K bit is different.. */	{		printk("spanner\n");		return 1;	}	return 0;}/* *	Queue a packet for transmission. Because we have rather *	hard to hit interrupt latencies for the Z85230 per packet  *	even in DMA mode we do the flip to DMA buffer if needed here *	not in the IRQ. */int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb){	unsigned long flags;	if(c->tx_next_skb)	{		skb->dev->tbusy=1;		return 1;	}		/* PC SPECIFIC - DMA limits */		/*	 *	If we will DMA the transmit and its gone over the ISA bus	 *	limit, then copy to the flip buffer	 */	 	if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))	{		/* 		 *	Send the flip buffer, and flip the flippy bit.		 *	We don't care which is used when just so long as		 *	we never use the same buffer twice in a row. Since		 *	only one buffer can be going out at a time the other		 *	has to be safe.		 */		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];		c->tx_dma_used^=1;	/* Flip temp buffer */		memcpy(c->tx_next_ptr, skb->data, skb->len);	}	else		c->tx_next_ptr=skb->data;		RT_LOCK;	c->tx_next_skb=skb;	RT_UNLOCK;		spin_lock_irqsave(&z8530_buffer_lock, flags);	z8530_tx_begin(c);	spin_unlock_irqrestore(&z8530_buffer_lock, flags);	return 0;}EXPORT_SYMBOL(z8530_queue_xmit);struct net_device_stats *z8530_get_stats(struct z8530_channel *c){	return &c->stats;}EXPORT_SYMBOL(z8530_get_stats);#ifdef MODULE/* *	Module support */ int init_module(void){	printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n");	return 0;}void cleanup_module(void){}#endif

⌨️ 快捷键说明

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