// write void PHYSICAL_CHANNEL_CLASS::Write(UMF_MESSAGE message) { // construct header unsigned char header[UMF_CHUNK_BYTES]; message->EncodeHeader(header); msg_count_out++; //fprintf(errfd,"attempting to write msg %d of length %d: %x\n", msg_count_out,message->GetLength(),*header); //write header to pipe pcieDevice->Write((const char *)header, UMF_CHUNK_BYTES); // write message data to pipe // NOTE: hardware demarshaller expects chunk pattern to start from most // significant chunk and end at least significant chunk, so we will // send chunks in reverse order message->StartReverseExtract(); while (message->CanReverseExtract()) { UMF_CHUNK chunk = message->ReverseExtractChunk(); //fprintf(errfd,"attempting to write %x\n",chunk); pcieDevice->Write((const char*)&chunk, UMF_CHUNK_BYTES); } // de-allocate message delete message; //fflush(errfd); }
void ROUTE_THROUGH_LI_CHANNEL_OUT_CLASS::push(UMF_MESSAGE &outMesg) { // Software expects encoding in terms of bytes while the credit scheme speaks in terms of chunks UINT32 messageLengthBytes = outMesg->GetLength(); UINT32 messageLengthChunks = 1 + ((outMesg->GetLength()) / sizeof(UMF_CHUNK)); // Each chunk takes a header plus one bit for encoding? if (DEBUG_CHANNELIO) { debugLog << endl << "****Outbound Channel "<< this->name << " Sends message " << endl; debugLog << endl << "Base Message length "<< dec << (UINT32) (outMesg->GetLength()) << endl; debugLog << "UMF_CHUNK (bytes) " << sizeof(UMF_CHUNK) << endl; debugLog << "Message Length (bytes) "<< dec << messageLengthBytes << endl; debugLog << "Message Credits (chunks) "<< dec << messageLengthChunks << endl; debugLog << "Channel ID "<< dec << this->channelID << endl; } // For now we will allow the system to deadlock here. What is really needed is an // means of back pressure all the way to the incoming route through. // TODO: Fix this deadlock with better backpressure cooperation among threads acquireCredits(messageLengthChunks); // Recode message for the outbound link and send { outMesg->SetServiceID(this->channelID); outputQ->push(outMesg); } if(DEBUG_CHANNELIO) { debugLog << endl << "****Outbound Route-through Channel "<< this->name << " message complete" << endl; } }
// Regional Manager has a credit queue to send back flowcontrol credits?? void FLOWCONTROL_LI_CHANNEL_IN_CLASS::freeCredits(UINT32 serviceID) { if(SWITCH_DEBUG) { cout << "Channel " << serviceID << "Freeing credits: local: " << flowcontrolCredits << " regional: " << regionalFlowcontrol->GetRegionalCredits() << " returnThreshold: " << regionalReturnThreshold << endl; } if(((flowcontrolCredits > 0) && (regionalFlowcontrol->GetRegionalCredits() > regionalReturnThreshold)) || (flowcontrolCredits > regionalReturnThreshold / 2)) { if(SWITCH_DEBUG) { cout << "Channel " << serviceID << " sending back credits " << flowcontrolCredits << endl; } UMF_MESSAGE outMesg = factory->createUMFMessage(); outMesg->SetLength(sizeof(UMF_CHUNK)); outMesg->SetServiceID(flowcontrolChannelID); // Atomic read returns the old value, making this operation thread safe under idempotence. UINT32 creditsToReturn = flowcontrolCredits.fetch_and_store(0); UINT32 phyPvt = (serviceID * 2 * MULTIFPGA_FIFO_SIZES) | creditsToReturn; if(SWITCH_DEBUG) { cout << "Setting phy pvt to " << hex << phyPvt << dec <<endl; } outMesg->AppendChunk((UINT128) phyPvt); regionalFlowcontrol->FreeRegionalCredits(creditsToReturn); flowcontrolQ->push(outMesg); } }
// accept a delivered message from channelio void RRR_SERVER_MONITOR_CLASS::DeliverMessage( UMF_MESSAGE message) { // record channelID for backwards compatibility int channelID = message->GetChannelID(); int serviceID = message->GetServiceID(); // validate serviceID if (isServerRegistered(serviceID) == false) { fprintf(stderr, "software server: invalid serviceID: %u\n", serviceID); parent->CallbackExit(1); } // call service and obtain result UMF_MESSAGE result = ServerMap[serviceID]->Request(message); // see if we need to respond if (result) { // set serviceID result->SetServiceID(serviceID); // send to channelio... send on original virtual channel (BC) channelio->Write(channelID, result); } }
// write void PHYSICAL_CHANNEL_CLASS::Write( UMF_MESSAGE message) { // construct header unsigned char header[UMF_CHUNK_BYTES]; message->EncodeHeader(header); // write header to pipe unixPipeDevice->Write(header, UMF_CHUNK_BYTES); // write message data to pipe // NOTE: hardware demarshaller expects chunk pattern to start from most // significant chunk and end at least significant chunk, so we will // send chunks in reverse order message->StartReverseExtract(); while (message->CanReverseExtract()) { UMF_CHUNK chunk = message->ReverseExtractChunk(); unixPipeDevice->Write((unsigned char*)&chunk, sizeof(UMF_CHUNK)); } // de-allocate message delete message; }
// write void PHYSICAL_CHANNEL_CLASS::Write( UMF_MESSAGE message) { pthread_mutex_lock(&channelLock); // block until buffer has sufficient space CSR_INDEX h2fTailPlusOne = (h2fTail == CSR_H2F_BUF_END) ? CSR_H2F_BUF_START : (h2fTail + 1); while (h2fTailPlusOne == h2fHeadCache) { h2fHeadCache = pciExpressDevice->ReadCommonCSR(CSR_H2F_HEAD); } // construct header UMF_CHUNK header = message->EncodeHeader(); CSR_DATA csr_data = CSR_DATA(header); // write header to physical channel pciExpressDevice->WriteCommonCSR(h2fTail, csr_data); h2fTail = h2fTailPlusOne; h2fTailPlusOne = (h2fTail == CSR_H2F_BUF_END) ? CSR_H2F_BUF_START : (h2fTail + 1); // write message data to physical channel // NOTE: hardware demarshaller expects chunk pattern to start from most // significant chunk and end at least significant chunk, so we will // send chunks in reverse order message->StartReverseExtract(); while (message->CanReverseExtract()) { // this gets ugly - we need to block until space is available while (h2fTailPlusOne == h2fHeadCache) { h2fHeadCache = pciExpressDevice->ReadCommonCSR(CSR_H2F_HEAD); } // space is available, write UMF_CHUNK chunk = message->ReverseExtractChunk(); csr_data = CSR_DATA(chunk); pciExpressDevice->WriteCommonCSR(h2fTail, csr_data); h2fTail = h2fTailPlusOne; h2fTailPlusOne = (h2fTail == CSR_H2F_BUF_END) ? CSR_H2F_BUF_START : (h2fTail + 1); } // sync h2fTail pointer. It is OPTIONAL to do this immediately, but we will do it // since this is probably the response to a request the hardware might be blocked on pciExpressDevice->WriteSystemCSR(genIID() | (OP_UPDATE_H2FTAIL << 16) | (h2fTail << 8)); pthread_mutex_unlock(&channelLock); // de-allocate message delete message; }
// constructor UMF_ALLOCATOR_CLASS::UMF_ALLOCATOR_CLASS() { SetTraceableName("umf_allocator"); // Preallocate some entries for the pool, hoping they will be contiguous for (int i = 0; i < UMF_POOL_SIZE; i++) { // Zero out message to make valgrind happy UMF_MESSAGE m = (UMF_MESSAGE) memset(malloc(sizeof(UMF_MESSAGE_CLASS)), 0, sizeof(UMF_MESSAGE_CLASS)); m->setAllocator(this); m->SetFreeListNext(NULL); memset(m, 0, sizeof(UMF_MESSAGE_CLASS)); freeList.Push(m); } }
void ROUTE_THROUGH_LI_CHANNEL_IN_CLASS::pushUMF(UMF_MESSAGE &inMesg) { // Software expects encoding in terms of bytes while the credit scheme speaks in terms of chunks UINT32 messageLengthBytes = inMesg->GetLength(); // Length of message already framed in bytes UINT32 messageLengthChunks = 1 + ((inMesg->GetLength()) / sizeof(UMF_CHUNK)); // Each chunk takes a header plus one bit for encoding? if(DEBUG_CHANNELIO) { debugLog << "Channel " << this->name << " is " << this << endl; inMesg->Print(debugLog); debugLog << this->name << " route through acquiring credit " << messageLengthChunks << endl; } // This technically frees our credits. // We need to push the message directly to the the outbound queue. // If the outbound queue doesn't have credit, in theory this push // will block. Currently this case is unhandled, potentially // leading to deadlocks, since the main handler threads are the // ones getting blocked. A better solution needs to check // channelPartner's status and store messages that will be unsent. msgBuffer.push(inMesg); if(DEBUG_CHANNELIO) { debugLog << "****In Route-through Channel " << this->name << " message is complete" << endl; } // Unlike the marshalled LI channels, we do not delete the // outbound message. channelPartner owns the message and is // responsible for deletion. }
void * QA_PHYSICAL_CHANNEL_CLASS::WriterThread(void *argv) { void ** args = (void**) argv; QA_PHYSICAL_CHANNEL physicalChannel = (QA_PHYSICAL_CHANNEL) args[1]; tbb::concurrent_bounded_queue<UMF_MESSAGE> *incomingQ = &(physicalChannel->writeQ); QA_DEVICE_WRAPPER qaDevice = (QA_DEVICE_WRAPPER) args[0]; while (1) { UMF_MESSAGE message; incomingQ->pop(message); // Check to see if we're being torn down -- this is // done by passing a special message through the writeQ if (message == NULL) { if (!physicalChannel->uninitialized) { cerr << "QA_PHYSICAL_CHANNEL got an unexpected NULL value" << endl; } pthread_exit(0); } // The FPGA side detects NULLs inserted for alignment by looking at the // length field. Having a length of 0 would break the protocol. ASSERTX(message->GetLength() != 0); // construct header UMF_CHUNK header = 0; message->EncodeHeader((unsigned char *)&header); qaDevice->Write(&header, sizeof(header)); size_t n_bytes = message->ExtractBytesLeft(); // Round up to multiple of UMF_CHUNK size n_bytes = (n_bytes + sizeof(UMF_CHUNK) - 1) & ~(sizeof(UMF_CHUNK) - 1); qaDevice->Write(message->ExtractGetRawPtr(), n_bytes); message->ExtractUpdateRawPtr(n_bytes); // de-allocate message delete message; // Flush output channel if there isn't another message ready. if (incomingQ->empty()) { qaDevice->Flush(); } } }