void common_wrapper(UArg arg0, UArg arg1)
{
	taskArgs* t = (taskArgs*)arg0 ;
	int tid = (int)arg1 ;
	int i, j, k ;
	
	for(i=0 ; i<NUM_ITER ; i++) {
		if(tid == 0) {
			callBarrier(0, /*lock_id=*/4) ;
		}

		callLocalBarrier() ;
		compute_histo(t->buffer1, t->buffer2, t->start_indx, t->end_indx) ;
		Cache_wbInv (t->buffer2, HISTO_SIZE*4, Cache_Type_ALL, FALSE) ;
		callLocalBarrier() ;
		if(tid == 0) {
			callBarrier(1, /*lock_id=*/4) ;
			compute_gray_level_mapping() ;
		}
		callLocalBarrier() ;
		compute_image(t->buffer1, m3_gray_level_mapping, t->start_indx, t->end_indx) ;

		if(tid == 0)
			Cache_wbInv (t->buffer1, IMG_SIZE*IMG_SIZE*4, Cache_Type_ALL, FALSE);
	}

	if(tid == 0)
		Event_post(edgeDetectEvent, Event_Id_00) ;
	else
		Event_post(edgeDetectEvent, Event_Id_01) ;
}
Пример #2
0
/*
 *  ======== NotifyDriverShm_unregisterEvent ========
 */
Void NotifyDriverShm_unregisterEvent(NotifyDriverShm_Object *obj,
                                     UInt32 eventId)
{
    NotifyDriverShm_EventEntry *eventEntry;
    Int i, j;

    /* 
     *  Disable interrupt line to ensure that NotifyDriverShm_isr doesn't 
     *  preempt registerEvent and encounter corrupt state
     */
    NotifyDriverShm_disable(obj);
     
    /* 
     *  First unset the registered bit in shared memory so no notifications
     *  arrive after this point
     */
    CLEAR_BIT(obj->selfProcCtrl->eventRegMask, eventId);
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
                    Cache_Type_ALL, TRUE);
    }
    
    /*
     *  Clear any pending unserviced event as there are no listeners
     *  for the pending event.  This should be done only after the event
     *  is unregistered from shared memory so the other processor doesn't
     *  successfully send an event our way immediately after unflagging this 
     *  event.
     */
    eventEntry = EVENTENTRY(obj->selfEventChart, obj->eventEntrySize, eventId); 
    eventEntry->flag = NotifyDriverShm_DOWN;
    
    /* Write back both the flag and the reg mask */
    if (obj->cacheEnabled) {
        Cache_wbInv(eventEntry, sizeof(NotifyDriverShm_EventEntry), 
                    Cache_Type_ALL, TRUE);
    }

    /* 
     *  Re-arrange eventIds in the Event Registration Chart so there is 
     *  no gap caused by the removal of this eventId
     *
     *  There is no need to make this atomic since Notify_exec cannot preempt:
     *  the event has already been disabled in shared memory (see above)
     */
    for (i = 0; i < ti_sdo_ipc_Notify_numEvents; i++) {
        if (eventId == obj->regChart[i]) {
            obj->regChart[i] = (UInt32)-1;
            for (j = i + 1; (j != ti_sdo_ipc_Notify_numEvents) && 
                    (obj->regChart[j] != (UInt32)-1); j++) {
                obj->regChart[j - 1] = obj->regChart[j];
                obj->regChart[j] = (UInt32)-1;
            }
            break;
        }
    }
    
    /* Restore the interrupt line */
    NotifyDriverShm_enable(obj);
}
Пример #3
0
/*
 *  ======== ListMP_putTail ========
 */
Int ListMP_putTail(ListMP_Handle handle, ListMP_Elem *elem)
{
    ti_sdo_ipc_ListMP_Object *obj = (ti_sdo_ipc_ListMP_Object *)handle;
    UInt key;
    UInt16  id;
    ListMP_Elem *localPrevElem;
    SharedRegion_SRPtr sharedElem;
    SharedRegion_SRPtr sharedHead;
    Bool localPrevElemIsCached;

    /* prevent another thread or processor from modifying the ListMP */
    key = GateMP_enter((GateMP_Handle)obj->gate);

    id = SharedRegion_getId(elem);
    if (ti_sdo_ipc_SharedRegion_translate == FALSE) {
        sharedElem = (SharedRegion_SRPtr)elem;
        sharedHead = (SharedRegion_SRPtr)&(obj->attrs->head);
        localPrevElem = (ListMP_Elem *)obj->attrs->head.prev;
    }
    else {
        sharedElem = SharedRegion_getSRPtr(elem, id);
        sharedHead = SharedRegion_getSRPtr(&(obj->attrs->head), obj->regionId);
        localPrevElem = SharedRegion_getPtr(obj->attrs->head.prev);
    }

    /* Assert that pointer is not NULL */
    Assert_isTrue(localPrevElem != NULL, ti_sdo_ipc_Ipc_A_nullPointer);

    localPrevElemIsCached = SharedRegion_isCacheEnabled(
        SharedRegion_getId(localPrevElem));
    if (localPrevElemIsCached) {
        Cache_inv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }

    /* add the new elem into the list */
    elem->next = sharedHead;
    elem->prev = obj->attrs->head.prev;
    localPrevElem->next = sharedElem;
    obj->attrs->head.prev = sharedElem;

    if (localPrevElemIsCached) {
        /* Write-back because localPrevElem->next changed */
        Cache_wbInv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    if (obj->cacheEnabled) {
        /* Write-back because obj->attrs->head.prev changed */
        Cache_wbInv(&(obj->attrs->head), sizeof(ListMP_Elem), Cache_Type_ALL,
                TRUE);
    }
    if (SharedRegion_isCacheEnabled(id)) {
        /* Write-back because elem->next & elem->prev changed */
        Cache_wbInv(elem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }

    GateMP_leave((GateMP_Handle)obj->gate, key);
    
    return (ListMP_S_SUCCESS);
}
Пример #4
0
/*
 *  ======== NotifyDriverShm_registerEvent ========
 */
Void NotifyDriverShm_registerEvent(NotifyDriverShm_Object *obj,
                                   UInt32 eventId)
{
    NotifyDriverShm_EventEntry *eventEntry;
    Int i, j;
    
    /* 
     *  Disable interrupt line to ensure that NotifyDriverShm_isr doesn't 
     *  preempt registerEvent and encounter corrupt state
     */
    NotifyDriverShm_disable(obj);
    
    /*
     *  Add an entry for the registered event into the Event Registration
     *  Chart, in ascending order of event numbers (and decreasing
     *  priorities).
     */
    for (i = 0; i < ti_sdo_ipc_Notify_numEvents; i++) {
        /* Find the correct slot in the registration array.*/
        if (obj->regChart[i] == (UInt32)-1) {
            for (j = i - 1; j >= 0; j--) {
                if (eventId < obj->regChart[j]) {
                    obj->regChart[j + 1] = obj->regChart[j];
                    i = j;
                }
                else {
                    /* End the loop, slot found.*/
                    j = -1;
                }
            }
            obj->regChart[i] = eventId;
            break;
        }
    }
    
    /*
     *  Clear any pending unserviced event as there are no listeners
     *  for the pending event
     */
    eventEntry = EVENTENTRY(obj->selfEventChart, obj->eventEntrySize, eventId) 
    eventEntry->flag = NotifyDriverShm_DOWN;
    if (obj->cacheEnabled) {
        Cache_wbInv(eventEntry, sizeof(NotifyDriverShm_EventEntry), 
                    Cache_Type_ALL, TRUE);
    }

    /* Set the 'registered' bit in shared memory and write back */
    SET_BIT(obj->selfProcCtrl->eventRegMask, eventId);
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
                    Cache_Type_ALL, TRUE);
    }
    
    /* Restore the interrupt line */
    NotifyDriverShm_enable(obj);
}
Пример #5
0
/*
 *  ======== GateAAMonitor_Instance_init ========
 */
