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.

RE: AM6422: IPC Enabling & disabling interrupts

This is a followup to the discussion here:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1500812/am6422-ipc-delay 

Hello,

    Regarding the use of rpmsg, there are numerous interrupt disable/enable operations in the library functions. These operations are currently affecting other interrupts in my real-time kernel. Are these interrupt disable/enable operations necessary? Why are they implemented this way?

RPMessage_LocalMsg *RPMessage_allocEndPtMsg(uint32_t remoteCoreId)
{
    RPMessage_Core *coreObj = &gIpcRpmsgCtrl.coreObj[remoteCoreId];
    RPMessage_LocalMsg *pMsg;
    uint32_t oldIntState;

    oldIntState = HwiP_disable();
    pMsg = (RPMessage_LocalMsg*)RPMessage_queueGet(&coreObj->freeQ);
    if(pMsg == NULL)
    {
        coreObj->freeQAllocPending = 1;
    }
    else
    {
        coreObj->freeQAllocPending = 0;
    }
    HwiP_restore(oldIntState);

    return pMsg;
}
uint32_t RPMessage_freeEndPtMsg(uint16_t remoteCoreId, RPMessage_LocalMsg *pMsg)
{
    RPMessage_Core *coreObj = &gIpcRpmsgCtrl.coreObj[remoteCoreId];
    uint32_t oldIntState, isAllocPending;

    oldIntState = HwiP_disable();
    isAllocPending = coreObj->freeQAllocPending;
    RPMessage_queuePut(&coreObj->freeQ, &pMsg->elem);
    HwiP_restore(oldIntState);

    return isAllocPending;
}

void RPMessage_putEndPtMsg(RPMessage_Struct *obj, RPMessage_LocalMsg *pMsg)
{
    uint32_t oldIntState;

    oldIntState = HwiP_disable();
    RPMessage_queuePut(&obj->endPtQ, &pMsg->elem);
    HwiP_restore(oldIntState);

    SemaphoreP_post(&obj->newEndPtMsgSem);
}

int32_t RPMessage_getEndPtMsg(RPMessage_Struct *obj, RPMessage_LocalMsg **pMsg, uint32_t timeout)
{
    uint32_t oldIntState, done;
    int32_t status = SystemP_TIMEOUT;

    done = 0;
    do {
        oldIntState = HwiP_disable();
        *pMsg = (RPMessage_LocalMsg*)RPMessage_queueGet(&obj->endPtQ);
        HwiP_restore(oldIntState);

        if(*pMsg==NULL)
        {
            status = SemaphoreP_pend(&obj->newEndPtMsgSem, timeout);
            if(status == SystemP_TIMEOUT)
            {
                done = 1;
            }
            if(status == SystemP_SUCCESS && obj->doRecvUnblock)
            {
                status = SystemP_TIMEOUT;
                done = 1;
            }
        }
        else
        {
            status = SystemP_SUCCESS;
            done = 1;
        }
    } while( ! done );

    return status;
}
int32_t RPMessage_vringGetEmptyTxBuf(uint16_t remoteCoreId, uint16_t *vringBufId, uint32_t timeout)
{
    RPMessage_Core *coreObj = &gIpcRpmsgCtrl.coreObj[remoteCoreId];
    RPMessage_Vring *vringObj = &coreObj->vringTxObj;
    uint32_t oldIntState;
    uint16_t head;
    int32_t status = SystemP_FAILURE;
    uint32_t done = 0;

    oldIntState = HwiP_disable();

    do
    {
        /* There's nothing available */
        if (vringObj->lastAvailIdx == vringObj->avail->idx)
        {
            /* We need to know about added buffers */
            vringObj->used->flags &= (uint16_t)~VRING_USED_F_NO_NOTIFY;

            HwiP_restore(oldIntState);

            status = SemaphoreP_pend(&coreObj->newEmptyVringBufSem, timeout);
            if(status==SystemP_TIMEOUT)
            {
                done = 1;
            }

            oldIntState = HwiP_disable();
        }
        else
        {
            head = vringObj->avail->ring[vringObj->lastAvailIdx % vringObj->vringNumBuf];
            vringObj->lastAvailIdx++;

            *vringBufId = head;
            done = 1;
            status = SystemP_SUCCESS;
        }
    } while( ! done );

    HwiP_restore(oldIntState);

    return status;
}

