This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C6678 SRIO Driver

Hello,

I'm trying to port the C6455 SRIO driver to C6678 Multicore DSP. I'm using the SRIO Loopback examples in PDK,  SRIO LLD and CPPI_QMSS_LLD design documents as reference. I'm following the detailed steps mentioned in the section 5.4.8.1 CPPI/QMSS LLD for implementing the transmit path of the SRIO driver. It seems, I couldn't find the code for setting up the transmit completion queue in the SRIO driver comes with the PDK package (\Texas Instruments\pdk_C6678_1_0_0_17\packages\ti\drv\srio\src\srio_drv.c)   

(Refer to CPPi/QMSS LLD Rev A Page 44 Section 5.4.8.1)

  • "Set up the transmit completion queue -
  • Recommendation is to use the queues with accumulation and interrupt support. There are low priority and high priority queues available"

I couldn't trace this in either application managed or driver managed configuration driver code, but I see the code for setting up the queues with accumulation and interrupt support for the receive path. Any specific reason why the transmit interrupt not implemented in the driver ? Are there any examples or reference for setting up the transmit completion queue interrupt support ?

 

Thanks,

Balaji   

  •  

    I suggest you look at srio_drv.c  and look for a line similar to the following:

     

    /* Open the SRIO Transmit Free Queue; this should support starvation. */

    ptr_srioDrvInst->txFreeQueue = Qmss_queueOpen

  • I think this part of code sets up the transmit free queue with starvation counters but my question is where is the implementation for programming the accumulator if interrupt mode is used for transmit completion notification similar to the following for receive path such that in the application one can hook up the ISR shown further below.   

                /* YES. Program the accumulator. */
                result = Qmss_programAccumulator (Qmss_PdspId_PDSP1, &ptr_srioDrvInst->cfg.u.appManagedCfg.accCfg);
                if (result != QMSS_ACC_SOK)
                {
                    Srio_osalLog ("Error: Program Accumulator for Rx Queue failed 0x%x\n", result);
              return -1;
                }

                /* Remember the accumulator channel which is being programmed. */
                ptr_srioDrvInst->accChannel = ptr_srioDrvInst->cfg.u.appManagedCfg.accCfg.channel;

        // Hook up ISR

       EventCombiner_dispatchPlug (48, (EventCombiner_FuncPtr)Srio_rxCompletionIsr, (UArg)hDrvManagedSrioDrv, TRUE);
       EventCombiner_enableEvent(48);

     

     

        

  • Hi Balaji,

    The SRIO examples in the PDK do not use the QMSS accumulator for generating a transmit interrupt. If required, it should be straight forward to add the accumulator functionality and generate a TX completion interrupt (similar to C6455). One possible reason, for not taking interrupts for TX compared to RX is that, in the case of TX operation, the SRIO HW takes care of recycling the TX descriptors to the TX completion queue after successful transmission of the message. However, in case of RX operation, it is the responsibility of the DSP core (SW) to recycle the descriptors in the RX destination queue to the RX free descriptor queue. Hence, we need an RX interrupt to signal the DSP core about the availability of data.

    The SRIO TX driver can be implemented using the following steps:

    1) Pop a descriptor from the TX completion queue. Associate a transmit buffer with this descriptor and appropriately populate the fields of this descriptor

    2) Push this descriptor into the SRIO TX queue

    3) Once the SRIO message associated with this descriptor is successfully transferred, subsequently this descriptor is recycled to the TX completion queue.

    4) For the next TX transactions, the SW can reuse the recycled descriptors in the TX completion queue.

    One important point, which needs to be taken care of is that, it is the responsibility of the TX driver to monitor the SRIO garbage collection queue to determine, if any of the TX descriptors encountered error conditions.

    I hope this helps. 

  • Hello karthik,

    Thanks for the response. As our existing C6455 driver supports TX interrupt and monitors the SRIO errors in the ISR, thought would implement the same with C6678 SRIO driver as well. I've modified the driver to support Tx interrupt with the  following changes. It seems now I'm neither seeing Tx completion interrupt nor the message reaches the Host succesfully. Earlier I could successfully transmit the messages from DSP to Host processor via SRIO in raw socket type 11 mode, application managed configuration and in polling mode.

    In order to incorporate the Tx interrupt, I switched to Type11 normal socket, driver manged configuration and non-blocking mode. Can you let me know if I'm missing any configuration. 

     

    Regards,

    Balaji

     

    Following are the changes:

    test_main.c 

     /* This is the table which maps the core to a specific receive queue. */
         coreToQueueSelector[0] = 704;
         coreToQueueSelector[1] = 705;
         coreToQueueSelector[2] = 706;
         coreToQueueSelector[3] = 707;

    /* Accumulator Configuration is VALID. */
      drvCfg.u.drvManagedCfg.txCfg.bIsAccumlatorCfgValid = 1; 

      /* Accumulator Configuration. */     
         drvCfg.u.drvManagedCfg.txCfg.accCfg.channel             = coreNum;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.command             = Qmss_AccCmd_ENABLE_CHANNEL;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.queueEnMask         = 0;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.queMgrIndex         = coreToQueueSelector[coreNum];
         drvCfg.u.drvManagedCfg.txCfg.accCfg.maxPageEntries      = 2;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.timerLoadCount      = 0;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.interruptPacingMode = Qmss_AccPacingMode_LAST_INTERRUPT;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.listEntrySize       = Qmss_AccEntrySize_REG_D;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.listCountMode       = Qmss_AccCountMode_ENTRY_COUNT;
         drvCfg.u.drvManagedCfg.txCfg.accCfg.multiQueueMode      = Qmss_AccQueueMode_SINGLE_QUEUE;

            /* Initialize the accumulator list memory */
            memset ((Void *)&gHiPriAccumList[0], 0, sizeof(gHiPriAccumList));
            drvCfg.u.drvManagedCfg.txCfg.accCfg.listAddress = l2_global_address((UInt32)&gHiPriAccumList[0]);

    srio_drv.c

    /* Program the tx free return queue to tx completion queue

    /* Remember the receive completion queue */
            ptr_srioDrvInst->txCompletionQueue = ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.txCompletionQueue;
          
           /* Get the Queue Information for the Transmit completion Queue */
         txCompQueueInfo = Qmss_getQueueNumber(ptr_srioDrvInst->txCompletionQueue);
          
     
         /* Initialize the Transmit descriptors. We want all the transmit descriptors to go
          * back to the Transmit Free Queue after transmission. */
         descCfg.memRegion                 = ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.txMemRegion;
         descCfg.descNum                   = ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.numTxBuffers;
         descCfg.destQueueNum              = QMSS_PARAM_NOT_SPECIFIED;
         descCfg.queueType                 = Qmss_QueueType_GENERAL_PURPOSE_QUEUE;
         descCfg.initDesc                  = Cppi_InitDesc_INIT_DESCRIPTOR;
         descCfg.descType                  = Cppi_DescType_HOST;
         descCfg.returnQueue               = txCompQueueInfo;
         descCfg.epibPresent               = Cppi_EPIB_NO_EPIB_PRESENT;
         descCfg.returnPushPolicy          = Qmss_Location_HEAD;
         descCfg.cfg.host.returnPolicy     = Cppi_ReturnPolicy_RETURN_ENTIRE_PACKET;
         descCfg.cfg.host.psLocation       = Cppi_PSLoc_PS_IN_DESC;

     

    /***********************************************************************
             ******************** Transmit Accumulator Configuration ************************
             ***********************************************************************/

            /* Check if we need to configure the accumulator? */
            if (ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.bIsAccumlatorCfgValid == 1)
            {
                /* YES. Program the accumulator. */
                result = Qmss_programAccumulator (Qmss_PdspId_PDSP1,
                                                  &ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.accCfg);
                if (result != QMSS_ACC_SOK)
                {
                    Srio_osalLog ("Error: Program Accumulator failed 0x%x\n", result);
              return -1;
                }

                /* Remember the accumulator channel which is being programmed. */
                ptr_srioDrvInst->accChannel = ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.accCfg.channel;

                /* Use the Ping List in the beginning. */
                ptr_srioDrvInst->rxUsePingList = 1;

                /* Initialize the PING & PONG Completion Address. */
                ptr_srioDrvInst->txPingAddress = ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.accCfg.listAddress;
                ptr_srioDrvInst->txPongAddress = ptr_srioDrvInst->txPingAddress +
                                                 ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.accCfg.maxPageEntries *
                                                 (sizeof(uint32_t) * (1 << ptr_srioDrvInst->cfg.u.drvManagedCfg.txCfg.accCfg.listEntrySize));

                /* Accumulator has been programmed */
                ptr_srioDrvInst->isTxAccumulatorProgrammed = 1;

                /* Debug Message: */
                Srio_osalLog ("Debug: DrvConfig Ping: 0x%x Pong: 0x%x\n", ptr_srioDrvInst->rxPingAddress,
                               ptr_srioDrvInst->rxPongAddress);
            }
            else
            {
                /* NO. The accumulator has not been programmed */
                ptr_srioDrvInst->isTxAccumulatorProgrammed = 0;
            }

     

    #pragma CODE_SECTION(Srio_txCompletionIsr, ".text:Srio_txCompletionIsr");
    void Srio_txCompletionIsr (Srio_DrvHandle hSrioDrv)
    {
        Srio_DriverInst*        ptr_srioDrvInst;
        uint32_t*               txCompletionQueueList;
        uint32_t                count;
        uint32_t                index;
        Cppi_Desc*              ptrDesc;

        /* Get the SRIO Driver Instance */
        ptr_srioDrvInst = (Srio_DriverInst*)hSrioDrv;

        /* Check if accumulator is programmed or not */
        if (ptr_srioDrvInst->isTxAccumulatorProgrammed == 1)
        {
            /* Increment the number of interrupts which were detected. */
            ptr_srioDrvInst->accInterrupts++;

            /* Interrupt Mode: Get the pointer to the Receive Completion Queue(Use PING or PONG) */
            if (ptr_srioDrvInst->txUsePingList == 1)
            {
                /* PING: Get the receive completion queue list. Next time we will use PONG */
                txCompletionQueueList = (uint32_t*)ptr_srioDrvInst->txPingAddress;
                ptr_srioDrvInst->txUsePingList = 0;
            }
            else
            {
                /* PONG: Get the receive completion queue list. Next time we will use PING */
                txCompletionQueueList = (uint32_t*)ptr_srioDrvInst->txPongAddress;
                ptr_srioDrvInst->txUsePingList = 1;
            }

            /* Determine the number of pending packets. */
            count = *txCompletionQueueList;

            /* Run through all the buffer descriptors */
            for (index = 0; index < count; index++)
            {
                /* Read the host descriptor. */
                ptrDesc = (Cppi_Desc*)QMSS_DESC_PTR(txCompletionQueueList[index + 1]);
                if (ptrDesc == NULL)
                 break;
     
                /* Process the received buffer descriptor. */
                Srio_processReceivedBD (ptr_srioDrvInst, ptrDesc);
     
                /* Clear the accumulator entry. */
                txCompletionQueueList[index + 1] = 0;
            }

            /* Clear INTD */
            Qmss_ackInterrupt(ptr_srioDrvInst->accTxChannel, 1);
            Qmss_setEoiVector(Qmss_IntdInterruptType_HIGH, ptr_srioDrvInst->accTxChannel);
        }
        else
        {
            /* Polled Mode: */
            count = Qmss_getQueueEntryCount(ptr_srioDrvInst->txCompletionQueue);

            /* Run through all the buffer descriptors */
            for (index = 0; index < count; index++)
            {
                /* Pop the buffer descriptor from the receive completion queue */
                ptrDesc = (Cppi_Desc*)QMSS_DESC_PTR(Qmss_queuePop(ptr_srioDrvInst->txCompletionQueue));
                if (ptrDesc == NULL)
                    break;

                /* Process the received buffer descriptor. */
                Srio_processReceivedBD (ptr_srioDrvInst, ptrDesc);
            }
        }
        return;
    }

     

     

     

     

     

     

     

     

                      

  • Hi Balaji,

    Sorry for the delayed response.

    I am currently working on this issue. Will it be fine with you, if I can get back on this issue by end of this week?

  • Hello Karthik,

         I'm able to transmit the SRIO messges continuously in the interrupt mode with the new changes in the SRIO driver implemented for the transmit interrupt functionality with the following configuration to suit our application requirements:

    1.  Application managed driver configuration
    2. Raw socket Type 11
    3. Interrupt mode with Tx completion support

     I would like to recommend the following change in the SRIO loopback example (\Texas Instruments\pdk_C6678_1_0_0_17\packages\ti\drv\srio\test\Loopback\test_main.c)comes with the 6678 PDK package.

    Use "ptrHostDesc = (Cppi_HostDesc *)QMSS_DESC_PTR(Qmss_queuePop(srioTempQueue));" instead of " ptrHostDesc = (Cppi_HostDesc *)Qmss_queuePop(srioTempQueue); 

    The above change is required to get the descriptor pointer correctly after the descriptor gets popped from the queue in order to continuously transmit the messages, if the count exceeds the transmit queue deep.

    Thanks for your support.

    Regards,

    Balaji   

     

  • Hi Balaji,

    Thanks for the update.

    It would be great, if you can further elaborate on " if the count exceeds the transmit queue deep". The macro QMSS_DESC_PTR masks the 4 LSBs of the descriptor address, which contain the descriptor size information. Whenever, you are trying to push descriptors into the TX queue, you should appropriately set the descriptor size in the 4 LSB's, for correct transmission of data.

  • Hi Karthik,

          Descriptor pointer is a 16-byte aligned address, so we should mask the least 4 bits when retrieving a descriptor pointer from the queue. QMSS_DESC_PTR macro masks the least significant 4 bits and provides the correct 16 byte aligned address. The example code in PDK works fine only if least significant four bits are zero (scenario during initialization) and breaks on a non-zero value in least significant four size bits  that happened in my case after recycling the transmit free queue. However irrespective of the descriptor size bits, we should align the descriptor address using the macro QMSS_DESC_PTR works for all the cases. Hope this answers your question.

     

    Regards,

    Balaji         

  • Hi Balaji,

    Thanks for your clarification. Now I understand your issue.

    Whenever, the SRIO HW recycles the TX descriptors to the TX FDQ, it does not clear the 4 LSBs of the descriptor, which contains the size of the descriptor information. As mentioned previously, the size of the descriptor is added, while the descriptor is pushed into the TX queue.

    Thanks for pointing this out.