Int GateAAMonitor_Instance_init(GateAAMonitor_Object *obj,
                                IGateProvider_Handle localGate,
                                const GateAAMonitor_Params *params,
                                Error_Block *eb)
{
    /* Assert that params->sharedAddr is valid */
    Assert_isTrue(
        (UInt32)params->sharedAddr >= GateAAMonitor_SL2_RANGE_BASE &&
        (UInt32)params->sharedAddr <  GateAAMonitor_SL2_RANGE_MAX,
        GateAAMonitor_A_invSharedAddr);

    obj->localGate  = localGate;
    obj->sharedAddr = (Ptr)_Ipc_roundup(params->sharedAddr,
            GateAAMonitor_CACHELINE_SIZE);
    obj->nested = 0;

    if (!params->openFlag) {
        /*
         *  The processor that inits the AAM initializes the value
         *  to zero (e.g. no one is using it). The other processors
         *  must invalidate the memory in case it is in cache.
         */
        *(obj->sharedAddr) = 0;
        Cache_wbInv((Ptr)obj->sharedAddr, GateAAMonitor_CACHELINE_SIZE,
                    Cache_Type_ALL, TRUE);
    }
    else {
        /* Opening. */
        Cache_inv((Ptr)obj->sharedAddr, GateAAMonitor_CACHELINE_SIZE,
                  Cache_Type_ALL, TRUE);
    }

    return (0);
}
Пример #6
0
/*
 *  ======== Ipc_stop ========
 */
Int Ipc_stop()
{
    Int status;
    
    /* clear local module state */
    Ipc_module->gateMPSharedAddr = NULL;
    Ipc_module->ipcSharedAddr = NULL;

    /* reset Shared Region 0 reservedSize and heap handle */
    ti_sdo_ipc_SharedRegion_resetInternalFields(0);

    /* delete any HeapMemMP created by owner of SR0 */
    status = ti_sdo_ipc_SharedRegion_stop();
    if (status < 0) {
        return (status);
    }

    /* delete default GateMP created by owner of SR0 */
    status = ti_sdo_ipc_GateMP_stop();
    if (status < 0) {
        return (status);
    }

    /* set sr0MemorySetup back to 0 if needed by Host */
    if ((ti_sdo_ipc_Ipc_generateSlaveDataForHost) &&
        !(ti_sdo_ipc_Ipc_sr0MemorySetup)) {
        Ipc_sr0MemorySetup = 0;
        Cache_wbInv(&Ipc_sr0MemorySetup,
              sizeof(Ipc_sr0MemorySetup),
              Cache_Type_ALL,
              TRUE);
    }

    return (Ipc_S_SUCCESS);
}
Пример #7
0
/*
 *  ======== ti_sdo_ipc_Ipc_procSyncFinish ========
 *  Each processor writes its reserve memory address in SharedRegion 0
 *  to let the other processors know its finished the process of
 *  synchronization.
 */
Int ti_sdo_ipc_Ipc_procSyncFinish(UInt16 remoteProcId, Ptr sharedAddr)
{
    volatile ti_sdo_ipc_Ipc_Reserved *self, *remote;
    SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
    Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
    UInt oldPri;

    /* don't do any synchronization if procSync is NONE */
    if (ti_sdo_ipc_Ipc_procSync == ti_sdo_ipc_Ipc_ProcSync_NONE) {
        return (Ipc_S_SUCCESS);
    }

    /* determine self and remote pointers */
    if (MultiProc_self() < remoteProcId) {
        self = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
        remote = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
    }
    else {
        self = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
        remote = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
    }

    /* set my processor's reserved key to finish */
    self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCFINISH;

    /* write back my processor's reserve key */
    if (cacheEnabled) {
        Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);
    }

    /* if slave processor, wait for remote to finish sync */
    if (MultiProc_self() < remoteProcId) {
        if (BIOS_getThreadType() == BIOS_ThreadType_Task) {
            oldPri = Task_getPri(Task_self());
        }

        /* wait for remote processor to finish */
        while (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCFINISH &&
                remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCDETACH) {
            /* Set self priority to 1 [lowest] and yield cpu */
            if (BIOS_getThreadType() == BIOS_ThreadType_Task) {
                Task_setPri(Task_self(), 1);
                Task_yield();
            }

            /* Check the remote's sync flag */
            if (cacheEnabled) {
                Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
            }
        }

        /* Restore self priority */
        if (BIOS_getThreadType() == BIOS_ThreadType_Task) {
            Task_setPri(Task_self(), oldPri);
        }
    }

    return (Ipc_S_SUCCESS);
}
Пример #8
0
/*
 *  ======== ListMP_remove ========
 */
