📄 skge.c
字号:
pRxPort->RxdRingFree--; Length = pAC->RxBufSize; PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, pMsgBlock->data, 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 */ while (pRxPort->RxdRingFree < pAC->RxDescrPerRing) { pRxd = pRxPort->pRxdRingHead; Control = pRxd->RBControl; /* check if this descriptor is ready */ if ((Control & RX_CTRL_OWN_BMU) != 0) { /* this descriptor is not yet ready */ 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; /* * if short frame then copy data to reduce memory waste */ pNewMsg = NULL; if (FrameLength < SK_COPY_THRESHOLD) { pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC); if (pNewMsg != NULL) { 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; } } /* * if large frame, or SKB allocation failed, pass * the SKB directly to the networking */ if (pNewMsg == NULL) { PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; /* release the DMA mapping */ pci_unmap_single(&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); 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 */ FrameStat = pRxd->FrameStat; if ((FrameStat & XMR_FS_LNG_ERR) != 0) { /* jumbo frame, count to correct statistic */ SK_PNMI_CNT_RX_LONGFRAMES(pAC, pRxPort->PortIndex); } pRxd = pRxd->pNextRxd; pRxPort->pRxdRingHead = pRxd; pRxPort->RxdRingFree ++; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("Received frame of length %d on port %d\n", FrameLength, PortIndex)); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("Number of free rx descriptors: %d\n", pRxPort->RxdRingFree)); if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID && (FrameStat & XMR_FS_ANY_ERR) == 0) { // was the following, changed to allow VLAN support // (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,("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) { /* send up only frames from active port */ if (PortIndex == pAC->ActivePort) { /* frame for upper layer */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("U"));#ifdef DUMP_RX DumpMsg(pMsg, "Rx");#endif pMsg->dev = pAC->dev; pMsg->protocol = eth_type_trans(pMsg, pAC->dev); SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, FrameLength); netif_rx(pMsg); pAC->dev->last_rx = jiffies; } else { /* drop frame */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("D")); DEV_KFREE_SKB_IRQ(pMsg); } } /* if not for rlmt */ else { /* packet for rlmt */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("R")); pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC, pAC->IoBase, FrameLength); if (pRlmtMbuf != NULL) { pRlmtMbuf->pNext = NULL; pRlmtMbuf->Length = FrameLength; pRlmtMbuf->PortIdx = PortIndex; EvPara.pParaPtr = pRlmtMbuf; memcpy((char*)(pRlmtMbuf->pData), (char*)(pMsg->data), FrameLength); SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PACKET_RECEIVED, EvPara); pAC->CheckQueue = SK_TRUE; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("Q")); } if ((pAC->dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0 || (ForRlmt & SK_RLMT_RX_PROTOCOL) == SK_RLMT_RX_PROTOCOL) { pMsg->dev = pAC->dev; pMsg->protocol = eth_type_trans(pMsg, pAC->dev); netif_rx(pMsg); pAC->dev->last_rx = jiffies; } else { DEV_KFREE_SKB_IRQ(pMsg); } } /* if packet for rlmt */ } /* if valid frame */ else { /* there is a receive error in this frame */ if ((FrameStat & XMR_FS_1L_VLAN) != 0) { printk("%s: Received frame" " with VLAN Level 1 header, check" " switch configuration\n", pAC->dev->name); } if ((FrameStat & XMR_FS_2L_VLAN) != 0) { printk("%s: Received frame" " with VLAN Level 2 header, check" " switch configuration\n", pAC->dev->name); } 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)); DEV_KFREE_SKB_IRQ(pMsg); } } /* while */ FillRxRing(pAC, pRxPort); /* do not start if called from Close */ if (pAC->BoardLevel > 0) { ClearAndStartRx(pAC, PortIndex); } return;rx_failed: /* remove error frame */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR, ("Schrottdescriptor, length: 0x%x\n", FrameLength)); /* release the DMA mapping */ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; pci_unmap_single(&pAC->PciDev, PhysAddr, pAC->RxBufSize - 2, PCI_DMA_FROMDEVICE); DEV_KFREE_SKB_IRQ(pRxd->pMBuf); pRxd->pMBuf = NULL; pRxPort->RxdRingFree++; pRxPort->pRxdRingHead = pRxd->pNextRxd; goto rx_start;} /* ReceiveIrq *//***************************************************************************** * * ClearAndStartRx - give a start receive command to BMU, clear IRQ * * Description: * This function sends a start command and a clear interrupt * command for one receive queue to the BMU. * * Returns: N/A * none */static void ClearAndStartRx(SK_AC *pAC, /* pointer to the adapter context */int PortIndex) /* index of the receive port (XMAC) */{ SK_OUT8(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CTRL, RX_Q_CTRL_START | RX_Q_CTRL_CLR_I_EOF);} /* ClearAndStartRx *//***************************************************************************** * * ClearTxIrq - give a clear transmit IRQ command to BMU * * Description: * This function sends a clear tx IRQ command for one * transmit queue to the BMU. * * Returns: N/A */static void ClearTxIrq(SK_AC *pAC, /* pointer to the adapter context */int PortIndex, /* index of the transmit port (XMAC) */int Prio) /* priority or normal queue */{ SK_OUT8(pAC->IoBase, TxQueueAddr[PortIndex][Prio]+TX_Q_CTRL, TX_Q_CTRL_CLR_I_EOF);} /* ClearTxIrq *//***************************************************************************** * * ClearRxRing - remove all buffers from the receive ring * * Description: * This function removes all receive buffers from the ring. * The receive BMU must be stopped before calling this function. * * Returns: N/A */static void ClearRxRing(SK_AC *pAC, /* pointer to adapter context */RX_PORT *pRxPort) /* pointer to rx port struct */{RXD *pRxd; /* pointer to the current descriptor */unsigned int Flags; SK_U64 PhysAddr; if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) { return; } spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); pRxd = pRxPort->pRxdRingHead; do { if (pRxd->pMBuf != NULL) { PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; pci_unmap_single(&pAC->PciDev, PhysAddr, pAC->RxBufSize - 2, PCI_DMA_FROMDEVICE); DEV_KFREE_SKB(pRxd->pMBuf); pRxd->pMBuf = NULL; } pRxd->RBControl &= RX_CTRL_OWN_BMU; pRxd = pRxd->pNextRxd; pRxPort->RxdRingFree++; } while (pRxd != pRxPort->pRxdRingTail); pRxPort->pRxdRingTail = pRxPort->pRxdRingHead; spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);} /* ClearRxRing *//***************************************************************************** * * ClearTxRing - remove all buffers from the transmit ring * * Description: * This function removes all transmit buffers from the ring. * The transmit BMU must be stopped before calling this function * and transmitting at the upper level must be disabled. * The BMU own bit of all descriptors is cleared, the rest is * done by calling FreeTxDescriptors. * * Returns: N/A */static void ClearTxRing(SK_AC *pAC, /* pointer to adapter context */TX_PORT *pTxPort) /* pointer to tx prt struct */{TXD *pTxd; /* pointer to the current descriptor */int i;unsigned int Flags; spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); pTxd = pTxPort->pTxdRingHead; for (i=0; i<pAC->TxDescrPerRing; i++) { pTxd->TBControl &= ~TX_CTRL_OWN_BMU; pTxd = pTxd->pNextTxd; } FreeTxDescriptors(pAC, pTxPort); spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);} /* ClearTxRing *//***************************************************************************** * * SetQueueSizes - configure the sizes of rx and tx queues * * Description: * This function assigns the sizes for active and passive port * to the appropriate HWinit structure variables. * The passive port(s) get standard values, all remaining RAM * is giv
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -