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

📄 82596.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	lp->iscp.stat = ISCP_BUSY;	lp->cmd_backlog = 0;	lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;	if (i596_debug > 1)		printk("%s: starting i82596.\n", dev->name);#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET)	(void) inb(ioaddr + 0x10);	outb(4, ioaddr + 0xf);#endif	CA(dev);	while (lp->iscp.stat)		if (--boguscnt == 0) {			printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",			     dev->name, lp->scb.status, lp->scb.command);			break;		}	lp->scb.command = 0;#ifdef CONFIG_MVME16x_NET	if (MACH_IS_MVME16x) {		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;		/* Enable ints, etc. now */		pcc2[0x2a] = 0x08;		pcc2[0x2a] = 0x55;	/* Edge sensitive */		pcc2[0x2b] = 0x55;	}#endif#ifdef CONFIG_BVME6000_NET	if (MACH_IS_BVME6000) {		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;		*ethirq = 3;	}#endif	memcpy(lp->i596_config, init_setup, 14);	lp->set_conf.command = CmdConfigure;	i596_add_cmd(dev, &lp->set_conf);	memcpy(lp->eth_addr, dev->dev_addr, 6);	lp->set_add.command = CmdSASetup;	i596_add_cmd(dev, &lp->set_add);	lp->tdr.command = CmdTDR;	i596_add_cmd(dev, &lp->tdr);	boguscnt = 200000;	save_flags(flags);	cli();	while (lp->scb.command)		if (--boguscnt == 0) {			printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",			     dev->name, lp->scb.status, lp->scb.command);			break;		}	lp->scb.command = RX_START;	CA(dev);	restore_flags(flags);	boguscnt = 2000;	while (lp->scb.command)		if (--boguscnt == 0) {			printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",			       lp->scb.status, lp->scb.command);			break;		}	return;}static inline int i596_rx(struct device *dev){	struct i596_private *lp = (struct i596_private *) dev->priv;	struct i596_rfd *rfd;	int frames = 0;	if (i596_debug > 3)		printk("i596_rx()\n");	rfd = WSWAPrfd(lp->scb.rfd);	/* Reference next frame descriptor to check */	while ((rfd->stat) & STAT_C) {	/* Loop while we have complete frames */		if (i596_debug > 2)			print_eth(rfd->data);		if ((rfd->stat) & STAT_OK) {			/* a good frame */			int pkt_len = rfd->count & 0x3fff;			struct sk_buff *skb = dev_alloc_skb(pkt_len);			frames++;			if (skb == NULL) {				printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);				lp->stats.rx_dropped++;			} else {				skb->dev = dev;				memcpy(skb_put(skb, pkt_len), rfd->data, pkt_len);				skb->protocol = eth_type_trans(skb, dev);				netif_rx(skb);				lp->stats.rx_packets++;				lp->stats.rx_bytes += pkt_len;			}		} else {			lp->stats.rx_errors++;			if ((rfd->stat) & 0x0001)				lp->stats.collisions++;			if ((rfd->stat) & 0x0080)				lp->stats.rx_length_errors++;			if ((rfd->stat) & 0x0100)				lp->stats.rx_over_errors++;			if ((rfd->stat) & 0x0200)				lp->stats.rx_fifo_errors++;			if ((rfd->stat) & 0x0400)				lp->stats.rx_frame_errors++;			if ((rfd->stat) & 0x0800)				lp->stats.rx_crc_errors++;			if ((rfd->stat) & 0x1000)				lp->stats.rx_length_errors++;		}		/* Clear the buffer descriptor count and EOF + F flags */		rfd->stat = 0;		rfd->count = 0;		rfd->cmd = CMD_EOL;		lp->rx_tail->cmd = 0;		lp->rx_tail = rfd;		lp->scb.rfd = rfd->next;		rfd = WSWAPrfd(lp->scb.rfd);	/* Next frame descriptor to check */	}	if (i596_debug > 3)		printk("frames %d\n", frames);	return 0;}static inline void i596_cleanup_cmd(struct i596_private *lp){	struct i596_cmd *ptr;	int boguscnt = 1000;	if (i596_debug > 4)		printk("i596_cleanup_cmd\n");	while (lp->cmd_head != (struct i596_cmd *) I596_NULL) {		ptr = lp->cmd_head;		lp->cmd_head = WSWAPcmd(lp->cmd_head->next);		lp->cmd_backlog--;		switch ((ptr->command) & 0x7) {		case CmdTx:			{				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;				struct sk_buff *skb = tx_cmd->skb;				dev_kfree_skb(skb);				lp->stats.tx_errors++;				lp->stats.tx_aborted_errors++;				ptr->next = (struct i596_cmd *) I596_NULL;				kfree(tx_cmd);				break;			}		case CmdMulticastList:			{				ptr->next = (struct i596_cmd *) I596_NULL;				kfree(ptr);				break;			}		default:			ptr->next = (struct i596_cmd *) I596_NULL;		}	}	while (lp->scb.command)		if (--boguscnt == 0) {			printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",			       lp->scb.status, lp->scb.command);			break;		}	lp->scb.cmd = WSWAPcmd(lp->cmd_head);}static inline void i596_reset(struct device *dev, struct i596_private *lp, int ioaddr){	int boguscnt = 1000;	unsigned long flags;	if (i596_debug > 1)		printk("i596_reset\n");	save_flags(flags);	cli();	while (lp->scb.command)		if (--boguscnt == 0) {			printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",			       lp->scb.status, lp->scb.command);			break;		}	dev->start = 0;	dev->tbusy = 1;	lp->scb.command = CUC_ABORT | RX_ABORT;	CA(dev);	/* wait for shutdown */	boguscnt = 4000;	while (lp->scb.command)		if (--boguscnt == 0) {			printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",			       lp->scb.status, lp->scb.command);			break;		}	restore_flags(flags);	i596_cleanup_cmd(lp);	i596_rx(dev);	dev->start = 1;	dev->tbusy = 0;	dev->interrupt = 0;	init_i596_mem(dev);}static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd){	struct i596_private *lp = (struct i596_private *) dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	int boguscnt = 1000;	if (i596_debug > 4)		printk("i596_add_cmd\n");	cmd->status = 0;	cmd->command |= (CMD_EOL | CMD_INTR);	cmd->next = (struct i596_cmd *) I596_NULL;	save_flags(flags);	cli();	/*	 * RGH  300597:  Looks to me like there could be a race condition	 * here.  Just because we havn't picked up all the command items	 * yet, doesn't mean that the 82596 hasn't finished processing	 * them.  So, we may need to do a CUC_START anyway.	 * Maybe not.  If it interrupts saying the CU is idle when there	 * is still something in the cmd queue, the int handler with restart	 * the CU.	 */	if (lp->cmd_head != (struct i596_cmd *) I596_NULL) {		lp->cmd_tail->next = WSWAPcmd(cmd);	} else {		lp->cmd_head = cmd;		while (lp->scb.command)			if (--boguscnt == 0) {				printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",				       lp->scb.status, lp->scb.command);				break;			}		lp->scb.cmd = WSWAPcmd(cmd);		lp->scb.command = CUC_START;		CA(dev);	}	lp->cmd_tail = cmd;	lp->cmd_backlog++;	lp->cmd_head = WSWAPcmd(lp->scb.cmd);	/* Is this redundant?  RGH 300597 */	restore_flags(flags);	if (lp->cmd_backlog > max_cmd_backlog) {		unsigned long tickssofar = jiffies - lp->last_cmd;		if (tickssofar < ticks_limit)			return;		printk("%s: command unit timed out, status resetting.\n", dev->name);		i596_reset(dev, lp, ioaddr);	}}static int i596_open(struct device *dev){	int i;	if (i596_debug > 1)		printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);	if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev))		return -EAGAIN;#ifdef CONFIG_MVME16x_NET	if (MACH_IS_MVME16x) {		if (request_irq(0x56, &i596_error, 0, "apricot_error", dev))			return -EAGAIN;	}#endif	if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)		printk("%s: only able to allocate %d receive buffers\n", dev->name, i);	if (i < 4) {		free_irq(dev->irq, dev);		return -EAGAIN;	}	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	MOD_INC_USE_COUNT;	/* Initialize the 82596 memory */	init_i596_mem(dev);	return 0;		/* Always succeed */}static int i596_start_xmit(struct sk_buff *skb, struct device *dev){	struct i596_private *lp = (struct i596_private *) dev->priv;	int ioaddr = dev->base_addr;	struct tx_cmd *tx_cmd;	if (i596_debug > 2)		printk("%s: 82596 start xmit\n", dev->name);	/* Transmitter timeout, serious problems. */	if (dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 5)			return 1;		printk("%s: transmit timed out, status resetting.\n",		       dev->name);		lp->stats.tx_errors++;		/* Try to restart the adaptor */		if (lp->last_restart == lp->stats.tx_packets) {			if (i596_debug > 1)				printk("Resetting board.\n");			/* Shutdown and restart */			i596_reset(dev, lp, ioaddr);		} else {			/* Issue a channel attention signal */			if (i596_debug > 1)				printk("Kicking board.\n");			lp->scb.command = CUC_START | RX_START;			CA(dev);			lp->last_restart = lp->stats.tx_packets;		}		dev->tbusy = 0;		dev->trans_start = jiffies;	}	if (i596_debug > 3)		printk("%s: i596_start_xmit() called\n", dev->name);	/* 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("%s: Transmitter access conflict.\n", dev->name);	else {		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;		dev->trans_start = jiffies;		tx_cmd = (struct tx_cmd *) kmalloc((sizeof(struct tx_cmd) + sizeof(struct i596_tbd)), GFP_ATOMIC);		if (tx_cmd == NULL) {			printk("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);			lp->stats.tx_dropped++;			dev_kfree_skb(skb);		} else {			struct i596_tbd *tbd = (struct i596_tbd *) (tx_cmd + 1);			tx_cmd->tbd = WSWAPtbd(tbd);			tbd->next = (struct i596_tbd *) I596_NULL;			tx_cmd->cmd.command = CMD_FLEX | CmdTx;			tx_cmd->skb = skb;			tx_cmd->pad = 0;			tx_cmd->size = 0;			tbd->pad = 0;			tbd->size = EOF | length;			tbd->data = WSWAPchar(skb->data);			if (i596_debug > 3)				print_eth(skb->data);			i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);			lp->stats.tx_packets++;			lp->stats.tx_bytes += length;		}	}	dev->tbusy = 0;	return 0;}static void print_eth(char *add){	int i;	printk("print_eth(%08x)\n", (unsigned int) add);	printk("Dest  ");	for (i = 0; i < 6; i++)		printk(" %2.2X", (unsigned char) add[i]);	printk("\n");	printk("Source");	for (i = 0; i < 6; i++)		printk(" %2.2X", (unsigned char) add[i + 6]);	printk("\n");	printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);}__initfunc(int i82596_probe(struct device *dev)){	int i;	struct i596_private *lp;	char eth_addr[6];#ifdef CONFIG_MVME16x_NET	if (MACH_IS_MVME16x) {		static int probed = 0;		if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {			printk("Ethernet probe disabled - chip not present\n");			return ENODEV;		}		if (probed)			return ENODEV;		probed++;		memcpy(eth_addr, (void *) 0xfffc1f2c, 6);	/* YUCK! Get addr from NOVRAM */		dev->base_addr = MVME_I596_BASE;		dev->irq = (unsigned) MVME16x_IRQ_I596;	}#endif#ifdef CONFIG_BVME6000_NET	if (MACH_IS_BVME6000) {		volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;		unsigned char msr = rtc[3];

⌨️ 快捷键说明

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