void avcDestroyResponsePacket(PB *packetBlock) { // clean up the resp packetBlock if (pbIsValid(packetBlock)) { if (pbIsNonBlocking(packetBlock) == FALSE) { packetBlock->creatorCBProc = NULL; pbPacketDone(packetBlock, PB_DONE_AVC_SEND_RSP); } } }
HRESULT nciCBGeneric(PB *packetBlock, uint32 nciCBtype) { HRESULT hResult = NO_ERROR; uint32 numBytes = 0; uint16 i; PB_HEADER *pHeader = NULL; QUADLET *pPayload = NULL; QUADLET *pRespPayload = NULL; PB* respPacket = NULL; PB_PACKETTYPE packetType = PB_TYPE_UNDEF; PB_LOCKTYPE lockType = PB_LOCKTYPE_NONE; RCODE_1394 rCode = RSP_ADDRESS_ERROR; OFFSET_1394 destOffset; uint16 reqType = LHL_REQ_READ; hResult = pbGetPacketHeader(packetBlock, &pHeader); if (hResult != NO_ERROR) return hResult; hResult = pbGetPacketType(packetBlock, &packetType); if (hResult != NO_ERROR) return hResult; hResult = pbGetLockType(packetBlock, &lockType); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(packetBlock, (void **) &pPayload); if (hResult != NO_ERROR) return hResult; // no broadcasts supported here if (pbPacketIsBroadcast(packetBlock)) { return hResult; } switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: reqType = LHL_REQ_READ; break; case PB_TYPE_WRITE_REQUEST_QUADLET: case PB_TYPE_WRITE_REQUEST: reqType = LHL_REQ_WRITE; break; case PB_TYPE_LOCK_REQUEST: reqType = LHL_REQ_LOCK; break; } switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_WRITE_REQUEST_QUADLET: numBytes = 4; break; case PB_TYPE_READ_REQUEST: case PB_TYPE_WRITE_REQUEST: case PB_TYPE_LOCK_REQUEST: hResult = pbGetDataLen(packetBlock, &numBytes); if (hResult != NO_ERROR) return hResult; break; } hResult = pbGetDestinationOffset(packetBlock, &destOffset); if (hResult != NO_ERROR) return hResult; switch (nciCBtype) { case NCI_CB_ARCH_SPACE: switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: case PB_TYPE_WRITE_REQUEST_QUADLET: case PB_TYPE_WRITE_REQUEST: if (destOffset.Low + numBytes <= CSR_ARCH_SPACE_END + 1) { QUADLET **pData = NULL; uint32 respLen = 0; switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: pData = &pRespPayload; respLen = numBytes; break; case PB_TYPE_WRITE_REQUEST_QUADLET: case PB_TYPE_WRITE_REQUEST: pData = &pPayload; respLen = 0; break; } hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) respLen, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; for (i = 0; i < numBytes / 4; i++) { hResult = lhlLLCHandleCSR(destOffset, 4, *pData + i, reqType); if (hResult != NO_ERROR) { break; } destOffset.Low += 4; } if (hResult == NO_ERROR) { rCode = RSP_COMPLETE; } numBytes = respLen; } break; } break; case NCI_CB_SB_SPACE: switch (destOffset.Low) { case CSR_SB_CYCLE_TIME: case CSR_SB_BUS_TIME: case CSR_SB_BUSY_TIME_OUT: switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; rCode = lhlWatchTransRead(destOffset.Low, pRespPayload); break; case PB_TYPE_WRITE_REQUEST_QUADLET: if (numBytes == 4) // only allow quadlet write { hResult = pbCreateDuplicatePacketWithSize (packetBlock, &respPacket, (uint16) 0, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; rCode = lhlWatchTransWrite(destOffset.Low, pPayload[0]); } break; } break; case CSR_SB_BM_ID: case CSR_SB_BW_AVAIL: case CSR_SB_CH_AVAIL_HI: case CSR_SB_CH_AVAIL_LO: case CSR_SB_BROADCAST_CH: #ifdef _IRMC_CAPS if (nciIRMIsThisNodeIRM()) { // handle IRM Registers here switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; rCode = nciIRMRead(destOffset.Low, pRespPayload); break; case PB_TYPE_LOCK_REQUEST: if (numBytes == 8) // only allow quadlet lock { if (lockType == PB_LOCKTYPE_COMPARE_SWAP) { uint32 lockArg = pPayload[0]; uint32 lockData = pPayload[1]; // response payload length is 1/2 size of request packet numBytes /= 2; hResult = pbCreateDuplicatePacketWithSize (packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; rCode = nciIRMLock(destOffset.Low, lockArg, lockData, pRespPayload); } } break; case PB_TYPE_WRITE_REQUEST: if (numBytes == 4) // only allow quadlet lock { hResult = pbCreateDuplicatePacketWithSize (packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; rCode = nciIRMWrite(destOffset.Low, pPayload[0]); } break; } } #endif //_IRMC_CAPS break; } break; case NCI_CB_CONFIG_ROM: switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: if ((destOffset.Low >= CSR_ROM_SPACE_START) && (destOffset.Low + numBytes <= CSR_ROM_SPACE_START + csrGetConfigROMQuadletSize() * 4)) { hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; for (i = 0; i < numBytes / 4; i++) { pRespPayload[i] = csrReadConfigROMQuadlet(destOffset.Low + (i * 4)); } rCode = RSP_COMPLETE; } break; } break; #ifdef _BMC_CAPS case NCI_CB_TOPOLOGY_MAP: switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: if (destOffset.Low + numBytes <= CSR_TOPOLOGY_MAP_END + 1) { uint32 index = (destOffset.Low - CSR_TOPOLOGY_MAP_START) / 4; BOOL bBusMaster = TRUE; hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; for (i = 0; i < numBytes / 4; i++) { hResult = nciBMGetTopologyMapIndex(bBusMaster, index + i, &(pRespPayload[i])); if (hResult != NO_ERROR) { break; } } if (hResult == NO_ERROR) { rCode = RSP_COMPLETE; } } break; } break; case NCI_CB_SPEED_MAP: switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: if (destOffset.Low + numBytes <= CSR_SPEED_MAP_END + 1) { uint32 index = (destOffset.Low - CSR_SPEED_MAP_START) / 4; BOOL bBusMaster = TRUE; hResult = pbCreateDuplicatePacketWithSize(packetBlock, &respPacket, (uint16) numBytes, NULL, PB_CREATE_NCI_CB); if (hResult != NO_ERROR) return hResult; hResult = pbGetPayload(respPacket, (void **) &pRespPayload); if (hResult != NO_ERROR) return hResult; for (i = 0; i < numBytes / 4; i++) { hResult = nciBMGetSpeedMapIndex(bBusMaster, index + i, &(pRespPayload[i])); if (hResult != NO_ERROR) { break; } } if (hResult == NO_ERROR) { rCode = RSP_COMPLETE; } } break; } break; #endif //_BMC_CAPS default: hResult = E_BAD_INPUT_PARAMETERS; sysLogError(hResult, __LINE__, moduleName); return hResult; } if (rCode != RSP_COMPLETE) { lhlReplyErrorResponse(packetBlock, rCode, TRUE); hResult = (HRESULT) (E_LHL_RSP_BASE + rCode); } else { switch (packetType) { case PB_TYPE_READ_REQUEST_QUADLET: case PB_TYPE_READ_REQUEST: hResult = lhlSendReadResponse(respPacket, rCode, (uint16) numBytes, pRespPayload); break; case PB_TYPE_WRITE_REQUEST_QUADLET: case PB_TYPE_WRITE_REQUEST: hResult = lhlSendWriteResponse(respPacket, rCode); break; case PB_TYPE_LOCK_REQUEST: hResult = lhlSendLockResponse(respPacket, rCode, (uint16) numBytes, pRespPayload); break; } } // clean up the resp packetBlock if (pbIsValid(respPacket)) { pbPacketDone(respPacket, PB_DONE_NCI_CB); } return hResult; }
/********************************************************* The tx thread calls this when any transmit queue has one or more packets to transmit. the priority queue is always checked first and serviced until empty, the general queue is ignored during bus reset. this allows node handles to be fixed up after a bus reset, making them transparent to the upper layers, unless a node has left the bus of course. this routine will call the appropriate send routine for request or response. */ static HRESULT lhlTxSndPacketPend(void) { HRESULT hResult = NO_ERROR; PB* packetBlock = NULL; PB_HEADER *pHeader = NULL; uint32 tLabel = 0; uint32 tCode = 0; uint32 nodeAddr = 0; uint32 busGenCurrent = 0; uint32 busGenPacket = 0; DO_FOREVER { // look for priority packets (non-blocking) hResult = lhlMsgQueueGetPacketBlock(LHL_QUEUE_PRIORITY, &packetBlock, TC_NO_WAIT); if (hResult != NO_ERROR) return hResult; if (pbIsValid(packetBlock)) { // if bus reset happened, queued requests must be thrown out briGetCurrentBusGeneration(&busGenCurrent); pbGetBusGeneration (packetBlock, &busGenPacket); if (busGenCurrent != busGenPacket) { pbSwapSrcDstNodeAddr(packetBlock); pbSetFinalStatus(packetBlock, E_LHL_BUS_RESET_IN_PROGRESS); pbPacketDone(packetBlock, PB_DONE_LHL_ATX_SND_PEND_1); hResult = E_BRI_NEW_BUS_RESET; sysLogError(hResult, __LINE__, moduleName); return hResult; } } else { if (briInBusReset() == FALSE) { // if not in bus reset processing, look for general packets (non-blocking) hResult = lhlMsgQueueGetPacketBlock(LHL_QUEUE_GENERAL, &packetBlock, TC_NO_WAIT); if (hResult != NO_ERROR) return hResult; } else { DO_FOREVER { // if in bus reset processing, free for general packets (non-blocking) hResult = lhlMsgQueueGetPacketBlock(LHL_QUEUE_GENERAL, &packetBlock, TC_NO_WAIT); if (hResult != NO_ERROR) return hResult; if (pbIsValid(packetBlock)) { #if 1 pbSwapSrcDstNodeAddr(packetBlock); #endif pbSetFinalStatus(packetBlock, E_LHL_BUS_RESET_IN_PROGRESS); pbPacketDone(packetBlock, PB_DONE_LHL_ATX_SND_PEND_2); } else { break; // no more packetBlocks to free } } } } if (pbIsValid(packetBlock)) { briGetCurrentBusGeneration(&busGenCurrent); pbGetBusGeneration (packetBlock, &busGenPacket); if (busGenCurrent != busGenPacket) { pbSwapSrcDstNodeAddr(packetBlock); pbSetFinalStatus(packetBlock, E_LHL_BUS_RESET_IN_PROGRESS); pbPacketDone(packetBlock, PB_DONE_LHL_ATX_SND_PEND_1); hResult = E_BRI_NEW_BUS_RESET; sysLogError(hResult, __LINE__, moduleName); return hResult; } hResult = pbGetPacketHeader (packetBlock, &pHeader); if (hResult != NO_ERROR) return hResult; hResult = pbGetPacketTLabel (packetBlock, &tLabel); if (hResult != NO_ERROR) return hResult; hResult = pbGetPacketDstNodeAddr (packetBlock, &nodeAddr); if (hResult != NO_ERROR) return hResult; hResult = lhlPendingTxAdd(tLabel, nodeAddr, packetBlock); // insert before send and remove if send error if (hResult != NO_ERROR) return hResult; hResult = context1PostPacket(packetBlock,lhlTxDoneSemID); if (hResult != NO_ERROR) { #if 1 pbSwapSrcDstNodeAddr(packetBlock); #endif pbSetFinalStatus(packetBlock, hResult); pbPacketDone(packetBlock, PB_DONE_LHL_ATX_SND_PEND_3); } else { // We have now posted the write, the semaphore will be signaled uint8 matchResponse = FALSE; // error in sending req/rsp - match corresponding type in PendingTx pbIsResponsePacket(packetBlock, &matchResponse); hResult = TCSemaphoreWait(lhlTxDoneSemID); tCode = (pHeader->quadlets[0] & MASK_TCODE) >> SHIFT_TCODE; lhlTxPacketDoneLLC(tLabel, tCode, nodeAddr, matchResponse); } } else { break; // no more packets to send } }
/*************************************************************************** Handling of the acknowledge transmitted packet request/response done */ static void lhlTxPacketDoneLLC(uint32 tLabel, uint16 tCode, uint32 nodeAddr, uint8 response) { HRESULT hResult = NO_ERROR; PB *pMatchPB = NULL; uint16 conf; BOOL bRemoveEntry = TRUE; uint8 pendingTxType; // ack for sending req/rsp/stm match corresponding type in PendingTx volatile POSTED_TX_CONTEXT * pContext = &postedTxState.contexts[1]; if ((pContext->txStat & LLC_ASY_TX_CMPLT) == 0) { sysLogError(E_LLC_TX_NEVER_COMPLETED, __LINE__, moduleName); } conf = (pContext->txStat & LLC_ASY_TX_EVENT_MASK) >> LLC_ASY_TX_EVENT_SHIFT; // Handling of packet hResult = lhlPendingTxGetType((PB_PACKETTYPE) tCode, &pendingTxType); if (hResult != NO_ERROR) return; if (response) { // response acked by destination bRemoveEntry = TRUE; } else { // OHCI_ACK_PENDING: succes, leave the packet in the pending list to be matched with the response packet // o.w. the transaction failed at the link layer, this status will be passed to the callback bRemoveEntry = (conf != ACK_1394_PENDING); } if (bRemoveEntry) { hResult = lhlPendingTxMatch(tLabel, nodeAddr, pendingTxType, &pMatchPB, bRemoveEntry); if (hResult == NO_ERROR) { // either packet acked by destination, or error returned, or request expects no response if (pbIsValid(pMatchPB)) { HRESULT hResultFinal = NO_ERROR; if (conf != ACK_1394_COMPLETE && conf != LLC_EVENT_INIT) // Termination of async packet with no ack (e.g. bcast, phy, async stream) { hResultFinal = (HRESULT) (E_LHL_CONF_BASE + conf); SYS_DEBUG(SYSDEBUG_TRACE_PACKETS, "lhlATx SndPacketDone: ack error for %s call CB (conf: %i)\n\r", (response) ? "rsp" : "req", conf); } else { SYS_DEBUG(SYSDEBUG_TRACE_PACKETS, "lhlATx SndPacketDone: ack complete for %s call CB\n\r", (response) ? "rsp" : "req" ); } pbSwapSrcDstNodeAddr(pMatchPB); pbSetFinalStatus(pMatchPB, hResultFinal); pbPacketDone(pMatchPB, PB_DONE_LHL_ATX_SND_DONE); } else { hResult = E_LHL_INVALID_PB; sysLogError(hResult, __LINE__, moduleName); } } else { SYS_DEBUG(SYSDEBUG_TRACE_PACKETS, "lhlATx SndPacketDone: match not found for %s\n\r", (response) ? "rsp" : "req" ); } } }