Int ListMP_remove(ListMP_Handle handle, ListMP_Elem *elem)
{
    ti_sdo_ipc_ListMP_Object *obj = (ti_sdo_ipc_ListMP_Object *)handle;
    UInt key;
    ListMP_Elem *localPrevElem;
    ListMP_Elem *localNextElem;
    Bool localPrevElemIsCached, localNextElemIsCached;

    /* Prevent another thread or processor from modifying the ListMP */
    key = GateMP_enter((GateMP_Handle)obj->gate);

    if (ti_sdo_ipc_SharedRegion_translate == FALSE) {
        localPrevElem = (ListMP_Elem *)(elem->prev);
        localNextElem = (ListMP_Elem *)(elem->next);
    }
    else {
        localPrevElem = SharedRegion_getPtr(elem->prev);
        localNextElem = SharedRegion_getPtr(elem->next);
    }
    
    localPrevElemIsCached = SharedRegion_isCacheEnabled(
            SharedRegion_getId(localPrevElem));
    localNextElemIsCached = SharedRegion_isCacheEnabled(
            SharedRegion_getId(localNextElem));

    if (localPrevElemIsCached) {
        Cache_inv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    if (localNextElemIsCached) {
        Cache_inv(localNextElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    localPrevElem->next = elem->next;
    localNextElem->prev = elem->prev;

    if (localPrevElemIsCached) {
        Cache_wbInv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    if (localNextElemIsCached) {
        Cache_wbInv(localNextElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    GateMP_leave((GateMP_Handle)obj->gate, key);
    
    return (ListMP_S_SUCCESS);
}
Пример #9
0
/*
 *  ======== Memory_cacheWbInv ========
 */
Void Memory_cacheWbInv(Ptr addr, Int sizeInBytes)
{
    Log_print2(Diags_ENTRY, "[+E] Memory_cacheWbInv> "
            "Enter(addr=0x%x, sizeInBytes=%d)", (IArg)addr, (IArg)sizeInBytes);

    Cache_wbInv(addr, sizeInBytes, Cache_Type_ALL, TRUE);

    Log_print0(Diags_EXIT, "[+X] Memory_cacheWbInv> return");
}
Пример #10
0
/*
 *  ======== ti_sdo_ipc_ListMP_elemClear ========
 */
Void ti_sdo_ipc_ListMP_elemClear(ti_sdo_ipc_ListMP_Elem *elem)
{
    SharedRegion_SRPtr sharedElem;
    UInt16 id;

    id = SharedRegion_getId(elem);
    sharedElem = SharedRegion_getSRPtr(elem, id);

    elem->next = elem->prev = sharedElem;
    if (SharedRegion_isCacheEnabled(id)) {
        Cache_wbInv(elem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
}
Пример #11
0
/*
 *  ======== GatePetersonN_postInit ========
 *  Function to be called during
 *  1. module startup to complete the initialization of all static instances
 *  2. instance_init to complete the initialization of a dynamic instance
 *
 *  Main purpose is to set up shared memory
 */
Void GatePetersonN_postInit(GatePetersonN_Object *obj)
{
    UInt16 i;

    /* Set up shared memory */
    for (i=0; i < obj->numProcessors; i++) {
        *(obj->enteredStage[i]) = GatePetersonN_NOT_INTERESTED;
    }

    for (i=0; i < obj->numProcessors - 1; i++) {
	*(obj->lastProcEnteringStage[i]) = 0;
    }

    /*
     * Write everything back to shared memory.
     */
    if (obj->cacheEnabled) {
        Cache_wbInv((Ptr)(obj->enteredStage[0]), obj->cacheLineSize *
                obj->numProcessors, Cache_Type_ALL, FALSE);
        Cache_wbInv((Ptr)(obj->lastProcEnteringStage[0]), obj->cacheLineSize *
                obj->numProcessors-1, Cache_Type_ALL, TRUE);
    }
}
Пример #12
0
/*
 *  ======== SemaphoreMP_post ========
 */
Void SemaphoreMP_post(SemaphoreMP_Object *obj)
{
    UInt tskKey;
    SemaphoreMP_PendElem *elem;
    IArg gateMPKey;
    Int status;

    /* Enter the gate */
    gateMPKey = GateMP_enter((GateMP_Handle)obj->gate);

    if (ListMP_empty((ListMP_Handle)obj->pendQ)) {
        if (obj->mode == SemaphoreMP_Mode_BINARY) {
            obj->attrs->count = 1;
        }
        else {
            obj->attrs->count++;
        }
        if (obj->cacheEnabled) {
            Cache_wbInv(obj->attrs, sizeof(SemaphoreMP_Attrs), Cache_Type_ALL,
                    TRUE);
        }
            
        /* Leave the gate */
        GateMP_leave((GateMP_Handle)obj->gate, gateMPKey);
        
        return;
    }

    /* lock task scheduler */
    tskKey = Task_disable();

    /* dequeue tsk from semaphore queue */
    elem = (SemaphoreMP_PendElem *)ListMP_getHead((ListMP_Handle)obj->pendQ);
    
    if (elem->procId != MultiProc_self()) {
        /* Unblock remote task */
        status = Notify_sendEvent(elem->procId, 0, SemaphoreMP_notifyEventId, 
                elem->task, TRUE);
        Assert_isTrue(status >= 0, ti_sdo_ipc_Ipc_A_internal);
    }
    else {
        /* put task back into readyQ */
        Task_unblock((Task_Handle)elem->task);
    }

    /* Leave the gate */
    GateMP_leave((GateMP_Handle)obj->gate, gateMPKey);

    Task_restore(tskKey);
}
Пример #13
0
/*
 *  ======== NotifyDriverShm_setNotifyHandle ========
 */
Void NotifyDriverShm_setNotifyHandle(NotifyDriverShm_Object *obj, 
                                     Ptr notifyHandle)
{
    /* Internally used, so no Assert needed */
    obj->notifyHandle = (ti_sdo_ipc_Notify_Handle)notifyHandle;
    
    /* Indicate that the driver is initialized for this processor */
    obj->selfProcCtrl->recvInitStatus = NotifyDriverShm_INIT_STAMP;
    obj->selfProcCtrl->sendInitStatus = NotifyDriverShm_INIT_STAMP;
    
    /* Write back our own ProcCtrl */
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
            Cache_Type_ALL, TRUE);
    }
}
Пример #14
0
/*
 *  ======== GatePetersonN_leave ========
 */
Void GatePetersonN_leave(GatePetersonN_Object *obj, IArg key)
{
    /* Release the resource and leave system gate. */
    obj->nested--;
    if (obj->nested == 0) {

        *(obj->enteredStage[obj->selfId]) = GatePetersonN_NOT_INTERESTED;

        if (obj->cacheEnabled) {
            Cache_wbInv((Ptr)obj->enteredStage[obj->selfId], obj->cacheLineSize,
                Cache_Type_ALL, TRUE);
        }
    }

    /* Leave local gate */
    IGateProvider_leave(obj->localGate, key);
}
Пример #15
0
/*
 *  ======== SemaphoreMP_Instance_finalize ========
 */
Void SemaphoreMP_Instance_finalize(SemaphoreMP_Object *obj, Int status)
{
    if (obj->objType & (ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC |
                        ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION)) {
        /* SemaphoreMP is being deleted */
        /* Remove entry from NameServer */
        if (obj->nsKey != NULL) {
            NameServer_removeEntry((NameServer_Handle)
                    SemaphoreMP_module->nameServer, obj->nsKey);
        }

        /* Set status to 'not created' */
        obj->attrs->status = 0;
        if (obj->cacheEnabled) {
            Cache_wbInv(obj->attrs, sizeof(SemaphoreMP_Attrs), 
                    Cache_Type_ALL, TRUE);
        }

        /* Delete the pendQ. If NULL, then ListMP_create failed. */
        if (obj->pendQ != NULL) {
            ListMP_delete((ListMP_Handle *)&(obj->pendQ));
        }

        /*
         *  Free the shared memory back to the region SemaphoreMP. If NULL, then
         *  the Memory_alloc failed.
         */
        if (obj->objType == ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION &&
            obj->attrs != NULL) {
            Memory_free(SharedRegion_getHeap(obj->regionId), obj->attrs, 
                    obj->allocSize);
        }
    }
    else {
        /* SemaphoreMP is being closed */
        /* Close the pendQ. If NULL, then ListMP_openByAddr failed. */
        if (obj->pendQ != NULL) {
            ListMP_close((ListMP_Handle *)&(obj->pendQ));
        }
        
        /* Close the gate. If NULL, then GateMP_openByAddr failed. */
        if (obj->gate != NULL) {
            GateMP_close((GateMP_Handle *)&(obj->gate));
        }
    }
}
Пример #16
0
/*
 *  ======== NotifyDriverShm_Instance_finalize ========
 */
Void NotifyDriverShm_Instance_finalize(NotifyDriverShm_Object *obj, int status)
{
    if (status == 0) {
        /* Indicate that driver is no longer ready to send/receive events */
        obj->selfProcCtrl->recvInitStatus = 0;
        obj->selfProcCtrl->sendInitStatus = 0;
        
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
            Cache_Type_ALL, TRUE);
            
        /* Unregister interrupt */
        NotifyDriverShm_InterruptProxy_intUnregister(obj->remoteProcId,
            &(obj->intInfo));

        /* Free memory alloc'ed for regChart */
        Memory_free(NotifyDriverShm_Object_heap(), obj->regChart, 
            sizeof(UInt32) * ti_sdo_ipc_Notify_numEvents);
    }
}
Пример #17
0
static RPC_OMX_ERRORTYPE RPC_SKEL_ShareRegion(UInt32 size, UInt32 *data)
{
    buffer_one  *buffer_args;
	
	Frame_dsp *pFrame = NULL;

    buffer_args = (buffer_one *)((UInt32)data + sizeof(map_info_type) + sizeof(int));

	pFrame = (Frame_dsp*)buffer_args->addr;
	
	Cache_inv(pFrame, buffer_args->size, Cache_Type_ALL, TRUE);

	BRIEF_match(pFrame->kpoint_left, pFrame->n_kpoint_left, pFrame->kpoint_right, pFrame->n_kpoint_right, 
		pFrame->range, pFrame->best_choice, IMG_WIDTH, IMG_HEIGHT);

	Cache_wbInv(pFrame, buffer_args->size, Cache_Type_ALL, TRUE);

    return(0);
}
Пример #18
0
/*
 *  ======== NotifyDriverShm_enableEvent ========
 */
Void NotifyDriverShm_enableEvent(NotifyDriverShm_Object *obj, UInt32 eventId)
{
    UInt sysKey;
    
    Assert_isTrue(eventId < ti_sdo_ipc_Notify_numEvents, 
            ti_sdo_ipc_Ipc_A_invArgument);

    /* 
     * Atomically set the corresponding bit in the processor's 
     * eventEnableMask 
     */
    sysKey = Hwi_disable();
    SET_BIT(obj->selfProcCtrl->eventEnableMask, eventId);
    Hwi_restore(sysKey);
    
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl), 
            Cache_Type_ALL, TRUE);
    }
}
Пример #19
0
/*
 *  ======== TransportShm_put ========
 *  Assuming MessageQ_put is making sure that the arguments are ok
 */
Bool TransportShm_put(TransportShm_Object *obj, Ptr msg)
{
    Int32 status;
    Bool retval = TRUE;
    IArg key;
    UInt16 id = SharedRegion_getId(msg);

    /* This transport only deals with messages allocated from SR's */
    Assert_isTrue(id != SharedRegion_INVALIDREGIONID,
            ti_sdo_ipc_SharedRegion_A_regionInvalid);

    /* writeback invalidate the message */
    if (SharedRegion_isCacheEnabled(id)) {
        Cache_wbInv(msg, ((MessageQ_Msg)(msg))->msgSize, Cache_Type_ALL,
            TRUE);
    }

    /* make sure ListMP_put and sendEvent are done before remote executes */
    key = GateMP_enter((GateMP_Handle)obj->gate);

    /* Put the message on the remoteList */
    ListMP_putTail((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);

    /* Notify the remote processor */
    status = Notify_sendEvent(obj->remoteProcId, 0, TransportShm_notifyEventId,
        0, FALSE);

    /* check the status of the sendEvent */
    if (status < 0) {
        /* remove the message from the List and return 'FALSE' */
        ListMP_remove((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);
        retval = FALSE;
    }

    /* leave the gate */
    GateMP_leave((GateMP_Handle)obj->gate, key);

    return (retval);
}
Пример #20
0
/*
 *  ======== Ipc_attach ========
 */
Int Ipc_attach(UInt16 remoteProcId)
{
    Int i;
    Ptr sharedAddr;
    SizeT memReq;
    volatile ti_sdo_ipc_Ipc_Reserved *slave;
    ti_sdo_ipc_Ipc_ProcEntry *ipc;
    Error_Block eb;
    SharedRegion_Entry entry;
    SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
    Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
    UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
    Int status;
    UInt hwiKey;

    /* Assert remoteProcId is in our cluster and isn't our own */
    Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
                  ti_sdo_utils_MultiProc_A_invalidMultiProcId);
    Assert_isTrue(remoteProcId != MultiProc_self(),
                  ti_sdo_ipc_Ipc_A_invArgument);

    /* Check whether Ipc_start has been called.  If not, fail. */
    if (Ipc_module->ipcSharedAddr == NULL) {
        return (Ipc_E_FAIL);
    }

    /* for checking and incrementing attached below */
    hwiKey = Hwi_disable();

    /* Make sure its not already attached */
    if (Ipc_module->procEntry[clusterId].attached) {
        Ipc_module->procEntry[clusterId].attached++;
        /* restore interrupts and return */
        Hwi_restore(hwiKey);
        return (Ipc_S_ALREADYSETUP);
    }

    /* restore interrupts */
    Hwi_restore(hwiKey);

    /* get region 0 information */
    SharedRegion_getEntry(0, &entry);

    /* Make sure we've attached to owner of SR0 if we're not owner */
    if ((MultiProc_self() != entry.ownerProcId) &&
        (remoteProcId != entry.ownerProcId) &&
        !(Ipc_module->procEntry[ti_sdo_utils_MultiProc_getClusterId(
            entry.ownerProcId)].attached)) {
        return (Ipc_E_FAIL);
    }

    /* Init error block */
    Error_init(&eb);

    /* determine the slave's slot */
    slave = Ipc_getSlaveAddr(remoteProcId, Ipc_module->ipcSharedAddr);

    if (cacheEnabled) {
        Cache_inv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
    }

    /* Synchronize the processors. */
    status = Ipc_procSyncStart(remoteProcId, Ipc_module->ipcSharedAddr);
    if (status < 0) {
        return (status);
    }

    /* must be called before SharedRegion_attach */
    status = ti_sdo_ipc_GateMP_attach(remoteProcId,
            Ipc_module->gateMPSharedAddr);
    if (status < 0) {
        return (status);
    }

    /* retrieves the SharedRegion Heap handles */
    status = ti_sdo_ipc_SharedRegion_attach(remoteProcId);
    if (status < 0) {
        return (status);
    }

    /* get the attach parameters associated with remoteProcId */
    ipc = &(Ipc_module->procEntry[clusterId]);

    /* attach Notify if not yet attached and specified to set internal setup */
    if (!(Notify_intLineRegistered(remoteProcId, 0)) &&
        (ipc->entry.setupNotify)) {
        /* call Notify_attach */
        memReq = Notify_sharedMemReq(remoteProcId, Ipc_module->ipcSharedAddr);
        if (memReq != 0) {
            if (MultiProc_self() < remoteProcId) {
                /*
                 *  calloc required here due to race condition.  Its possible
                 *  that the slave, who creates the instance, tries a sendEvent
                 *  before the master has created its instance because the
                 *  state of memory was enabled from a previous run.
                 */
                sharedAddr = Memory_calloc(SharedRegion_getHeap(0),
                                       memReq,
                                       SharedRegion_getCacheLineSize(0),
                                       &eb);

                /* make sure alloc did not fail */
                if (sharedAddr == NULL) {
                    return (Ipc_E_MEMORY);
                }

                /* if cache enabled, wbInv the calloc above */
                if (cacheEnabled) {
                    Cache_wbInv(sharedAddr, memReq, Cache_Type_ALL, TRUE);
                }

                /* set the notify SRPtr */
                slave->notifySRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
            }
            else {
                /* get the notify SRPtr */
                sharedAddr = SharedRegion_getPtr(slave->notifySRPtr);
            }
        }
        else {
            sharedAddr = NULL;
            slave->notifySRPtr = 0;
        }

        /* call attach to remote processor */
        status = Notify_attach(remoteProcId, sharedAddr);

        if (status < 0) {
            if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
            }

            return (Ipc_E_FAIL);
        }
    }

    /* Must come after GateMP_start because depends on default GateMP */
    if (!(ti_sdo_utils_NameServer_isRegistered(remoteProcId)) &&
        (ipc->entry.setupNotify)) {
        memReq = ti_sdo_utils_NameServer_SetupProxy_sharedMemReq(
            Ipc_module->ipcSharedAddr);
        if (memReq != 0) {
            if (MultiProc_self() < remoteProcId) {
                sharedAddr = Memory_alloc(SharedRegion_getHeap(0),
                                     memReq,
                                     SharedRegion_getCacheLineSize(0),
                                     &eb);

                /* make sure alloc did not fail */
                if (sharedAddr == NULL) {
                    return (Ipc_E_MEMORY);
                }

                /* set the NSRN SRPtr */
                slave->nsrnSRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
            }
            else {
                /* get the NSRN SRPtr */
                sharedAddr = SharedRegion_getPtr(slave->nsrnSRPtr);
            }
        }
        else {
            sharedAddr = NULL;
            slave->nsrnSRPtr = 0;
        }

        /* call attach to remote processor */
        status = ti_sdo_utils_NameServer_SetupProxy_attach(remoteProcId,
                                                           sharedAddr);

        if (status < 0) {
            if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
            }

            return (Ipc_E_FAIL);
        }
    }

    /* Must come after GateMP_start because depends on default GateMP */
    if (!(ti_sdo_ipc_MessageQ_SetupTransportProxy_isRegistered(remoteProcId)) &&
        (ipc->entry.setupMessageQ)) {
        memReq = ti_sdo_ipc_MessageQ_SetupTransportProxy_sharedMemReq(
            Ipc_module->ipcSharedAddr);

        if (memReq != 0) {
            if (MultiProc_self() < remoteProcId) {
                sharedAddr = Memory_alloc(SharedRegion_getHeap(0),
                    memReq, SharedRegion_getCacheLineSize(0), &eb);

                /* make sure alloc did not fail */
                if (sharedAddr == NULL) {
                    return (Ipc_E_MEMORY);
                }

                /* set the transport SRPtr */
                slave->transportSRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
            }
            else {
                /* get the transport SRPtr */
                sharedAddr = SharedRegion_getPtr(slave->transportSRPtr);
            }
        }
        else {
            sharedAddr = NULL;
            slave->transportSRPtr = 0;
        }

        /* call attach to remote processor */
        status = ti_sdo_ipc_MessageQ_SetupTransportProxy_attach(remoteProcId,
            sharedAddr);

        if (status < 0) {
            if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
            }

            return (Ipc_E_FAIL);
        }
    }

    /* writeback invalidate slave's shared memory if cache enabled */
    if (cacheEnabled) {
        if (MultiProc_self() < remoteProcId) {
            Cache_wbInv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
        }
    }

    /* Call user attach fxns */
    for (i = 0; i < ti_sdo_ipc_Ipc_numUserFxns; i++) {
        if (ti_sdo_ipc_Ipc_userFxns[i].userFxn.attach) {
            status = ti_sdo_ipc_Ipc_userFxns[i].userFxn.attach(
                ti_sdo_ipc_Ipc_userFxns[i].arg, remoteProcId);

            if (status < 0) {
                return (status);
            }
        }
    }

    /* Finish the processor synchronization */
    status = ti_sdo_ipc_Ipc_procSyncFinish(remoteProcId,
        Ipc_module->ipcSharedAddr);

    if (status < 0) {
        return (status);
    }

    /* for atomically incrementing attached */
    hwiKey = Hwi_disable();

    /* now attached to remote processor */
    Ipc_module->procEntry[clusterId].attached++;

    /* restore interrupts */
    Hwi_restore(hwiKey);

    return (status);
}
Пример #21
0
/*
 *  ======== ListMP_insert ========
 */
