// 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;
}
Beispiel #6
0
// 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();
        }
    }
}