📄 sky2.c
字号:
/****************************************************************************** * * Name: sky2.c * Project: Yukon2 specific functions and implementations * Version: $Revision: 1.38.4.31 $ * Date: $Date: 2008/03/20 14:31:37 $ * Purpose: The main driver source module * *****************************************************************************//****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. * (C)Copyright 2002-2007 Marvell. * * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet * Server Adapters. * * Address all question to: gr-msgg-linux@marvell.com * * LICENSE: * (C)Copyright Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The information in this file is provided "AS IS" without warranty. * /LICENSE * *****************************************************************************/#include "h/skdrv1st.h"#include "h/skdrv2nd.h"#include <linux/tcp.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,14)#include <linux/ip.h>#endif/****************************************************************************** * * Local Function Prototypes * *****************************************************************************/static void InitPacketQueues(SK_AC *pAC,int Port);static void GiveTxBufferToHw(SK_AC *pAC,SK_IOC IoC,int Port);static void GiveRxBufferToHw(SK_AC *pAC,SK_IOC IoC,int Port,SK_PACKET *pPacket);#ifdef SK_EXTREMEstatic SK_BOOL HandleReceives(SK_AC *pAC,int Port,SK_U16 Len,SK_U32 FrameStatus,SK_U16 Tcp1,SK_U16 Tcp2,SK_U32 Tist,SK_U16 Vlan, SK_U32 ExtremeCsumResult);#elsestatic SK_BOOL HandleReceives(SK_AC *pAC,int Port,SK_U16 Len,SK_U32 FrameStatus,SK_U16 Tcp1,SK_U16 Tcp2,SK_U32 Tist,SK_U16 Vlan);#endifstatic void CheckForSendComplete(SK_AC *pAC,SK_IOC IoC,int Port,SK_PKT_QUEUE *pPQ,SK_LE_TABLE *pLETab,unsigned int Done);static void UnmapAndFreeTxPktBuffer(SK_AC *pAC,SK_PACKET *pSkPacket,int TxPort);static SK_BOOL AllocateAndInitLETables(SK_AC *pAC);static SK_BOOL AllocatePacketBuffersYukon2(SK_AC *pAC);static void FreeLETables(SK_AC *pAC);static void FreePacketBuffers(SK_AC *pAC);static SK_BOOL AllocAndMapRxBuffer(SK_AC *pAC,SK_PACKET *pSkPacket,int Port);#ifdef CONFIG_SK98LIN_NAPIstatic SK_BOOL HandleStatusLEs(SK_AC *pAC,int *WorkDone,int WorkToDo);#elsestatic SK_BOOL HandleStatusLEs(SK_AC *pAC);#endifextern void SkGeCheckTimer (DEV_NET *pNet);extern void SkLocalEventQueue( SK_AC *pAC, SK_U32 Class, SK_U32 Event, SK_U32 Param1, SK_U32 Param2, SK_BOOL Flag);extern void SkLocalEventQueue64( SK_AC *pAC, SK_U32 Class, SK_U32 Event, SK_U64 Param, SK_BOOL Flag);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)/* Need way to schedule device 0 even when it's offline. */static inline int __netif_rx_schedule_prep(struct net_device *dev){ return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);}#endif#endif/****************************************************************************** * * Local Variables * *****************************************************************************/#define MAX_NBR_RX_BUFFERS_IN_HW 0x15static SK_U8 NbrRxBuffersInHW;#define FLUSH_OPC(le)/****************************************************************************** * * Global Functions * *****************************************************************************/int SkY2Xmit( struct sk_buff *skb, struct SK_NET_DEVICE *dev); void FillReceiveTableYukon2(SK_AC *pAC,SK_IOC IoC,int Port);/***************************************************************************** * * SkY2RestartStatusUnit - restarts teh status unit * * Description: * Reenables the status unit after any De-Init (e.g. when altering * the sie of the MTU via 'ifconfig a.b.c.d mtu xxx') * * Returns: N/A */void SkY2RestartStatusUnit(SK_AC *pAC) /* pointer to adapter control context */{ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("==> SkY2RestartStatusUnit\n")); /* ** It might be that the TX timer is not started. Therefore ** it is initialized here -> to be more investigated! */ SK_OUT32(pAC->IoBase, STAT_TX_TIMER_INI, HW_MS_TO_TICKS(pAC,10)); pAC->StatusLETable.Done = 0; pAC->StatusLETable.Put = 0; pAC->StatusLETable.HwPut = 0; SkGeY2InitStatBmu(pAC, pAC->IoBase, &pAC->StatusLETable); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("<== SkY2RestartStatusUnit\n"));}/***************************************************************************** * * SkY2RlmtSend - sends out a single RLMT notification * * Description: * This function sends out an RLMT frame * * Returns: * > 0 - on succes: the number of bytes in the message * = 0 - on resource shortage: this frame sent or dropped, now * the ring is full ( -> set tbusy) * < 0 - on failure: other problems ( -> return failure to upper layers) */int SkY2RlmtSend (SK_AC *pAC, /* pointer to adapter control context */int PortNr, /* index of port the packet(s) shall be send to */struct sk_buff *pMessage) /* pointer to send-message */{ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("=== SkY2RlmtSend\n"));#if 0 return -1; // temporarily do not send out RLMT frames#endif skb_shinfo(pMessage)->nr_frags = (2*MAX_SKB_FRAGS) + PortNr; return(SkY2Xmit(pMessage, pAC->dev[PortNr])); // SkY2Xmit needs device}/***************************************************************************** * * SkY2AllocateResources - Allocates all required resources for Yukon2 * * Description: * This function allocates all memory needed for the Yukon2. * It maps also RX buffers to the LETables and initializes the * status list element table. * * Returns: * SK_TRUE, if all resources could be allocated and setup succeeded * SK_FALSE, if an error */SK_BOOL SkY2AllocateResources (SK_AC *pAC) /* pointer to adapter control context */{ int CurrMac; SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT, ("==> SkY2AllocateResources\n")); /* ** Initialize the packet queue variables first */ for (CurrMac = 0; CurrMac < pAC->GIni.GIMacsFound; CurrMac++) { InitPacketQueues(pAC, CurrMac); } /* ** Get sufficient memory for the LETables */ if (!AllocateAndInitLETables(pAC)) { SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT | SK_DBGCAT_DRV_ERROR, ("No memory for LETable.\n")); return(SK_FALSE); } /* ** Allocate and intialize memory for both RX and TX ** packet and fragment buffers. On an error, free ** previously allocated LETable memory and quit. */ if (!AllocatePacketBuffersYukon2(pAC)) { FreeLETables(pAC); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT | SK_DBGCAT_DRV_ERROR, ("No memory for Packetbuffers.\n")); return(SK_FALSE); } /* ** Rx and Tx LE tables will be initialized in SkGeOpen() ** ** It might be that the TX timer is not started. Therefore ** it is initialized here -> to be more investigated! */ SK_OUT32(pAC->IoBase, STAT_TX_TIMER_INI, HW_MS_TO_TICKS(pAC,10)); SkGeY2InitStatBmu(pAC, pAC->IoBase, &pAC->StatusLETable); pAC->MaxUnusedRxLeWorking = MAX_UNUSED_RX_LE_WORKING; SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT, ("<== SkY2AllocateResources\n")); return (SK_TRUE);}/***************************************************************************** * * SkY2FreeResources - Frees previously allocated resources of Yukon2 * * Description: * This function frees all previously allocated memory of the Yukon2. * * Returns: N/A */void SkY2FreeResources (SK_AC *pAC) /* pointer to adapter control context */{ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("==> SkY2FreeResources\n")); FreeLETables(pAC); FreePacketBuffers(pAC); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("<== SkY2FreeResources\n"));}/***************************************************************************** * * SkY2AllocateRxBuffers - Allocates the receive buffers for a port * * Description: * This function allocated all the RX buffers of the Yukon2. * * Returns: N/A */void SkY2AllocateRxBuffers (SK_AC *pAC, /* pointer to adapter control context */SK_IOC IoC, /* I/O control context */int Port) /* port index of RX */{ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT, ("==> SkY2AllocateRxBuffers (Port %c)\n", Port)); FillReceiveTableYukon2(pAC, IoC, Port); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_INIT, ("<== SkY2AllocateRxBuffers\n"));}/***************************************************************************** * * SkY2FreeRxBuffers - Free's all allocates RX buffers of * * Description: * This function frees all RX buffers of the Yukon2 for a single port * * Returns: N/A */void SkY2FreeRxBuffers (SK_AC *pAC, /* pointer to adapter control context */SK_IOC IoC, /* I/O control context */int Port) /* port index of RX */{ SK_PACKET *pSkPacket; unsigned long Flags; /* for POP/PUSH macros */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("==> SkY2FreeRxBuffers (Port %c)\n", Port)); if (pAC->RxPort[Port].ReceivePacketTable != NULL) { POP_FIRST_PKT_FROM_QUEUE(&pAC->RxPort[Port].RxQ_working, pSkPacket); while (pSkPacket != NULL) { if ((pSkPacket->pFrag) != NULL) { pci_unmap_page(pAC->PciDev, (dma_addr_t) pSkPacket->pFrag->pPhys, pSkPacket->pFrag->FragLen - 2, PCI_DMA_FROMDEVICE); /* wipe out any rubbish data that may interfere */ skb_shinfo(pSkPacket->pMBuf)->nr_frags = 0; skb_shinfo(pSkPacket->pMBuf)->frag_list = NULL; DEV_KFREE_SKB_ANY(pSkPacket->pMBuf); pSkPacket->pMBuf = NULL; pSkPacket->pFrag->pPhys = (SK_U64) 0; pSkPacket->pFrag->pVirt = NULL; } PUSH_PKT_AS_LAST_IN_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pSkPacket); POP_FIRST_PKT_FROM_QUEUE(&pAC->RxPort[Port].RxQ_working, pSkPacket); } } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("<== SkY2FreeRxBuffers\n"));}/***************************************************************************** * * SkY2FreeTxBuffers - Free's any currently maintained Tx buffer * * Description: * This function frees the TX buffers of the Yukon2 for a single port * which might be in use by a transmit action * * Returns: N/A */void SkY2FreeTxBuffers (SK_AC *pAC, /* pointer to adapter control context */SK_IOC IoC, /* I/O control context */int Port) /* port index of TX */{ SK_PACKET *pSkPacket; SK_FRAG *pSkFrag; unsigned long Flags; SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("==> SkY2FreeTxBuffers (Port %c)\n", Port)); if (pAC->TxPort[Port][0].TransmitPacketTable != NULL) { POP_FIRST_PKT_FROM_QUEUE(&pAC->TxPort[Port][0].TxAQ_working, pSkPacket); while (pSkPacket != NULL) { if ((pSkFrag = pSkPacket->pFrag) != NULL) { UnmapAndFreeTxPktBuffer(pAC, pSkPacket, Port); } PUSH_PKT_AS_LAST_IN_QUEUE(&pAC->TxPort[Port][0].TxQ_free, pSkPacket); POP_FIRST_PKT_FROM_QUEUE(&pAC->TxPort[Port][0].TxAQ_working, pSkPacket); }#ifdef USE_SYNC_TX_QUEUE POP_FIRST_PKT_FROM_QUEUE(&pAC->TxPort[Port][0].TxSQ_working, pSkPacket); while (pSkPacket != NULL) { if ((pSkFrag = pSkPacket->pFrag) != NULL) { UnmapAndFreeTxPktBuffer(pAC, pSkPacket, Port); } PUSH_PKT_AS_LAST_IN_QUEUE(&pAC->TxPort[Port][0].TxQ_free, pSkPacket); POP_FIRST_PKT_FROM_QUEUE(&pAC->TxPort[Port][0].TxSQ_working, pSkPacket); }#endif } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MSG, ("<== SkY2FreeTxBuffers\n"));}/***************************************************************************** * * SkY2Isr - handle a receive IRQ for all yukon2 cards * * Description: * This function is called when a receive IRQ is set. (only for yukon2) * HandleReceives does the deferred processing of all outstanding * interrupt operations. * * Returns: N/A */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)SkIsrRetVar SkY2Isr (int irq, /* the irq we have received (might be shared!) */void *dev_id) /* current device id */#elseSkIsrRetVar SkY2Isr (int irq, /* the irq we have received (might be shared!) */void *dev_id, /* current device id */struct pt_regs *ptregs) /* not used by our driver */#endif{ struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; DEV_NET *pNet = (DEV_NET*) dev->priv; SK_AC *pAC = pNet->pAC;#ifndef CONFIG_SK98LIN_NAPI SK_BOOL handledStatLE = SK_FALSE; unsigned long Flags;#endif SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("==> SkY2Isr\n")); SK_IN32(pAC->IoBase, B0_Y2_SP_ISRC2, &pAC->InterruptSource); if ((pAC->InterruptSource == 0) && (!pNet->NetConsoleMode)){ SK_OUT32(pAC->IoBase, B0_Y2_SP_ICR, 2); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("No Interrupt\n ==> SkY2Isr\n")); return SkIsrRetNone; }#ifdef Y2_RECOVERY if (pNet->InRecover) { SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("Already in recover\n ==> SkY2Isr\n")); SK_OUT32(pAC->IoBase, B0_Y2_SP_ICR, 2); return SkIsrRetNone; }#endif#ifdef CONFIG_SK98LIN_NAPI /* Since both boards share one irq, they share one poll routine */ if (__netif_rx_schedule_prep(pAC->dev[0])) { __netif_rx_schedule(pAC->dev[0]); }#else handledStatLE = HandleStatusLEs(pAC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -