📄 skge.c
字号:
/* no enough free descriptors in ring at the moment */ FreeTxDescriptors(pAC, pTxPort); if (pTxPort->TxdRingFree == 0) { spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("XmitFrame failed\n")); /* this message can not be sent now */ return (-1); } } /* advance head counter behind descriptor needed for this frame */ pTxd = pTxPort->pTxdRingHead; pTxPort->pTxdRingHead = pTxd->pNextTxd; pTxPort->TxdRingFree--; /* the needed descriptor is reserved now */ /* * everything allocated ok, so add buffer to descriptor */#ifdef SK_DUMP_TX DumpMsg(pMessage, "XmitFrame");#endif /* set up descriptor and CONTROL dword */ PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev, virt_to_page(pMessage->data), ((unsigned long) pMessage->data & ~PAGE_MASK), pMessage->len, PCI_DMA_TODEVICE); pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF | TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |#ifdef USE_TX_COMPLETE TX_CTRL_EOF | TX_CTRL_EOF_IRQ | pMessage->len;#else TX_CTRL_EOF | pMessage->len;#endif if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) { /* previous descriptor already done, so give tx start cmd */ /* StartTx(pAC, pTxPort->HwAddr); */ SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START); } pTxPort->pTxdRingPrev = pTxd; BytesSend = pMessage->len; /* after releasing the lock, the skb may be immidiately freed */ if (pTxPort->TxdRingFree != 0) { spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); return (BytesSend); } else { /* ring full: set tbusy on return */ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); return (0); }} /* XmitFrame *//***************************************************************************** * * FreeTxDescriptors - release descriptors from the descriptor ring * * Description: * This function releases descriptors from a transmit ring if they * have been sent by the BMU. * If a descriptors is sent, it can be freed and the message can * be freed, too. * The SOFTWARE controllable bit is used to prevent running around a * completely free ring for ever. If this bit is no set in the * frame (by XmitFrame), this frame has never been sent or is * already freed. * The Tx descriptor ring lock must be held while calling this function !!! * * Returns: * none */static void FreeTxDescriptors(SK_AC *pAC, /* pointer to the adapter context */TX_PORT *pTxPort) /* pointer to destination port structure */{TXD *pTxd; /* pointer to the checked descriptor */TXD *pNewTail; /* pointer to 'end' of the ring */SK_U32 Control; /* TBControl field of descriptor */SK_U64 PhysAddr; /* address of DMA mapping */ pNewTail = pTxPort->pTxdRingTail; pTxd = pNewTail; /* * loop forever; exits if TX_CTRL_SOFTWARE bit not set in start frame * or TX_CTRL_OWN_BMU bit set in any frame */ while (1) { Control = pTxd->TBControl; if ((Control & TX_CTRL_SOFTWARE) == 0) { /* * software controllable bit is set in first * fragment when given to BMU. Not set means that * this fragment was never sent or is already * freed ( -> ring completely free now). */ pTxPort->pTxdRingTail = pTxd; netif_start_queue(pAC->dev[pTxPort->PortIndex]); return; } if (Control & TX_CTRL_OWN_BMU) { pTxPort->pTxdRingTail = pTxd; if (pTxPort->TxdRingFree > 0) { netif_start_queue(pAC->dev[pTxPort->PortIndex]); } return; } /* release the DMA mapping */ PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; PhysAddr |= (SK_U64) pTxd->VDataLow; pci_unmap_page(&pAC->PciDev, PhysAddr, pTxd->pMBuf->len, PCI_DMA_TODEVICE); /* free message */ DEV_KFREE_SKB_ANY(pTxd->pMBuf); pTxPort->TxdRingFree++; pTxd->TBControl &= ~TX_CTRL_SOFTWARE; pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */ } /* while(forever) */} /* FreeTxDescriptors *//***************************************************************************** * * FillRxRing - fill the receive ring with valid descriptors * * Description: * This function fills the receive ring descriptors with data * segments and makes them valid for the BMU. * The active ring is filled completely, if possible. * The non-active ring is filled only partial to save memory. * * Description of rx ring structure: * head - points to the descriptor which will be used next by the BMU * tail - points to the next descriptor to give to the BMU * * Returns: N/A */static void FillRxRing(SK_AC *pAC, /* pointer to the adapter context */RX_PORT *pRxPort) /* ptr to port struct for which the ring should be filled */{unsigned long Flags; spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) { if(!FillRxDescriptor(pAC, pRxPort)) break; } spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);} /* FillRxRing *//***************************************************************************** * * FillRxDescriptor - fill one buffer into the receive ring * * Description: * The function allocates a new receive buffer and * puts it into the next descriptor. * * Returns: * SK_TRUE - a buffer was added to the ring * SK_FALSE - a buffer could not be added */static SK_BOOL FillRxDescriptor(SK_AC *pAC, /* pointer to the adapter context struct */RX_PORT *pRxPort) /* ptr to port struct of ring to fill */{struct sk_buff *pMsgBlock; /* pointer to a new message block */RXD *pRxd; /* the rxd to fill */SK_U16 Length; /* data fragment length */SK_U64 PhysAddr; /* physical address of a rx buffer */ pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC); if (pMsgBlock == NULL) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("%s: Allocation of rx buffer failed !\n", pAC->dev[pRxPort->PortIndex]->name)); SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex); return(SK_FALSE); } skb_reserve(pMsgBlock, 2); /* to align IP frames */ /* skb allocated ok, so add buffer */ pRxd = pRxPort->pRxdRingTail; pRxPort->pRxdRingTail = pRxd->pNextRxd; pRxPort->RxdRingFree--; Length = pAC->RxBufSize; PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev, virt_to_page(pMsgBlock->data), ((unsigned long) pMsgBlock->data & ~PAGE_MASK), pAC->RxBufSize - 2, PCI_DMA_FROMDEVICE); pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pRxd->pMBuf = pMsgBlock; pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF | RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length; return (SK_TRUE);} /* FillRxDescriptor *//***************************************************************************** * * ReQueueRxBuffer - fill one buffer back into the receive ring * * Description: * Fill a given buffer back into the rx ring. The buffer * has been previously allocated and aligned, and its phys. * address calculated, so this is no more necessary. * * Returns: N/A */static void ReQueueRxBuffer(SK_AC *pAC, /* pointer to the adapter context struct */RX_PORT *pRxPort, /* ptr to port struct of ring to fill */struct sk_buff *pMsg, /* pointer to the buffer */SK_U32 PhysHigh, /* phys address high dword */SK_U32 PhysLow) /* phys address low dword */{RXD *pRxd; /* the rxd to fill */SK_U16 Length; /* data fragment length */ pRxd = pRxPort->pRxdRingTail; pRxPort->pRxdRingTail = pRxd->pNextRxd; pRxPort->RxdRingFree--; Length = pAC->RxBufSize; pRxd->VDataLow = PhysLow; pRxd->VDataHigh = PhysHigh; pRxd->pMBuf = pMsg; pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF | RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length; return;} /* ReQueueRxBuffer *//***************************************************************************** * * ReceiveIrq - handle a receive IRQ * * Description: * This function is called when a receive IRQ is set. * It walks the receive descriptor ring and sends up all * frames that are complete. * * Returns: N/A */static void ReceiveIrq(SK_AC *pAC, /* pointer to adapter context */RX_PORT *pRxPort) /* pointer to receive port struct */{RXD *pRxd; /* pointer to receive descriptors */SK_U32 Control; /* control field of descriptor */struct sk_buff *pMsg; /* pointer to message holding frame */struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */int FrameLength; /* total length of received frame */SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */SK_EVPARA EvPara; /* an event parameter union */ int PortIndex = pRxPort->PortIndex;unsigned int Offset;unsigned int NumBytes;unsigned int ForRlmt;SK_BOOL IsBc;SK_BOOL IsMc;SK_U32 FrameStat;unsigned short Csum1;unsigned short Csum2;unsigned short Type;int Result;SK_U64 PhysAddr;rx_start: /* do forever; exit if RX_CTRL_OWN_BMU found */ for ( pRxd = pRxPort->pRxdRingHead ; pRxPort->RxdRingFree < pAC->RxDescrPerRing ; pRxd = pRxd->pNextRxd, pRxPort->pRxdRingHead = pRxd, pRxPort->RxdRingFree ++) { /* * For a better understanding of this loop * Go through every descriptor beginning at the head * Please note: the ring might be completely received so the OWN bit * set is not a good crirteria to leave that loop. * Therefore the RingFree counter is used. * On entry of this loop pRxd is a pointer to the Rxd that needs * to be checked next. */ Control = pRxd->RBControl; /* check if this descriptor is ready */ if ((Control & RX_CTRL_OWN_BMU) != 0) { /* this descriptor is not yet ready */ /* This is the usual end of the loop */ /* We don't need to start the ring again */ FillRxRing(pAC, pRxPort); return; } /* get length of frame and check it */ FrameLength = Control & RX_CTRL_LEN_MASK; if (FrameLength > pAC->RxBufSize) { goto rx_failed; } /* check for STF and EOF */ if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) != (RX_CTRL_STF | RX_CTRL_EOF)) { goto rx_failed; } /* here we have a complete frame in the ring */ pMsg = pRxd->pMBuf; FrameStat = pRxd->FrameStat; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, ("Received frame of length %d on port %d\n", FrameLength, PortIndex)); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, ("Number of free rx descriptors: %d\n", pRxPort->RxdRingFree)); /*DumpMsg(pMsg, "Rx"); */ if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID || (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) { /* there is a receive error in this frame */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("skge: Error in received frame, dropped!\n" "Control: %x\nRxStat: %x\n", Control, FrameStat)); PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; pci_dma_sync_single(&pAC->PciDev, (dma_addr_t) PhysAddr, FrameLength, PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); continue; } /* * if short frame then copy data to reduce memory waste */ if ((FrameLength < SK_COPY_THRESHOLD) && ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) { /* * Short frame detected and allocation successfull */ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; /* use new skb and copy data */ skb_reserve(pNewMsg, 2); skb_put(pNewMsg, FrameLength); pci_dma_sync_single(&pAC->PciDev, (dma_addr_t) PhysAddr, FrameLength, PCI_DMA_FROMDEVICE); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); pMsg = pNewMsg; } else { /* * if large frame, or SKB allocation failed, pass * the SKB directly to the networking */ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; /* release the DMA mapping */ pci_unmap_page(&pAC->PciDev, PhysAddr, pAC->RxBufSize - 2, PCI_DMA_FROMDEVICE); /* set length in message */ skb_put(pMsg, FrameLength); /* hardware checksum */ Type = ntohs(*((short*)&pMsg->data[12])); if (Type == 0x800) { Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff); if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) { Result = SkCsGetReceiveInfo(pAC, &pMsg->data[14], Csum1, Csum2, pRxPort->PortIndex); if (Result == SKCS_STATUS_IP_FRAGMENT || Result == SKCS_STATUS_IP_CSUM_OK || Result == SKCS_STATUS_TCP_CSUM_OK || Result == SKCS_STATUS_UDP_CSUM_OK) { pMsg->ip_summed = CHECKSUM_UNNECESSARY; } } /* checksum calculation valid */ } /* IP frame */ } /* frame > SK_COPY_TRESHOLD */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); ForRlmt = SK_RLMT_RX_PROTOCOL; IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC; SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength, IsBc, &Offset, &NumBytes); if (NumBytes != 0) { IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC; SK_RLMT_LOOKAHEAD(pAC, PortIndex, &pMsg->data[Offset], IsBc, IsMc, &ForRlmt); } if (ForRlmt == SK_RLMT_RX_PROTOCOL) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W")); /* send up only frames from active port */ if ((PortIndex == pAC->ActivePort) || (pAC->RlmtNets == 2)) { /* frame for upper layer *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -