📄 sky2.c
字号:
#endif FLUSH_OPC(pLE) ; }#endif GET_TX_LE(pLE, pLETab); Ctrl = 0; SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("\tGot empty LE %p idx %d\n", pLE, GET_PUT_IDX(pLETab))); SK_DBG_DUMP_TX_LE(pLE); LowAddress = (SK_U32) (pFrag->pPhys & 0xffffffff); HighAddress = (SK_U32) (pFrag->pPhys >> 32); if (HighAddress != pLETab->BufHighAddr) { /* set opcode high part of the address in one LE */ OpCode = OP_ADDR64 | HW_OWNER; /* Set now the 32 high bits of the address */ TXLE_SET_ADDR( pLE, HighAddress); /* Set the opcode into the LE */ TXLE_SET_OPC(pLE, OpCode); /* Flush the LE to memory */ FLUSH_OPC(pLE); /* remember the HighAddress we gave to the Hardware */ pLETab->BufHighAddr = HighAddress; /* get a new LE because we filled one with high address */ GET_TX_LE(pLE, pLETab); } /* ** TCP checksum offload */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) if ((pSkPacket->pMBuf->ip_summed == CHECKSUM_PARTIAL) && #else if ((pSkPacket->pMBuf->ip_summed == CHECKSUM_HW) && #endif (SetOpcodePacketFlag == SK_TRUE)) { Protocol = ((SK_U8)pSkPacket->pMBuf->data[C_OFFSET_IPPROTO] & 0xff); /* if (Protocol & C_PROTO_ID_IP) { Ctrl = 0; } */ // Yukon Extreme B0 if (HW_FEATURE(pAC, HWF_WA_DEV_510)) { if (Protocol & C_PROTO_ID_TCP) { Ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; /* TCP Checksum Calculation Start Position */ TcpSumStart = C_LEN_ETHERMAC_HEADER + IP_HDR_LEN; /* TCP Checksum Write Position */ TcpSumWrite = TcpSumStart + TCP_CSUM_OFFS; } else { Ctrl = UDPTCP | CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; /* TCP Checksum Calculation Start Position */ TcpSumStart = ETHER_MAC_HDR_LEN + IP_HDR_LEN; /* UDP Checksum Write Position */ TcpSumWrite = TcpSumStart + UDP_CSUM_OFFS; } } // Yukon 2, Yukon Extreme besides B0 else { if (Protocol & C_PROTO_ID_TCP) {#ifdef SK_EXTREME if (!HW_IS_EXT_LE_FORMAT(pAC)) {#endif Ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; /* TCP Checksum Calculation Start Position */ TcpSumStart = C_LEN_ETHERMAC_HEADER + IP_HDR_LEN; /* TCP Checksum Write Position */ TcpSumWrite = TcpSumStart + TCP_CSUM_OFFS;#ifdef SK_EXTREME } else { Ctrl = CALSUM; }#endif } else {#ifdef SK_EXTREME if (!HW_IS_EXT_LE_FORMAT(pAC)) {#endif Ctrl = UDPTCP | CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; /* TCP Checksum Calculation Start Position */ TcpSumStart = ETHER_MAC_HDR_LEN + IP_HDR_LEN; /* UDP Checksum Write Position */ TcpSumWrite = TcpSumStart + UDP_CSUM_OFFS;#ifdef SK_EXTREME } else { Ctrl = CALSUM; }#endif } } if ((Ctrl) && (pLETab->Bmu.RxTx.TcpWp != TcpSumWrite)) { /* Update the last value of the write position */ pLETab->Bmu.RxTx.TcpWp = TcpSumWrite; /* Set the Lock field for this LE: */ /* Checksum calculation for one packet only */ TXLE_SET_LCKCS(pLE, 1); /* Set the start position for checksum. */ TXLE_SET_STACS(pLE, TcpSumStart); /* Set the position where the checksum will be writen */ TXLE_SET_WRICS(pLE, TcpSumWrite); /* Set the initial value for checksum */ /* PseudoHeader CS passed from Linux -> 0! */ TXLE_SET_INICS(pLE, 0); /* Set the opcode for tcp checksum */ TXLE_SET_OPC(pLE, OP_TCPLISW | HW_OWNER); /* Flush the LE to memory */ FLUSH_OPC(pLE); /* get a new LE because we filled one with data for checksum */ GET_TX_LE(pLE, pLETab); } } /* end TCP offload handling */ TXLE_SET_ADDR(pLE, LowAddress); TXLE_SET_LEN(pLE, pFrag->FragLen); if (SetOpcodePacketFlag){#ifdef NETIF_F_TSO if (Mss) { OpCode = OP_LARGESEND | HW_OWNER; } else {#endif OpCode = OP_PACKET | HW_OWNER;#ifdef NETIF_F_TSO }#endif SetOpcodePacketFlag = SK_FALSE; } else { /* Follow packet in a sequence has always OP_BUFFER */ OpCode = OP_BUFFER | HW_OWNER; } /* Check if the low address is near the upper limit. */ CHECK_LOW_ADDRESS(pLETab->BufHighAddr, LowAddress, pFrag->FragLen); pFrag = pFrag->pNext; if (pFrag == NULL) { /* mark last fragment */ Ctrl |= EOP; } TXLE_SET_CTRL(pLE, Ctrl); TXLE_SET_OPC(pLE, OpCode); FLUSH_OPC(pLE); SK_DBG_DUMP_TX_LE(pLE); } /* ** Remember next LE for tx complete */ pSkPacket->NextLE = GET_PUT_IDX(pLETab); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("\tNext LE for pkt %p is %d\n", pSkPacket, pSkPacket->NextLE)); /* ** Add packet to working packets queue */ PUSH_PKT_AS_LAST_IN_QUEUE(pWorkQueue, pSkPacket); /* ** give transmit start command */ if (HW_FEATURE(pAC, HWF_WA_DEV_42)) { spin_lock(&pAC->SetPutIndexLock); SkGeY2SetPutIndex(pAC, pAC->IoBase, Y2_PREF_Q_ADDR(Q_XA1,0), &pAC->TxPort[0][0].TxALET); spin_unlock(&pAC->SetPutIndexLock); } else { /* write put index */ if (Port == 0) { SK_OUT32(pAC->IoBase, Y2_PREF_Q_ADDR(Q_XA1,PREF_UNIT_PUT_IDX_REG), GET_PUT_IDX(&pAC->TxPort[0][0].TxALET)); UPDATE_HWPUT_IDX(&pAC->TxPort[0][0].TxALET); } else { SK_OUT32(pAC->IoBase, Y2_PREF_Q_ADDR(Q_XA2, PREF_UNIT_PUT_IDX_REG), GET_PUT_IDX(&pAC->TxPort[1][0].TxALET)); UPDATE_HWPUT_IDX(&pAC->TxPort[1][0].TxALET); } } if (IS_Q_EMPTY(&(pAC->TxPort[Port][TX_PRIO_LOW].TxAQ_waiting))) { break; /* get out of while */ } POP_FIRST_PKT_FROM_QUEUE(pWaitQueue, pSkPacket); } /* while (pSkPacket != NULL) */ spin_unlock_irqrestore(&pAC->TxQueueLock, LockFlag); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("<== GiveTxBufferToHw\n")); return;} /* GiveTxBufferToHw *//*********************************************************************** * * GiveRxBufferToHw - commits a previously allocated DMA area to HW * * Description: * This functions gives receive buffers to HW. If no list elements * are available the buffers will be queued. * * Notes: * This function can run only once in a system at one time. * * Returns: N/A */static void GiveRxBufferToHw(SK_AC *pAC, /* pointer to adapter control context */SK_IOC IoC, /* I/O control context (address of registers) */int Port, /* port index for which the buffer is used */SK_PACKET *pPacket) /* receive buffer(s) */{ SK_HWLE *pLE; SK_LE_TABLE *pLETab; SK_BOOL Done = SK_FALSE; /* at least on LE changed? */ SK_U32 LowAddress; SK_U32 HighAddress; SK_U32 PrefetchReg; /* register for Put index */ unsigned NumFree; unsigned Required; unsigned long Flags; SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("==> GiveRxBufferToHw(Port %c, Packet %p)\n", 'A' + Port, pPacket)); pLETab = &pAC->RxPort[Port].RxLET; if (Port == 0) { PrefetchReg = Y2_PREF_Q_ADDR(Q_R1, PREF_UNIT_PUT_IDX_REG); } else { PrefetchReg = Y2_PREF_Q_ADDR(Q_R2, PREF_UNIT_PUT_IDX_REG); } if (pPacket != NULL) { /* ** For the time being, we have only one packet passed ** to this function which might be changed in future! */ PUSH_PKT_AS_LAST_IN_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); } /* ** now pPacket contains the very first waiting packet */ POP_FIRST_PKT_FROM_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); while (pPacket != NULL) { if (HW_FEATURE(pAC, HWF_WA_DEV_420)) { if (NbrRxBuffersInHW >= MAX_NBR_RX_BUFFERS_IN_HW) { PUSH_PKT_AS_FIRST_IN_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("<== GiveRxBufferToHw()\n")); return; } NbrRxBuffersInHW++; } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("Try to add packet %p\n", pPacket)); /* ** Check whether we have enough listelements: ** ** we have to take into account that each fragment ** may need an additional list element for the high ** part of the address here I simplified it by ** using MAX_FRAG_OVERHEAD maybe it's worth to split ** this constant for Rx and Tx or to calculate the ** real number of needed LE's */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tNum %d Put %d Done %d Free %d %d\n", pLETab->Num, pLETab->Put, pLETab->Done, NUM_FREE_LE_IN_TABLE(pLETab), (NUM_FREE_LE_IN_TABLE(pLETab)))); Required = pPacket->NumFrags + MAX_FRAG_OVERHEAD; NumFree = NUM_FREE_LE_IN_TABLE(pLETab); if (NumFree) { NumFree--; } if (Required > NumFree ) { SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS | SK_DBGCAT_DRV_ERROR, ("\tOut of LEs have %d need %d\n", NumFree, Required)); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tWaitQueue starts with packet %p\n", pPacket)); PUSH_PKT_AS_FIRST_IN_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); if (Done) { /* ** write Put index to BMU or Polling Unit and make the LE's ** available for the hardware */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tWrite new Put Idx\n")); SK_OUT32(IoC, PrefetchReg, GET_PUT_IDX(pLETab)); UPDATE_HWPUT_IDX(pLETab); } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("<== GiveRxBufferToHw()\n")); return; } else { if (!AllocAndMapRxBuffer(pAC, pPacket, Port)) { /* ** Failure while allocating sk_buff might ** be due to temporary short of resources ** Maybe next time buffers are available. ** Until this, the packet remains in the ** RX waiting queue... */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS | SK_DBGCAT_DRV_ERROR, ("Failed to allocate Rx buffer\n")); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("WaitQueue starts with packet %p\n", pPacket)); PUSH_PKT_AS_FIRST_IN_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); if (Done) { /* ** write Put index to BMU or Polling ** Unit and make the LE's ** available for the hardware */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tWrite new Put Idx\n")); SK_OUT32(IoC, PrefetchReg, GET_PUT_IDX(pLETab)); UPDATE_HWPUT_IDX(pLETab); } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("<== GiveRxBufferToHw()\n")); return; } } Done = SK_TRUE; LowAddress = (SK_U32) (pPacket->pFrag->pPhys & 0xffffffff); HighAddress = (SK_U32) (pPacket->pFrag->pPhys >> 32); if (HighAddress != pLETab->BufHighAddr) { /* get a new LE for high address */ GET_RX_LE(pLE, pLETab); /* Set now the 32 high bits of the address */ RXLE_SET_ADDR(pLE, HighAddress); /* Set the control bits of the address */ RXLE_SET_CTRL(pLE, 0); /* Set the opcode into the LE */ RXLE_SET_OPC(pLE, (OP_ADDR64 | HW_OWNER)); /* Flush the LE to memory */ FLUSH_OPC(pLE); /* remember the HighAddress we gave to the Hardware */ pLETab->BufHighAddr = HighAddress; } /* ** Fill data into listelement */ GET_RX_LE(pLE, pLETab); RXLE_SET_ADDR(pLE, LowAddress); RXLE_SET_LEN(pLE, pPacket->pFrag->FragLen); RXLE_SET_CTRL(pLE, 0); RXLE_SET_OPC(pLE, (OP_PACKET | HW_OWNER)); FLUSH_OPC(pLE); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("=== LE filled\n")); SK_DBG_DUMP_RX_LE(pLE); /* ** Remember next LE for rx complete */ pPacket->NextLE = GET_PUT_IDX(pLETab); SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tPackets Next LE is %d\n", pPacket->NextLE)); /* ** Add packet to working receive buffer queue and get ** any next packet out of the waiting queue */ PUSH_PKT_AS_LAST_IN_QUEUE(&pAC->RxPort[Port].RxQ_working, pPacket); if (IS_Q_EMPTY(&(pAC->RxPort[Port].RxQ_waiting))) { break; /* get out of while processing */ } POP_FIRST_PKT_FROM_QUEUE(&pAC->RxPort[Port].RxQ_waiting, pPacket); } SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tWaitQueue is empty\n")); if (Done) { /* ** write Put index to BMU or Polling Unit and make the LE's ** available for the hardware */ SK_DBG_MSG(pAC, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("\tWrite new Put Idx\n")); /* 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_R1,0), pLETab); spin_unlock_irqrestore(&pAC->SetPutIndexLock, Flags); } else { /* write put index */ if (Port == 0) { SK_OUT32(IoC, Y2_PREF_Q_ADDR(Q_R1, PREF_UNIT_PUT_IDX_REG), GET_PUT_IDX(pLETab)); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -