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

📄 3c527.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	mc32_ring_poll(dev);		if(lp->tx_box->mbox&(1<<13))		printk("TX begin error!\n");#endif			lp->tx_halted=0;}	/* *	Load the rx ring */ static int mc32_load_rx_ring(struct 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;}	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]);}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]);	}} 	/* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. */static int mc32_open(struct device *dev){	int ioaddr = dev->base_addr;	u16 zero_word=0;	u8 one=1;	u8 regs;		dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	/*	 *	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);		MOD_INC_USE_COUNT;	return 0;}static int mc32_send_packet(struct sk_buff *skb, struct device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	if (dev->tbusy) {		/*		 * If we get here, some higher level has decided we are broken.		 * There should really be a "kick me" function call instead.		 */		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 5)			return 1;		printk(KERN_WARNING "%s: transmit timed out?\n", dev->name);		/* Try to restart the adaptor. */		dev->tbusy=0;		dev->trans_start = jiffies;	}	/*	 * Block a timer-based transmit from overlapping. This could better be	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.	 */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)	{		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);		dev_kfree_skb(skb);	}	else 	{		unsigned long flags;				u16 tx_head;		volatile struct skb_header *p, *np;		save_flags(flags);		cli();				if(atomic_read(&lp->tx_count)==0)		{			dev->tbusy=1;			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);				/* 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;		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);				dev->tbusy	= 0;			/* Keep feeding me */						lp->tx_box->mbox=0;		restore_flags(flags);	}	return 0;}static void mc32_update_stats(struct device *dev){}static void mc32_rx_ring(struct 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;		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);		/* 	 *	This is curious. It seems the receive stop and receive continue	 *	commands race against each other, even though we poll for 	 *	command ready to be issued. The delay is hackish but is a workaround	 *	while I investigate in depth	 */		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);	}/* * The typical workload of the driver: *   Handle the network interface interrupts. */static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct device *dev = dev_id;	struct mc32_local *lp;	int ioaddr, status, boguscount = 0;	int rx_event = 0;		if (dev == NULL) {		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);		return;	}	dev->interrupt = 1;	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(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);				dev->tbusy=0;				mark_bh(NET_BH);				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 */				rx_event=1;				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 */				/* Must restart */				lp->net_stats.rx_dropped++;				rx_event = 1; 	/* To restart */				break;			default:				printk("%s: strange rx ack %d\n", 					dev->name, status&7);					}		status>>=3;		if(status&1)		{			/* 0=no 1=yes 2=reply clearing */			lp->exec_pending=2;			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.	 */	 	if(rx_event)		mc32_rx_ring(dev);	dev->interrupt = 0;	return;}/* The inverse routine to mc32_open(). */static int mc32_close(struct device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	u8 regs;	u16 one=1;	/*	 *	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);		dev->tbusy = 1;	dev->start = 0;	/* Update the statistics here. */	MOD_DEC_USE_COUNT;	return 0;}/* * Get the current statistics. * This may be called with the card open or closed. */static struct net_device_stats *mc32_get_stats(struct device *dev){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	return &lp->net_stats;}/* * Set or clear the multicast filter for this adaptor. * 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 mc32_set_multicast_list(struct device *dev){	u16 filt;	if (dev->flags&IFF_PROMISC)	{		/* Enable promiscuous mode */		filt = 1;		mc32_command(dev, 0, &filt, 2);	}	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)	{		dev->flags|=IFF_PROMISC;		filt = 1;		mc32_command(dev, 0, &filt, 2);	}	else if(dev->mc_count)	{		unsigned char block[62];		unsigned char *bp;		struct dev_mc_list *dmc=dev->mc_list;				int i;				filt = 0;		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;		}		mc32_command(dev, 2, block, 2+6*dev->mc_count);		mc32_command(dev, 0, &filt, 2);	}	else 	{		filt = 0;		mc32_command(dev, 0, &filt, 2);	}}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device this_device = {	devicename, /* will be inserted by linux/drivers/net/mc32_init.c */	0, 0, 0, 0,	0, 0,  /* I/O address, IRQ */	0, 0, 0, NULL, mc32_probe };int init_module(void){	int result;	if ((result = register_netdev(&this_device)) != 0)		return result;	return 0;}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.	 * Release irq/dma here, when you have jumpered versions and	 * allocate them in mc32_probe1().	 */	 	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_s(this_device.priv, sizeof(struct mc32_local));	}	free_irq(this_device.irq, &this_device);}#endif /* MODULE */

⌨️ 快捷键说明

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