Int ListMP_insert(ListMP_Handle handle, ListMP_Elem *newElem,
                  ListMP_Elem *curElem)
{
    ti_sdo_ipc_ListMP_Object *obj = (ti_sdo_ipc_ListMP_Object *)handle;
    UInt key;
    Int  id;
    ListMP_Elem *localPrevElem;
    SharedRegion_SRPtr sharedNewElem;
    SharedRegion_SRPtr sharedCurElem;
    Bool curElemIsCached, localPrevElemIsCached;

    /* prevent another thread or processor from modifying the ListMP */
    key = GateMP_enter((GateMP_Handle)obj->gate);

    if (ti_sdo_ipc_SharedRegion_translate == FALSE) {
        sharedNewElem = (SharedRegion_SRPtr)newElem;
        sharedCurElem = (SharedRegion_SRPtr)curElem;
        localPrevElem = (ListMP_Elem *)(curElem->prev);
    }
    else {
        /* get SRPtr for newElem */
        id = SharedRegion_getId(newElem);
        sharedNewElem = SharedRegion_getSRPtr(newElem, id);

        /* get SRPtr for curElem */
        id = SharedRegion_getId(curElem);
        sharedCurElem = SharedRegion_getSRPtr(curElem, id);
    }

    curElemIsCached = SharedRegion_isCacheEnabled(SharedRegion_getId(curElem));
    if (curElemIsCached) {
        Cache_inv(curElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    /* get Ptr for curElem->prev */
    localPrevElem = SharedRegion_getPtr(curElem->prev);

    localPrevElemIsCached = SharedRegion_isCacheEnabled(
            SharedRegion_getId(localPrevElem));
    if (localPrevElemIsCached) {
        Cache_inv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    newElem->next       = sharedCurElem;
    newElem->prev       = curElem->prev;
    localPrevElem->next = sharedNewElem;
    curElem->prev       = sharedNewElem;

    if (localPrevElemIsCached) {
        Cache_wbInv(localPrevElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    /* 
     *  The next two Cache_wbInv needs to be done because curElem
     *  and newElem are passed in and maybe already in the cache
     */
    if (curElemIsCached) {
        /* writeback invalidate current elem structure */
        Cache_wbInv(curElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }
    
    if (SharedRegion_isCacheEnabled(SharedRegion_getId(newElem))) {
        /* writeback invalidate new elem structure  */
        Cache_wbInv(newElem, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
    }

    GateMP_leave((GateMP_Handle)obj->gate, key);
    
    return (ListMP_S_SUCCESS);
}
Пример #22
0
/*
 *  ======== Ipc_detach ========
 */
Int Ipc_detach(UInt16 remoteProcId)
{
    Int i;
    UInt16 baseId = MultiProc_getBaseIdOfCluster();
    UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
    Ptr notifySharedAddr;
    Ptr nsrnSharedAddr;
    Ptr msgqSharedAddr;
    volatile ti_sdo_ipc_Ipc_Reserved *slave, *master;
    SharedRegion_Entry entry;
    ti_sdo_ipc_Ipc_ProcEntry *ipc;
    SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
    Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
    Int status = Ipc_S_SUCCESS;
    UInt hwiKey;

    /* Assert remoteProcId is in our cluster and isn't our own */
    Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
                  ti_sdo_utils_MultiProc_A_invalidMultiProcId);
    Assert_isTrue(remoteProcId != MultiProc_self(),
                  ti_sdo_ipc_Ipc_A_invArgument);

    /* for checking and incrementing attached below */
    hwiKey = Hwi_disable();

    if (Ipc_module->procEntry[clusterId].attached > 1) {
        /* only detach if attach count reaches 1 */
        Ipc_module->procEntry[clusterId].attached--;
        Hwi_restore(hwiKey);
        return (Ipc_S_BUSY);
    }
    else if (Ipc_module->procEntry[clusterId].attached == 0) {
        /* already detached, restore interrupts and return success */
        Hwi_restore(hwiKey);
        return (Ipc_S_SUCCESS);
    }

    /* restore interrupts */
    Hwi_restore(hwiKey);

    /* get region 0 information */
    SharedRegion_getEntry(0, &entry);

    /*
     *  Make sure we detach from all other procs in cluster before
     *  detaching from owner of SR 0.
     */
    if (remoteProcId == entry.ownerProcId) {
        for (i = 0; i < ti_sdo_utils_MultiProc_numProcsInCluster; i++, baseId++) {
            if ((baseId != MultiProc_self()) && (baseId != entry.ownerProcId) &&
                (Ipc_module->procEntry[i].attached)) {
                return (Ipc_E_FAIL);
            }
        }
    }

    /* get the paramters associated with remoteProcId */
    ipc = &(Ipc_module->procEntry[clusterId]);

    /* determine the slave's slot */
    slave = Ipc_getSlaveAddr(remoteProcId, Ipc_module->ipcSharedAddr);

    /* determine the master's slot */
    master = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId,
        Ipc_module->ipcSharedAddr);

    if (cacheEnabled) {
        Cache_inv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
        Cache_inv((Ptr)master, reservedSize, Cache_Type_ALL, TRUE);
    }

    if (MultiProc_self() < remoteProcId) {
        /* check to make sure master is not trying to attach */
        if (master->startedKey == ti_sdo_ipc_Ipc_PROCSYNCSTART) {
            return (Ipc_E_NOTREADY);
        }
    }
    else {
        /* check to make sure slave is not trying to attach */
        if (slave->startedKey == ti_sdo_ipc_Ipc_PROCSYNCSTART) {
            return (Ipc_E_NOTREADY);
        }
    }

    /* The slave processor waits for master to finish its detach sequence */
    if (MultiProc_self() < remoteProcId) {
        if (master->startedKey != ti_sdo_ipc_Ipc_PROCSYNCDETACH) {
            return (Ipc_E_NOTREADY);
        }
    }

    /* Call user detach fxns */
    for (i = 0; i < ti_sdo_ipc_Ipc_numUserFxns; i++) {
        if (ti_sdo_ipc_Ipc_userFxns[i].userFxn.detach) {
            status = ti_sdo_ipc_Ipc_userFxns[i].userFxn.detach(
                ti_sdo_ipc_Ipc_userFxns[i].arg, remoteProcId);

            if (status < 0) {
                return (status);
            }
        }
    }

    if ((ipc->entry.setupMessageQ) &&
       (ti_sdo_ipc_MessageQ_SetupTransportProxy_isRegistered(remoteProcId))) {
        /* call MessageQ_detach for remote processor */
        status = ti_sdo_ipc_MessageQ_SetupTransportProxy_detach(remoteProcId);
        if (status < 0) {
            return (Ipc_E_FAIL);
        }

        if (slave->transportSRPtr) {
            /* free the memory if slave processor */
            if (MultiProc_self() < remoteProcId) {
                /* get the pointer to MessageQ transport instance */
                msgqSharedAddr = SharedRegion_getPtr(slave->transportSRPtr);

                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0),
                    msgqSharedAddr,
                    ti_sdo_ipc_MessageQ_SetupTransportProxy_sharedMemReq(
                        msgqSharedAddr));

                /* set pointer for MessageQ transport instance back to NULL */
                slave->transportSRPtr = NULL;
            }
        }
    }

    if ((ipc->entry.setupNotify) &&
        (ti_sdo_utils_NameServer_isRegistered(remoteProcId))) {
        /* call NameServer_SetupProxy_detach for remote processor */
        status = ti_sdo_utils_NameServer_SetupProxy_detach(remoteProcId);
        if (status < 0) {
            return (Ipc_E_FAIL);
        }

        if (slave->nsrnSRPtr) {
            /* free the memory if slave processor */
            if (MultiProc_self() < remoteProcId) {
                /* get the pointer to NSRN instance */
                nsrnSharedAddr = SharedRegion_getPtr(slave->nsrnSRPtr);

                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0),
                            nsrnSharedAddr,
                            ti_sdo_utils_NameServer_SetupProxy_sharedMemReq(
                                nsrnSharedAddr));

                /* set pointer for NSRN instance back to NULL */
                slave->nsrnSRPtr = NULL;
            }
        }
    }

    if ((ipc->entry.setupNotify) &&
        (Notify_intLineRegistered(remoteProcId, 0))) {
        /* call Notify_detach for remote processor */
        status = ti_sdo_ipc_Notify_detach(remoteProcId);
        if (status < 0) {
            return (Ipc_E_FAIL);
        }

        if (slave->notifySRPtr) {
            /* free the memory if slave processor */
            if (MultiProc_self() < remoteProcId) {
                /* get the pointer to Notify instance */
                notifySharedAddr = SharedRegion_getPtr(slave->notifySRPtr);

                /* free the memory back to SharedRegion 0 heap */
                Memory_free(SharedRegion_getHeap(0),
                            notifySharedAddr,
                            Notify_sharedMemReq(remoteProcId, notifySharedAddr));

                /* set pointer for Notify instance back to NULL */
                slave->notifySRPtr = NULL;
            }
        }
    }

    /* close any HeapMemMP which may have been opened */
    status = ti_sdo_ipc_SharedRegion_detach(remoteProcId);
    if (status < 0) {
        return (status);
    }
    
    /* close any GateMP which may have been opened */
    status = ti_sdo_ipc_GateMP_detach(remoteProcId);
    if (status < 0) {
        return (status);
    }

    if (MultiProc_self() < remoteProcId) {
        slave->configListHead = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
        slave->startedKey = ti_sdo_ipc_Ipc_PROCSYNCDETACH;
        if (cacheEnabled) {
            Cache_wbInv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
        }
    }
    else {
        master->configListHead = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
        master->startedKey = ti_sdo_ipc_Ipc_PROCSYNCDETACH;
        if (cacheEnabled) {
            Cache_wbInv((Ptr)master, reservedSize, Cache_Type_ALL, TRUE);
        }
    }

    /* attached must be decremented atomically */
    hwiKey = Hwi_disable();

    /* now detached from remote processor */
    Ipc_module->procEntry[clusterId].attached--;

    /* restore interrupts */
    Hwi_restore(hwiKey);

    return (status);
}
Пример #23
0
/*
 *  ======== NotifyDriverShm_sendEvent ========
 */
Int NotifyDriverShm_sendEvent(NotifyDriverShm_Object *obj,
                              UInt32                 eventId,
                              UInt32                 payload,
                              Bool                   waitClear)
{
    NotifyDriverShm_EventEntry *eventEntry;
    UInt32 i;
    UInt sysKey;
    
    eventEntry = EVENTENTRY(obj->otherEventChart, obj->eventEntrySize, eventId);

    /* Check whether driver on other processor is initialized */
    if (obj->cacheEnabled) {
        Cache_inv(obj->otherProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
                  Cache_Type_ALL, TRUE);
    }

    if (obj->otherProcCtrl->recvInitStatus != NotifyDriverShm_INIT_STAMP) {
        /*
         * This may be used for polling till the other driver is ready, so
         * do not assert or error
         */
        return (Notify_E_NOTINITIALIZED);
    }

    /* Check to see if the remote event is enabled */
    if (!TEST_BIT(obj->otherProcCtrl->eventEnableMask, eventId)) {
        return (Notify_E_EVTDISABLED);
    }

    /* Check to see if the remote event is registered */
    if (!TEST_BIT(obj->otherProcCtrl->eventRegMask, eventId)) {
        return (Notify_E_EVTNOTREGISTERED);
    }

    
    if (waitClear) {
        i = 0;

        if (obj->cacheEnabled) {
            Cache_inv(eventEntry, sizeof(NotifyDriverShm_EventEntry),
                Cache_Type_ALL, TRUE);
        }

        /* 
         *  The system gate is needed to ensure that checking eventEntry->flag 
         *  is atomic with the eventEntry modifications (flag/payload).
         */
        sysKey = Hwi_disable();

        /* Wait for completion of previous event from other side. */
        while ((eventEntry->flag != NotifyDriverShm_DOWN)) {
            /* 
             * Leave critical section protection. Create a window
             * of opportunity for other interrupts to be handled.
             */
            Hwi_restore(sysKey);
            i++;
            if ((i != (UInt32)-1) &&  
                (i == ti_sdo_ipc_Notify_sendEventPollCount)) {
                return (Notify_E_TIMEOUT);
            }
            
            if (obj->cacheEnabled) {
                Cache_inv(eventEntry, sizeof(NotifyDriverShm_EventEntry),
                    Cache_Type_ALL, TRUE);
            }
            
            /* Re-enter the system gate */
            sysKey = Hwi_disable();
        }
    }
    else {
        /* 
         *  The system gate is needed to ensure that checking eventEntry->flag 
         *  is atomic with the eventEntry modifications (flag/payload).
         */
        sysKey = Hwi_disable();
    }
    
    /* Set the event bit field and payload.*/
    eventEntry->payload = payload;
    eventEntry->flag    = NotifyDriverShm_UP;
    if (obj->cacheEnabled) {
        Cache_wbInv(eventEntry, sizeof(NotifyDriverShm_EventEntry),
            Cache_Type_ALL, TRUE);
    }

    /* Send an interrupt to the Remote Processor */
    NotifyDriverShm_InterruptProxy_intSend(obj->remoteProcId, &(obj->intInfo),
                                           eventId);
                                           
    /* must not restore interrupts before sending the interrupt */
    Hwi_restore(sysKey);   
    
    return (Notify_S_SUCCESS);
}
Пример #24
0
/*
 *  ======== ti_sdo_ipc_Ipc_procSyncStart ========
 *  The owner of SharedRegion 0 writes to its reserve memory address
 *  in region 0 to let the other processors know it has started.
 *  It then spins until the other processors start.
 *  The other processors write their reserve memory address in
 *  region 0 to let the owner processor know they've started.
 *  The other processors then spin until the owner processor writes
 *  to let them know that its finished the process of synchronization
 *  before continuing.
 */
Int ti_sdo_ipc_Ipc_procSyncStart(UInt16 remoteProcId, Ptr sharedAddr)
{
    volatile ti_sdo_ipc_Ipc_Reserved *self, *remote;
    ti_sdo_ipc_Ipc_ProcEntry *ipc;
    UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
    SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
    Bool cacheEnabled = SharedRegion_isCacheEnabled(0);

    /* don't do any synchronization if procSync is NONE */
    if (ti_sdo_ipc_Ipc_procSync == ti_sdo_ipc_Ipc_ProcSync_NONE) {
        return (Ipc_S_SUCCESS);
    }

    /* determine self and remote pointers */
    if (MultiProc_self() < remoteProcId) {
        self = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
        remote = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
    }
    else {
        self = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
        remote = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
    }

    /* construct the config list */
    ipc = &(Ipc_module->procEntry[clusterId]);

    ipc->localConfigList = (Ptr)&self->configListHead;
    ipc->remoteConfigList = (Ptr)&remote->configListHead;

    *ipc->localConfigList = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;

    if (cacheEnabled) {
        Cache_wbInv(ipc->localConfigList, reservedSize, Cache_Type_ALL, TRUE);
    }

    if (MultiProc_self() < remoteProcId) {
        /* set my processor's reserved key to start */
        self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCSTART;

        /* write back my processor's reserve key */
        if (cacheEnabled) {
            Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);
        }

        /* wait for remote processor to start */
        if (cacheEnabled) {
            Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
        }

        if (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART) {
            return (Ipc_E_NOTREADY);
        }
    }
    else {
        /*  wait for remote processor to start */
        if (cacheEnabled) {
            Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
        }

        if ((self->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART) &&
            (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART)) {
            return (Ipc_E_NOTREADY);
        }

        /* set my processor's reserved key to start */
        self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCSTART;

        /* write my processor's reserve key back */
        if (cacheEnabled) {
            Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);

            /* wait for remote processor to finish */
            Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
        }

        if (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCFINISH) {
            return (Ipc_E_NOTREADY);
        }
    }

    return (Ipc_S_SUCCESS);
}
Пример #25
0
/*
 *  ======== NotifyDriverShm_disableEvent ========
 */
Void NotifyDriverShm_disableEvent(NotifyDriverShm_Object *obj, UInt32 eventId)
{
    UInt sysKey;
    NotifyDriverShm_EventEntry *eventEntry;
    
    Assert_isTrue(eventId < ti_sdo_ipc_Notify_numEvents, 
            ti_sdo_ipc_Ipc_A_invArgument);

    /* 
     *  Atomically unset the corresponding bit in the processor's 
     *  eventEnableMask 
     */
    sysKey = Hwi_disable();
    CLEAR_BIT(obj->selfProcCtrl->eventEnableMask, eventId);
    Hwi_restore(sysKey);
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl), 
            Cache_Type_ALL, TRUE);
    }

    eventEntry = EVENTENTRY(obj->selfEventChart, obj->eventEntrySize, 
            eventId);
    if (obj->cacheEnabled) {
        Cache_inv(eventEntry,
                  sizeof(NotifyDriverShm_EventEntry),
                  Cache_Type_ALL, TRUE);
    }
    
    /* 
     *  Disable incoming Notify interrupts.  This is done to ensure that the
     *  eventEntry->flag is read atomically with any write back to shared
     *  memory
     */
    NotifyDriverShm_disable(obj);

    /* 
     *  Is the local NotifyDriverShm_disableEvent happening between the 
     *  following two NotifyDriverShm_sendEvent operations on the remote 
     *  processor?
     *  1. Writing NotifyDriverShm_UP to shared memory
     *  2. Sending the interrupt across
     *  If so, we should handle this event so the other core isn't left spinning
     *  until the event is re-enabled and the next NotifyDriverShm_isr executes
     *  This race condition is very rare but we need to account for it:
     */
    if (eventEntry->flag == NotifyDriverShm_UP) {
        /* 
         *  Acknowledge the event. No need to store the payload. The other side 
         *  will not send this event again even though flag is down, because the
         *  event is now disabled. So the payload within the eventChart will not
         *  get overwritten. 
         */
        eventEntry->flag = NotifyDriverShm_DOWN;
        
        /* Write back acknowledgement */
        if (obj->cacheEnabled) {
            Cache_wbInv(eventEntry, sizeof(NotifyDriverShm_EventEntry),
                Cache_Type_ALL, TRUE);
        }
        
        /* 
         *  Execute the callback function. This will execute in a Task
         *  or Swi context (not Hwi!)
         */
        ti_sdo_ipc_Notify_exec(obj->notifyHandle, eventId, eventEntry->payload);
    }

    /* Re-enable incoming Notify interrupts */
    NotifyDriverShm_enable(obj);
}
Пример #26
0
/*
 *  ======== NotifyDriverShm_isr ========
 */
