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

📄 3c527.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if(lp->exec_pending)		return -1;			lp->exec_pending=3;	lp->exec_box->mbox=0;	lp->exec_box->mbox=cmd;	memcpy((void *)lp->exec_box->data, data, len);	barrier();	/* the memcpy forgot the volatile so be sure */	/* Send the command */	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	outb(1<<6, ioaddr+HOST_CMD);		return 0;}/** *	mc32_command:  *	@dev: The 3c527 card to issue the command to *	@cmd: The command word to write to the mailbox *	@data: A data block if the command expects one *	@len: Length of the data block * *	Sends exec commands in a user context. This permits us to wait around *	for the replies and also to wait for the command buffer to complete *	from a previous command before we execute our command. After our  *	command completes we will complete any pending multicast reload *	we blocked off by hogging the exec buffer. * *	You feed the card a command, you wait, it interrupts you get a  *	reply. All well and good. The complication arises because you use *	commands for filter list changes which come in at bh level from things *	like IPV6 group stuff. * *	We have a simple state machine * *	0	- nothing issued * *	1	- command issued, wait reply * *	2	- reply waiting - reader then goes to state 0 * *	3	- command issued, trash reply. In which case the irq *		  takes it back to state 0 * *	Send command and block for results. On completion spot and reissue *	multicasts */  static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	int ret = 0;		/*	 *	Wait for a command	 */	 	save_flags(flags);	cli();	 	while(lp->exec_pending)		sleep_on(&lp->event);			/*	 *	Issue mine	 */	lp->exec_pending=1;		restore_flags(flags);		lp->exec_box->mbox=0;	lp->exec_box->mbox=cmd;	memcpy((void *)lp->exec_box->data, data, len);	barrier();	/* the memcpy forgot the volatile so be sure */	/* Send the command */	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	outb(1<<6, ioaddr+HOST_CMD);			save_flags(flags);	cli();	while(lp->exec_pending!=2)		sleep_on(&lp->event);	lp->exec_pending=0;	restore_flags(flags);		 	if(lp->exec_box->data[0]&(1<<13))		ret = -1;	/*	 *	A multicast set got blocked - do it now	 */			if(lp->mc_reload_wait)		mc32_reset_multicast_list(dev);	return ret;}/** *	mc32_rx_abort: *	@dev: 3c527 to abort * *	Peforms a receive abort sequence on the card. In fact after some *	experimenting we now simply tell the card to suspend reception. When *	issuing aborts occasionally odd things happened. */ static void mc32_rx_abort(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));		lp->rx_box->mbox=0;	outb(3<<3, ioaddr+HOST_CMD);	/* Suspend reception */} /** *	mc32_rx_begin: *	@dev: 3c527 to enable * *	We wait for any pending command to complete and then issue  *	a start reception command to the board itself. At this point  *	receive handling continues as it was before. */ static void mc32_rx_begin(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));		lp->rx_box->mbox=0;	outb(1<<3, ioaddr+HOST_CMD);	/* GO */	mc32_ring_poll(dev);			lp->rx_halted=0;	lp->rx_pending=0;}/** *	mc32_tx_abort: *	@dev: 3c527 to abort * *	Peforms a receive abort sequence on the card. In fact after some *	experimenting we now simply tell the card to suspend transmits . When *	issuing aborts occasionally odd things happened. In theory we want *	an abort to be sure we can recycle our buffers. As it happens we *	just have to be careful to shut the card down on close, and *	boot it carefully from scratch on setup. */ static void mc32_tx_abort(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));		lp->tx_box->mbox=0;	outb(3, ioaddr+HOST_CMD);	/* Suspend */		/* Ring empty */		atomic_set(&lp->tx_count, lp->tx_len);		/* Flush */	if(lp->tx_skb_top!=lp->tx_skb_end)	{		int i;		if(lp->tx_skb_top<=lp->tx_skb_end)		{			for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)			{				dev_kfree_skb(lp->tx_skb[i]);				lp->tx_skb[i]=NULL;			}		}		else		{			for(i=lp->tx_skb_end;i<TX_RING_MAX;i++)			{				dev_kfree_skb(lp->tx_skb[i]);				lp->tx_skb[i]=NULL;			}			for(i=0;i<lp->tx_skb_top;i++)			{				dev_kfree_skb(lp->tx_skb[i]);				lp->tx_skb[i]=NULL;			}		}	}	lp->tx_skb_top=lp->tx_skb_end=0;}/** *	mc32_tx_begin: *	@dev: 3c527 to enable * *	We wait for any pending command to complete and then issue  *	a start transmit command to the board itself. At this point  *	transmit handling continues as it was before. The ring must *	be setup before you do this and must have an end marker in it. *	It turns out we can avoid issuing this specific command when *	doing our setup so we avoid it. */ static void mc32_tx_begin(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));		lp->tx_box->mbox=0;#if 0		outb(5, ioaddr+HOST_CMD);	/* GO */	printk("TX=>5\n");	mc32_ring_poll(dev);		if(lp->tx_box->mbox&(1<<13))		printk("TX begin error!\n");#endif			lp->tx_halted=0;}	/** *	mc32_load_rx_ring: *	@dev: 3c527 to build the ring for * *	The card setups up the receive ring for us. We are required to *	use the ring it provides although we can change the size of the *	ring. * *	We allocate an sk_buff for each ring entry in turn and set the entry *	up for a single non s/g buffer. The first buffer we mark with the *	end marker bits. Finally we clear the rx mailbox. */ static int mc32_load_rx_ring(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int i;	u16 base;	volatile struct skb_header *p;		base = lp->rx_box->data[0];		/* Fix me - should use card size - also fix flush ! */ 	for(i=0;i<RX_RING_MAX;i++)	{		lp->rx_skb[i]=alloc_skb(1532, GFP_KERNEL);		if(lp->rx_skb[i]==NULL)		{			for(;i>=0;i--)				kfree_skb(lp->rx_skb[i]);			return -ENOBUFS;		}		lp->rx_ptr[i]=lp->rx_skb[i]->data+18;				p=bus_to_virt(lp->base+base);		p->control=0;		p->data = virt_to_bus(lp->rx_ptr[i]);		p->status=0;		p->length = 1532;		base = p->next;	}	p->control = (1<<6);	lp->rx_box->mbox = 0;	return 0;}	/** *	mc32_flush_rx_ring: *	@lp: Local data of 3c527 to flush the rx ring of * *	Free the buffer for each ring slot. Because of the receive  *	algorithm we use the ring will always be loaded will a full set *	of buffers. */static void mc32_flush_rx_ring(struct mc32_local *lp){	int i;	for(i=0;i<RX_RING_MAX;i++)		kfree_skb(lp->rx_skb[i]);}/** *	mc32_flush_tx_ring: *	@lp: Local data of 3c527 to flush the tx ring of * *	We have to consider two cases here. We want to free the pending *	buffers only. If the ring buffer head is past the start then the *	ring segment we wish to free wraps through zero. */static void mc32_flush_tx_ring(struct mc32_local *lp){	int i;		if(lp->tx_skb_top <= lp->tx_skb_end)	{		for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)			dev_kfree_skb(lp->tx_skb[i]);	}	else	{		for(i=0;i<lp->tx_skb_end;i++)			dev_kfree_skb(lp->tx_skb[i]);		for(i=lp->tx_skb_top;i<TX_RING_MAX;i++)			dev_kfree_skb(lp->tx_skb[i]);	}} 	/** *	mc32_open *	@dev: device to open * *	The user is trying to bring the card into ready state. This requires *	a brief dialogue with the card. Firstly we enable interrupts and then *	'indications'. Without these enabled the card doesn't bother telling *	us what it has done. This had me puzzled for a week. * *	We then load the network address and multicast filters. Turn on the *	workaround mode. This works around a bug in the 82586 - it asks the *	firmware to do so. It has a performance hit but is needed on busy *	[read most] lans. We load the ring with buffers then we kick it *	all off. */static int mc32_open(struct net_device *dev){	int ioaddr = dev->base_addr;	u16 zero_word=0;	u8 one=1;	u8 regs;		/*	 *	Interrupts enabled	 */	regs=inb(ioaddr+HOST_CTRL);	regs|=HOST_CTRL_INTE;	outb(regs, ioaddr+HOST_CTRL);		/*	 *	Send the indications on command	 */	mc32_command(dev, 4, &one, 2);	 		/*	 *	Send the command sequence "abort, resume" for RX and TX.	 *	The abort cleans up the buffer chains if needed.	 */	mc32_rx_abort(dev);	mc32_tx_abort(dev);		/* Set Network Address */	mc32_command(dev, 1, dev->dev_addr, 6);		/* Set the filters */	mc32_set_multicast_list(dev);		/* Issue the 82586 workaround command - this is for "busy lans",	   but basically means for all lans now days - has a performance	   cost but best set */	   	mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */		/* Load the ring we just initialised */		if(mc32_load_rx_ring(dev))	{		mc32_close(dev);		return -ENOBUFS;	}		/* And the resume command goes last */		mc32_rx_begin(dev);	mc32_tx_begin(dev);	netif_start_queue(dev);		return 0;}/** *	mc32_timeout: *	@dev: 3c527 that timed out * *	Handle a timeout on transmit from the 3c527. This normally means *	bad things as the hardware handles cable timeouts and mess for *	us. * */static void mc32_timeout(struct net_device *dev){	printk(KERN_WARNING "%s: transmit timed out?\n", dev->name);	/* Try to restart the adaptor. */	netif_wake_queue(dev);} /** *	mc32_send_packet: *	@skb: buffer to transmit *	@dev: 3c527 to send it out of * *	Transmit a buffer. This normally means throwing the buffer onto *	the transmit queue as the queue is quite large. If the queue is *	full then we set tx_busy and return. Once the interrupt handler *	gets messages telling it to reclaim transmit queue entries we will *	clear tx_busy and the kernel will start calling this again. * *	We use cli rather than spinlocks. Since I have no access to an SMP *	MCA machine I don't plan to change it. It is probably the top  *	performance hit for this driver on SMP however. */ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;			u16 tx_head;	volatile struct skb_header *p, *np;	netif_stop_queue(dev);		save_flags(flags);	cli();			if(atomic_read(&lp->tx_count)==0)	{		restore_flags(flags);		return 1;	}	tx_head = lp->tx_box->data[0];	atomic_dec(&lp->tx_count);	/* We will need this to flush the buffer out */		lp->tx_skb[lp->tx_skb_end] = skb;	lp->tx_skb_end++;	lp->tx_skb_end&=(TX_RING_MAX-1);	/* TX suspend - shouldnt be needed but apparently is.	   This is a research item ... */		   	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	lp->tx_box->mbox=0;	outb(3, ioaddr+HOST_CMD);		/* Transmit now stopped */	/* P is the last sending/sent buffer as a pointer */	p=(struct skb_header *)bus_to_virt(lp->base+tx_head);		/* NP is the buffer we will be loading */	np=(struct skb_header *)bus_to_virt(lp->base+p->next);			np->control	|= (1<<6);	/* EOL */	wmb();			np->length	= skb->len;			if(np->length < 60)		np->length = 60;				np->data	= virt_to_bus(skb->data);	np->status	= 0;	np->control	= (1<<7)|(1<<6);	/* EOP EOL */	wmb();			p->status	= 0;	p->control	&= ~(1<<6);		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	lp->tx_box->mbox=0;	outb(5, ioaddr+HOST_CMD);		/* Restart TX */	restore_flags(flags);		netif_wake_queue(dev);	return 0;

⌨️ 快捷键说明

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