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

📄 tms380tr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	return;}/* * Initializes the open parameter block. */static void tms380tr_init_opb(struct net_device *dev){	struct net_local *tp;	unsigned long Addr;	unsigned short RplSize    = RPL_SIZE;	unsigned short TplSize    = TPL_SIZE;	unsigned short BufferSize = BUFFER_SIZE;	int i;	tp = netdev_priv(dev);	tp->ocpl.OPENOptions 	 = 0;	tp->ocpl.OPENOptions 	|= ENABLE_FULL_DUPLEX_SELECTION;	tp->ocpl.FullDuplex 	 = 0;	tp->ocpl.FullDuplex 	|= OPEN_FULL_DUPLEX_OFF;        /* 	 * Set node address 	 *	 * We go ahead and put it in the OPB even though on	 * most of the generic adapters this isn't required.	 * Its simpler this way.  -- ASF	 */        for (i=0;i<6;i++)                tp->ocpl.NodeAddr[i] = ((unsigned char *)dev->dev_addr)[i];	tp->ocpl.GroupAddr	 = 0;	tp->ocpl.FunctAddr	 = 0;	tp->ocpl.RxListSize	 = cpu_to_be16((unsigned short)RplSize);	tp->ocpl.TxListSize	 = cpu_to_be16((unsigned short)TplSize);	tp->ocpl.BufSize	 = cpu_to_be16((unsigned short)BufferSize);	tp->ocpl.Reserved	 = 0;	tp->ocpl.TXBufMin	 = TX_BUF_MIN;	tp->ocpl.TXBufMax	 = TX_BUF_MAX;	Addr = htonl(((char *)tp->ProductID - (char *)tp) + tp->dmabuffer);	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);	return;}/* * Send OPEN command to adapter */static void tms380tr_open_adapter(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	if(tp->OpenCommandIssued)		return;	tp->OpenCommandIssued = 1;	tms380tr_exec_cmd(dev, OC_OPEN);	return;}/* * Clear the adapter's interrupt flag. Clear system interrupt enable * (SINTEN): disable adapter to system interrupts. */static void tms380tr_disable_interrupts(struct net_device *dev){	SIFWRITEB(0, SIFACL);	return;}/* * Set the adapter's interrupt flag. Set system interrupt enable * (SINTEN): enable adapter to system interrupts. */static void tms380tr_enable_interrupts(struct net_device *dev){	SIFWRITEB(ACL_SINTEN, SIFACL);	return;}/* * Put command in command queue, try to execute it. */static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command){	struct net_local *tp = netdev_priv(dev);	tp->CMDqueue |= Command;	tms380tr_chk_outstanding_cmds(dev);	return;}static void tms380tr_timeout(struct net_device *dev){	/*	 * If we get here, some higher level has decided we are broken.	 * There should really be a "kick me" function call instead.	 *	 * Resetting the token ring adapter takes a long time so just	 * fake transmission time and go on trying. Our own timeout	 * routine is in tms380tr_timer_chk()	 */	dev->trans_start = jiffies;	netif_wake_queue(dev);}/* * Gets skb from system, queues it and checks if it can be sent */static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	int err;	err = tms380tr_hardware_send_packet(skb, dev);	if(tp->TplFree->NextTPLPtr->BusyFlag)		netif_stop_queue(dev);	return (err);}/* * Move frames into adapter tx queue */static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device *dev){	TPL *tpl;	short length;	unsigned char *buf;	unsigned long flags;	int i;	dma_addr_t dmabuf, newbuf;	struct net_local *tp = netdev_priv(dev);   	/* Try to get a free TPL from the chain.	 *	 * NOTE: We *must* always leave one unused TPL in the chain,	 * because otherwise the adapter might send frames twice.	 */	spin_lock_irqsave(&tp->lock, flags);	if(tp->TplFree->NextTPLPtr->BusyFlag)  { /* No free TPL */		if (tms380tr_debug > 0)			printk(KERN_DEBUG "%s: No free TPL\n", dev->name);		spin_unlock_irqrestore(&tp->lock, flags);		return 1;	}	dmabuf = 0;	/* Is buffer reachable for Busmaster-DMA? */	length	= skb->len;	dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE);	if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) {		/* Copy frame to local buffer */		dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE);		dmabuf  = 0;		i 	= tp->TplFree->TPLIndex;		buf 	= tp->LocalTxBuffers[i];		memcpy(buf, skb->data, length);		newbuf 	= ((char *)buf - (char *)tp) + tp->dmabuffer;	}	else {		/* Send direct from skb->data */		newbuf	= dmabuf;		buf	= skb->data;	}	/* Source address in packet? */	tms380tr_chk_src_addr(buf, dev->dev_addr);	tp->LastSendTime	= jiffies;	tpl 			= tp->TplFree;	/* Get the "free" TPL */	tpl->BusyFlag 		= 1;		/* Mark TPL as busy */	tp->TplFree 		= tpl->NextTPLPtr;    	/* Save the skb for delayed return of skb to system */	tpl->Skb = skb;	tpl->DMABuff = dmabuf;	tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length);	tpl->FragList[0].DataAddr  = htonl(newbuf);	/* Write the data length in the transmit list. */	tpl->FrameSize 	= cpu_to_be16((unsigned short)length);	tpl->MData 	= buf;	/* Transmit the frame and set the status values. */	tms380tr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME				| TX_END_FRAME | TX_PASS_SRC_ADDR				| TX_FRAME_IRQ);	/* Let adapter send the frame. */	tms380tr_exec_sifcmd(dev, CMD_TX_VALID);	spin_unlock_irqrestore(&tp->lock, flags);	return 0;}/* * Write the given value to the 'Status' field of the specified TPL. * NOTE: This function should be used whenever the status of any TPL must be * modified by the driver, because the compiler may otherwise change the * order of instructions such that writing the TPL status may be executed at * an undesireable time. When this function is used, the status is always * written when the function is called. */static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status){	tpl->Status = Status;}static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr){	unsigned char SRBit;	if((((unsigned long)frame[8]) & ~0x80) != 0)	/* Compare 4 bytes */		return;	if((unsigned short)frame[12] != 0)		/* Compare 2 bytes */		return;	SRBit = frame[8] & 0x80;	memcpy(&frame[8], hw_addr, 6);	frame[8] |= SRBit;	return;}/* * The timer routine: Check if adapter still open and working, reopen if not.  */static void tms380tr_timer_chk(unsigned long data){	struct net_device *dev = (struct net_device*)data;	struct net_local *tp = netdev_priv(dev);	if(tp->HaltInProgress)		return;	tms380tr_chk_outstanding_cmds(dev);	if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies)		&& (tp->TplFree != tp->TplBusy))	{		/* Anything to send, but stalled too long */		tp->LastSendTime = jiffies;		tms380tr_exec_cmd(dev, OC_CLOSE);	/* Does reopen automatically */	}	tp->timer.expires = jiffies + 2*HZ;	add_timer(&tp->timer);	if(tp->AdapterOpenFlag || tp->ReOpenInProgress)		return;	tp->ReOpenInProgress = 1;	tms380tr_open_adapter(dev);	return;}/* * The typical workload of the driver: Handle the network interface interrupts. */irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct net_local *tp;	unsigned short irq_type;	int handled = 0;	if(dev == NULL) {		printk(KERN_INFO "%s: irq %d for unknown device.\n", dev->name, irq);		return IRQ_NONE;	}	tp = netdev_priv(dev);	irq_type = SIFREADW(SIFSTS);	while(irq_type & STS_SYSTEM_IRQ) {		handled = 1;		irq_type &= STS_IRQ_MASK;		if(!tms380tr_chk_ssb(tp, irq_type)) {			printk(KERN_DEBUG "%s: DATA LATE occurred\n", dev->name);			break;		}		switch(irq_type) {		case STS_IRQ_RECEIVE_STATUS:			tms380tr_reset_interrupt(dev);			tms380tr_rcv_status_irq(dev);			break;		case STS_IRQ_TRANSMIT_STATUS:			/* Check if TRANSMIT.HALT command is complete */			if(tp->ssb.Parm[0] & COMMAND_COMPLETE) {				tp->TransmitCommandActive = 0;					tp->TransmitHaltScheduled = 0;					/* Issue a new transmit command. */					tms380tr_exec_cmd(dev, OC_TRANSMIT);				}				tms380tr_reset_interrupt(dev);				tms380tr_tx_status_irq(dev);				break;		case STS_IRQ_COMMAND_STATUS:			/* The SSB contains status of last command			 * other than receive/transmit.			 */			tms380tr_cmd_status_irq(dev);			break;					case STS_IRQ_SCB_CLEAR:			/* The SCB is free for another command. */			tp->ScbInUse = 0;			tms380tr_chk_outstanding_cmds(dev);			break;					case STS_IRQ_RING_STATUS:			tms380tr_ring_status_irq(dev);			break;		case STS_IRQ_ADAPTER_CHECK:			tms380tr_chk_irq(dev);			break;		case STS_IRQ_LLC_STATUS:			printk(KERN_DEBUG "tms380tr: unexpected LLC status IRQ\n");			break;					case STS_IRQ_TIMER:			printk(KERN_DEBUG "tms380tr: unexpected Timer IRQ\n");			break;					case STS_IRQ_RECEIVE_PENDING:			printk(KERN_DEBUG "tms380tr: unexpected Receive Pending IRQ\n");			break;					default:			printk(KERN_DEBUG "Unknown Token Ring IRQ (0x%04x)\n", irq_type);			break;		}		/* Reset system interrupt if not already done. */		if(irq_type != STS_IRQ_TRANSMIT_STATUS			&& irq_type != STS_IRQ_RECEIVE_STATUS) {			tms380tr_reset_interrupt(dev);		}		irq_type = SIFREADW(SIFSTS);	}	return IRQ_RETVAL(handled);}/* *  Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. */static void tms380tr_reset_interrupt(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	SSB *ssb = &tp->ssb;	/*	 * [Workaround for "Data Late"]	 * Set all fields of the SSB to well-defined values so we can	 * check if the adapter has written the SSB.	 */	ssb->STS	= (unsigned short) -1;	ssb->Parm[0] 	= (unsigned short) -1;	ssb->Parm[1] 	= (unsigned short) -1;	ssb->Parm[2] 	= (unsigned short) -1;	/* Free SSB by issuing SSB_CLEAR command after reading IRQ code	 * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts.	 */	tms380tr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ);	return;}/* * Check if the SSB has actually been written by the adapter. */static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType){	SSB *ssb = &tp->ssb;	/* The address of the SSB. */	/* C 0 1 2 INTERRUPT CODE	 * - - - - --------------	 * 1 1 1 1 TRANSMIT STATUS	 * 1 1 1 1 RECEIVE STATUS	 * 1 ? ? 0 COMMAND STATUS	 * 0 0 0 0 SCB CLEAR	 * 1 1 0 0 RING STATUS	 * 0 0 0 0 ADAPTER CHECK	 *	 * 0 = SSB field not affected by interrupt	 * 1 = SSB field is affected by interrupt	 *	 * C = SSB ADDRESS +0: COMMAND	 * 0 = SSB ADDRESS +2: STATUS 0	 * 1 = SSB ADDRESS +4: STATUS 1	 * 2 = SSB ADDRESS +6: STATUS 2	 */	/* Check if this interrupt does use the SSB. */	if(IrqType != STS_IRQ_TRANSMIT_STATUS		&& IrqType != STS_IRQ_RECEIVE_STATUS		&& IrqType != STS_IRQ_COMMAND_STATUS		&& IrqType != STS_IRQ_RING_STATUS)	{		return (1);	/* SSB not involved. */	}	/* Note: All fields of the SSB have been set to all ones (-1) after it	 * has last been used by the software (see DriverIsr()).	 *	 * Check if the affected SSB fields are still unchanged.	 */	if(ssb->STS == (unsigned short) -1)		return (0);	/* Command field not yet available. */	if(IrqType == STS_IRQ_COMMAND_STATUS)		return (1);	/* Status fields not always affected. */	if(ssb->Parm[0] == (unsigned short) -1)		return (0);	/* Status 1 field not yet available. */	if(IrqType == STS_IRQ_RING_STATUS)		return (1);	/* Status 2 & 3 fields not affected. */	/* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */	if(ssb->Parm[1] == (unsigned short) -1)		return (0);	/* Status 2 field not yet available. */	if(ssb->Parm[2] == (unsigned short) -1)		return (0);	/* Status 3 field not yet available. */	return (1);	/* All SSB fields have been written by the adapter. */}/* * Evaluates the command results status in the SSB status field. */static void tms380tr_cmd_status_irq(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	unsigned short ssb_cmd, ssb_parm_0;	unsigned short ssb_parm_1;	char *open_err = "Open error -";	char *code_err = "Open code -";	/* Copy the ssb values to local variables */	ssb_cmd    = tp->ssb.STS;	ssb_parm_0 = tp->ssb.Parm[0];	ssb_parm_1 = tp->ssb.Parm[1];	if(ssb_cmd == OPEN)	{		tp->Sleeping = 0;		if(!tp->ReOpenInProgress)	    		wake_up_interruptible(&tp->wait_for_tok_int);		tp->OpenCommandIssued = 0;		tp->ScbInUse = 0;		if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION)		{			/* Success, the adapter is open. */			tp->LobeWireFaultLogged	= 0;			tp->AdapterOpenFlag 	= 1;			tp->AdapterVirtOpenFlag = 1;			tp->TransmitCommandActive = 0;			tms380tr_exec_cmd(dev, OC_TRANSMIT);

⌨️ 快捷键说明

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