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

📄 3c527.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
}/** *	mc32_update_stats: *	@dev: 3c527 to service * *	When the board signals us that its statistics need attention we *	should query the table and clear it. In actual fact we currently *	track all our statistics in software and I haven't implemented it yet. */ static void mc32_update_stats(struct net_device *dev){}/** *	mc32_rx_ring: *	@dev: 3c527 that needs its receive ring processing * *	We have received one or more indications from the card that *	a receive has completed. The ring buffer thus contains dirty *	entries. Firstly we tell the card to stop receiving, then We walk  *	the ring from the first filled entry, which is pointed to by the  *	card rx mailbox and for each completed packet we will either copy  *	it and pass it up the stack or if the packet is near MTU sized we  *	allocate another buffer and flip the old one up the stack. * *	We must succeed in keeping a buffer on the ring. If neccessary we *	will toss a received packet rather than lose a ring entry. Once the *	first packet that is unused is found we reload the mailbox with the *	buffer so that the card knows it can use the buffers again. Finally *	we set it receiving again.  * *	We must stop reception during the ring walk. I thought it would be *	neat to avoid it by clever tricks, but it turns out the event order *	on the card means you have to play by the manual. */ static void mc32_rx_ring(struct net_device *dev){	struct mc32_local *lp=dev->priv;	int ioaddr = dev->base_addr;	int x=0;	volatile struct skb_header *p;	u16 base;	u16 top;	/* Halt RX before walking the ring */		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	outb(3<<3, ioaddr+HOST_CMD);	while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR);		top = base = lp->rx_box->data[0];	do	{		p=(struct skb_header *)bus_to_virt(base+lp->base);		if(!(p->status & (1<<7)))			break;		if(p->status & (1<<6))		{			u16 length = p->length;			struct sk_buff *skb=dev_alloc_skb(length+2);			if(skb!=NULL)			{				skb_reserve(skb,2);				/*printk("Frame at %p\n", bus_to_virt(p->data)); */				memcpy(skb_put(skb, length),					bus_to_virt(p->data), length);				skb->protocol=eth_type_trans(skb,dev);				skb->dev=dev;				lp->net_stats.rx_packets++;				lp->net_stats.rx_bytes+=skb->len;				netif_rx(skb);			}			else				lp->net_stats.rx_dropped++;		}		else		{			lp->net_stats.rx_errors++;			switch(p->status&0x0F)			{				case 1:					lp->net_stats.rx_crc_errors++;break;				case 2:					lp->net_stats.rx_fifo_errors++;break;				case 3:					lp->net_stats.rx_frame_errors++;break;				case 4:					lp->net_stats.rx_missed_errors++;break;				case 5:					lp->net_stats.rx_length_errors++;break;			}		}		p->length = 1532;		p->control &= ~(1<<6);		p->status = 0;		base = p->next;	}	while(x++<48);	/*	 *	Restart ring processing	 */			while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	lp->rx_box->mbox=0;	lp->rx_box->data[0] = top;	outb(1<<3, ioaddr+HOST_CMD);		lp->rx_halted=0;}/** *	mc32_interrupt: *	@irq: Interrupt number *	@dev_id: 3c527 that requires servicing *	@regs: Registers (unused) * *	The 3c527 interrupts us for four reasons. The command register  *	contains the message it wishes to send us packed into a single *	byte field. We keep reading status entries until we have processed *	all the transmit and control items, but simply count receive *	reports. When the receive reports are in we can call the mc32_rx_ring *	and empty the ring. This saves the overhead of multiple command requests */ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = dev_id;	struct mc32_local *lp;	int ioaddr, status, boguscount = 0;		if (dev == NULL) {		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);		return;	}	ioaddr = dev->base_addr;	lp = (struct mc32_local *)dev->priv;	/* See whats cooking */		while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000)	{		status=inb(ioaddr+HOST_CMD);#ifdef DEBUG_IRQ				printk("Status TX%d RX%d EX%d OV%d\n",			(status&7), (status>>3)&7, (status>>6)&1,			(status>>7)&1);#endif					switch(status&7)		{			case 0:				break;			case 6: /* TX fail */				lp->net_stats.tx_errors++;			case 2:	/* TX ok */				lp->net_stats.tx_packets++;				/* Packets are sent in order - this is				   basically a FIFO queue of buffers matching				   the card ring */				lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len;				dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]);				lp->tx_skb[lp->tx_skb_top]=NULL;				lp->tx_skb_top++;				lp->tx_skb_top&=(TX_RING_MAX-1);				atomic_inc(&lp->tx_count);				netif_wake_queue(dev);				break;			case 3: /* Halt */			case 4: /* Abort */				lp->tx_halted=1;				wake_up(&lp->event);				break;			case 5:				lp->tx_halted=0;				wake_up(&lp->event);				break;			default:				printk("%s: strange tx ack %d\n", 					dev->name, status&7);		}		status>>=3;		switch(status&7)		{			case 0:				break;			case 2:	/* RX */				lp->rx_pending=1;				if(!lp->rx_halted)				{					/*					 *	Halt ring receive					 */					while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));					outb(3<<3, ioaddr+HOST_CMD);				}				break;			case 3:			case 4:				lp->rx_halted=1;				wake_up(&lp->event);				break;			case 5:				lp->rx_halted=0;				wake_up(&lp->event);				break;			case 6:				/* Out of RX buffers stat */				lp->net_stats.rx_dropped++;				lp->rx_pending=1;				/* Must restart */				lp->rx_halted=1;				break;			default:				printk("%s: strange rx ack %d\n", 					dev->name, status&7);					}		status>>=3;		if(status&1)		{			/* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */			if(lp->exec_pending!=3)				lp->exec_pending=2;			else				lp->exec_pending=0;			wake_up(&lp->event);		}		if(status&2)		{			/*			 *	Update the stats as soon as			 *	we have it flagged and can 			 *	send an immediate reply (CRR set)			 */			 			if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)			{				mc32_update_stats(dev);				outb(0, ioaddr+HOST_CMD);			}		}	}		/*	 *	Process and restart the receive ring. This has some state	 *	as we must halt the ring to process it and halting the ring	 *	might not occur in the same IRQ handling loop as we issue	 *	the halt.	 */	 	if(lp->rx_pending && lp->rx_halted)	{		mc32_rx_ring(dev);		lp->rx_pending = 0;	}	return;}/** *	mc32_close: *	@dev: 3c527 card to shut down * *	The 3c527 is a bus mastering device. We must be careful how we *	shut it down. It may also be running shared interrupt so we have *	to be sure to silence it properly * *	We abort any receive and transmits going on and then wait until *	any pending exec commands have completed in other code threads. *	In theory we can't get here while that is true, in practice I am *	paranoid * *	We turn off the interrupt enable for the board to be sure it can't *	intefere with other devices. */ static int mc32_close(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	u8 regs;	u16 one=1;	netif_stop_queue(dev);		/*	 *	Send the indications on command (handy debug check)	 */	mc32_command(dev, 4, &one, 2);	/* Abort RX and Abort TX */		mc32_rx_abort(dev);		mc32_tx_abort(dev);		/* Catch any waiting commands */		while(lp->exec_pending==1)		sleep_on(&lp->event);			/* Ok the card is now stopping */			regs=inb(ioaddr+HOST_CTRL);	regs&=~HOST_CTRL_INTE;	outb(regs, ioaddr+HOST_CTRL);	mc32_flush_rx_ring(lp);	mc32_flush_tx_ring(lp);		/* Update the statistics here. */	return 0;}/** *	mc32_get_stats: *	@dev: The 3c527 card to handle * *	As we currently handle our statistics in software this one is *	easy to handle. With hardware statistics it will get messy *	as the get_stats call will need to send exec mailbox messages and *	need to lock out the multicast reloads. */static struct net_device_stats *mc32_get_stats(struct net_device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	return &lp->net_stats;}/** *	do_mc32_set_multicast_list: *	@dev: 3c527 device to load the list on *	@retry: indicates this is not the first call.  * * Actually set or clear the multicast filter for this adaptor. The locking * issues are handled by this routine. We have to track state as it may take * multiple calls to get the command sequence completed. We just keep trying * to schedule the loads until we manage to process them all. * * num_addrs == -1	Promiscuous mode, receive all packets * * num_addrs == 0	Normal mode, clear multicast list * * num_addrs > 0	Multicast mode, receive normal and MC packets, *			and do best-effort filtering. */static void do_mc32_set_multicast_list(struct net_device *dev, int retry){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	u16 filt;	if (dev->flags&IFF_PROMISC)		/* Enable promiscuous mode */		filt = 1;	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)	{		dev->flags|=IFF_PROMISC;		filt = 1;	}	else if(dev->mc_count)	{		unsigned char block[62];		unsigned char *bp;		struct dev_mc_list *dmc=dev->mc_list;				int i;				filt = 0;				if(retry==0)			lp->mc_list_valid = 0;		if(!lp->mc_list_valid)		{			block[1]=0;			block[0]=dev->mc_count;			bp=block+2;					for(i=0;i<dev->mc_count;i++)			{				memcpy(bp, dmc->dmi_addr, 6);				bp+=6;				dmc=dmc->next;			}			if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1)			{				lp->mc_reload_wait = 1;				return;			}			lp->mc_list_valid=1;		}	}	else 	{		filt = 0;	}	if(mc32_command_nowait(dev, 0, &filt, 2)==-1)	{		lp->mc_reload_wait = 1;	}}/** *	mc32_set_multicast_list: *	@dev: The 3c527 to use * *	Commence loading the multicast list. This is called when the kernel *	changes the lists. It will override any pending list we are trying to *	load. */ static void mc32_set_multicast_list(struct net_device *dev){	do_mc32_set_multicast_list(dev,0);}/** *	mc32_reset_multicast_list: *	@dev: The 3c527 to use * *	Attempt the next step in loading the multicast lists. If this attempt *	fails to complete then it will be scheduled and this function called *	again later from elsewhere. */ static void mc32_reset_multicast_list(struct net_device *dev){	do_mc32_set_multicast_list(dev,1);}#ifdef MODULEstatic struct net_device this_device;/** *	init_module: * *	Probe and locate a 3c527 card. This really should probe and locate *	all the 3c527 cards in the machine not just one of them. Yes you can *	insmod multiple modules for now but its a hack. */ int init_module(void){	int result;	this_device.init = mc32_probe;	if ((result = register_netdev(&this_device)) != 0)		return result;	return 0;}/** *	cleanup_module: * *	Unloading time. We release the MCA bus resources and the interrupt *	at which point everything is ready to unload. The card must be stopped *	at this point or we would not have been called. When we unload we *	leave the card stopped but not totally shut down. When the card is *	initialized it must be rebooted or the rings reloaded before any *	transmit operations are allowed to start scribbling into memory. */ void cleanup_module(void){	int slot;		/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	unregister_netdev(&this_device);	/*	 * If we don't do this, we can't re-insmod it later.	 */	 	if (this_device.priv)	{		struct mc32_local *lp=this_device.priv;		slot = lp->slot;		mca_mark_as_unused(slot);		mca_set_adapter_name(slot, NULL);		kfree(this_device.priv);	}	free_irq(this_device.irq, &this_device);}#endif /* MODULE */

⌨️ 快捷键说明

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