3c527.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,676 行 · 第 1/3 页

C
1,676
字号
 *	mc32_command_nowait	-	send a command non blocking *	@dev: The 3c527 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 * *	Send a command from interrupt state. If there is a command *	currently being executed then we return an error of -1. It *	simply isn't viable to wait around as commands may be *	slow. This can theoretically be starved on SMP, but it's hard *	to see a realistic situation.  We do not wait for the command *	to complete --- we rely on the interrupt handler to tidy up *	after us. */static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len){	struct mc32_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	int ret = -1;	if (down_trylock(&lp->cmd_mutex) == 0)	{		lp->cmd_nonblocking=1;		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 */		mc32_ready_poll(dev);		outb(1<<6, ioaddr+HOST_CMD);		ret = 0;		/* Interrupt handler will signal mutex on completion */	}	return ret;}/** *	mc32_command	-	send a command and sleep until completion *	@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 attempt 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. */  static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len){	struct mc32_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	int ret = 0;		down(&lp->cmd_mutex);	/*	 *     My Turn	 */	lp->cmd_nonblocking=0;	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 */	mc32_ready_poll(dev);	outb(1<<6, ioaddr+HOST_CMD);	wait_for_completion(&lp->execution_cmd);		if(lp->exec_box->mbox&(1<<13))		ret = -1;	up(&lp->cmd_mutex);	/*	 *	A multicast set got blocked - try it now         */	if(lp->mc_reload_wait)	{		mc32_reset_multicast_list(dev);	}	return ret;}/** *	mc32_start_transceiver	-	tell board to restart tx/rx *	@dev: The 3c527 card to issue the command to * *	This may be called from the interrupt state, where it is used *	to restart the rx ring if the card runs out of rx buffers.  *	 * 	We must first check if it's ok to (re)start the transceiver. See *      mc32_close for details. */static void mc32_start_transceiver(struct net_device *dev) {	struct mc32_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	/* Ignore RX overflow on device closure */ 	if (lp->xceiver_desired_state==HALTED)		return; 	/* Give the card the offset to the post-EOL-bit RX descriptor */	mc32_ready_poll(dev); 	lp->rx_box->mbox=0;	lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; 	outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);      	mc32_ready_poll(dev); 	lp->tx_box->mbox=0;	outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */ 		/* We are not interrupted on start completion */ }/** *	mc32_halt_transceiver	-	tell board to stop tx/rx *	@dev: The 3c527 card to issue the command to * *	We issue the commands to halt the card's transceiver. In fact, *	after some experimenting we now simply tell the card to *	suspend. When issuing aborts occasionally odd things happened. * *	We then sleep until the card has notified us that both rx and *	tx have been suspended. */ static void mc32_halt_transceiver(struct net_device *dev) {	struct mc32_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	mc32_ready_poll(dev);		lp->rx_box->mbox=0;	outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);				wait_for_completion(&lp->xceiver_cmd);	mc32_ready_poll(dev); 	lp->tx_box->mbox=0;	outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);		wait_for_completion(&lp->xceiver_cmd);}/** *	mc32_load_rx_ring	-	load the ring of receive buffers *	@dev: 3c527 to build the ring for * *	This initalises the on-card and driver datastructures to *	the point where mc32_start_transceiver() can be called. * *	The card sets up the receive ring for us. We are required to use the *	ring it provides, although the size of the ring is configurable. * * 	We allocate an sk_buff for each ring entry in turn and * 	initalise its house-keeping info. At the same time, we read * 	each 'next' pointer in our rx_ring array. This reduces slow * 	shared-memory reads and makes it easy to access predecessor * 	descriptors. * *	We then set the end-of-list bit for the last entry so that the * 	card will know when it has run out of buffers. */	 static int mc32_load_rx_ring(struct net_device *dev){	struct mc32_local *lp = netdev_priv(dev);	int i;	u16 rx_base;	volatile struct skb_header *p;		rx_base=lp->rx_chain;	for(i=0; i<RX_RING_LEN; i++) {		lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);		if (lp->rx_ring[i].skb==NULL) {			for (;i>=0;i--)				kfree_skb(lp->rx_ring[i].skb);			return -ENOBUFS;		}		skb_reserve(lp->rx_ring[i].skb, 18);		p=isa_bus_to_virt(lp->base+rx_base);						p->control=0;		p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);		p->status=0;		p->length=1532;			lp->rx_ring[i].p=p; 		rx_base=p->next; 	}	lp->rx_ring[i-1].p->control |= CONTROL_EOL;	lp->rx_ring_tail=0;	return 0;}	/** *	mc32_flush_rx_ring	-	free the ring of receive buffers *	@lp: Local data of 3c527 to flush the rx ring of * *	Free the buffer for each ring slot. This may be called  *      before mc32_load_rx_ring(), eg. on error in mc32_open(). *      Requires rx skb pointers to point to a valid skb, or NULL. */static void mc32_flush_rx_ring(struct net_device *dev){	struct mc32_local *lp = netdev_priv(dev);	int i; 	for(i=0; i < RX_RING_LEN; i++) 	{ 		if (lp->rx_ring[i].skb) {			dev_kfree_skb(lp->rx_ring[i].skb);			lp->rx_ring[i].skb = NULL;		}		lp->rx_ring[i].p=NULL; 	} }/** *	mc32_load_tx_ring	-	load transmit ring *	@dev: The 3c527 card to issue the command to * *	This sets up the host transmit data-structures.  * *	First, we obtain from the card it's current postion in the tx *	ring, so that we will know where to begin transmitting *	packets. * 	 * 	Then, we read the 'next' pointers from the on-card tx ring into *  	our tx_ring array to reduce slow shared-mem reads. Finally, we * 	intitalise the tx house keeping variables. *  */ static void mc32_load_tx_ring(struct net_device *dev){ 	struct mc32_local *lp = netdev_priv(dev);	volatile struct skb_header *p;	int i; 	u16 tx_base;	tx_base=lp->tx_box->data[0]; 	for(i=0 ; i<TX_RING_LEN ; i++)	{		p=isa_bus_to_virt(lp->base+tx_base);		lp->tx_ring[i].p=p; 		lp->tx_ring[i].skb=NULL;		tx_base=p->next;	}	/* -1 so that tx_ring_head cannot "lap" tx_ring_tail */	/* see mc32_tx_ring */	atomic_set(&lp->tx_count, TX_RING_LEN-1); 	atomic_set(&lp->tx_ring_head, 0); 	lp->tx_ring_tail=0; } /** *	mc32_flush_tx_ring 	-	free transmit ring *	@lp: Local data of 3c527 to flush the tx ring of * *      If the ring is non-empty, zip over the it, freeing any *      allocated skb_buffs.  The tx ring house-keeping variables are *      then reset. Requires rx skb pointers to point to a valid skb, *      or NULL. */static void mc32_flush_tx_ring(struct net_device *dev){	struct mc32_local *lp = netdev_priv(dev);	int i;	for (i=0; i < TX_RING_LEN; i++)	{		if (lp->tx_ring[i].skb)		{			dev_kfree_skb(lp->tx_ring[i].skb);			lp->tx_ring[i].skb = NULL;		}	}	atomic_set(&lp->tx_count, 0); 	atomic_set(&lp->tx_ring_head, 0); 	lp->tx_ring_tail=0;} 	/** *	mc32_open	-	handle 'up' of card *	@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 configure the number of card descriptors, 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 (latency) 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;	struct mc32_local *lp = netdev_priv(dev);	u8 one=1;	u8 regs;	u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};	/*	 *	Interrupts enabled	 */	regs=inb(ioaddr+HOST_CTRL);	regs|=HOST_CTRL_INTE;	outb(regs, ioaddr+HOST_CTRL);		/*	 *      Allow ourselves to issue commands	 */	up(&lp->cmd_mutex);	/*	 *	Send the indications on command	 */	mc32_command(dev, 4, &one, 2);	/*	 *	Poke it to make sure it's really dead. 	 */	mc32_halt_transceiver(dev); 	mc32_flush_tx_ring(dev); 	/* 	 *	Ask card to set up on-card descriptors to our spec 	 */ 	if(mc32_command(dev, 8, descnumbuffs, 4)) { 		printk("%s: %s rejected our buffer configuration!\n",	 	       dev->name, cardname);		mc32_close(dev); 		return -ENOBUFS; 	}		/* Report new configuration */ 	mc32_command(dev, 6, NULL, 0); 	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */ 	/* Set Network Address */	mc32_command(dev, 1, dev->dev_addr, 6);		/* Set the filters */	mc32_set_multicast_list(dev);		   	if (WORKAROUND_82586) { 		u16 zero_word=0;		mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */	}	mc32_load_tx_ring(dev);		if(mc32_load_rx_ring(dev)) 	{		mc32_close(dev);		return -ENOBUFS;	}	lp->xceiver_desired_state = RUNNING;		/* And finally, set the ball rolling... */	mc32_start_transceiver(dev);	netif_start_queue(dev);	return 0;}/** *	mc32_timeout	-	handle a timeout from the network layer *	@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	-	queue a frame for transmit *	@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 do not disable interrupts or acquire any locks; this can *      run concurrently with mc32_tx_ring(), and the function itself *      is serialised at a higher layer. However, similarly for the *      card itself, we must ensure that we update tx_ring_head only *      after we've established a valid packet on the tx ring (and *      before we let the card "see" it, to prevent it racing with the *      irq handler). *  */static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev){	struct mc32_local *lp = netdev_priv(dev);	u32 head = atomic_read(&lp->tx_ring_head);		volatile struct skb_header *p, *np;	netif_stop_queue(dev);	if(atomic_read(&lp->tx_count)==0) {		return 1;	}	skb = skb_padto(skb, ETH_ZLEN);	if (skb == NULL) {		netif_wake_queue(dev);		return 0;	}	atomic_dec(&lp->tx_count); 	/* P is the last sending/sent buffer as a pointer */	p=lp->tx_ring[head].p;			head = next_tx(head);	/* NP is the buffer we will be loading */	np=lp->tx_ring[head].p; 		/* We will need this to flush the buffer out */	lp->tx_ring[head].skb=skb;	np->length      = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;				np->data	= isa_virt_to_bus(skb->data);	np->status	= 0;	np->control     = CONTROL_EOP | CONTROL_EOL;     	wmb();			/*	 * The new frame has been setup; we can now	 * let the interrupt handler and card "see" it	 */	atomic_set(&lp->tx_ring_head, head); 	p->control     &= ~CONTROL_EOL;	netif_wake_queue(dev);	return 0;}/** *	mc32_update_stats	-	pull off the on board statistics *	@dev: 3c527 to service * *  *	Query and reset the on-card stats. There's the small possibility *	of a race here, which would result in an underestimation of *	actual errors. As such, we'd prefer to keep all our stats *	collection in software. As a rule, we do. However it can't be *	used for rx errors and collisions as, by default, the card discards *	bad rx packets.  * *	Setting the SAV BP in the rx filter command supposedly *	stops this behaviour. However, testing shows that it only seems to *	enable the collation of on-card rx statistics --- the driver *	never sees an RX descriptor with an error status set. * */static void mc32_update_stats(struct net_device *dev){	struct mc32_local *lp = netdev_priv(dev);	volatile struct mc32_stats *st = lp->stats; 	u32 rx_errors=0;       	rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;         	                                           st->rx_crc_errors=0;	rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;   	                                           st->rx_overrun_errors=0; 	rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;  	                                           st->rx_alignment_errors=0;	rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; 	                                           st->rx_tooshort_errors=0;	rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;	                                           st->rx_outofresource_errors=0;         lp->net_stats.rx_errors=rx_errors; 						   	/* Number of packets which saw one collision */	lp->net_stats.collisions+=st->dataC[10];	st->dataC[10]=0; 	/* Number of packets which saw 2--15 collisions */ 	lp->net_stats.collisions+=st->dataC[11]; 	st->dataC[11]=0; }	

⌨️ 快捷键说明

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