sun3_82586.c

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

C
1,212
字号
	volatile struct iasetup_cmd_struct *ias_cmd;	volatile struct tdr_cmd_struct *tdr_cmd;	volatile struct mcsetup_cmd_struct *mc_cmd;	struct dev_mc_list *dmi=dev->mc_list;	int num_addrs=dev->mc_count;	ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));	cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */	cfg_cmd->cmd_status	= 0;	cfg_cmd->cmd_cmd	= swab16(CMD_CONFIGURE | CMD_LAST);	cfg_cmd->cmd_link	= 0xffff;	cfg_cmd->byte_cnt	= 0x0a; /* number of cfg bytes */	cfg_cmd->fifo		= fifo; /* fifo-limit (8=tx:32/rx:64) */	cfg_cmd->sav_bf		= 0x40; /* hold or discard bad recv frames (bit 7) */	cfg_cmd->adr_len	= 0x2e; /* addr_len |!src_insert |pre-len |loopback */	cfg_cmd->priority	= 0x00;	cfg_cmd->ifs		= 0x60;	cfg_cmd->time_low	= 0x00;	cfg_cmd->time_high	= 0xf2;	cfg_cmd->promisc	= 0;	if(dev->flags & IFF_ALLMULTI) {		int len = ((char *) p->iscp - (char *) ptr - 8) / 6;		if(num_addrs > len)	{			printk("%s: switching to promisc. mode\n",dev->name);			dev->flags|=IFF_PROMISC;		}	}	if(dev->flags&IFF_PROMISC)	{			 cfg_cmd->promisc=1;			 dev->flags|=IFF_PROMISC;	}	cfg_cmd->carr_coll	= 0x00;	p->scb->cbl_offset	= make16(cfg_cmd);	p->scb->cmd_ruc		= 0;	p->scb->cmd_cuc		= CUC_START; /* cmd.-unit start */	sun3_attn586();	WAIT_4_STAT_COMPL(cfg_cmd);	if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))	{		printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));		return 1;	}	/*	 * individual address setup	 */	ias_cmd = (struct iasetup_cmd_struct *)ptr;	ias_cmd->cmd_status	= 0;	ias_cmd->cmd_cmd	= swab16(CMD_IASETUP | CMD_LAST);	ias_cmd->cmd_link	= 0xffff;	memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);	p->scb->cbl_offset = make16(ias_cmd);	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */	sun3_attn586();	WAIT_4_STAT_COMPL(ias_cmd);	if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {		printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));		return 1;	}	/*	 * TDR, wire check .. e.g. no resistor e.t.c	 */	 	tdr_cmd = (struct tdr_cmd_struct *)ptr;	tdr_cmd->cmd_status	= 0;	tdr_cmd->cmd_cmd	= swab16(CMD_TDR | CMD_LAST);	tdr_cmd->cmd_link	= 0xffff;	tdr_cmd->status		= 0;	p->scb->cbl_offset = make16(tdr_cmd);	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */	sun3_attn586();	WAIT_4_STAT_COMPL(tdr_cmd);	if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))	{		printk("%s: Problems while running the TDR.\n",dev->name);	}	else	{		DELAY_16(); /* wait for result */		result = swab16(tdr_cmd->status);		p->scb->cmd_cuc = p->scb->cus & STAT_MASK;		sun3_attn586(); /* ack the interrupts */		if(result & TDR_LNK_OK)			;		else if(result & TDR_XCVR_PRB)			printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);		else if(result & TDR_ET_OPN)			printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);		else if(result & TDR_ET_SRT)		{			if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */				printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);		}		else			printk("%s: TDR: Unknown status %04x\n",dev->name,result);	}	/*	 * Multicast setup	 */	if(num_addrs && !(dev->flags & IFF_PROMISC) )	{		mc_cmd = (struct mcsetup_cmd_struct *) ptr;		mc_cmd->cmd_status = 0;		mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);		mc_cmd->cmd_link = 0xffff;		mc_cmd->mc_cnt = swab16(num_addrs * 6);		for(i=0;i<num_addrs;i++,dmi=dmi->next)			memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);		p->scb->cbl_offset = make16(mc_cmd);		p->scb->cmd_cuc = CUC_START;		sun3_attn586();		WAIT_4_STAT_COMPL(mc_cmd);		if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )			printk("%s: Can't apply multicast-address-list.\n",dev->name);	}	/*	 * alloc nop/xmit-cmds	 */#if (NUM_XMIT_BUFFS == 1)	for(i=0;i<2;i++)	{		p->nop_cmds[i] 			= (struct nop_cmd_struct *)ptr;		p->nop_cmds[i]->cmd_cmd		= swab16(CMD_NOP);		p->nop_cmds[i]->cmd_status 	= 0;		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);	}#else	for(i=0;i<NUM_XMIT_BUFFS;i++)	{		p->nop_cmds[i]			= (struct nop_cmd_struct *)ptr;		p->nop_cmds[i]->cmd_cmd		= swab16(CMD_NOP);		p->nop_cmds[i]->cmd_status	= 0;		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);	}#endif	ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */	/*	 * alloc xmit-buffs / init xmit_cmds	 */	for(i=0;i<NUM_XMIT_BUFFS;i++)	{		p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/		ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);		p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */		ptr = (char *) ptr + XMIT_BUFF_SIZE;		p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */		ptr = (char *) ptr + sizeof(struct tbd_struct);		if((void *)ptr > (void *)dev->mem_end)		{			printk("%s: not enough shared-mem for your configuration!\n",dev->name);			return 1;		}		memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));		memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));		p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);		p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);		p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);		p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));		p->xmit_buffs[i]->next = 0xffff;		p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));	}	p->xmit_count = 0;	p->xmit_last	= 0;#ifndef NO_NOPCOMMANDS	p->nop_point	= 0;#endif	 /*		* 'start transmitter'		*/#ifndef NO_NOPCOMMANDS	p->scb->cbl_offset = make16(p->nop_cmds[0]);	p->scb->cmd_cuc = CUC_START;	sun3_attn586();	WAIT_4_SCB_CMD();#else	p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);	p->xmit_cmds[0]->cmd_cmd	= swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);#endif	/*	 * ack. interrupts	 */	p->scb->cmd_cuc = p->scb->cus & STAT_MASK;	sun3_attn586();	DELAY_16();	sun3_enaint();	sun3_active();	return 0;}/****************************************************** * This is a helper routine for sun3_82586_rnr_int() and init586(). * It sets up the Receive Frame Area (RFA). */static void *alloc_rfa(struct net_device *dev,void *ptr){	volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;	volatile struct rbd_struct *rbd;	int i;	struct priv *p = (struct priv *) dev->priv;	memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));	p->rfd_first = rfd;	for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {		rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );		rfd[i].rbd_offset = 0xffff;	}	rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;	 /* RU suspend */	ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );	rbd = (struct rbd_struct *) ptr;	ptr = (void *) (rbd + p->num_recv_buffs);	 /* clr descriptors */	memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));	for(i=0;i<p->num_recv_buffs;i++)	{		rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));		rbd[i].size = swab16(RECV_BUFF_SIZE);		rbd[i].buffer = make24(ptr);		ptr = (char *) ptr + RECV_BUFF_SIZE;	}	p->rfd_top	= p->rfd_first;	p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);	p->scb->rfa_offset		= make16(p->rfd_first);	p->rfd_first->rbd_offset	= make16(rbd);	return ptr;}/************************************************** * Interrupt Handler ... */static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr){	struct net_device *dev = dev_id;	unsigned short stat;	int cnt=0;	struct priv *p;	if (!dev) {		printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);		return IRQ_NONE;	}	p = (struct priv *) dev->priv;	if(debuglevel > 1)		printk("I");	WAIT_4_SCB_CMD(); /* wait for last command	*/	while((stat=p->scb->cus & STAT_MASK))	{		p->scb->cmd_cuc = stat;		sun3_attn586();		if(stat & STAT_FR)	 /* received a frame */			sun3_82586_rcv_int(dev);		if(stat & STAT_RNR) /* RU went 'not ready' */		{			printk("(R)");			if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */			{				WAIT_4_SCB_CMD();				p->scb->cmd_ruc = RUC_RESUME;				sun3_attn586();				WAIT_4_SCB_CMD_RUC();			}			else			{				printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);				sun3_82586_rnr_int(dev);			}		}		if(stat & STAT_CX)		/* command with I-bit set complete */			 sun3_82586_xmt_int(dev);#ifndef NO_NOPCOMMANDS		if(stat & STAT_CNA)	/* CU went 'not ready' */		{			if(netif_running(dev))				printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);		}#endif		if(debuglevel > 1)			printk("%d",cnt++);		WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */		if(p->scb->cmd_cuc)	 /* timed out? */		{			printk("%s: Acknowledge timed out.\n",dev->name);			sun3_disint();			break;		}	}	if(debuglevel > 1)		printk("i");	return IRQ_HANDLED;}/******************************************************* * receive-interrupt */static void sun3_82586_rcv_int(struct net_device *dev){	int status,cnt=0;	unsigned short totlen;	struct sk_buff *skb;	struct rbd_struct *rbd;	struct priv *p = (struct priv *) dev->priv;	if(debuglevel > 0)		printk("R");	for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)	{			rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);			if(status & RFD_OK) /* frame received without error? */			{				if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */				{					totlen &= RBD_MASK; /* length of this frame */					rbd->status = 0;					skb = (struct sk_buff *) dev_alloc_skb(totlen+2);					if(skb != NULL)					{						skb->dev = dev;						skb_reserve(skb,2);						skb_put(skb,totlen);						eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);						skb->protocol=eth_type_trans(skb,dev);						netif_rx(skb);						p->stats.rx_packets++;					}					else						p->stats.rx_dropped++;				}				else				{					int rstat;						 /* free all RBD's until RBD_LAST is set */					totlen = 0;					while(!((rstat=swab16(rbd->status)) & RBD_LAST))					{						totlen += rstat & RBD_MASK;						if(!rstat)						{							printk("%s: Whoops .. no end mark in RBD list\n",dev->name);							break;						}						rbd->status = 0;						rbd = (struct rbd_struct *) make32(rbd->next);					}					totlen += rstat & RBD_MASK;					rbd->status = 0;

⌨️ 快捷键说明

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