Void NotifyDriverShm_isr(UArg arg)
{
    UInt                            i;
    NotifyDriverShm_EventEntry      *eventEntry;
    NotifyDriverShm_Object          *obj;
    UInt32                          eventId;
    UInt32                          payload;

    obj = (NotifyDriverShm_Object *)arg;

    /* Make sure the NotifyDriverShm_Object is not NULL */
    Assert_isTrue(obj != NULL, ti_sdo_ipc_Ipc_A_internal);
    
    /* Clear the remote interrupt */
    NotifyDriverShm_InterruptProxy_intClear(obj->remoteProcId, 
                                            &(obj->intInfo));
    
    /*
     * Iterate till no asserted event is found for one complete loop
     * through all registered events.
     */
    i = 0;
    do {
        eventId = obj->regChart[i];

        /* Check if the entry is a valid registered event. */
        if (eventId != (UInt32)-1) {
            /*
             *  Check whether the event is disabled. If so, avoid the 
             *  unnecessary Cache invalidate. NOTE: selfProcCtrl does not have
             *  to be cache-invalidated because:
             *  1) Whenever self is written to by the local processor its memory
             *     is also invalidated
             *  2) 'selfProcCtrl' is never written to by the remote processor
             */
            if (!TEST_BIT(obj->selfProcCtrl->eventEnableMask, 
                (UInt32)eventId)) {
                i++;
                continue; 
            }
            
            eventEntry = EVENTENTRY(obj->selfEventChart, obj->eventEntrySize, 
                eventId);
            
            if (obj->cacheEnabled) {
                Cache_inv(eventEntry,
                          sizeof(NotifyDriverShm_EventEntry),
                          Cache_Type_ALL, TRUE);
            }

            /* Check if the event is set */
            if (eventEntry->flag == NotifyDriverShm_UP) {
                /* 
                 *  Save the payload since it may be overwritten before 
                 *  Notify_exec is called 
                 */
                payload = eventEntry->payload;
                
                /* Acknowledge the event. */
                eventEntry->flag = NotifyDriverShm_DOWN;
                
                /* Write back acknowledgement */
                if (obj->cacheEnabled) {
                    Cache_wbInv(eventEntry, sizeof(NotifyDriverShm_EventEntry),
                        Cache_Type_ALL, TRUE);
                }

                /* Execute the callback function */
                ti_sdo_ipc_Notify_exec(obj->notifyHandle, eventId, payload);

                /* reinitialize the event check counter. */
                i = 0;
            }
            else {
                /* check for next event. */
                i++;
            }
        }
    }
    while ((eventId != (UInt32)-1) && (i < ti_sdo_ipc_Notify_numEvents));
}
Пример #27
0
/*
 *  ======== NotifyDriverShm_Instance_init ========
 */
