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

📄 dgrs.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
				break; /* For safety */			if ( (p-putp) >= len)			{				printk("%s: cbp = %x\n", devN->name, H2S(cbp));				proc_reset(dev0, 1);	/* Freeze IDT */				break; /* For Safety */			}			ddp_h->pciaddr = (ulong) phys_p;			ddp_h->lcladdr = S2DMA(tbdp->buf);			ddp_h->len = amt;			phys_p += amt;			p += amt;			if (count & I596_TBD_EOF)			{				ddp_h->next = PLX_DMA_DESC_TO_HOST						| PLX_DMA_DESC_EOC;				++ddp_h;				break;			}			else			{				++ddp_s;				ddp_h->next = PLX_DMA_DESC_TO_HOST						| (ulong) ddp_s;				tbdp = (I596_TBD *) S2H(tbdp->next);				++ddp_h;			}		}		if (ddp_h - priv0->dmadesc_h)		{			int	rc;			rc = do_plx_dma(dev0,				0, (ulong) priv0->dmadesc_s, len, 0);			if (rc)			{				printk("%s: Chained DMA failure\n", devN->name);				goto again;			}		}	}	else if (priv0->use_dma)	{		/*		 *	If we can use DMA and its a shorter frame, copy it		 *	using single DMA transfers.		 */		uchar		*phys_p;		/*		 *	Get the physical address of the STREAMS buffer.		 *	NOTE: allocb() guarantees that the whole buffer		 *	is in a single page if the length < 4096.		 */		phys_p = (uchar *) virt_to_phys(putp);		tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);		for (;;)		{			int	count;			int	amt;			int	rc;			count = tbdp->count;			amt = count & 0x3fff;			if (amt == 0)				break; /* For safety */			if ( (p-putp) >= len)			{				printk("%s: cbp = %x\n", devN->name, H2S(cbp));				proc_reset(dev0, 1);	/* Freeze IDT */				break; /* For Safety */			}			rc = do_plx_dma(dev0, (ulong) phys_p,						S2DMA(tbdp->buf), amt, 1);			if (rc)			{				memcpy(p, S2H(tbdp->buf), amt);				printk("%s: Single DMA failed\n", devN->name);			}			phys_p += amt;			p += amt;			if (count & I596_TBD_EOF)				break;			tbdp = (I596_TBD *) S2H(tbdp->next);		}	}	else	{		/*		 *	Otherwise, copy it piece by piece using memcpy()		 */		tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);		for (;;)		{			int	count;			int	amt;			count = tbdp->count;			amt = count & 0x3fff;			if (amt == 0)				break; /* For safety */			if ( (p-putp) >= len)			{				printk("%s: cbp = %x\n", devN->name, H2S(cbp));				proc_reset(dev0, 1);	/* Freeze IDT */				break; /* For Safety */			}			memcpy(p, S2H(tbdp->buf), amt);			p += amt;			if (count & I596_TBD_EOF)				break;			tbdp = (I596_TBD *) S2H(tbdp->next);		}	}	/*	 *	Pass the frame to upper half	 */	skb->protocol = eth_type_trans(skb, devN);	netif_rx(skb);	++privN->stats.rx_packets;out:	cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;}/* *	Start transmission of a frame * *	The interface to the board is simple: we pretend that we are *	a fifth 82596 ethernet controller 'receiving' data, and copy the *	data into the same structures that a real 82596 would.  This way, *	the board firmware handles the host 'port' the same as any other. * *	NOTE: we do not use Bus master DMA for this routine.  Turns out *	that it is not needed.  Slave writes over the PCI bus are about *	as fast as DMA, due to the fact that the PLX part can do burst *	writes.  The same is not true for data being read from the board. * *	For multi-NIC mode, we tell the firmware the desired 82596 *	output port by setting the special "dstchan" member at the *	end of the traditional 82596 RFD structure. */static int dgrs_start_xmit(struct sk_buff *skb, struct device *devN){	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;	struct device	*dev0;	DGRS_PRIV	*priv0;	I596_RBD	*rbdp;	int		count;	int		i, len, amt;#	define		mymin(A,B)	( (A) < (B) ? (A) : (B) )	/*	 *	Determine 0th priv and dev structure pointers	 */	if (dgrs_nicmode)	{		dev0 = privN->devtbl[0];		priv0 = (DGRS_PRIV *) dev0->priv;	}	else	{		dev0 = devN;		priv0 = privN;	}	if (dgrs_debug > 1)		printk("%s: xmit len=%d\n", devN->name, (int) skb->len);	devN->trans_start = jiffies;	devN->tbusy = 0;	if (priv0->rfdp->cmd & I596_RFD_EL)	{	/* Out of RFD's */		if (0) printk("%s: NO RFD's\n", devN->name);		goto no_resources;	}	rbdp = priv0->rbdp;	count = 0;	priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp);	i = 0; len = skb->len;	for (;;)	{		if (rbdp->size & I596_RBD_EL)		{	/* Out of RBD's */			if (0) printk("%s: NO RBD's\n", devN->name);			goto no_resources;		}		amt = mymin(len, rbdp->size - count);		memcpy( (char *) S2H(rbdp->buf) + count, skb->data + i, amt);		i += amt;		count += amt;		len -= amt;		if (len == 0)		{			if (skb->len < 60)				rbdp->count = 60 | I596_RBD_EOF;			else				rbdp->count = count | I596_RBD_EOF;			rbdp = (I596_RBD *) S2H(rbdp->next);			goto frame_done;		}		else if (count < 32)		{			/* More data to come, but we used less than 32			 * bytes of this RBD.  Keep filling this RBD.			 */			{}	/* Yes, we do nothing here */		}		else		{			rbdp->count = count;			rbdp = (I596_RBD *) S2H(rbdp->next);			count = 0;		}	}frame_done:	priv0->rbdp = rbdp;	if (dgrs_nicmode)		priv0->rfdp->dstchan = privN->chan;	priv0->rfdp->status = I596_RFD_C | I596_RFD_OK;	priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next);	++privN->stats.tx_packets;	dev_kfree_skb (skb);	return (0);no_resources:	priv0->scbp->status |= I596_SCB_RNR;	/* simulate I82596 */	return (-EAGAIN);}/* *	Open the interface */static intdgrs_open( struct device *dev ){	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;#ifdef MODULE	MOD_INC_USE_COUNT;#endif	return (0);}/* *	Close the interface */static int dgrs_close( struct device *dev ){	dev->start = 0;	dev->tbusy = 1;#ifdef MODULE	MOD_DEC_USE_COUNT;#endif	return (0);}/* *	Get statistics */static struct net_device_stats *dgrs_get_stats( struct device *dev ){	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;	return (&priv->stats);}/* *	Set multicast list and/or promiscuous mode */static void dgrs_set_multicast_list( struct device *dev){	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;	priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;}/* *	Unique ioctl's */static int dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd){	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;	DGRS_IOCTL	ioc;	int		i;	if (cmd != DGRSIOCTL)		return -EINVAL;	if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))		return -EFAULT;	switch (ioc.cmd)	{		case DGRS_GETMEM:			if (ioc.len != sizeof(ulong))				return -EINVAL;			if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len))				return -EFAULT;			return (0);		case DGRS_SETFILTER:			if (ioc.port > privN->bcomm->bc_nports)				return -EINVAL;			if (ioc.filter >= NFILTERS)				return -EINVAL;			if (ioc.len > privN->bcomm->bc_filter_area_len)				return -EINVAL;			/* Wait for old command to finish */			for (i = 0; i < 1000; ++i)			{				if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )					break;				udelay(1);			}			if (i >= 1000)				return -EIO;			privN->bcomm->bc_filter_port = ioc.port;			privN->bcomm->bc_filter_num = ioc.filter;			privN->bcomm->bc_filter_len = ioc.len;				if (ioc.len)			{				if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),					ioc.data, ioc.len))					return -EFAULT;				privN->bcomm->bc_filter_cmd = BC_FILTER_SET;			}			else				privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;			return(0);		default:			return -EOPNOTSUPP;	}}/* *	Process interrupts * *	dev, priv will always refer to the 0th device in Multi-NIC mode. */static void dgrs_intr(int irq, void *dev_id, struct pt_regs *regs){	struct device	*dev0 = (struct device *) dev_id;	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;	I596_CB		*cbp;	int		cmd;	int		i;	++priv0->intrcnt;	if (1) ++priv0->bcomm->bc_cnt[4];	if (0)	{		static int cnt = 100;		if (--cnt > 0)		printk("%s: interrupt: irq %d\n", dev0->name, irq);	}	/*	 *	Get 596 command	 */	cmd = priv0->scbp->cmd;	/*	 *	See if RU has been restarted	 */	if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START)	{		if (0) printk("%s: RUC start\n", dev0->name);		priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);		priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);		priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS);		/*		 * Tell upper half (halves)		 */		if (dgrs_nicmode)		{			for (i = 0; i < priv0->nports; ++i)				priv0->devtbl[i]->tbusy = 0;		}		else			dev0->tbusy = 0;		/* if (bd->flags & TX_QUEUED)			DL_sched(bd, bdd); */	}	/*	 *	See if any CU commands to process	 */	if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START)	{		priv0->scbp->cmd = 0;	/* Ignore all other commands */		goto ack_intr;	}	priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS);	/*	 *	Process a command	 */	cbp = (I596_CB *) S2H(priv0->scbp->cbp);	priv0->scbp->cmd = 0;	/* Safe to clear the command */	for (;;)	{		switch (cbp->nop.cmd & I596_CB_CMD)		{		case I596_CB_CMD_XMIT:			dgrs_rcv_frame(dev0, priv0, cbp);			break;		default:			cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;			break;		}		if (cbp->nop.cmd & I596_CB_CMD_EL)			break;		cbp = (I596_CB *) S2H(cbp->nop.next);	}	priv0->scbp->status |= I596_SCB_CNA;	/*	 * Ack the interrupt	 */ack_intr:	if (priv0->plxreg)		OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);}/* *	Download the board firmware */__initfunc(static intdgrs_download(struct device *dev0)){	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;	int		is;	int		i;	static int	iv2is[16] = {				0, 0, 0, ES4H_IS_INT3,				0, ES4H_IS_INT5, 0, ES4H_IS_INT7,				0, 0, ES4H_IS_INT10, ES4H_IS_INT11,				ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 };	/*	 * Map in the dual port memory	 */	priv0->vmem = IOREMAP(dev0->mem_start, 2048*1024);	if (!priv0->vmem)	{		printk("%s: cannot map in board memory\n", dev0->name);		return -ENXIO;	}	/*	 *	Hold the processor and configure the board addresses	 */	if (priv0->plxreg)	{	/* PCI bus */		proc_reset(dev0, 1);	}	else	{	/* EISA bus */		is = iv2is[dev0->irq & 0x0f];		if (!is)		{			printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq);			return -ENXIO;		}		OUTB(dev0->base_addr + ES4H_AS_31_24,			(uchar) (dev0->mem_start >> 24) );		OUTB(dev0->base_addr + ES4H_AS_23_16,			(uchar) (dev0->mem_start >> 16) );		priv0->is_reg = ES4H_IS_LINEAR | is |			((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15);		OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg);		OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE);		OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET);		OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00);	}	/*	 *	See if we can do DMA on the SE-6	 */	priv0->use_dma = check_board_dma(dev0);	if (priv0->use_dma)		printk("%s: Bus Master DMA is enabled.\n", dev0->name);	/*	 * Load and verify the code at the desired address	 */	memcpy(priv0->vmem, dgrs_code, dgrs_ncode);	/* Load code */	if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))	{		IOUNMAP(priv0->vmem);		priv0->vmem = NULL;		printk("%s: download compare failed\n", dev0->name);		return -ENXIO;	}	/*	 * Configurables	 */	priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100);	priv0->bcomm->bc_nowait = 1;	/* Tell board to make printf not wait */	priv0->bcomm->bc_squelch = 0;	/* Flag from Space.c */	priv0->bcomm->bc_150ohm = 0;	/* Flag from Space.c */	priv0->bcomm->bc_spew = 0;	/* Debug flag from Space.c */	priv0->bcomm->bc_maxrfd = 0;	/* Debug flag from Space.c */	priv0->bcomm->bc_maxrbd = 0;	/* Debug flag from Space.c */	/*	 * Tell board we are operating in switch mode (1) or in	 * multi-NIC mode (2).	 */	priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH;	/*	 * Request memory space on board for DMA chains	 */	if (priv0->use_dma)		priv0->bcomm->bc_hostarea_len = (2048/64) * 16;

⌨️ 快捷键说明

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