void RPMessage_vringPutFullTxBuf(uint16_t remoteCoreId, uint16_t vringBufId, uint16_t dataLen)
{
    RPMessage_Core *coreObj = &gIpcRpmsgCtrl.coreObj[remoteCoreId];
    RPMessage_Vring *vringObj = &coreObj->vringTxObj;
    struct vring_used_elem *used;
    uint32_t oldIntState;
    uint32_t txMsgValue = RPMESSAGE_MSG_VRING_NEW_FULL;

    if(RPMessage_isLinuxCore(remoteCoreId))
    {
        /* for linux we need to send the TX VRING ID in the mailbox message */
        txMsgValue = RPMESSAGE_LINUX_TX_VRING_ID;
    }

    oldIntState = HwiP_disable();

    used = &vringObj->used->ring[vringObj->used->idx % vringObj->vringNumBuf];
    used->id = vringBufId;
    used->len = dataLen;
    vringObj->used->idx++;

    #if defined(__aarch64__) || defined(__arm__)
    __asm__ __volatile__ ( "dsb sy"  "\n\t": : : "memory");
    __asm__ __volatile__ ( "isb sy"  "\n\t": : : "memory");
    #endif
    #if defined(_TMS320C6X)
    _mfence();
    _mfence();
    #endif

    HwiP_restore(oldIntState);

    IpcNotify_sendMsg(remoteCoreId,
        IPC_NOTIFY_CLIENT_ID_RPMSG,
        txMsgValue,
        1 /* wait for message to be posted */
        );
}

void RPMessage_vringCheckEmptyTxBuf(uint16_t remoteCoreId)
{
    RPMessage_Core *coreObj = &gIpcRpmsgCtrl.coreObj[remoteCoreId];
    RPMessage_Vring *vringObj = &coreObj->vringTxObj;
    uint32_t isNewEmptyBuf = 1;
    uint32_t oldIntState;

    oldIntState = HwiP_disable();

    if (vringObj->lastAvailIdx == vringObj->avail->idx)
    {
        isNewEmptyBuf = 0;
    }

    HwiP_restore(oldIntState);

    if(isNewEmptyBuf)
    {
        SemaphoreP_post(&coreObj->newEmptyVringBufSem);
    }
}

  • Hello Wanglili,

    Can you point me to the file where you got those functions? I do not see them when I do an initial search of ti-rpmsg-char, rpmsg_char_zerocopy, or the Linux drivers.

    Regards,

    Nick

  • Hello,

    The library files I shared are for the real-time core. When the real-time core receives messages from the non-real-time core, it frequently disables and re-enables interrupts within the interrupt handler. If message sending occurs too frequently, this may cause other interrupts in the real-time core to be lost.Can we use polling instead of interrupt-driven methods for message reception? If so, could you provide relevant implementation examples?

    C:\ti\mcu_plus_sdk_am64x_08_06_00_43\source\drivers\ipc_rpmsg  

  • Hello Wanglili,

    I am sending your thread to another team member for comment. Feel free to ping the thread if you do not get a response within a couple of business days.

    Regards,

    Nick

  • Hi Wanglili,

    The library files I shared are for the real-time core. When the real-time core receives messages from the non-real-time core, it frequently disables and re-enables interrupts within the interrupt handler.

    Are you referring to HwiP_disable()? If not, can you please point me to which portions of the code are you referring to?

    As a background, IPC RPmsg underneath uses IPC Notify, which in turns uses Interrupt HW mechanisms to interrupt the receiving cores. Changing IPC RPmsg to polling will require a complete re-work in my mind.

    AM64x MCU+ SDK: IPC RPMessage

    AM64x MCU+ SDK: IPC Notify

    You could potentially use IPC Notify directly for the most critical communication. 

    thank you,

    Paula

  • To clarify Paula's comment, IPC Notify is supported for communication between MCU+ cores. While Linux has a low-level mailbox driver that can be used by other higher-level Linux drivers (like RPMsg), TI does not provide software support for exposing mailboxes up to Linux userspace.

    Regards,

    Nick

  • Thank you and I understand it.

    "I have been following up on the issue I raised earlier for a long time but have not yet received a response. I would appreciate your assistance with this."

    e2e.ti.com/.../5809724