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

📄 sky2.c

📁 这是Marvell Technology Group Ltd. 4355 (rev 12)网卡在linux下的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* 	** Check for Special Interrupts 	*/	if ((pAC->InterruptSource & ~Y2_IS_STAT_BMU) || pAC->CheckQueue || pNet->TimerExpired) {		pAC->CheckQueue = SK_FALSE;		spin_lock_irqsave(&pAC->SetPutIndexLock, Flags);		SkGeSirqIsr(pAC, pAC->IoBase, pAC->InterruptSource);		SkEventDispatcher(pAC, pAC->IoBase);		spin_unlock_irqrestore(&pAC->SetPutIndexLock, Flags);	}	/* Speed enhancement for a2 chipsets */	if (HW_FEATURE(pAC, HWF_WA_DEV_42)) {		spin_lock_irqsave(&pAC->SetPutIndexLock, Flags);		SkGeY2SetPutIndex(pAC, pAC->IoBase, Y2_PREF_Q_ADDR(Q_XA1,0), &pAC->TxPort[0][0].TxALET);		SkGeY2SetPutIndex(pAC, pAC->IoBase, Y2_PREF_Q_ADDR(Q_R1,0), &pAC->RxPort[0].RxLET);		spin_unlock_irqrestore(&pAC->SetPutIndexLock, Flags);	}	/* 	** Reenable interrupts and signal end of ISR 	*/	SK_OUT32(pAC->IoBase, B0_Y2_SP_ICR, 2);	/*	** Stop and restart TX timer in case a Status LE was handled	*/	if ((HW_FEATURE(pAC, HWF_WA_DEV_43_418)) && (handledStatLE)) {		SK_OUT8(pAC->IoBase, STAT_TX_TIMER_CTRL, TIM_STOP);		SK_OUT8(pAC->IoBase, STAT_TX_TIMER_CTRL, TIM_START);	}	if (!(IS_Q_EMPTY(&(pAC->TxPort[0][TX_PRIO_LOW].TxAQ_waiting)))) {		GiveTxBufferToHw(pAC, pAC->IoBase, 0);	}	if (!(IS_Q_EMPTY(&(pAC->TxPort[1][TX_PRIO_LOW].TxAQ_waiting)))) {		GiveTxBufferToHw(pAC, pAC->IoBase, 1);	}#endif	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,		("<== SkY2Isr\n"));	return SkIsrRetHandled;}	/* SkY2Isr *//***************************************************************************** * *	SkY2Xmit - Linux frame transmit function for Yukon2 * * Description: *	The system calls this function to send frames onto the wire. *	It puts the frame in the tx descriptor ring. If the ring is *	full then, the 'tbusy' flag is set. * * Returns: *	0, if everything is ok *	!=0, on error * * WARNING:  *	returning 1 in 'tbusy' case caused system crashes (double *	allocated skb's) !!! */int SkY2Xmit(struct sk_buff       *skb,  /* socket buffer to be sent */struct SK_NET_DEVICE *dev)  /* via which device?        */{	DEV_NET         *pNet    = (DEV_NET*) dev->priv;	SK_AC           *pAC     = pNet->pAC;	SK_U8            FragIdx = 0;	SK_PACKET       *pSkPacket;	SK_FRAG         *PrevFrag;	SK_FRAG         *CurrFrag;	SK_PKT_QUEUE    *pWorkQueue;  /* corresponding TX queue */	SK_PKT_QUEUE    *pWaitQueue; 	SK_PKT_QUEUE    *pFreeQueue; 	SK_LE_TABLE     *pLETab;      /* corresponding LETable  */ 	skb_frag_t      *sk_frag;	SK_U64           PhysAddr;	unsigned long    Flags;	unsigned int     Port;	int              CurrFragCtr;	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,		("==> SkY2Xmit\n"));	/*	** Get port and return if no free packet is available 	*/	if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) {		Port = skb_shinfo(skb)->nr_frags - (2*MAX_SKB_FRAGS);		skb_shinfo(skb)->nr_frags = 0;	} else {		Port = (pAC->RlmtNets == 2) ? pNet->PortNr : pAC->ActivePort;	}#ifdef USE_ASF_DASH_FW	if ((pAC->dev[Port]->flags & IFF_RUNNING) == 0) {		DEV_KFREE_SKB_ANY(skb);		return 0;	}#endif	if (IS_Q_EMPTY(&(pAC->TxPort[Port][TX_PRIO_LOW].TxQ_free))) {		SK_DBG_MSG(pAC, SK_DBGMOD_DRV, 			SK_DBGCAT_DRV_TX_PROGRESS | SK_DBGCAT_DRV_ERROR,			("Not free packets available for send\n"));		return 1; /* zero bytes sent! */	}	/*	** Put any new packet to be sent in the waiting queue and 	** handle also any possible fragment of that packet.	*/	pWorkQueue = &(pAC->TxPort[Port][TX_PRIO_LOW].TxAQ_working);	pWaitQueue = &(pAC->TxPort[Port][TX_PRIO_LOW].TxAQ_waiting);	pFreeQueue = &(pAC->TxPort[Port][TX_PRIO_LOW].TxQ_free);	pLETab     = &(pAC->TxPort[Port][TX_PRIO_LOW].TxALET);	/*	** Normal send operations require only one fragment, because 	** only one sk_buff data area is passed. 	** In contradiction to this, scatter-gather (zerocopy) send	** operations might pass one or more additional fragments 	** where each fragment needs a separate fragment info packet.	*/	if (((skb_shinfo(skb)->nr_frags + 1) * MAX_FRAG_OVERHEAD) > 					NUM_FREE_LE_IN_TABLE(pLETab)) {		SK_DBG_MSG(pAC, SK_DBGMOD_DRV, 			SK_DBGCAT_DRV_TX_PROGRESS | SK_DBGCAT_DRV_ERROR,			("Not enough LE available for send\n"));		return 1; /* zero bytes sent! */	}		if ((skb_shinfo(skb)->nr_frags + 1) > MAX_NUM_FRAGS) {		SK_DBG_MSG(pAC, SK_DBGMOD_DRV, 			SK_DBGCAT_DRV_TX_PROGRESS | SK_DBGCAT_DRV_ERROR,			("Not even one fragment available for send\n"));		return 1; /* zero bytes sent! */	}	/*	** Get first packet from free packet queue	*/	POP_FIRST_PKT_FROM_QUEUE(pFreeQueue, pSkPacket);	if(pSkPacket == NULL) {		SK_DBG_MSG(pAC, SK_DBGMOD_DRV, 			SK_DBGCAT_DRV_TX_PROGRESS | SK_DBGCAT_DRV_ERROR,			("Could not obtain free packet used for xmit\n"));		return 1; /* zero bytes sent! */	}	pSkPacket->pFrag = &(pSkPacket->FragArray[FragIdx]);	/* 	** map the sk_buff to be available for the adapter 	*/	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,			virt_to_page(skb->data),			((unsigned long) skb->data & ~PAGE_MASK),			skb_headlen(skb),			PCI_DMA_TODEVICE);	pSkPacket->pMBuf	  = skb;	pSkPacket->pFrag->pPhys   = PhysAddr;	pSkPacket->pFrag->FragLen = skb_headlen(skb);	pSkPacket->pFrag->pNext   = NULL; /* initial has no next default */	pSkPacket->NumFrags	  = skb_shinfo(skb)->nr_frags + 1;	PrevFrag = pSkPacket->pFrag;	/*	** Each scatter-gather fragment need to be mapped...	*/        for (	CurrFragCtr = 0; 		CurrFragCtr < skb_shinfo(skb)->nr_frags;		CurrFragCtr++) {		FragIdx++;		sk_frag = &skb_shinfo(skb)->frags[CurrFragCtr];		CurrFrag = &(pSkPacket->FragArray[FragIdx]);		/* 		** map the sk_buff to be available for the adapter 		*/		PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,				sk_frag->page,		 		sk_frag->page_offset,		 		sk_frag->size,		 		PCI_DMA_TODEVICE);		CurrFrag->pPhys   = PhysAddr; 		CurrFrag->FragLen = sk_frag->size; 		CurrFrag->pNext   = NULL;		/*		** Add the new fragment to the list of fragments		*/		PrevFrag->pNext = CurrFrag;		PrevFrag = CurrFrag;	}	/* 	** Add packet to waiting packets queue 	*/	PUSH_PKT_AS_LAST_IN_QUEUE(pWaitQueue, pSkPacket);	GiveTxBufferToHw(pAC, pAC->IoBase, Port);	dev->trans_start = jiffies;	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,		("<== SkY2Xmit(return 0)\n"));	return (0);}	/* SkY2Xmit */#ifdef CONFIG_SK98LIN_NAPI/***************************************************************************** * *	SkY2Poll - NAPI Rx polling callback for Yukon2 chipsets * * Description: *	Called by the Linux system in case NAPI polling is activated * * Returns *	The number of work data still to be handled * * Notes *	The slowpath lock needs to be set because HW accesses may *	interfere with slowpath events (e.g. TWSI) */int SkY2Poll(struct net_device *dev,     /* device that needs to be polled */int               *budget)  /* how many budget do we have?    */{	DEV_NET       *pNet         = (DEV_NET*) dev->priv;	SK_AC	      *pAC          = pNet->pAC;	int           WorkToDo      = min(*budget, dev->quota);	int           WorkDone      = 0;	SK_BOOL       handledStatLE = SK_FALSE;	handledStatLE = HandleStatusLEs(pAC, &WorkDone, WorkToDo);	*budget -= WorkDone;	dev->quota -= WorkDone;	/* 	** Check for Special Interrupts 	*/	if ((pAC->InterruptSource & ~Y2_IS_STAT_BMU) || pAC->CheckQueue || pNet->TimerExpired) {		pAC->CheckQueue = SK_FALSE;		spin_lock(&pAC->SlowPathLock);		SkGeSirqIsr(pAC, pAC->IoBase, pAC->InterruptSource);		SkEventDispatcher(pAC, pAC->IoBase);		spin_unlock(&pAC->SlowPathLock);	}	/* Speed enhancement for a2 chipsets */	if (HW_FEATURE(pAC, HWF_WA_DEV_42)) {		spin_lock(&pAC->SlowPathLock);		SkGeY2SetPutIndex(pAC, pAC->IoBase, Y2_PREF_Q_ADDR(Q_XA1,0), &pAC->TxPort[0][0].TxALET);		SkGeY2SetPutIndex(pAC, pAC->IoBase, Y2_PREF_Q_ADDR(Q_R1,0), &pAC->RxPort[0].RxLET);		spin_unlock(&pAC->SlowPathLock);	}	if(WorkDone < WorkToDo) {		netif_rx_complete(dev);		/*		** Stop and restart TX timer in case a Status LE was handled		*/		if ((HW_FEATURE(pAC, HWF_WA_DEV_43_418)) && (handledStatLE)) {			SK_OUT8(pAC->IoBase, STAT_TX_TIMER_CTRL, TIM_STOP);			SK_OUT8(pAC->IoBase, STAT_TX_TIMER_CTRL, TIM_START);		}		/* 		** Reenable interrupts		*/		SK_OUT32(pAC->IoBase, B0_Y2_SP_ICR, 2);		if (!(IS_Q_EMPTY(&(pAC->TxPort[0][TX_PRIO_LOW].TxAQ_waiting)))) {			GiveTxBufferToHw(pAC, pAC->IoBase, 0);		}		if (!(IS_Q_EMPTY(&(pAC->TxPort[1][TX_PRIO_LOW].TxAQ_waiting)))) {			GiveTxBufferToHw(pAC, pAC->IoBase, 1);		}	}	return (WorkDone >= WorkToDo);}	/* SkY2Poll */#endif/****************************************************************************** * *	SkY2PortStop - stop a port on Yukon2 * * Description: *	This function stops a port of the Yukon2 chip. This stop  *	stop needs to be performed in a specific order: *  *	a) Stop the Prefetch unit *	b) Stop the Port (MAC, PHY etc.) * * Returns: N/A */void SkY2PortStop(SK_AC   *pAC,      /* adapter control context                             */SK_IOC   IoC,      /* I/O control context (address of adapter registers)  */int      Port,     /* port to stop (MAC_1 + n)                            */int      Dir,      /* StopDirection (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */int      RstMode)  /* Reset Mode (SK_SOFT_RST, SK_HARD_RST)               */{	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG,		("==> SkY2PortStop (Port %c)\n", 'A' + Port));	/*	** Stop the HW	*/	SkGeStopPort(pAC, IoC, Port, Dir, RstMode);	/*	** Move any TX packet from work queues into the free queue again	** and initialize the TX LETable variables	*/	SkY2FreeTxBuffers(pAC, pAC->IoBase, Port);	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Bmu.RxTx.TcpWp    = 0;	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Bmu.RxTx.MssValue = 0;	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.BufHighAddr       = 0;	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Done              = 0;    	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Put               = 0;#ifndef USE_ASF_DASH_FW	pAC->GIni.GP[Port].PState = SK_PRT_STOP;#endif	/*	** Move any RX packet from work queue into the waiting queue	** and initialize the RX LETable variables	*/	SkY2FreeRxBuffers(pAC, pAC->IoBase, Port);	pAC->RxPort[Port].RxLET.BufHighAddr = 0;	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG,		("<== SkY2PortStop()\n"));}/****************************************************************************** * *	SkY2PortStart - start a port on Yukon2 * * Description: *	This function starts a port of the Yukon2 chip. This start  *	action needs to be performed in a specific order: *  *	a) Initialize the LET indices (PUT/GET to 0) *	b) Initialize the LET in HW (enables also prefetch unit) *	c) Move all RX buffers from waiting queue to working queue *	   which involves also setting up of RX list elements *	d) Initialize the FIFO settings of Yukon2 (Watermark etc.) *	e) Initialize the Port (MAC, PHY etc.) *	f) Initialize the MC addresses * * Returns:	N/A */void SkY2PortStart(SK_AC   *pAC,   /* adapter control context                            */SK_IOC   IoC,   /* I/O control context (address of adapter registers) */int      Port)  /* port to start                                      */{	// SK_GEPORT *pPrt = &pAC->GIni.GP[Port];	SK_HWLE   *pLE;	SK_U32     DWord;	SK_U32     PrefetchReg; /* register for Put index */	SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG,		("==> SkY2PortStart (Port %c)\n", 'A' + Port));	/*	** Initialize the LET indices	*/	pAC->RxPort[Port].RxLET.Done                = 0; 	pAC->RxPort[Port].RxLET.Put                 = 0;	pAC->RxPort[Port].RxLET.HwPut               = 0;	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Done  = 0;    	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.Put   = 0;	pAC->TxPort[Port][TX_PRIO_LOW].TxALET.HwPut = 0;	if (HW_SYNC_TX_SUPPORTED(pAC)) {		pAC->TxPort[Port][TX_PRIO_LOW].TxSLET.Done  = 0;    		pAC->TxPort[Port][TX_PRIO_LOW].TxSLET.Put   = 0;		pAC->TxPort[Port][TX_PRIO_LOW].TxSLET.HwPut = 0;	}		if (HW_FEATURE(pAC, HWF_WA_DEV_420)) {		/*		** It might be that we have to limit the RX buffers 		** effectively passed to HW. Initialize the start		** value in that case...		*/		NbrRxBuffersInHW = 0;	}	/*	** TODO on dual net adapters we need to check if	** StatusLETable need to be set...	** 	** pAC->StatusLETable.Done  = 0;	** pAC->StatusLETable.Put   = 0;	** pAC->StatusLETable.HwPut = 0;	** SkGeY2InitPrefetchUnit(pAC, pAC->IoBase, Q_ST, &pAC->StatusLETable);	*/	/*	** Initialize the LET in HW (enables also prefetch unit)	*/	SkGeY2InitPrefetchUnit(pAC, IoC,(Port == 0) ? Q_R1 : Q_R2,			&pAC->RxPort[Port].RxLET);	SkGeY2InitPrefetchUnit( pAC, IoC,(Port == 0) ? Q_XA1 : Q_XA2, 			&pAC->TxPort[Port][TX_PRIO_LOW].TxALET);	if (HW_SYNC_TX_SUPPORTED(pAC)) {		SkGeY2InitPrefetchUnit( pAC, IoC, (Port == 0) ? Q_XS1 : Q_XS2,				&pAC->TxPort[Port][TX_PRIO_HIGH].TxSLET);	}	/*	** Using new values for the watermarks and the timer for	** low latency optimization	*/	if (pAC->LowLatency) {		SK_OUT8(IoC, STAT_FIFO_WM, 1);		SK_OUT8(IoC, STAT_FIFO_ISR_WM, 1);		SK_OUT32(IoC, STAT_LEV_TIMER_INI, 50);		SK_OUT32(IoC, STAT_ISR_TIMER_INI, 10);	}	/*	** Initialize the Port (MAC, PHY etc.)

⌨️ 快捷键说明

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