Int NotifyDriverShm_Instance_init(NotifyDriverShm_Object *obj,
                                  const NotifyDriverShm_Params *params,
                                  Error_Block *eb)
{
    UInt16 regionId;
    SizeT regionCacheSize, minAlign, procCtrlSize;
    
   /*
    * Check whether remote proc ID has been set and isn't the same as the
    * local proc ID
    */
    Assert_isTrue ((params->remoteProcId != MultiProc_INVALIDID) &&
                   (params->remoteProcId != MultiProc_self()),
                   ti_sdo_ipc_Ipc_A_invParam);
                   
    /* 
     *  Determine obj->cacheEnabled using params->cacheEnabled and SharedRegion
     *  cache flag setting, if applicable.
     */
    obj->cacheEnabled = params->cacheEnabled;
    minAlign = params->cacheLineSize;
    if (minAlign == 0) {
        /* Fix alignment of zero */
        minAlign = sizeof(Ptr);
    }
    regionId = SharedRegion_getId(params->sharedAddr);
    if (regionId != SharedRegion_INVALIDREGIONID) {
        /* 
         *  Override the user cacheEnabled setting if the region 
         *  cacheEnabled is FALSE.
         */
        if (!SharedRegion_isCacheEnabled(regionId)) {
            obj->cacheEnabled = FALSE;
        }
        
        regionCacheSize = SharedRegion_getCacheLineSize(regionId);
        
        /* 
         *  Override the user cache line size setting if the region 
         *  cache line size is smaller.
         */
        if (regionCacheSize < minAlign) {
            minAlign = regionCacheSize;
        }
    }
    
    /* Check if shared memory base addr is aligned to cache line boundary.*/
    Assert_isTrue ((UInt32)params->sharedAddr % minAlign == 0, 
        ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
    
    obj->remoteProcId           = params->remoteProcId;

    /* 
     *  Store all interrupt information so it may be used (if neccessary) by
     *  the IInterrupt delegates
     */
    obj->intInfo.remoteIntId    = params->remoteIntId;
    obj->intInfo.localIntId     = params->localIntId;
    obj->intInfo.intVectorId    = params->intVectorId;

    obj->nesting            = 0;

    if (params->remoteProcId > MultiProc_self()) {
        obj->selfId  = 0;
        obj->otherId = 1;
    }
    else {
        obj->selfId  = 1;
        obj->otherId = 0;
    }
    
    /* Initialize pointers to shared memory regions */
    procCtrlSize = _Ipc_roundup(sizeof(NotifyDriverShm_ProcCtrl), minAlign);

    /* 
     *  Save the eventEntrySize in obj since we will need it at runtime to 
     *  index the event charts
     */
    obj->eventEntrySize = _Ipc_roundup(sizeof(NotifyDriverShm_EventEntry), 
        minAlign);
    
    obj->selfProcCtrl = (NotifyDriverShm_ProcCtrl *)
        ((UInt32)params->sharedAddr + (obj->selfId * procCtrlSize));
    obj->otherProcCtrl = (NotifyDriverShm_ProcCtrl *)
        ((UInt32)params->sharedAddr + (obj->otherId * procCtrlSize));
    obj->selfEventChart  = (NotifyDriverShm_EventEntry *)
        ((UInt32)params->sharedAddr
         + (2 * procCtrlSize)
         + (obj->eventEntrySize * ti_sdo_ipc_Notify_numEvents * obj->selfId));
    obj->otherEventChart  = (NotifyDriverShm_EventEntry *)
         ((UInt32)params->sharedAddr
         + (2 * procCtrlSize)
         + (obj->eventEntrySize * ti_sdo_ipc_Notify_numEvents * obj->otherId));

    /* Allocate memory for regChart and init to (UInt32)-1 (unregistered) */
    obj->regChart = Memory_valloc(
            NotifyDriverShm_Object_heap(),
            (sizeof(UInt32) * ti_sdo_ipc_Notify_numEvents),
            NULL,
            ~0,
            eb);
    if (obj->regChart == NULL) { 
        return (1);
    }

    /* Enable all events initially.*/
    obj->selfProcCtrl->eventEnableMask = 0xFFFFFFFF;
    
    /* Write back our own ProcCtrl */
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->selfProcCtrl, sizeof(NotifyDriverShm_ProcCtrl),
            Cache_Type_ALL, TRUE);
    }

    /* Register the incoming interrupt */
    NotifyDriverShm_InterruptProxy_intRegister(obj->remoteProcId, 
        &(obj->intInfo), (Fxn)NotifyDriverShm_isr, (UArg)obj);

    return (0);
}
Пример #28
0
/*
 *  ======== GatePetersonN_enter ========
 */
IArg GatePetersonN_enter(GatePetersonN_Object *obj)
{
    IArg key;
    SizeT   numProcessors;
    SizeT   myProcId;
    Int32   curStage;
    SizeT   proc;

    /* Enter local gate */
    key = IGateProvider_enter(obj->localGate);

    /* If the gate object has already been entered, return the key */
    obj->nested++;
    if (obj->nested > 1) {
        return (key);
    }
    numProcessors = obj->numProcessors;
    myProcId      = obj->selfId;

    for (curStage=0; curStage < (numProcessors - 1); curStage++) {

        *(obj->enteredStage[myProcId]) = curStage;
        *(obj->lastProcEnteringStage[curStage]) = myProcId;

	if (obj->cacheEnabled) {

            Cache_wbInv((Ptr)obj->enteredStage[myProcId], obj->cacheLineSize,
                    Cache_Type_ALL, FALSE);
            Cache_wbInv((Ptr)obj->lastProcEnteringStage[curStage],
                    obj->cacheLineSize, Cache_Type_ALL, TRUE);
        }

        for (proc=0; proc < numProcessors; proc++) {

            if (proc != myProcId) {

	        if (obj->cacheEnabled) {

                    Cache_inv((Ptr)obj->enteredStage[proc],
                            obj->cacheLineSize, Cache_Type_ALL, FALSE);
                    Cache_inv((Ptr)obj->lastProcEnteringStage[curStage],
                            obj->cacheLineSize, Cache_Type_ALL, TRUE);
		}

                while ((*(obj->enteredStage[proc]) >= curStage) &&
                       (*(obj->lastProcEnteringStage[curStage]) == myProcId)) {

                    /* wait till 'proc' leaves or another 'proc' enters stage */
	            if (obj->cacheEnabled) {

                        Cache_inv((Ptr)obj->enteredStage[proc],
                                obj->cacheLineSize, Cache_Type_ALL, FALSE);
                        Cache_inv((Ptr)obj->lastProcEnteringStage[curStage],
                                obj->cacheLineSize, Cache_Type_ALL, TRUE);
                    }
                }
            }
        }

    } /* stages */

    return (key);
}
Пример #29
0
/*
 *  ======== ListMP_getTail ========
 */
Ptr ListMP_getTail(ListMP_Handle handle)
{
    ti_sdo_ipc_ListMP_Object *obj = (ti_sdo_ipc_ListMP_Object *)handle;
    ListMP_Elem *elem;
    ListMP_Elem *localHeadPrev;
    ListMP_Elem *localPrev;
    Bool localPrevIsCached;
    UInt key;

    /* prevent another thread or processor from modifying the ListMP */
    key = GateMP_enter((GateMP_Handle)obj->gate);

    if (ti_sdo_ipc_SharedRegion_translate == FALSE) {
        localHeadPrev = (ListMP_Elem *)obj->attrs->head.prev;
    }
    else {
        localHeadPrev = SharedRegion_getPtr(obj->attrs->head.prev);
    }

    /* Assert that pointer is not NULL */
    Assert_isTrue(localHeadPrev != NULL, ti_sdo_ipc_Ipc_A_nullPointer);

    /* See if the ListMP was empty */
    if (localHeadPrev == (ListMP_Elem *)(&(obj->attrs->head))) {
        /* Empty, return NULL */
        elem = NULL;
    }
    else {
        if (SharedRegion_isCacheEnabled(SharedRegion_getId(localHeadPrev))) {
            /* invalidate elem */
            Cache_inv(localHeadPrev, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
        }

        if (ti_sdo_ipc_SharedRegion_translate == FALSE) {
            localPrev = (ListMP_Elem *)localHeadPrev->prev;
        }
        else {
            localPrev = SharedRegion_getPtr(localHeadPrev->prev);
        }

        /* Assert that pointer is not NULL */
        Assert_isTrue(localPrev != NULL, ti_sdo_ipc_Ipc_A_nullPointer);

        /* Elem to return */
        elem = localHeadPrev;
        localPrevIsCached = SharedRegion_isCacheEnabled(
                SharedRegion_getId(localPrev));
        if (localPrevIsCached) {
            Cache_inv(localPrev, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
        }
        
        /* Fix the head of the list prev pointer */
        obj->attrs->head.prev = elem->prev;

        /* Fix the next pointer of the new last elem on the list */
        localPrev->next = localHeadPrev->next;
        if (localPrevIsCached) {
            Cache_wbInv(localPrev, sizeof(ListMP_Elem), Cache_Type_ALL, TRUE);
        }
    }

    if (obj->cacheEnabled) {
        Cache_wbInv(&(obj->attrs->head), sizeof(ListMP_Elem),
                    Cache_Type_ALL, TRUE);
    }

    GateMP_leave((GateMP_Handle)obj->gate, key);

    return (elem);
}
Пример #30
0
/*
 *  ======== ti_sdo_ipc_ListMP_Instance_init ========
 */
Int ti_sdo_ipc_ListMP_Instance_init(ti_sdo_ipc_ListMP_Object *obj,
        const ti_sdo_ipc_ListMP_Params *params,
        Error_Block *eb)
{
    SharedRegion_SRPtr sharedShmBase;
    Ptr localAddr;
    Int status;
    ListMP_Params sparams;
    IHeap_Handle regionHeap;

    if (params->openFlag == TRUE) {
        /* Open by sharedAddr */
        obj->objType = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
        obj->attrs = (ti_sdo_ipc_ListMP_Attrs *)params->sharedAddr;
        obj->regionId = SharedRegion_getId(&(obj->attrs->head));
        obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
        obj->cacheLineSize = SharedRegion_getCacheLineSize(obj->regionId);
    
        /* get the local address of the SRPtr */
        localAddr = SharedRegion_getPtr(obj->attrs->gateMPAddr);
        
        status = GateMP_openByAddr(localAddr, (GateMP_Handle *)&(obj->gate));
        if (status != GateMP_S_SUCCESS) {
            Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
            return (1);
        }
        
        return (0);
    }

    /* init the gate */
    if (params->gate != NULL) {
        obj->gate = params->gate;
    }
    else {
        obj->gate = (ti_sdo_ipc_GateMP_Handle)GateMP_getDefaultRemote();
    }
    
    if (params->sharedAddr == NULL) {
        /* Creating using a shared region ID */                
        obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION;
        obj->regionId = params->regionId;
        obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
        obj->cacheLineSize = SharedRegion_getCacheLineSize(obj->regionId);
                
        /* Need to allocate from the heap */
        ListMP_Params_init(&sparams);
        sparams.regionId = params->regionId;
        obj->allocSize = ListMP_sharedMemReq(&sparams);
            
        regionHeap = SharedRegion_getHeap(obj->regionId);
        Assert_isTrue(regionHeap != NULL, ti_sdo_ipc_SharedRegion_A_noHeap);

        /* The region heap will take care of the alignment */
        obj->attrs = Memory_alloc(regionHeap, obj->allocSize, 0, eb);

        if (obj->attrs == NULL) {
            return (2);
        }
    }
    else {
        /* Creating using sharedAddr */
        obj->regionId = SharedRegion_getId(params->sharedAddr);
            
        /* Assert that the buffer is in a valid shared region */
        Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID, 
                      ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
                        
        /* set object's cacheEnabled, objType, and attrs  */
        obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
        obj->cacheLineSize = SharedRegion_getCacheLineSize(obj->regionId);
        obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
        obj->attrs = (ti_sdo_ipc_ListMP_Attrs *)params->sharedAddr;

        /* Assert that sharedAddr is cache aligned */
        Assert_isTrue((obj->cacheLineSize == 0) ||
                      ((UInt32)params->sharedAddr % obj->cacheLineSize == 0),
                      ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
    }

    /* init the head (to be empty) */
    ListMP_elemClear(&(obj->attrs->head));
       
    /* store the GateMP sharedAddr in the Attrs */
    obj->attrs->gateMPAddr = ti_sdo_ipc_GateMP_getSharedAddr(obj->gate);

    /* last thing, set the status */
    obj->attrs->status = ti_sdo_ipc_ListMP_CREATED;
        
    if (obj->cacheEnabled) {
        Cache_wbInv(obj->attrs, sizeof(ti_sdo_ipc_ListMP_Attrs), 
                Cache_Type_ALL, TRUE);
    }
        
    /* add to NameServer if name not NULL */
    if (params->name != NULL) {
        sharedShmBase = SharedRegion_getSRPtr(obj->attrs, obj->regionId);
        obj->nsKey = NameServer_addUInt32(
            (NameServer_Handle)ListMP_module->nameServer, params->name,
            (UInt32)sharedShmBase);
        
        if (obj->nsKey == NULL) {
            Error_raise(eb, ti_sdo_ipc_Ipc_E_nameFailed, params->name, 0);
            return (3);
        }
    }

    return (0);
}