diff options
Diffstat (limited to 'drivers/staging/nmf-cm/cm/engine/component/src')
8 files changed, 4851 insertions, 0 deletions
diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/binder.c b/drivers/staging/nmf-cm/cm/engine/component/src/binder.c new file mode 100644 index 00000000000..5f08713833b --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/binder.c @@ -0,0 +1,1313 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include "../inc/bind.h" +#include "../inc/dspevent.h" +#include <cm/engine/communication/fifo/inc/nmf_fifo_arm.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/component/inc/introspection.h> + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/trace/inc/xtitrace.h> + +#include <cm/engine/utils/inc/string.h> + +#define CM_IT_NAME_MAX_LENGTH 8 + +t_nmf_table Host2MpcBindingTable; /**< list (table) of host2mpc bindings */ + +static void cm_fillItName(int interruptLine, char *itName); +static t_uint16 getNumberOfBind(t_component_instance* component); + +/* + * Bind virtual interface, here we assume that: + * - client component require this interface as last one and without collection, + * - server component provide only this interface and without collection. + * Fixed in loader.c. + */ +static void cm_bindVirtualInterface( + t_component_instance* client, + const t_component_instance* server) { + t_interface_require_description itfRequire; + + if(cm_getRequiredInterface(client, "coms", &itfRequire) == CM_OK) + { + t_interface_reference* itfRef = client->interfaceReferences[itfRequire.requireIndex]; + + /* + * Memorise this reference + */ + itfRef->provideIndex = 0; + itfRef->collectionIndex = 0; + itfRef->instance = server; + itfRef->bfInfoID = (t_bf_info_ID)0; + itfRef->bfInfo = (void*)-1; // TODO + } + else + { + ERROR("Internal Error in cm_bindVirtualInterface\n", 0, 0, 0, 0, 0, 0); + } +} + +static void cm_unbindVirtualInterface( + t_component_instance* client) { + t_interface_require_description itfRequire; + + if(cm_getRequiredInterface(client, "coms", &itfRequire) == CM_OK) + { + t_interface_reference* itfRef = client->interfaceReferences[itfRequire.requireIndex]; + itfRef->instance = NULL; + } + else + { + ERROR("Internal Error in cm_unbindVirtualInterface\n", 0, 0, 0, 0, 0, 0); + } +} + +/* + * Bind component + */ +static void cm_bindLowLevelInterface( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfLocalBC, /* On the same DSP */ + t_bf_info_ID bfInfoID, void* bfInfo) +{ + const t_component_instance* client = itfRequire->client; + t_component_instance* server = (t_component_instance*)itfLocalBC->server; + t_interface_require *require = &client->Template->requires[itfRequire->requireIndex]; + t_interface_provide* provide = &server->Template->provides[itfLocalBC->provideIndex]; + t_interface_provide_loaded* provideLoaded = &server->Template->providesLoaded[itfLocalBC->provideIndex]; + int k, j; + + if(require->indexes != NULL) + { + t_interface_require_index *requireindex = &require->indexes[itfRequire->collectionIndex]; + + for(k = 0; k < requireindex->numberOfClient; k++) { + t_uint32 *hostAddr; + + hostAddr = (t_uint32*)( + cm_DSP_GetHostLogicalAddress(client->memories[requireindex->memories[k].memory->id]) + + requireindex->memories[k].offset * requireindex->memories[k].memory->memEntSize); + + LOG_INTERNAL(2, "Fill ItfRef %s.%s mem=%s Off=%x @=%x\n", + client->pathname, require->name, + requireindex->memories[k].memory->memoryName, + requireindex->memories[k].offset, + hostAddr, 0); + + /* + * Fill the interface references. We start by This then methods in order to keep + * Unbinded panic as long as possible and not used method with wrong This. This is + * relevent only for optional since we must go in stop state before rebinding other + * required interface. + * + * Direct write to DSP memory without go through DSP abstraction since we know we are in 24bits + */ + // Write THIS reference into the Data field of the interface reference + // Write the interface methods reference + + if(((t_uint32)hostAddr & 0x7) == 0 && require->interface->methodNumber > 0) + { + // We are 64word byte aligned, combine this write with first method + *(volatile t_uint64*)hostAddr = + ((t_uint64)server->thisAddress << 0) | + ((t_uint64)provideLoaded->indexesLoaded[itfLocalBC->collectionIndex][0].methodAddresses << 32); + hostAddr += 2; + j = 1; + } + else + { + // We are not, write this which will align us + *hostAddr++ = (t_uint32)server->thisAddress; + j = 0; + } + + // Word align copy + for(; j < require->interface->methodNumber - 1; j+=2) { + *(volatile t_uint64*)hostAddr = + ((t_uint64)provideLoaded->indexesLoaded[itfLocalBC->collectionIndex][j].methodAddresses << 0) | + ((t_uint64)provideLoaded->indexesLoaded[itfLocalBC->collectionIndex][j+1].methodAddresses << 32); + hostAddr += 2; + } + + // Last word align if required + if(j < require->interface->methodNumber) + *hostAddr = provideLoaded->indexesLoaded[itfLocalBC->collectionIndex][j].methodAddresses; + } + } + else + { + t_function_relocation *reloc = client->Template->delayedRelocation; + while(reloc != NULL) { + for(j = 0; j < provide->interface->methodNumber; j++) + { + if(provide->interface->methodNames[j] == reloc->symbol_name) { + cm_ELF_performRelocation( + reloc->type, + reloc->symbol_name, + provideLoaded->indexesLoaded[itfLocalBC->collectionIndex][j].methodAddresses, + reloc->reloc_addr); + break; + } + } + + reloc = reloc -> next; + } + } + + /* + * Memorise this reference + */ + { + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + + itfRef->provideIndex = itfLocalBC->provideIndex; + itfRef->collectionIndex = itfLocalBC->collectionIndex; + itfRef->instance = itfLocalBC->server; + itfRef->bfInfoID = bfInfoID; + itfRef->bfInfo = bfInfo; + + /* + * Do not count binding from EE (ie interrupt line), as this will prevent + * cm_destroyInstance() of server to succeed (interrupt line bindings are + * destroyed after the check in cm_destroyInstance() + */ + if (client->Template->classe != FIRMWARE) + server->providedItfUsedCount++; + } +} + +static void cm_registerLowLevelInterfaceToConst( + const t_interface_require_description *itfRequire, + const t_component_instance* targetInstance) +{ + const t_component_instance* client = itfRequire->client; + + /* + * Memorise this no reference + */ + { + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + + // This is an unbind from a true component (not to void) + // Do not count bindings from EE (ie interrupt line) + if ((targetInstance == NULL) + && (client->Template->classe != FIRMWARE) + && (itfRef->instance != (t_component_instance *)NMF_VOID_COMPONENT) + && (itfRef->instance != NULL)) + { + ((t_component_instance*)itfRef->instance)->providedItfUsedCount--; + } + + itfRef->instance = targetInstance; + itfRef->bfInfoID = BF_SYNCHRONOUS; // Just to memorize no Binding component used and unbind ToVoid happy ;-). + } +} + +static void cm_bindLowLevelInterfaceToConst( + const t_interface_require_description *itfRequire, + const t_dsp_address functionAddress, + const t_component_instance* targetInstance) { + const t_component_instance* client = itfRequire->client; + t_interface_require *require = &client->Template->requires[itfRequire->requireIndex]; + int j, k; + + + // If DSP is off/panic/... -> write nothing + if( + require->indexes != NULL + && cm_DSP_GetState(client->Template->dspId)->state == MPC_STATE_BOOTED) + { + t_interface_require_index *requireindex = &require->indexes[itfRequire->collectionIndex]; + + for(k = 0; k < requireindex->numberOfClient; k++) { + t_uint32 *hostAddr; + + hostAddr = (t_uint32*)( + cm_DSP_GetHostLogicalAddress(client->memories[requireindex->memories[k].memory->id]) + + requireindex->memories[k].offset * requireindex->memories[k].memory->memEntSize); + + /* + * Fill the interface references. We start by Methods then This in order to swith to + * Unbinded panic as fast as possible and not used method with wrong This. This is + * relevent only for optional since we must go in stop state before rebinding other + * required interface. + * + * Direct write to DSP memory without go through DSP abstraction since we know we are in 24bits + */ + /* + * Write THIS reference into the Data field of the interface reference + * Hack for simplifying debug just to keep THIS reference with caller one + * (could be removed if __return_address MMDSP intrinsec provided by compiler). + */ + // Write the interface methods reference + + if(((t_uint32)hostAddr & 0x7) == 0 && require->interface->methodNumber > 0) + { + // We are 64word byte aligned, combine this write with first method + *(volatile t_uint64*)hostAddr = + ((t_uint64)client->thisAddress << 0) | + ((t_uint64)functionAddress << 32); + hostAddr += 2; + j = 1; + } + else + { + // We are not, write this which will align us + *hostAddr++ = (t_uint32)client->thisAddress; + j = 0; + } + + // Word align copy + for(; j < require->interface->methodNumber - 1; j+=2) { + *(volatile t_uint64*)hostAddr = + ((t_uint64)functionAddress << 0) | + ((t_uint64)functionAddress << 32); + hostAddr += 2; + } + + // Last word align if required + if(j < require->interface->methodNumber) + *hostAddr = functionAddress; + } + } + + cm_registerLowLevelInterfaceToConst(itfRequire, targetInstance); +} + +/* + * Bind User component though primitive binding factory + */ +t_cm_error cm_bindInterface( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide) { + + LOG_INTERNAL(1, "\n##### Bind Synchronous %s/%x.%s -> %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server, itfProvide->origName); + + cm_bindLowLevelInterface( + itfRequire, + itfProvide, + BF_SYNCHRONOUS, NULL); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_SYNCHRONOUS, + itfRequire->client, itfProvide->server, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + itfProvide->server->Template->provides[itfProvide->provideIndex].name); + + return CM_OK; +} + +/* + * + */ +void cm_unbindInterface( + const t_interface_require_description *itfRequire) { + + LOG_INTERNAL(1, "\n##### UnBind synchronous %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_SYNCHRONOUS, + itfRequire->client, NULL, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + cm_bindLowLevelInterfaceToConst(itfRequire, + 0x0, + NULL); +} + +/* + * + */ +t_cm_error cm_bindInterfaceToVoid( + const t_interface_require_description *itfRequire) { + LOG_INTERNAL(1, "\n##### Bind %s/%x.%s -> Void #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_bindLowLevelInterfaceToConst(itfRequire, + cm_EEM_getExecutiveEngine(itfRequire->client->Template->dspId)->voidAddr, + (t_component_instance*)NMF_VOID_COMPONENT); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_SYNCHRONOUS, + itfRequire->client, NULL, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + return CM_OK; +} +/* + * Find the server and its interface inded to a given required interface for a given component + */ +t_cm_error cm_lookupInterface( + const t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide) { + const t_component_instance* client = itfRequire->client; + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + + if(itfRef->instance != NULL) + { + itfProvide->server = itfRef->instance; + itfProvide->provideIndex = itfRef->provideIndex; + itfProvide->collectionIndex = itfRef->collectionIndex; + + return CM_OK; + } else { + itfProvide->server = NULL; + return CM_INTERFACE_NOT_BINDED; + } +} + +/* + * + */ +t_cm_error cm_bindInterfaceTrace( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide, + t_elfdescription *elfhandleTrace) +{ + t_interface_require *require = &itfRequire->client->Template->requires[itfRequire->requireIndex]; + t_interface_require_description bcitfRequire; + t_interface_provide_description bcitfProvide; + t_trace_bf_info *bfInfo; + t_cm_error error; + + LOG_INTERNAL(1, "\n##### Bind Synchronous Trace %s/%x.%s -> %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server, itfProvide->origName); + + /* Allocate aynchronous binding factory information */ + bfInfo = (t_trace_bf_info*)OSAL_Alloc(sizeof(t_trace_bf_info)); + if(bfInfo == 0) + return CM_NO_MORE_MEMORY; + + /* + * Instantiate related trace on dsp + */ + { + char traceTemplateName[4 + MAX_INTERFACE_TYPE_NAME_LENGTH + 1]; + + cm_StringCopy(traceTemplateName,"_tr.", sizeof(traceTemplateName)); + cm_StringConcatenate(traceTemplateName, require->interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + + if ((error = cm_instantiateComponent( + traceTemplateName, + itfRequire->client->domainId, + itfProvide->server->priority, + traceDup, + elfhandleTrace, + &bfInfo->traceInstance)) != CM_OK) { + OSAL_Free(bfInfo); + return (error == CM_COMPONENT_NOT_FOUND)?CM_BINDING_COMPONENT_NOT_FOUND : error; + } + } + + /* Bind event to server interface (Error must not occure) */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->traceInstance, "target", &bcitfRequire) == CM_OK); + + cm_bindLowLevelInterface(&bcitfRequire, itfProvide, BF_SYNCHRONOUS, NULL); + + /* Get the event interface (Error must not occure) */ + CM_ASSERT(cm_getProvidedInterface(bfInfo->traceInstance, "target", &bcitfProvide) == CM_OK); + + /* Bind client to event (Error must not occure) */ + cm_bindLowLevelInterface(itfRequire, &bcitfProvide, BF_TRACE, bfInfo); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_SYNCHRONOUS, + itfRequire->client, itfProvide->server, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + itfProvide->server->Template->provides[itfProvide->provideIndex].name); + + return CM_OK; +} + +void cm_unbindInterfaceTrace( + const t_interface_require_description *itfRequire, + t_trace_bf_info *bfInfo) +{ + t_interface_require_description traceitfRequire; + + LOG_INTERNAL(1, "\n##### UnBind trace synchronous %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_SYNCHRONOUS, + itfRequire->client, NULL, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + /* Unbind Client from Event Binding Component */ + cm_bindLowLevelInterfaceToConst(itfRequire, 0x0, NULL); + + /* Unbind explicitly Event from Server Binding Component */ + /* This is mandatory to fix the providedItfUsedCount of the server */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->traceInstance, "target", &traceitfRequire) == CM_OK); + + cm_registerLowLevelInterfaceToConst(&traceitfRequire, NULL); + + /* Destroy Event Binding Component */ + cm_destroyInstance(bfInfo->traceInstance, DESTROY_WITHOUT_CHECK); + + /* Free BF info */ + OSAL_Free(bfInfo); +} + + +/* + * + */ +t_cm_error cm_bindInterfaceAsynchronous( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide, + t_uint32 fifosize, + t_dsp_memory_type_id dspEventMemType, + t_elfdescription *elfhandleEvent) { + t_interface_require *require = &itfRequire->client->Template->requires[itfRequire->requireIndex]; + t_interface_require_description eventitfRequire; + t_interface_provide_description eventitfProvide; + t_async_bf_info *bfInfo; + t_cm_error error; + + LOG_INTERNAL(1, "\n##### Bind Asynchronous %s/%x.%s -> %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server, itfProvide->origName); + + /* Allocate aynchronous binding factory information */ + bfInfo = (t_async_bf_info*)OSAL_Alloc(sizeof(t_async_bf_info)); + if(bfInfo == 0) + return CM_NO_MORE_MEMORY; + + /* + * Instantiate related event on dsp + */ + { + char eventTemplateName[4 + MAX_INTERFACE_TYPE_NAME_LENGTH + 1]; + + cm_StringCopy(eventTemplateName,"_ev.", sizeof(eventTemplateName)); + cm_StringConcatenate(eventTemplateName, require->interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + + if ((error = cm_instantiateComponent( + eventTemplateName, + itfRequire->client->domainId, + itfProvide->server->priority, + eventDup, + elfhandleEvent, + &bfInfo->eventInstance)) != CM_OK) { + OSAL_Free(bfInfo); + return (error == CM_COMPONENT_NOT_FOUND)?CM_BINDING_COMPONENT_NOT_FOUND : error; + } + } + + /* + * Initialize the event component + */ + { + unsigned int size; + + // Get fifo elem size (which was store in TOP by convention) + size = cm_readAttributeNoError(bfInfo->eventInstance, "TOP"); + LOG_INTERNAL(3, "DspEvent Fifo element size = %d\n", size, 0, 0, 0, 0, 0); + + // Allocate fifo + if ((error = dspevent_createDspEventFifo(bfInfo->eventInstance, + "TOP", + fifosize, size, + dspEventMemType, + &bfInfo->dspfifoHandle)) != CM_OK) + { + cm_destroyInstance(bfInfo->eventInstance, DESTROY_WITHOUT_CHECK); + OSAL_Free(bfInfo); + return error; + } + } + + /* Bind event to server interface (Error must not occure) */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->eventInstance, "target", &eventitfRequire) == CM_OK); + + cm_bindLowLevelInterface(&eventitfRequire, itfProvide, BF_SYNCHRONOUS, NULL); + + /* Get the event interface (Error must not occure) */ + CM_ASSERT(cm_getProvidedInterface(bfInfo->eventInstance, "target", &eventitfProvide) == CM_OK); + + /* Bind client to event (Error must not occure) */ + cm_bindLowLevelInterface(itfRequire, &eventitfProvide, BF_ASYNCHRONOUS, bfInfo); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_ASYNCHRONOUS, + itfRequire->client, itfProvide->server, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + itfProvide->server->Template->provides[itfProvide->provideIndex].name); + + return CM_OK; +} + +void cm_unbindInterfaceAsynchronous( + const t_interface_require_description *itfRequire, + t_async_bf_info *bfInfo) +{ + t_interface_require_description eventitfRequire; + + LOG_INTERNAL(1, "\n##### UnBind asynchronous %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_ASYNCHRONOUS, + itfRequire->client, NULL, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + /* Unbind Client from Event Binding Component */ + cm_bindLowLevelInterfaceToConst(itfRequire, 0x0, NULL); + + /* Unbind explicitly Event from Server Binding Component */ + /* This is mandatory to fix the providedItfUsedCount of the server */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->eventInstance, "target", &eventitfRequire) == CM_OK); + + cm_registerLowLevelInterfaceToConst(&eventitfRequire, NULL); + + /* Destroy Event fifo */ + dspevent_destroyDspEventFifo(bfInfo->dspfifoHandle); + + /* Destroy Event Binding Component */ + cm_destroyInstance(bfInfo->eventInstance, DESTROY_WITHOUT_CHECK); + + /* Free BF info */ + OSAL_Free(bfInfo); +} + +/*! + * Create Shared FIFO and set stub and skeleton to it + */ +PRIVATE t_cm_error cm_createParamsFifo(t_component_instance *stub, + t_component_instance *skeleton, + t_cm_domain_id domainId, + t_uint32 fifosize, + t_nmf_fifo_arm_desc **fifo, + t_uint32 *fifoElemSize, + t_uint32 bcDescSize) +{ + t_nmf_core_id stubcore = (stub != NULL) ?(stub->Template->dspId): ARM_CORE_ID; + t_nmf_core_id skelcore = (skeleton != NULL) ?(skeleton->Template->dspId) : ARM_CORE_ID; + t_component_instance *bcnotnull = (stub != NULL) ? stub : skeleton; + int _fifoelemsize; + + CM_ASSERT(bcnotnull != NULL); + + /* Get fifo param elem size (which was store in FIFO by convention) */ + _fifoelemsize = cm_readAttributeNoError(bcnotnull, "FIFO"); + LOG_INTERNAL(3, "Fifo Params element size = %d\n", _fifoelemsize, 0, 0, 0, 0, 0); + if(fifoElemSize != NULL) + *fifoElemSize = _fifoelemsize; + + /* Allocation of the fifo params */ + *fifo = fifo_alloc(stubcore, skelcore, _fifoelemsize, fifosize, 1+bcDescSize, paramsLocation, extendedFieldLocation, domainId); /* 1+nbMethods fro hostBCThis_or_TOP space */ + if(*fifo == NULL) { + ERROR("CM_NO_MORE_MEMORY: fifo_alloc() failed in cm_createParamsFifo()\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + if(stub != NULL) + { + /* Set stub FIFO attribute (Error mut not occure) */ + cm_writeAttribute(stub, "FIFO", (*fifo)->dspAdress); + + LOG_INTERNAL(2, " FIFO param %x:%x\n", *fifo, (*fifo)->dspAdress, 0, 0, 0, 0); + } + + if(skeleton != NULL) + { + /* Set Skeleton FIFO attribute (Error mut not occure) */ + cm_writeAttribute(skeleton, "FIFO", (*fifo)->dspAdress); + + LOG_INTERNAL(2, " FIFO param %x:%x\n", *fifo, (*fifo)->dspAdress, 0, 0, 0, 0); + } + + return CM_OK; +} +/** + * + */ +static void cm_destroyParamsFifo(t_nmf_fifo_arm_desc *fifo) { + fifo_free(fifo); +} + +/*! + * Create DSP skeleton + */ +PRIVATE t_cm_error cm_createDSPSkeleton( + const t_interface_provide_description *itfProvide, + t_uint32 fifosize, + t_dsp_memory_type_id dspEventMemType, //INTERNAL_XRAM24 + t_elfdescription *elfhandleSkeleton, + t_dspskel_bf_info *bfInfo) +{ + t_interface_provide *provide = &itfProvide->server->Template->provides[itfProvide->provideIndex]; + t_interface_require_description skelitfRequire; + t_cm_error error; + unsigned int fifoeventsize = 0; + + /* Instantiate related stub on dsp */ + { + char stubTemplateName[4 + MAX_INTERFACE_TYPE_NAME_LENGTH + 1]; + + cm_StringCopy(stubTemplateName,"_sk.", sizeof(stubTemplateName)); + cm_StringConcatenate(stubTemplateName, provide->interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + + if ((error = cm_instantiateComponent( + stubTemplateName, + itfProvide->server->domainId, + itfProvide->server->priority, + skeletonDup, + elfhandleSkeleton, + &bfInfo->skelInstance)) != CM_OK) { + return ((error == CM_COMPONENT_NOT_FOUND)?CM_BINDING_COMPONENT_NOT_FOUND:error); + } + } + + /* Get fifo elem size (which was store in TOP by convention) */ + fifoeventsize = cm_readAttributeNoError(bfInfo->skelInstance, "TOP"); + LOG_INTERNAL(3, "DspEvent Fifo element size = %d\n", fifoeventsize, 0, 0, 0, 0, 0); + + /* Allocation of the itf event dsp fifo */ + if ((error = dspevent_createDspEventFifo( + bfInfo->skelInstance, + "TOP", + fifosize, + fifoeventsize, + dspEventMemType, + &bfInfo->dspfifoHandle)) != CM_OK) + { + cm_destroyInstance(bfInfo->skelInstance, DESTROY_WITHOUT_CHECK); + return error; + } + + /* Bind stub to server component (Error must not occure) */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->skelInstance, "target", &skelitfRequire) == CM_OK); + + cm_bindLowLevelInterface(&skelitfRequire, itfProvide, BF_SYNCHRONOUS, NULL); + + return CM_OK; +} + +/** + * Destroy DSP Skeleton + */ +PRIVATE t_cm_error cm_destroyDSPSkeleton(t_dspskel_bf_info *bfInfo) { + t_interface_require_description skelitfRequire; + + /* Unbind explicitly stub from server component (Error must not occure) */ + /* This is mandatory to fix the providedItfUsedCount of the server */ + CM_ASSERT(cm_getRequiredInterface(bfInfo->skelInstance, "target", &skelitfRequire) == CM_OK); + + cm_registerLowLevelInterfaceToConst(&skelitfRequire, NULL); + + /* Destroy Event fifo */ + dspevent_destroyDspEventFifo(bfInfo->dspfifoHandle); + + /* Destroy Event Binding Component */ + return cm_destroyInstance(bfInfo->skelInstance, DESTROY_WITHOUT_CHECK); +} + +/* + * + */ +t_cm_error cm_bindComponentFromCMCore( + const t_interface_provide_description *itfProvide, + t_uint32 fifosize, + t_dsp_memory_type_id dspEventMemType, + t_elfdescription *elfhandleSkeleton, + t_host2mpc_bf_info **bfInfo) { + t_interface_provide *provide = &itfProvide->server->Template->provides[itfProvide->provideIndex]; + t_dsp_offset shareVarOffset; + t_cm_error error; + + LOG_INTERNAL(1, "\n##### Bind HOST -> %s/%x.%s #####\n", + itfProvide->server->pathname, itfProvide->server, itfProvide->origName, 0, 0, 0); + + /* Allocate host2dsp binding factory information */ + *bfInfo = (t_host2mpc_bf_info*)OSAL_Alloc(sizeof(t_host2mpc_bf_info)); + if((*bfInfo) == 0) + return CM_NO_MORE_MEMORY; + + /* Create the Skeleton */ + if ((error = cm_createDSPSkeleton(itfProvide, + fifo_normalizeDepth(fifosize), /* We SHALL create DSP Skeleton before creating the Params Fifo, but we need in advance the real depth of this fifo */ + dspEventMemType, + elfhandleSkeleton, + &(*bfInfo)->dspskeleton)) != CM_OK) + { + OSAL_Free((*bfInfo)); + return error; + } + + /* Create the FIFO Params */ + if ((error = cm_createParamsFifo(NULL, + (*bfInfo)->dspskeleton.skelInstance, + itfProvide->server->domainId, + fifosize, + &(*bfInfo)->fifo, + NULL, + provide->interface->methodNumber)) != CM_OK) + { + cm_destroyDSPSkeleton(&(*bfInfo)->dspskeleton); + OSAL_Free((*bfInfo)); + return error; + } + + /* Set Target info in FIFO param to TOP */ + shareVarOffset = cm_getAttributeMpcAddress((*bfInfo)->dspskeleton.skelInstance, "TOP"); + + /* + * Set Target info in FIFO param to armThis + * Should not return any error + */ + fifo_params_setSharedField((*bfInfo)->fifo, 0, (t_shared_field)shareVarOffset /* ArmBCThis_or_TOP */); + + /* Initialise FIFO Param bcDesc with Skeleton methods */ + { + int i; + t_component_instance *skel = (*bfInfo)->dspskeleton.skelInstance; + for (i=0; i < provide->interface->methodNumber; i++) + { + /* should not return error */ + fifo_params_setSharedField( + (*bfInfo)->fifo, + 1+i, + skel->Template->providesLoaded[0].indexesLoaded[0][i].methodAddresses + ); + } + } + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_ASYNCHRONOUS, + ARM_TRACE_COMPONENT, itfProvide->server, + NULL, + itfProvide->server->Template->provides[itfProvide->provideIndex].name); + + return CM_OK; +} + +void cm_unbindComponentFromCMCore( + t_host2mpc_bf_info* bfInfo) { + t_component_instance *skel = bfInfo->dspskeleton.skelInstance; + t_interface_reference* itfProvide = &skel->interfaceReferences[0][0]; + t_interface_provide *provide = &itfProvide->instance->Template->provides[itfProvide->provideIndex]; + + LOG_INTERNAL(1, "\n##### UnBind HOST -> %s/%x.%s #####\n", + itfProvide->instance->pathname, itfProvide->instance, provide->name, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_ASYNCHRONOUS, + ARM_TRACE_COMPONENT, itfProvide->instance, + NULL, + itfProvide->instance->Template->provides[itfProvide->provideIndex].name); + + // Destroy FIFO params + cm_destroyParamsFifo(bfInfo->fifo); + + // Destory Skeleton + cm_destroyDSPSkeleton(&bfInfo->dspskeleton); + + // Free BF info (which contains bcDecr(==dspfct) and arm This) + OSAL_Free(bfInfo); +} + +/** + * Create DSP Stub + */ +PRIVATE t_cm_error cm_createDSPStub( + const t_interface_require_description *itfRequire, + const char* itfType, + t_dspstub_bf_info* bfInfo, + t_elfdescription *elfhandleStub, + t_interface_provide_description *itfstubProvide) { + t_cm_error error; + + /* + * Instantiate related skel on dsp + */ + { + char skelTemplateName[4 + MAX_INTERFACE_TYPE_NAME_LENGTH + 1]; + + cm_StringCopy(skelTemplateName, "_st.", sizeof(skelTemplateName)); + cm_StringConcatenate(skelTemplateName, itfType, MAX_INTERFACE_TYPE_NAME_LENGTH); + + if ((error = cm_instantiateComponent( + skelTemplateName, + itfRequire->client->domainId, + itfRequire->client->priority, + stubDup, + elfhandleStub, + &bfInfo->stubInstance)) != CM_OK) { + return (error == CM_COMPONENT_NOT_FOUND)?CM_BINDING_COMPONENT_NOT_FOUND : error; + } + } + + /* Get the internal component that serve this interface (Error must not occure) */ + (void)cm_getProvidedInterface(bfInfo->stubInstance, "source", itfstubProvide); + + return CM_OK; +} + +PRIVATE t_cm_error cm_destroyDSPStub( + const t_interface_require_description *itfRequire, + t_dspstub_bf_info* bfInfo) { + + /* Unbind Client from Event Binding Component */ + cm_bindLowLevelInterfaceToConst(itfRequire, + 0x0, + NULL); + + /* Destroy Event Binding Component */ + return cm_destroyInstance(bfInfo->stubInstance, DESTROY_WITHOUT_CHECK); +} +/* + * + */ +t_cm_error cm_bindComponentToCMCore( + const t_interface_require_description *itfRequire, + t_uint32 fifosize, + t_uint32 context, + t_elfdescription *elfhandleStub, + t_mpc2host_bf_info ** bfInfo) { + t_interface_require *require = &itfRequire->client->Template->requires[itfRequire->requireIndex]; + t_interface_provide_description itfstubProvide; + t_cm_error error; + t_uint32 fifoelemsize; + + LOG_INTERNAL(1, "\n##### Bind %s/%x.%s -> HOST #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + /* Allocate dsp2host binding factory information */ + *bfInfo = (t_mpc2host_bf_info*)OSAL_Alloc(sizeof(t_mpc2host_bf_info)); + if(*bfInfo == 0) + return CM_NO_MORE_MEMORY; + (*bfInfo)->context = context; + + if ((error = cm_createDSPStub(itfRequire, + require->interface->type, + &(*bfInfo)->dspstub, + elfhandleStub, + &itfstubProvide)) != CM_OK) + { + OSAL_Free(*bfInfo); + return error; + } + + /* Create the FIFO Params */ + if ((error = cm_createParamsFifo( + (*bfInfo)->dspstub.stubInstance, + NULL, + itfRequire->client->domainId, + fifosize, + &(*bfInfo)->fifo, + &fifoelemsize, + 1)) != CM_OK) /* 1 => we used first field as max params size */ + { + cm_destroyDSPStub(itfRequire, &(*bfInfo)->dspstub); + OSAL_Free(*bfInfo); + return error; + } + + /* Bind client to stub component (Error must not occure) */ + cm_bindLowLevelInterface(itfRequire, &itfstubProvide, BF_DSP2HOST, *bfInfo); + + /* Bind stub component to host (virtual bind) */ + cm_bindVirtualInterface((*bfInfo)->dspstub.stubInstance, (t_component_instance*)NMF_HOST_COMPONENT); + + /* + * Set Target info in FIFO param to armThis + * Initialise FIFO Param bcDesc with Jumptable + * Should not return any error + */ + fifo_params_setSharedField((*bfInfo)->fifo, 0, (t_shared_field)context /* ArmBCThis_or_TOP */); + fifo_params_setSharedField((*bfInfo)->fifo, 1, (t_shared_field)fifoelemsize * 2/* bcDescRef */); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_ASYNCHRONOUS, + itfRequire->client, ARM_TRACE_COMPONENT, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + return error; +} + +void cm_unbindComponentToCMCore( + const t_interface_require_description *itfRequire, + t_mpc2host_bf_info *bfInfo) +{ + LOG_INTERNAL(1, "\n##### UnBind %s/%x.%s -> HOST #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_ASYNCHRONOUS, + itfRequire->client, ARM_TRACE_COMPONENT, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + /* Unbind virtual interface coms */ + cm_unbindVirtualInterface(bfInfo->dspstub.stubInstance); + + // Destroy FIFO params + cm_destroyParamsFifo(bfInfo->fifo); + + // Destroy DSP Stub + cm_destroyDSPStub(itfRequire, &bfInfo->dspstub); + + /* Free BF info */ + OSAL_Free(bfInfo); +} + +/*! + * + */ +t_cm_error cm_bindInterfaceDistributed( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide, + t_uint32 fifosize, + t_dsp_memory_type_id dspEventMemType, + t_elfdescription *elfhandleSkeleton, + t_elfdescription *elfhandleStub) { + t_interface_require *require = &itfRequire->client->Template->requires[itfRequire->requireIndex]; + t_interface_provide_description itfstubProvide; + t_cm_error error; + t_mpc2mpc_bf_info *bfInfo; + t_dsp_offset shareVarOffset; + + LOG_INTERNAL(1, "\n##### Bind Distributed %s/%x.%s -> %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server, itfProvide->origName); + + /* Allocate aynchronous binding factory information */ + bfInfo = (t_mpc2mpc_bf_info*)OSAL_Alloc(sizeof(t_mpc2mpc_bf_info)); + if(bfInfo == 0) + return CM_NO_MORE_MEMORY; + + /* Create the Skeleton */ + if ((error = cm_createDSPSkeleton(itfProvide, + fifo_normalizeDepth(fifosize), /* We SHALL create DSP Skeleton before creating the Params Fifo, but we need in advance the real depth of this fifo */ + dspEventMemType, + elfhandleSkeleton, + &bfInfo->dspskeleton)) != CM_OK) + { + OSAL_Free(bfInfo); + return error; + } + + // Create DSP Stub + if ((error = cm_createDSPStub(itfRequire, + require->interface->type, + &bfInfo->dspstub, + elfhandleStub, + &itfstubProvide)) != CM_OK) + { + cm_destroyDSPSkeleton(&bfInfo->dspskeleton); + OSAL_Free(bfInfo); + return error; + } + + /* Bind client to stub component (Error must not occure) */ + cm_bindLowLevelInterface(itfRequire, &itfstubProvide, BF_DSP2DSP, bfInfo); + + /* Create the FIFO Params */ + if ((error = cm_createParamsFifo( + bfInfo->dspstub.stubInstance, + bfInfo->dspskeleton.skelInstance, + itfProvide->server->domainId, + fifosize, + &bfInfo->fifo, + NULL, + require->interface->methodNumber)) != CM_OK) + { + cm_destroyDSPStub(itfRequire, &bfInfo->dspstub); + cm_destroyDSPSkeleton(&bfInfo->dspskeleton); + OSAL_Free(bfInfo); + return error; + } + + /* Bind stub component to host (virtual bind) */ + cm_bindVirtualInterface(bfInfo->dspstub.stubInstance, bfInfo->dspskeleton.skelInstance); + + /* Set Target info in FIFO param to TOP */ + shareVarOffset = cm_getAttributeMpcAddress(bfInfo->dspskeleton.skelInstance, "TOP"); + + /* + * Set Target info in FIFO param to armThis + * Should not return any error + */ + fifo_params_setSharedField(bfInfo->fifo, 0, (t_shared_field)shareVarOffset /* ArmBCThis_or_TOP */); + + /* Initialise FIFO Param bcDesc with Skeleton methods */ + { + int i; + t_component_instance *skel = bfInfo->dspskeleton.skelInstance; + for (i=0; i < require->interface->methodNumber; i++) + { + /* should not return error */ + fifo_params_setSharedField( + bfInfo->fifo, + 1+i, + skel->Template->providesLoaded[0].indexesLoaded[0][i].methodAddresses + ); + } + } + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_BIND_ASYNCHRONOUS, + itfRequire->client, itfProvide->server, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + itfProvide->server->Template->provides[itfProvide->provideIndex].name); + + return CM_OK; +} + +/*! + * + */ +void cm_unbindInterfaceDistributed( + const t_interface_require_description *itfRequire, + t_mpc2mpc_bf_info *bfInfo) +{ + LOG_INTERNAL(1, "\n##### UnBind distributed %s/%x.%s #####\n", + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0, 0); + + cm_TRC_traceBinding(TRACE_BIND_COMMAND_UNBIND_ASYNCHRONOUS, + itfRequire->client, NULL, + itfRequire->client->Template->requires[itfRequire->requireIndex].name, + NULL); + + /* Unbind virtual interface */ + cm_unbindVirtualInterface(bfInfo->dspstub.stubInstance); + + // Destroy FIFO params + cm_destroyParamsFifo(bfInfo->fifo); + + // Destroy DSP Stub + cm_destroyDSPStub(itfRequire, &bfInfo->dspstub); + + // Destory DSP Skeleton + cm_destroyDSPSkeleton(&bfInfo->dspskeleton); + + // Destroy BF Info + OSAL_Free(bfInfo); +} + +t_cm_error cm_bindInterfaceStaticInterrupt( + const t_nmf_core_id coreId, + const int interruptLine, + const t_component_instance *server, + const char* providedItfServerName +) +{ + char requiredItfClientName[CM_IT_NAME_MAX_LENGTH]; + t_component_instance *client = cm_EEM_getExecutiveEngine(coreId)->instance; + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_cm_error error; + + //build it[%d] name + if (interruptLine < 0 || interruptLine > 255) {return CM_OUT_OF_LIMITS;} + cm_fillItName(interruptLine, requiredItfClientName); + + //do binding + if ((error = cm_getRequiredInterface(client,requiredItfClientName,&itfRequire)) != CM_OK) {return error;} + if ((error = cm_getProvidedInterface(server,providedItfServerName,&itfProvide)) != CM_OK) {return error;} + if((error = cm_bindInterface(&itfRequire, &itfProvide)) != CM_OK) {return error;} + + return CM_OK; +} + +t_cm_error cm_unbindInterfaceStaticInterrupt( + const t_nmf_core_id coreId, + const int interruptLine +) +{ + char requiredItfClientName[CM_IT_NAME_MAX_LENGTH]; + t_component_instance *client = cm_EEM_getExecutiveEngine(coreId)->instance; + t_interface_require_description itfRequire; + t_cm_error error; + + //build it[%d] name + if (interruptLine < 0 || interruptLine > 255) {return CM_OUT_OF_LIMITS;} + cm_fillItName(interruptLine, requiredItfClientName); + + //do unbinding + if ((error = cm_getRequiredInterface(client,requiredItfClientName,&itfRequire)) != CM_OK) {return error;} + cm_unbindInterface(&itfRequire); + + return CM_OK; +} + +void cm_destroyRequireInterface(t_component_instance* component, t_nmf_client_id clientId) +{ + int i, j; + + /* + * Special code for SINGLETON handling + */ + if(component->Template->classe == SINGLETON) + { + if(getNumberOfBind(component) > 0) + return; + } + + for(i = 0; i < component->Template->requireNumber; i++) + { + int nb = component->Template->requires[i].collectionSize; + for(j = 0; j < nb; j++) + { + if(component->interfaceReferences[i][j].instance != NULL) + { + t_interface_reference* itfRef = &component->interfaceReferences[i][j]; + t_interface_require_description itfRequire; + + itfRequire.client = component; + itfRequire.requireIndex = i; + itfRequire.collectionIndex = j; + itfRequire.origName = component->Template->requires[i].name; + + switch (itfRef->bfInfoID) { + case BF_SYNCHRONOUS: + /* Error ignored as it is always OK */ + cm_unbindInterface(&itfRequire); + break; + case BF_TRACE: + cm_unbindInterfaceTrace(&itfRequire, + (t_trace_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + break; + case BF_ASYNCHRONOUS: + cm_unbindInterfaceAsynchronous(&itfRequire, + (t_async_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + break; + case BF_DSP2HOST: + /* This 'mpc2host handle' is provided by the host at OS Integration level. + It must then be handled and released in OS specific part. + */ + cm_unbindComponentToCMCore(&itfRequire, + (t_mpc2host_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + break; + case BF_HOST2DSP: + /* These bindings are from CM Core to DSP, they are not listed + here and must be handles/freed by host at OS Integration level + */ + break; + case BF_DSP2DSP: + cm_unbindInterfaceDistributed(&itfRequire, + (t_mpc2mpc_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + break; + default: + break; + } + } + } + } +} + +void cm_registerSingletonBinding( + t_component_instance* component, + t_interface_require_description* itfRequire, + t_interface_provide_description* itfProvide, + t_nmf_client_id clientId) +{ + if(component->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, FALSE, clientId); + if(cl != NULL) + cl->numberOfBind++; + + if(itfProvide != NULL) + LOG_INTERNAL(1, " -> Singleton[%d] : Register binding %s/%x.%s -> %s/%x\n", + clientId, + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server); + else + LOG_INTERNAL(1, " -> Singleton[%d] : Register binding %s/%x.%s -> ARM/VOID\n", + clientId, + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0); + } +} + +t_bool cm_unregisterSingletonBinding( + t_component_instance* component, + t_interface_require_description* itfRequire, + t_interface_provide_description* itfProvide, + t_nmf_client_id clientId) +{ + if(component->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, FALSE, clientId); + if(cl != NULL) + cl->numberOfBind--; + + if(itfProvide->server == (t_component_instance *)NMF_VOID_COMPONENT) + LOG_INTERNAL(1, " -> Singleton[%d] : Unregister binding %s/%x.%s -> ARM/VOID\n", + clientId, + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0); + else if(itfProvide->server == NULL) + LOG_INTERNAL(1, " -> Singleton[%d] : Unregister binding %s/%x.%s -> ?? <already unbound>\n", + clientId, + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, 0, 0); + else + LOG_INTERNAL(1, " -> Singleton[%d] : Unregister binding %s/%x.%s -> %s/%x\n", + clientId, + itfRequire->client->pathname, itfRequire->client, itfRequire->origName, + itfProvide->server->pathname, itfProvide->server); + + if(getNumberOfBind(component) == 0) + { + LOG_INTERNAL(1, " -> Singleton[%d] : All required of %s/%x logically unbound, perform physical unbind\n", + clientId, itfRequire->client->pathname, itfRequire->client, 0, 0, 0); + + (void)cm_EEM_ForceWakeup(component->Template->dspId); + + // This is the last binding unbind all !!! + cm_destroyRequireInterface(component, clientId); + + cm_EEM_AllowSleep(component->Template->dspId); + } + else if(itfProvide->server != NULL) + { + t_interface_require* itfReq; + itfReq = &itfRequire->client->Template->requires[itfRequire->requireIndex]; + if((itfReq->requireTypes & OPTIONAL_REQUIRE) != 0x0) + return TRUE; + } + + return FALSE; + } + + return TRUE; +} + +static t_uint16 getNumberOfBind(t_component_instance* component) +{ + t_uint16 bindNumber = 0; + struct t_client_of_singleton* cur = component->clientOfSingleton; + + for( ; cur != NULL ; cur = cur->next) + { + bindNumber += cur->numberOfBind; + } + + return bindNumber; +} + +static void cm_fillItName(int interruptLine, char *itName) +{ + int divider = 10000; + + *itName++ = 'i'; + *itName++ = 't'; + *itName++ = '['; + + // Find first significant divider + while(divider > interruptLine) + divider /= 10; + + // Compute number + do + { + *itName++ = "0123456789"[interruptLine / divider]; + interruptLine %= divider; + divider /= 10; + } while(divider != 0); + + *itName++ = ']'; + *itName++ = '\0'; +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/binder_check.c b/drivers/staging/nmf-cm/cm/engine/component/src/binder_check.c new file mode 100644 index 00000000000..373fea0cd47 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/binder_check.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include "../inc/bind.h" +#include <cm/engine/trace/inc/trace.h> + +#include <cm/engine/utils/inc/string.h> + +t_cm_error cm_checkValidClient( + const t_component_instance* client, + const char* requiredItfClientName, + t_interface_require_description *itfRequire, + t_bool *bindable) { + t_cm_error error; + + // Component LC state check + if (NULL == client) + return CM_INVALID_COMPONENT_HANDLE; + + // Check if the requiredItfClientName is required by client component + if ((error = cm_getRequiredInterface(client, requiredItfClientName, itfRequire)) != CM_OK) + return error; + + // Check required interface not already binded + { + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + + if(itfRef->instance != (t_component_instance*)NULL) + { + if(client->Template->classe == SINGLETON) + { + // Singleton is immutable thus we can't rebind it, nevertheless it's not an issue + *bindable = FALSE; + return CM_OK; + } + else + { + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + + if(itfRef->instance == (const t_component_instance*)NMF_VOID_COMPONENT) + ERROR("CM_INTERFACE_ALREADY_BINDED(): Component (%s<%s>.%s) already bound to VOID\n", + client->pathname, client->Template->name, requiredItfClientName, 0, 0, 0); + else + ERROR("CM_INTERFACE_ALREADY_BINDED(): Component (%s<%s>.%s) already bound to another server (%s<%s>.%s)\n", + client->pathname, client->Template->name, requiredItfClientName, + itfRef->instance->pathname, itfRef->instance->Template->name, itfRef->instance->Template->provides[itfRef->provideIndex].name); + return CM_INTERFACE_ALREADY_BINDED; + } + } + } + + // Delayed Component LC state check done only if not optional required interface or intrinsic one that has been solved by loader + { + t_interface_require* itfReq = &client->Template->requires[itfRequire->requireIndex]; + + if((itfReq->requireTypes & (OPTIONAL_REQUIRE | INTRINSEC_REQUIRE)) == 0) { + if(client->state == STATE_RUNNABLE) + return CM_COMPONENT_NOT_STOPPED; + } + } + + *bindable = TRUE; + + return CM_OK; +} + +t_cm_error cm_checkValidServer( + const t_component_instance* server, + const char* providedItfServerName, + t_interface_provide_description *itfProvide) { + t_cm_error error; + + // Check if the components are initialized + //if (server->state == STATE_INSTANCIATED) + // return CM_COMPONENT_NOT_INITIALIZED; + if(NULL == server) + return CM_INVALID_COMPONENT_HANDLE; + + // Check if the providedItfServerName is provided by server component + if((error = cm_getProvidedInterface(server, providedItfServerName, itfProvide)) != CM_OK) + return error; + + return CM_OK; +} + +t_cm_error cm_checkValidBinding( + const t_component_instance* client, + const char* requiredItfClientName, + const t_component_instance* server, + const char* providedItfServerName, + t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide, + t_bool *bindable) { + t_interface_require *require; + t_interface_provide *provide; + t_cm_error error; + + // Check Server + if((error = cm_checkValidServer(server, providedItfServerName, itfProvide)) != CM_OK) + return error; + + // Check Client + if((error = cm_checkValidClient(client, requiredItfClientName, itfRequire, bindable)) != CM_OK) + return error; + + // If this is a singleton which has been already bound check that next binding is at the same server + if(*bindable == FALSE + && client->Template->classe == SINGLETON) + { + t_interface_reference* itfRef = &client->interfaceReferences[itfRequire->requireIndex][itfRequire->collectionIndex]; + while( itfRef->instance != server + || itfRef->provideIndex != itfProvide->provideIndex + || itfRef->collectionIndex != itfProvide->collectionIndex ) + { + if(itfRef->instance == (const t_component_instance*)NMF_VOID_COMPONENT) + { + ERROR("CM_INTERFACE_ALREADY_BINDED(): Singleton (%s<%s>.%s) already bound to VOID\n", + client->pathname, client->Template->name, requiredItfClientName, 0, 0, 0); + return CM_INTERFACE_ALREADY_BINDED; + } + else if(itfRef->bfInfoID == BF_ASYNCHRONOUS || itfRef->bfInfoID == BF_TRACE) + { + t_interface_require_description eventitfRequire; + CM_ASSERT(cm_getRequiredInterface(itfRef->instance, "target", &eventitfRequire) == CM_OK); + itfRef = &itfRef->instance->interfaceReferences[eventitfRequire.requireIndex][eventitfRequire.collectionIndex]; + + // Go to see client of event if the same + } + else + { + ERROR("CM_INTERFACE_ALREADY_BINDED(): Singleton (%s<%s>.%s) already bound to different server (%s<%s>.%s)\n", + client->pathname, client->Template->name, requiredItfClientName, + itfRef->instance->pathname, itfRef->instance->Template->name, itfRef->instance->Template->provides[itfRef->provideIndex].name); + return CM_INTERFACE_ALREADY_BINDED; + } + } + } + + // Check if provided and required type matches + require = &client->Template->requires[itfRequire->requireIndex]; + provide = &server->Template->provides[itfProvide->provideIndex]; + if(require->interface != provide->interface) + { + ERROR("CM_ILLEGAL_BINDING(%s, %s)\n", require->interface->type, provide->interface->type, 0, 0, 0, 0); + return CM_ILLEGAL_BINDING; + } + + // Check if static required interface binded to singleton component + if((require->requireTypes & STATIC_REQUIRE) && + (server->Template->classe != SINGLETON)) + { + ERROR("CM_ILLEGAL_BINDING(): Can't bind static required interface to not singleton component\n", + 0, 0, 0, 0, 0, 0); + return CM_ILLEGAL_BINDING; + } + + return CM_OK; +} + +t_cm_error cm_checkValidUnbinding( + const t_component_instance* client, + const char* requiredItfClientName, + t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide) { + t_cm_error error; + t_interface_require* itfReq; + + // Component LC state check + if (NULL == client) + return CM_INVALID_COMPONENT_HANDLE; + + // Check if the requiredItfClientName is required by client component + if ((error = cm_getRequiredInterface(client, requiredItfClientName, itfRequire)) != CM_OK) + return error; + + itfReq = &client->Template->requires[itfRequire->requireIndex]; + + // Check if the requiredItfClientName is required by client component + if ((error = cm_lookupInterface(itfRequire, itfProvide)) != CM_OK) + { + // We allow to unbind optional required of singleton even if not binded, since it could have been unbound previously but we don't + // want to break bind singleton reference counter + if((client->Template->classe == SINGLETON) && + (itfReq->requireTypes & OPTIONAL_REQUIRE) != 0x0) + return CM_OK; + + return error; + } + + // Singleton is immutable, don't unbind it + if(client->Template->classe == SINGLETON) + return CM_OK; + + /* if interface is optionnal then allow unbinding even if not stop */ + if((itfReq->requireTypes & OPTIONAL_REQUIRE) == 0x0) + { + if(client->state == STATE_RUNNABLE) + return CM_COMPONENT_NOT_STOPPED; + } + + return CM_OK; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/component_wrapper.c b/drivers/staging/nmf-cm/cm/engine/component/src/component_wrapper.c new file mode 100644 index 00000000000..d593950cd97 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/component_wrapper.c @@ -0,0 +1,1332 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/engine/api/component_engine.h> +#include <cm/engine/api/communication_engine.h> + +#include <cm/engine/component/inc/bind.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/memory/inc/domain.h> + +#include <cm/engine/configuration/inc/configuration.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> + +/* + * Component mangement wrapping. + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_InstantiateComponent( + const char* templateName, + t_cm_domain_id domainId, + t_nmf_client_id clientId, + t_nmf_ee_priority priority, + const char localName[MAX_COMPONENT_NAME_LENGTH], + const char *dataFile, + t_cm_instance_handle *instance) { + t_cm_error error; + t_nmf_core_id coreId; + t_component_instance *comp; + t_elfdescription *elfhandle = NULL; + + OSAL_LOCK_API(); + + /* + * Load Elf File + */ + if(dataFile != NULL && + (error = cm_ELF_CheckFile( + dataFile, + TRUE, + &elfhandle)) != CM_OK) + goto out; + + //only allow instantiation in non-scratch domains (ie. DOMAIN_NORMAL)! + if ((error = cm_DM_CheckDomainWithClient(domainId, DOMAIN_NORMAL, clientId)) != CM_OK) + goto out; + + coreId = cm_DM_GetDomainCoreId(domainId); + + if(coreId < FIRST_MPC_ID || coreId > LAST_CORE_ID) + { + error = CM_INVALID_PARAMETER; + goto out; + } + + if ((error = cm_CFG_CheckMpcStatus(coreId)) != CM_OK) + goto out; + + if ((error = cm_EEM_ForceWakeup(coreId)) != CM_OK) + goto out; + + error = cm_instantiateComponent( + templateName, + domainId, + priority, + localName, + elfhandle, + &comp); + if(error == CM_OK) + *instance = comp->instance; + + cm_EEM_AllowSleep(coreId); + +out: + cm_ELF_CloseFile(TRUE, elfhandle); + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_StartComponent( + t_cm_instance_handle instance, + t_nmf_client_id clientId) { + t_cm_error error; + t_component_instance *component; + + OSAL_LOCK_API(); + + component = cm_lookupComponent(instance); + if (NULL == component) + error = CM_INVALID_COMPONENT_HANDLE; + else + { + error = cm_startComponent(component, clientId); + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_StopComponent( + t_cm_instance_handle instance, + t_nmf_client_id clientId) { + t_cm_error error; + t_component_instance *component; + + OSAL_LOCK_API(); + + component = cm_lookupComponent(instance); + if (NULL == component) + error = CM_INVALID_COMPONENT_HANDLE; + else + { + error = cm_stopComponent(component, clientId); + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_DestroyComponent( + t_cm_instance_handle instance, + t_nmf_client_id clientId) +{ + t_cm_error error; + t_component_instance *component; + + OSAL_LOCK_API(); + + component = cm_lookupComponent(instance); + if (NULL == component) + { + error = CM_INVALID_COMPONENT_HANDLE; + } + else + { + t_nmf_core_id coreId = component->Template->dspId; + + (void)cm_EEM_ForceWakeup(coreId); + + error = cm_destroyInstanceForClient(component, DESTROY_NORMAL, clientId); + + cm_CFG_ReleaseMpc(coreId); + + cm_EEM_AllowSleep(coreId); + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_FlushComponents(t_nmf_client_id clientId) +{ + t_cm_error error = CM_OK; + t_component_instance *instance; + t_uint32 i; + + if (clientId == 0) + return CM_INVALID_PARAMETER; + + OSAL_LOCK_API(); + + // We don't know exactly where components will be, wake up everybody !! + (void)cm_EEM_ForceWakeup(SVA_CORE_ID); + (void)cm_EEM_ForceWakeup(SIA_CORE_ID); + + /* Destroy all host2mpc bindings */ + OSAL_LOCK_COM(); + for (i=0; i<Host2MpcBindingTable.idxMax; i++) + { + t_host2mpc_bf_info* bfInfo; + bfInfo = Host2MpcBindingTable.entries[i]; + if ((bfInfo != NULL) && (bfInfo->clientId == clientId)) { + cm_delEntry(&Host2MpcBindingTable, i); + OSAL_UNLOCK_COM(); + cm_unbindComponentFromCMCore(bfInfo); + OSAL_LOCK_COM(); + } + } + OSAL_UNLOCK_COM(); + + /* First, stop all remaining components for this client */ + for (i=0; i<ComponentTable.idxMax; i++) + { + if ((instance = componentEntry(i)) == NULL) + continue; + if (/* skip EE */ + (instance->Template->classe == FIRMWARE) || + /* Skip all binding components */ + (cm_StringCompare(instance->Template->name, "_ev.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_st.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_sk.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_tr.", 4) == 0)) + continue; + + /* + * Special code for SINGLETON handling + */ + if(instance->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(instance, FALSE, clientId); + if(cl == NULL) + continue; + + cl->numberOfStart = 1; // == 1 since it will go to 0 in cm_stopComponent + cl->numberOfInstance = 1; // == 1 since it will go to 0 in cm_destroyInstanceForClient + cl->numberOfBind = 0; // == 0 since we don't want anymore binding for this component + } + else if(domainDesc[instance->domainId].client != clientId) + /* Skip all components not belonging to our client */ + continue; + + // Stop the component + error = cm_stopComponent(instance, clientId); + if (error != CM_OK && error != CM_COMPONENT_NOT_STARTED) + LOG_INTERNAL(0, "Error stopping component %s/%x (%s, error=%d, client=%u)\n", instance->pathname, instance, instance->Template->name, error, clientId, 0); + + // Destroy dependencies + cm_destroyRequireInterface(instance, clientId); + } + + /* Destroy all remaining components for this client */ + for (i=0; i<ComponentTable.idxMax; i++) + { + if ((instance = componentEntry(i)) == NULL) + continue; + if (/* skip EE */ + (instance->Template->classe == FIRMWARE) || + /* Skip all binding components */ + (cm_StringCompare(instance->Template->name, "_ev.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_st.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_sk.", 4) == 0) || + (cm_StringCompare(instance->Template->name, "_tr.", 4) == 0)) { + continue; + } + + + /* + * Special code for SINGLETON handling + */ + if(instance->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(instance, FALSE, clientId); + if(cl == NULL) + continue; + } + else if(domainDesc[instance->domainId].client != clientId) + /* Skip all components not belonging to our client */ + continue; + + + // Destroy the component + error = cm_destroyInstanceForClient(instance, DESTROY_WITHOUT_CHECK, clientId); + + if (error != CM_OK) + { + /* FIXME : add component name instance in log message but need to make a copy before cm_flushComponent() + * because it's no more available after. + */ + LOG_INTERNAL(0, "Error flushing component (error=%d, client=%u)\n", error, clientId, 0, 0, 0, 0); + } + } + + cm_CFG_ReleaseMpc(SVA_CORE_ID); + cm_CFG_ReleaseMpc(SIA_CORE_ID); + + cm_EEM_AllowSleep(SVA_CORE_ID); + cm_EEM_AllowSleep(SIA_CORE_ID); + + OSAL_UNLOCK_API(); + + return error; +} + +/* + * Component binding wrapping. + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_BindComponent( + const t_cm_instance_handle clientInstance, + const char* requiredItfClientName, + const t_cm_instance_handle serverInstance, + const char* providedItfServerName, + t_bool traced, + t_nmf_client_id clientId, + const char *dataFileTrace) { + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_bool bindable; + t_cm_error error; + t_component_instance *client, *server; + t_elfdescription *elfhandleTrace = NULL; + + OSAL_LOCK_API(); + + /* + * Load Elf File + */ + if(dataFileTrace != NULL && + (error = cm_ELF_CheckFile( + dataFileTrace, + TRUE, + &elfhandleTrace)) != CM_OK) + goto out; + + client = cm_lookupComponent(clientInstance); + server = cm_lookupComponent(serverInstance); + // Sanity check + if((error = cm_checkValidBinding(client, requiredItfClientName, + server, providedItfServerName, + &itfRequire, &itfProvide, &bindable)) != CM_OK) + goto out; + + // Check that client and server component run on same DSP + if (itfRequire.client->Template->dspId != itfProvide.server->Template->dspId) + { + error = CM_ILLEGAL_BINDING; + goto out; + } + + // Check if we really need to bind + if(bindable) + { + if ((error = cm_EEM_ForceWakeup(itfRequire.client->Template->dspId)) != CM_OK) + goto out; + + /* + * Synchronous binding, so no binding component + */ + if(traced) + error = cm_bindInterfaceTrace(&itfRequire, &itfProvide, elfhandleTrace); + else + error = cm_bindInterface(&itfRequire, &itfProvide); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + } + + cm_registerSingletonBinding(client, &itfRequire, &itfProvide, clientId); + +out: + cm_ELF_CloseFile(TRUE, elfhandleTrace); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_UnbindComponent( + const t_cm_instance_handle clientInstance, + const char* requiredItfClientName, + t_nmf_client_id clientId) { + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_bf_info_ID bfInfoID; + t_cm_error error; + t_component_instance *client; + + OSAL_LOCK_API(); + + client = cm_lookupComponent(clientInstance); + // Sanity check + if((error = cm_checkValidUnbinding(client, requiredItfClientName, + &itfRequire, &itfProvide)) != CM_OK) + goto out; + + // Check if this is a Primitive binding + bfInfoID = itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfoID; + if(bfInfoID != BF_SYNCHRONOUS && bfInfoID != BF_TRACE) + { + error = CM_ILLEGAL_UNBINDING; + goto out; + } + + // Check if we really need to unbind + if(cm_unregisterSingletonBinding(client, &itfRequire, &itfProvide, clientId)) + { + (void)cm_EEM_ForceWakeup(itfRequire.client->Template->dspId); + + if(bfInfoID == BF_SYNCHRONOUS) + cm_unbindInterface(&itfRequire); + else + cm_unbindInterfaceTrace( + &itfRequire, + (t_trace_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + + error = CM_OK; + } + +out: + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_BindComponentToVoid( + const t_cm_instance_handle clientInstance, + const char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH], + t_nmf_client_id clientId) +{ + t_interface_require_description itfRequire; + t_bool bindable; + t_cm_error error; + t_component_instance *client; + + OSAL_LOCK_API(); + + client = cm_lookupComponent(clientInstance); + // Check invalid binding + if((error = cm_checkValidClient(client, requiredItfClientName, + &itfRequire, &bindable)) != CM_OK) + goto out; + + // Check if we really need to bind + if(bindable) + { + if ((error = cm_EEM_ForceWakeup(itfRequire.client->Template->dspId)) != CM_OK) + goto out; + + error = cm_bindInterfaceToVoid(&itfRequire); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + } + + cm_registerSingletonBinding(client, &itfRequire, NULL, clientId); + +out: + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_BindComponentAsynchronous( + const t_cm_instance_handle clientInstance, + const char* requiredItfClientName, + const t_cm_instance_handle serverInstance, + const char* providedItfServerName, + t_uint32 fifosize, + t_cm_mpc_memory_type eventMemType, + t_nmf_client_id clientId, + const char *dataFileSkeletonOrEvent, + const char *dataFileStub) { + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_dsp_memory_type_id dspEventMemType; + t_bool bindable; + t_cm_error error; + t_component_instance *client, *server; + t_elfdescription *elfhandleSkeletonOrEvent = NULL; + t_elfdescription *elfhandleStub = NULL; + + OSAL_LOCK_API(); + + /* + * Load Elf File + */ + if(dataFileSkeletonOrEvent != NULL && + (error = cm_ELF_CheckFile( + dataFileSkeletonOrEvent, + TRUE, + &elfhandleSkeletonOrEvent)) != CM_OK) + goto out; + if(dataFileStub != NULL && + (error = cm_ELF_CheckFile( + dataFileStub, + TRUE, + &elfhandleStub)) != CM_OK) + goto out; + + client = cm_lookupComponent(clientInstance); + server = cm_lookupComponent(serverInstance); + // Check invalid binding + if((error = cm_checkValidBinding(client, requiredItfClientName, + server, providedItfServerName, + &itfRequire, &itfProvide, &bindable)) != CM_OK) + goto out; + + switch(eventMemType) + { + case CM_MM_MPC_TCM24_X: + dspEventMemType = INTERNAL_XRAM24; + break; + case CM_MM_MPC_ESRAM24: + dspEventMemType = ESRAM_EXT24; + break; + case CM_MM_MPC_SDRAM24: + dspEventMemType = SDRAM_EXT24; + break; + default: + error = CM_INVALID_PARAMETER; + goto out; + } + + // Check if we really need to bind + if(bindable) + { + // Create the binding and bind it to the client (or all sub-components clients ....) + if (itfRequire.client->Template->dspId != itfProvide.server->Template->dspId) + { + if ((error = cm_EEM_ForceWakeup(itfRequire.client->Template->dspId)) != CM_OK) + goto out; + if ((error = cm_EEM_ForceWakeup(itfProvide.server->Template->dspId)) != CM_OK) + { + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + goto out; + } + + // This is a distribute communication + error = cm_bindInterfaceDistributed( + &itfRequire, + &itfProvide, + fifosize, + dspEventMemType, + elfhandleSkeletonOrEvent, + elfhandleStub); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + cm_EEM_AllowSleep(itfProvide.server->Template->dspId); + } + else + { + if ((error = cm_EEM_ForceWakeup(itfRequire.client->Template->dspId)) != CM_OK) + goto out; + + // This is a acynchronous communication + error = cm_bindInterfaceAsynchronous( + &itfRequire, + &itfProvide, + fifosize, + dspEventMemType, + elfhandleSkeletonOrEvent); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + } + } + + cm_registerSingletonBinding(client, &itfRequire, &itfProvide, clientId); + +out: + cm_ELF_CloseFile(TRUE, elfhandleSkeletonOrEvent); + cm_ELF_CloseFile(TRUE, elfhandleStub); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentAsynchronous( + const t_cm_instance_handle instance, + const char* requiredItfClientName, + t_nmf_client_id clientId) { + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_bf_info_ID bfInfoID; + t_cm_error error; + t_component_instance *client; + + OSAL_LOCK_API(); + + client = cm_lookupComponent(instance); + // Sanity check + if((error = cm_checkValidUnbinding(client, requiredItfClientName, + &itfRequire, &itfProvide)) != CM_OK) + goto out; + + bfInfoID = itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfoID; + + // Check if we really need to unbind + if(cm_unregisterSingletonBinding(client, &itfRequire, &itfProvide, clientId)) + { + // Check if this is a Asynchronous binding + if(bfInfoID == BF_DSP2DSP) + { + t_nmf_core_id clientDsp = itfRequire.client->Template->dspId; + t_nmf_core_id serverDsp = itfProvide.server->Template->dspId; + + (void)cm_EEM_ForceWakeup(clientDsp); + (void)cm_EEM_ForceWakeup(serverDsp); + + cm_unbindInterfaceDistributed( + &itfRequire, + (t_mpc2mpc_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + + cm_EEM_AllowSleep(clientDsp); + cm_EEM_AllowSleep(serverDsp); + + error = CM_OK; + } + else if(bfInfoID == BF_ASYNCHRONOUS) + { + t_nmf_core_id clientDsp = itfRequire.client->Template->dspId; + + (void)cm_EEM_ForceWakeup(clientDsp); + + cm_unbindInterfaceAsynchronous( + &itfRequire, + (t_async_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo); + + cm_EEM_AllowSleep(clientDsp); + + error = CM_OK; + } + else + error = CM_ILLEGAL_UNBINDING; + } + + out: + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_BindComponentFromCMCore( + const t_cm_instance_handle server, + const char* providedItfServerName, + t_uint32 fifosize, + t_cm_mpc_memory_type eventMemType, + t_cm_bf_host2mpc_handle *bfHost2mpcHdl, + t_nmf_client_id clientId, + const char *dataFileSkeleton) { + t_interface_provide_description itfProvide; + t_dsp_memory_type_id dspEventMemType; + t_cm_error error; + t_component_instance* component; + t_host2mpc_bf_info *bfInfo; + t_elfdescription *elfhandleSkeleton = NULL; + + OSAL_LOCK_API(); + + /* + * Load Elf File + */ + if(dataFileSkeleton != NULL && + (error = cm_ELF_CheckFile( + dataFileSkeleton, + TRUE, + &elfhandleSkeleton)) != CM_OK) + goto out; + + component = cm_lookupComponent(server); + // Check server validity + if((error = cm_checkValidServer(component, providedItfServerName, + &itfProvide)) != CM_OK) + goto out; + + if ((error = cm_EEM_ForceWakeup(itfProvide.server->Template->dspId)) != CM_OK) + goto out; + + switch(eventMemType) + { + case CM_MM_MPC_TCM24_X: + dspEventMemType = INTERNAL_XRAM24; + break; + case CM_MM_MPC_ESRAM24: + dspEventMemType = ESRAM_EXT24; + break; + case CM_MM_MPC_SDRAM24: + dspEventMemType = SDRAM_EXT24; + break; + default: + error = CM_INVALID_PARAMETER; + goto out; + } + + error = cm_bindComponentFromCMCore(&itfProvide, + fifosize, + dspEventMemType, + elfhandleSkeleton, + &bfInfo); + + cm_EEM_AllowSleep(itfProvide.server->Template->dspId); + +out: + cm_ELF_CloseFile(TRUE, elfhandleSkeleton); + OSAL_UNLOCK_API(); + + if (error == CM_OK) { + bfInfo->clientId = clientId; + OSAL_LOCK_COM(); + *bfHost2mpcHdl = cm_addEntry(&Host2MpcBindingTable, bfInfo); + if (*bfHost2mpcHdl == 0) + error = CM_NO_MORE_MEMORY; + OSAL_UNLOCK_COM(); + + if (error != CM_OK) { + OSAL_LOCK_API(); + (void)cm_EEM_ForceWakeup(itfProvide.server->Template->dspId); + cm_unbindComponentFromCMCore(bfInfo); + cm_EEM_AllowSleep(itfProvide.server->Template->dspId); + OSAL_UNLOCK_API(); + } + } + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentFromCMCore( + t_cm_bf_host2mpc_handle bfHost2mpcId) { + t_host2mpc_bf_info* bfInfo; + t_nmf_core_id coreId; + + OSAL_LOCK_COM(); + bfInfo = cm_lookupEntry(&Host2MpcBindingTable, bfHost2mpcId); + if (bfInfo) + cm_delEntry(&Host2MpcBindingTable, bfHost2mpcId & INDEX_MASK); + OSAL_UNLOCK_COM(); + if (NULL == bfInfo) + return CM_INVALID_PARAMETER; + + OSAL_LOCK_API(); + + // Check if this is a DSP to Host binding + //if(bfInfo->id != BF_HOST2DSP) + // return CM_ILLEGAL_UNBINDING; + coreId = bfInfo->dspskeleton.skelInstance->Template->dspId; + + (void)cm_EEM_ForceWakeup(coreId); + + cm_unbindComponentFromCMCore(bfInfo); + + cm_EEM_AllowSleep(coreId); + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_BindComponentToCMCore( + const t_cm_instance_handle instance, + const char *requiredItfClientName, + t_uint32 fifosize, + t_nmf_mpc2host_handle upLayerThis, + const char *dataFileStub, + t_cm_bf_mpc2host_handle *mpc2hostId, + t_nmf_client_id clientId) { + t_interface_require_description itfRequire; + t_bool bindable; + t_cm_error error; + t_component_instance* client; + t_elfdescription *elfhandleStub = NULL; + + OSAL_LOCK_API(); + + /* + * Load Elf File + */ + if(dataFileStub != NULL && + (error = cm_ELF_CheckFile( + dataFileStub, + TRUE, + &elfhandleStub)) != CM_OK) + goto out; + + client = cm_lookupComponent(instance); + // Check invalid binding + if((error = cm_checkValidClient(client, requiredItfClientName, + &itfRequire, &bindable)) != CM_OK) + goto out; + + // Check if we really need to bind + if(bindable) + { + if ((error = cm_EEM_ForceWakeup(itfRequire.client->Template->dspId)) != CM_OK) + goto out; + + error = cm_bindComponentToCMCore( + &itfRequire, + fifosize, + upLayerThis, + elfhandleStub, + (t_mpc2host_bf_info**)mpc2hostId); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + } + + cm_registerSingletonBinding(client, &itfRequire, NULL, clientId); + +out: + cm_ELF_CloseFile(TRUE, elfhandleStub); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentToCMCore( + const t_cm_instance_handle instance, + const char *requiredItfClientName, + t_nmf_mpc2host_handle *upLayerThis, + t_nmf_client_id clientId) { + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_cm_error error; + t_mpc2host_bf_info *bfInfo; + t_component_instance* client; + + OSAL_LOCK_API(); + + client = cm_lookupComponent(instance); + // Sanity check + if((error = cm_checkValidUnbinding(client, requiredItfClientName, + &itfRequire, &itfProvide)) != CM_OK) + goto out; + + // Check if this is a DSP to Host binding + if(itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfoID != BF_DSP2HOST) + { + error = CM_ILLEGAL_UNBINDING; + goto out; + } + + bfInfo = (t_mpc2host_bf_info*)itfRequire.client->interfaceReferences[itfRequire.requireIndex][itfRequire.collectionIndex].bfInfo; + + // Get client information + *upLayerThis = bfInfo->context; + + // Check if we really need to unbind + if(cm_unregisterSingletonBinding(client, &itfRequire, &itfProvide, clientId)) + { + (void)cm_EEM_ForceWakeup(itfRequire.client->Template->dspId); + + cm_unbindComponentToCMCore(&itfRequire, bfInfo); + + cm_EEM_AllowSleep(itfRequire.client->Template->dspId); + + error = CM_OK; + } +out: + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_event_params_handle CM_ENGINE_AllocEvent(t_cm_bf_host2mpc_handle host2mpcId) { + t_host2mpc_bf_info* bfInfo; + t_event_params_handle eventHandle; + + OSAL_LOCK_COM(); + bfInfo = cm_lookupEntry(&Host2MpcBindingTable, host2mpcId); + if (NULL == bfInfo) { + OSAL_UNLOCK_COM(); + return NULL; + } + + if(bfInfo->dspskeleton.skelInstance->interfaceReferences[0][0].instance->state != STATE_RUNNABLE) { + ERROR("CM_COMPONENT_NOT_STARTED: Call interface before start component %s<%s>\n", + bfInfo->dspskeleton.skelInstance->pathname, + bfInfo->dspskeleton.skelInstance->Template->name, 0, 0, 0, 0); + } + + eventHandle = cm_AllocEvent(bfInfo->fifo); + + OSAL_UNLOCK_COM(); + + return eventHandle; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_PushEvent(t_cm_bf_host2mpc_handle host2mpcId, t_event_params_handle h, t_uint32 methodIndex) { + t_host2mpc_bf_info* bfInfo; + t_cm_error error; + + OSAL_LOCK_COM(); + bfInfo = cm_lookupEntry(&Host2MpcBindingTable, host2mpcId); + if (NULL == bfInfo) { + OSAL_UNLOCK_COM(); + return CM_INVALID_PARAMETER; + } + error = cm_PushEvent(bfInfo->fifo, h, methodIndex); + OSAL_UNLOCK_COM(); + + return error; +} + +PUBLIC EXPORT_SHARED void CM_ENGINE_AcknowledgeEvent(t_cm_bf_mpc2host_handle mpc2hostId) { + t_mpc2host_bf_info* bfInfo = (t_mpc2host_bf_info*)mpc2hostId; + + //t_dsp2host_bf_info* bfInfo = (t_host2mpc_bf_info*)mpc2hostId; + OSAL_LOCK_COM(); + cm_AcknowledgeEvent(bfInfo->fifo); + OSAL_UNLOCK_COM(); +} + +/* + * Get a reference on a given attribute of a given component + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_ReadComponentAttribute( + const t_cm_instance_handle instance, + const char* attrName, + t_uint24 *attrValue) +{ + t_cm_error error; + t_component_instance* component; + + OSAL_LOCK_API(); + + component = cm_lookupComponent(instance); + if (NULL == component) + error = CM_INVALID_COMPONENT_HANDLE; + else + { + if ((error = cm_EEM_ForceWakeup(component->Template->dspId)) != CM_OK) + goto out; + + // t_uint24 -> t_uint32 possible since we know it same size + error = cm_readAttribute(component, attrName, (t_uint32*)attrValue); + + cm_EEM_AllowSleep(component->Template->dspId); + } + +out: + OSAL_UNLOCK_API(); + return error; +} + +/* + * Get a reference on a given attribute of a given component + */ + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_WriteComponentAttribute( + const t_cm_instance_handle instance, + const char* attrName, + t_uint24 attrValue) +{ + t_cm_error error; + t_component_instance* component; + + OSAL_LOCK_API(); + + component = cm_lookupComponent(instance); + if (NULL == component) + error = CM_INVALID_COMPONENT_HANDLE; + else + { + if ((error = cm_EEM_ForceWakeup(component->Template->dspId)) != CM_OK) + goto out; + + //t_uint24 -> t_uint32 possible since we know it same size + error = cm_writeAttribute(component, attrName, attrValue); + + cm_EEM_AllowSleep(component->Template->dspId); + } + +out: + OSAL_UNLOCK_API(); + return error; +} + +/*=============================================================================== + * Introspection API + *===============================================================================*/ +/* + * Component + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentListHeader( + const t_nmf_client_id client, + t_cm_instance_handle *headerComponent) { + t_uint32 i; + + OSAL_LOCK_API(); + + *headerComponent = 0; + for (i=0; i < ComponentTable.idxMax; i++) { + if ((componentEntry(i) != NULL) && + (componentEntry(i)->Template->classe != FIRMWARE) && + (domainDesc[componentEntry(i)->domainId].client == client)) { + *headerComponent = ENTRY2HANDLE(componentEntry(i), i);; + break; + } + } + + OSAL_UNLOCK_API(); + + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentListNext( + const t_nmf_client_id client, + const t_cm_instance_handle prevComponent, + t_cm_instance_handle *nextComponent){ + t_cm_error error; + t_uint32 i = prevComponent & INDEX_MASK; + + OSAL_LOCK_API(); + + // Sanity check + if ((i >= ComponentTable.idxMax) + || (((unsigned int)componentEntry(i) << INDEX_SHIFT) != (prevComponent & ~INDEX_MASK))) + error = CM_INVALID_COMPONENT_HANDLE; + else { + *nextComponent = 0; + for (i++; i < ComponentTable.idxMax; i++) { + if ((componentEntry(i) != NULL) && + (componentEntry(i)->Template->classe != FIRMWARE) && + (domainDesc[componentEntry(i)->domainId].client == client)) { + *nextComponent = ENTRY2HANDLE(componentEntry(i), i);; + break; + } + } + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentDescription( + const t_cm_instance_handle instance, + char *templateName, + t_uint32 templateNameLength, + t_nmf_core_id *coreId, + char *localName, + t_uint32 localNameLength, + t_nmf_ee_priority *priority) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else { + cm_StringCopy( + templateName, + comp->Template->name, + templateNameLength); + *coreId = comp->Template->dspId; + cm_StringCopy( + localName, + comp->pathname, + localNameLength); + if (priority) + *priority = comp->priority; + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +/* + * Require interface + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterfaceNumber( + const t_cm_instance_handle instance, + t_uint8 *numberRequiredInterfaces) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else { + *numberRequiredInterfaces = comp->Template->requireNumber; + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterface( + const t_cm_instance_handle instance, + const t_uint8 index, + char *itfName, + t_uint32 itfNameLength, + char *itfType, + t_uint32 itfTypeLength, + t_cm_require_state *requireState, + t_sint16 *collectionSize) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else if(index >= comp->Template->requireNumber) { + error = CM_NO_SUCH_REQUIRED_INTERFACE; + } else { + cm_StringCopy( + itfName, + comp->Template->requires[index].name, + itfNameLength); + cm_StringCopy( + itfType, + comp->Template->requires[index].interface->type, + itfTypeLength); + if(comp->Template->requires[index].requireTypes & COLLECTION_REQUIRE) + *collectionSize = comp->Template->requires[index].collectionSize; + else + *collectionSize = -1; + + if(requireState != NULL) { + *requireState = 0; + if(comp->Template->requires[index].requireTypes & COLLECTION_REQUIRE) + *requireState |= CM_REQUIRE_COLLECTION; + if(comp->Template->requires[index].requireTypes & OPTIONAL_REQUIRE) + *requireState |= CM_REQUIRE_OPTIONAL; + if(comp->Template->requires[index].requireTypes & STATIC_REQUIRE) + *requireState |= CM_REQUIRE_STATIC; + } + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterfaceBinding( + const t_cm_instance_handle instance, + const char *itfName, + t_cm_instance_handle *server, + char *serverItfName, + t_uint32 serverItfNameLength) { + t_component_instance *comp; + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if(NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else if ((error = cm_getRequiredInterface(comp, itfName, &itfRequire)) != CM_OK) { + // Check if the requiredItfClientName is required by client component + } else if ((error = cm_lookupInterface(&itfRequire, &itfProvide)) != CM_OK) { + // Check if the requiredItfClientName is required by client component + } else { + if ((t_cm_instance_handle)itfProvide.server == NMF_HOST_COMPONENT + || (t_cm_instance_handle)itfProvide.server == NMF_VOID_COMPONENT) + *server = (t_cm_instance_handle)itfProvide.server; + else + *server = itfProvide.server->instance; + if(*server == NMF_HOST_COMPONENT) { + cm_StringCopy( + serverItfName, + "unknown", + serverItfNameLength); + } else if(*server == NMF_VOID_COMPONENT) { + cm_StringCopy( + serverItfName, + "void", + serverItfNameLength); + } else if(*server != 0) { + cm_StringCopy( + serverItfName, + itfProvide.server->Template->provides[itfProvide.provideIndex].name, + serverItfNameLength); + if(itfProvide.server->Template->provides[itfProvide.provideIndex].provideTypes & COLLECTION_PROVIDE) { + int len = cm_StringLength(serverItfName, serverItfNameLength); + serverItfName[len++] = '['; + if(itfProvide.collectionIndex >= 100) + serverItfName[len++] = '0' + (itfProvide.collectionIndex / 100); + if(itfProvide.collectionIndex >= 10) + serverItfName[len++] = '0' + ((itfProvide.collectionIndex % 100) / 10); + serverItfName[len++] = '0' + (itfProvide.collectionIndex % 10); + serverItfName[len++] = ']'; + serverItfName[len] = 0; + } + } + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +/* + * Provide interface + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentProvidedInterfaceNumber( + const t_cm_instance_handle instance, + t_uint8 *numberProvidedInterfaces) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else { + *numberProvidedInterfaces = comp->Template->provideNumber; + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentProvidedInterface( + const t_cm_instance_handle instance, + const t_uint8 index, + char *itfName, + t_uint32 itfNameLength, + char *itfType, + t_uint32 itfTypeLength, + t_sint16 *collectionSize) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else if(index >= comp->Template->provideNumber) { + error = CM_NO_SUCH_PROVIDED_INTERFACE; + } else { + cm_StringCopy( + itfName, + comp->Template->provides[index].name, + itfNameLength); + cm_StringCopy( + itfType, + comp->Template->provides[index].interface->type, + itfTypeLength); + if(comp->Template->provides[index].provideTypes & COLLECTION_PROVIDE) + *collectionSize = comp->Template->provides[index].collectionSize; + else + *collectionSize = -1; + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +/* + * Component Property + */ +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyNumber( + const t_cm_instance_handle instance, + t_uint8 *numberProperties) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else { + *numberProperties = comp->Template->propertyNumber; + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyName( + const t_cm_instance_handle instance, + const t_uint8 index, + char *propertyName, + t_uint32 propertyNameLength) { + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + // Sanity check + if (NULL == comp) { + error = CM_INVALID_COMPONENT_HANDLE; + } else if(index >= comp->Template->propertyNumber) { + error = CM_NO_SUCH_PROPERTY; + } else { + cm_StringCopy( + propertyName, + comp->Template->properties[index].name, + propertyNameLength); + + error = CM_OK; + } + + OSAL_UNLOCK_API(); + + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyValue( + const t_cm_instance_handle instance, + const char *propertyName, + char *propertyValue, + t_uint32 propertyValueLength) +{ + t_component_instance *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + comp = cm_lookupComponent(instance); + if (NULL == comp) + error = CM_INVALID_COMPONENT_HANDLE; + else + { + error = cm_getComponentProperty( + comp, + propertyName, + propertyValue, + propertyValueLength); + + if(error == CM_NO_SUCH_PROPERTY) + ERROR("CM_NO_SUCH_PROPERTY(%s, %s)\n", comp->pathname, propertyName, 0, 0, 0, 0); + } + + OSAL_UNLOCK_API(); + + return error; +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/dspevent.c b/drivers/staging/nmf-cm/cm/engine/component/src/dspevent.c new file mode 100644 index 00000000000..0d5e89e0515 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/dspevent.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/inc/cm_type.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/communication/inc/communication.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h> +#include <cm/engine/trace/inc/trace.h> +#include "../inc/dspevent.h" + + +#define DSP_REMOTE_EVENT_SIZE_IN_BYTE (4*DSP_REMOTE_EVENT_SIZE_IN_DSPWORD) +#define DSP_REMOTE_EVENT_NEXT_FIELD_OFFSET 0 +#define DSP_REMOTE_EVENT_REACTION_FIELD_OFFSET 1 +#define DSP_REMOTE_EVENT_THIS_FIELD_OFFSET 2 +#define DSP_REMOTE_EVENT_PRIORITY_FIELD_OFFSET 3 +#define DSP_REMOTE_EVENT_DATA_FIELD_OFFSET 4 + +t_cm_error dspevent_createDspEventFifo( + const t_component_instance *pComp, + const char* nameOfTOP, + t_uint32 fifoNbElem, + t_uint32 fifoElemSizeInWord, + t_dsp_memory_type_id dspEventMemType, + t_memory_handle *pHandle) +{ + t_uint32 dspElementAddr; + t_uint32 *elemAddr32; + int i; + + // Allocate fifo + *pHandle = cm_DM_Alloc(pComp->domainId, dspEventMemType, fifoNbElem*fifoElemSizeInWord, CM_MM_ALIGN_2WORDS, TRUE); + if(*pHandle == INVALID_MEMORY_HANDLE) { + ERROR("CM_NO_MORE_MEMORY: dspevent_createDspEventFifo()\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + cm_DSP_GetDspAddress(*pHandle, &dspElementAddr); + + elemAddr32 = (t_uint32*)cm_DSP_GetHostLogicalAddress(*pHandle); + + LOG_INTERNAL(2, "\n##### FIFO (dsp event): ARM=0x%x DSP=0x%x\n", elemAddr32, dspElementAddr, 0, 0, 0, 0); + + // Read attribute addr (we assume that variable in XRAM) + cm_writeAttribute(pComp, nameOfTOP, dspElementAddr); + + // Initialise the linked list (next...) + for (i = 0; i < fifoNbElem - 1; i++) + { + dspElementAddr += fifoElemSizeInWord; + + /* Write next field */ + *elemAddr32 = dspElementAddr; + /* Write THIS field & priority field */ + *(volatile t_uint64*)&elemAddr32[DSP_REMOTE_EVENT_THIS_FIELD_OFFSET] = + ((t_uint64)pComp->thisAddress | (((t_uint64)pComp->priority) << 32)); + + elemAddr32 += fifoElemSizeInWord; + } + + /* Last element: Write next field */ + *elemAddr32 = 0x0 /* NULL */; + /* Last element: Write THIS field & priority field */ + *(volatile t_uint64*)&elemAddr32[DSP_REMOTE_EVENT_THIS_FIELD_OFFSET] = + ((t_uint64)pComp->thisAddress | (((t_uint64)pComp->priority) << 32)); + + return CM_OK; +} + + + +void dspevent_destroyDspEventFifo(t_memory_handle handle) +{ + (void)cm_DM_Free(handle, TRUE); +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/initializer.c b/drivers/staging/nmf-cm/cm/engine/component/src/initializer.c new file mode 100644 index 00000000000..7f99b710401 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/initializer.c @@ -0,0 +1,383 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/inc/cm_type.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/communication/inc/communication.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h> + +#include <cm/engine/power_mgt/inc/power.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +#include <cm/engine/trace/inc/trace.h> + +#include "../inc/dspevent.h" +#include "../inc/initializer.h" + +// Since now due to semaphore use call is synchrone so we only need a fifo size of three +// (due to updateStack + (InstructionCacheLock or InstructionCacheUnlock)) +#define DEFAULT_INITIALIZER_FIFO_SIZE 3 + +/* private prototype */ +PRIVATE t_cm_error cm_COMP_generic(t_nmf_core_id coreId, t_event_params_handle paramArray, t_uint32 paramNumber, t_uint32 serviceIndex); +PRIVATE void cm_COMP_generatePanic(t_nmf_core_id coreId); + +/* + * This module is tightly coupled with cm_DSP_components one (communication/initializer) + */ +static struct { + t_nmf_fifo_arm_desc* downlinkFifo; + t_nmf_fifo_arm_desc* uplinkFifo; + t_memory_handle dspfifoHandle; + t_nmf_osal_sem_handle fifoSemHandle; + t_uint32 servicePending; // TODO : Use sem counter instead of defining such variable (need to create new OSAL) +} initializerDesc[NB_CORE_IDS]; + +PUBLIC t_cm_error cm_COMP_INIT_Init(t_nmf_core_id coreId) +{ + t_uint32 i; + t_cm_error error; + t_component_instance *ee; + t_dsp_offset sharedVarOffset; + t_interface_provide_description itfProvide; + t_interface_provide* provide; + t_interface_provide_loaded* provideLoaded; + + ee = cm_EEM_getExecutiveEngine(coreId)->instance; + + // Get interface description + if((error = cm_getProvidedInterface(ee, "service", &itfProvide)) != CM_OK) + return error; + provide = &ee->Template->provides[itfProvide.provideIndex]; + provideLoaded = &ee->Template->providesLoaded[itfProvide.provideIndex]; + + + if ((error = dspevent_createDspEventFifo( + ee, "comms/TOP", + DEFAULT_INITIALIZER_FIFO_SIZE, + DSP_REMOTE_EVENT_SIZE_IN_DSPWORD, + INTERNAL_XRAM24, + &initializerDesc[coreId].dspfifoHandle)) != CM_OK) + return error; + + /* create fifo semaphore */ + initializerDesc[coreId].servicePending = 0; + initializerDesc[coreId].fifoSemHandle = OSAL_CreateSemaphore(DEFAULT_INITIALIZER_FIFO_SIZE); + if (initializerDesc[coreId].fifoSemHandle == 0) { + dspevent_destroyDspEventFifo(initializerDesc[coreId].dspfifoHandle); + return CM_NO_MORE_MEMORY; + } + + /* static armTHis initialisation */ + /* + * In the two next fifo_alloc call (1+n) means that we want to manage the hostThis_or_TOP and one method for each params fifos */ + initializerDesc[coreId].downlinkFifo = + fifo_alloc(ARM_CORE_ID, coreId, + INIT_COMPONENT_CMD_SIZE, DEFAULT_INITIALIZER_FIFO_SIZE, + (1+provide->interface->methodNumber), paramsLocation, extendedFieldLocation, cm_DSP_GetState(coreId)->domainEE); + if (initializerDesc[coreId].downlinkFifo == NULL) + { + OSAL_DestroySemaphore(initializerDesc[coreId].fifoSemHandle); + dspevent_destroyDspEventFifo(initializerDesc[coreId].dspfifoHandle); + ERROR("CM_NO_MORE_MEMORY: fifo_alloc() failed in cm_COMP_INIT_Init()\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + initializerDesc[coreId].uplinkFifo = + fifo_alloc(coreId, ARM_CORE_ID, + INIT_COMPONENT_ACK_SIZE, DEFAULT_INITIALIZER_FIFO_SIZE, + (1), paramsLocation, extendedFieldLocation, cm_DSP_GetState(coreId)->domainEE); /* 1 is mandatory to compute internally the indexMask */ + /* this statement is acceptable only written by skilled man ;) */ + /* We don't used bcDescRef, since we assume that we don't need params size */ + if (initializerDesc[coreId].uplinkFifo == NULL) + { + OSAL_DestroySemaphore(initializerDesc[coreId].fifoSemHandle); + fifo_free(initializerDesc[coreId].downlinkFifo); + dspevent_destroyDspEventFifo(initializerDesc[coreId].dspfifoHandle); + ERROR("CM_NO_MORE_MEMORY: fifo_alloc() failed in cm_COMP_INIT_Init()\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + cm_writeAttribute(ee, "comms/FIFOcmd", initializerDesc[coreId].downlinkFifo->dspAdress); + + cm_writeAttribute(ee, "comms/FIFOack", initializerDesc[coreId].uplinkFifo->dspAdress); + + sharedVarOffset = cm_getAttributeMpcAddress(ee, "comms/TOP"); + + /* HOST->DSP ParamsFifo extended fields initialisation */ + fifo_params_setSharedField( + initializerDesc[coreId].downlinkFifo, + 0, + (t_shared_field)sharedVarOffset /* TOP DSP Address */ + ); + for(i=0; i<provide->interface->methodNumber; i++) + { + fifo_params_setSharedField( + initializerDesc[coreId].downlinkFifo, + i + 1, + provideLoaded->indexesLoaded[itfProvide.collectionIndex][i].methodAddresses); + } + + /* DSP->HOST ParamsFifo extended fields initialisation */ + fifo_params_setSharedField( + initializerDesc[coreId].uplinkFifo, + 0, + (t_shared_field)NMF_INTERNAL_USERTHIS + ); + + return CM_OK; +} + + +PUBLIC t_cm_error cm_COMP_CallService( + int serviceIndex, + t_component_instance *pComp, + t_uint32 methodAddress) { + t_cm_error error; + t_uint16 params[INIT_COMPONENT_CMD_SIZE]; + t_bool isSynchronous = (serviceIndex == NMF_CONSTRUCT_SYNC_INDEX || + serviceIndex == NMF_START_SYNC_INDEX || + serviceIndex == NMF_STOP_SYNC_INDEX || + serviceIndex == NMF_DESTROY_INDEX)?TRUE:FALSE; + + params[INIT_COMPONENT_CMD_HANDLE_INDEX] = (t_uint16)((unsigned int)pComp & 0xFFFF); + params[INIT_COMPONENT_CMD_HANDLE_INDEX+1] = (t_uint16)((unsigned int)pComp >> 16); + params[INIT_COMPONENT_CMD_THIS_INDEX] = (t_uint16)(pComp->thisAddress & 0xFFFF); + params[INIT_COMPONENT_CMD_THIS_INDEX+1] = (t_uint16)(pComp->thisAddress >> 16); + params[INIT_COMPONENT_CMD_METHOD_INDEX] = (t_uint16)(methodAddress & 0xFFFF); + params[INIT_COMPONENT_CMD_METHOD_INDEX+1] = (t_uint16)(methodAddress >> 16); + + error = cm_COMP_generic(pComp->Template->dspId, params, sizeof(params) / sizeof(t_uint16), serviceIndex); + + if (isSynchronous == TRUE && error == CM_OK) { + if (OSAL_SEMAPHORE_WAIT_TIMEOUT(semHandle) != SYNC_OK) { + cm_COMP_generatePanic(pComp->Template->dspId); + error = CM_MPC_NOT_RESPONDING; + } + } + + return error; +} + +PUBLIC void cm_COMP_Flush(t_nmf_core_id coreId) { + + if(initializerDesc[coreId].servicePending > 0) + { + t_uint16 params[INIT_COMPONENT_CMD_SIZE]; + t_uint32 methodAddress = cm_EEM_getExecutiveEngine(coreId)->voidAddr; + + // If service still pending on MMDSP side, send a flush command (today, we reuse Destroy to not create new empty service) + // When we receive the result, this mean that we have flushed all previous request. + + params[INIT_COMPONENT_CMD_HANDLE_INDEX] = (t_uint16)(0x0 & 0xFFFF); + params[INIT_COMPONENT_CMD_HANDLE_INDEX+1] = (t_uint16)(0x0 >> 16); + params[INIT_COMPONENT_CMD_THIS_INDEX] = (t_uint16)(0x0 & 0xFFFF); + params[INIT_COMPONENT_CMD_THIS_INDEX+1] = (t_uint16)(0x0 >> 16); + params[INIT_COMPONENT_CMD_METHOD_INDEX] = (t_uint16)(methodAddress & 0xFFFF); + params[INIT_COMPONENT_CMD_METHOD_INDEX+1] = (t_uint16)(methodAddress >> 16); + + if (cm_COMP_generic(coreId, params, sizeof(params) / sizeof(t_uint16), NMF_DESTROY_INDEX) != CM_OK || + OSAL_SEMAPHORE_WAIT_TIMEOUT(semHandle) != SYNC_OK) + { + cm_COMP_generatePanic(coreId); + ERROR("CM_MPC_NOT_RESPONDING: can't call flush service\n", 0, 0, 0, 0, 0, 0); + } + } +} + +PUBLIC void cm_COMP_INIT_Close(t_nmf_core_id coreId) +{ + unsigned int i; + + /* wait for semaphore to be sure it would not be touch later on */ + /* in case of timeout we break and try to clean everythink */ + for(i = 0; i < DEFAULT_INITIALIZER_FIFO_SIZE; i++) { + if (OSAL_SEMAPHORE_WAIT_TIMEOUT(initializerDesc[coreId].fifoSemHandle) != SYNC_OK) + break; + } + + /* destroy semaphore */ + OSAL_DestroySemaphore(initializerDesc[coreId].fifoSemHandle); + + /* Unallocate initializerDesc[index].uplinkFifo */ + /* (who is used in this particular case to store dummy (with no data space (only descriptor)) DSP->HOST params fifo */ + fifo_free(initializerDesc[coreId].uplinkFifo); + + /* Unallocate initializerDesc[index].downlinkFifo */ + fifo_free(initializerDesc[coreId].downlinkFifo); + + /* Unallocate initializerDesc[index].dspfifoHandle */ + dspevent_destroyDspEventFifo(initializerDesc[coreId].dspfifoHandle); +} + +PUBLIC void processAsyncAcknowledge(t_nmf_core_id coreId, t_event_params_handle pParam) +{ + cm_AcknowledgeEvent(initializerDesc[coreId].uplinkFifo); + + initializerDesc[coreId].servicePending--; + OSAL_SemaphorePost(initializerDesc[coreId].fifoSemHandle,1); +} + +PUBLIC void processSyncAcknowledge(t_nmf_core_id coreId, t_event_params_handle pParam) +{ + cm_AcknowledgeEvent(initializerDesc[coreId].uplinkFifo); + + initializerDesc[coreId].servicePending--; + OSAL_SemaphorePost(initializerDesc[coreId].fifoSemHandle,1); + OSAL_SemaphorePost(semHandle,1); +} + +PUBLIC t_cm_error cm_COMP_UpdateStack( + t_nmf_core_id coreId, + t_uint32 stackSize +) +{ + t_uint16 params[2]; + + // Marshall parameter + params[0] = (t_uint16)((unsigned int)stackSize & 0xFFFF); + params[1] = (t_uint16)((unsigned int)stackSize >> 16); + + return cm_COMP_generic(coreId, params, sizeof(params) / sizeof(t_uint16), NMF_UPDATE_STACK); +} + +PUBLIC t_cm_error cm_COMP_ULPForceWakeup( + t_nmf_core_id coreId +) +{ + t_cm_error error; + + error = cm_COMP_generic(coreId, NULL, 0, NMF_ULP_FORCEWAKEUP); + + if (error == CM_OK) { + if (OSAL_SEMAPHORE_WAIT_TIMEOUT(semHandle) != SYNC_OK) { + cm_COMP_generatePanic(coreId); + error = CM_MPC_NOT_RESPONDING; + } + } + + return error; +} + +PUBLIC t_cm_error cm_COMP_ULPAllowSleep( + t_nmf_core_id coreId +) +{ + return cm_COMP_generic(coreId, NULL, 0, NMF_ULP_ALLOWSLEEP); +} + +PUBLIC t_cm_error cm_COMP_InstructionCacheLock( + t_nmf_core_id coreId, + t_uint32 mmdspAddr, + t_uint32 mmdspSize +) +{ + t_uint16 params[4]; + t_uint32 startAddr = cm_DSP_GetState(coreId)->locked_offset; + int way; + + for(way = 1; startAddr < mmdspAddr + mmdspSize; startAddr += MMDSP_CODE_CACHE_WAY_SIZE, way++) + { + if(mmdspAddr < startAddr + MMDSP_CODE_CACHE_WAY_SIZE) + { + t_cm_error error; + + // Marshall parameter + params[0] = (t_uint16)((unsigned int)startAddr & 0xFFFF); + params[1] = (t_uint16)((unsigned int)startAddr >> 16); + params[2] = (t_uint16)((unsigned int)way & 0xFFFF); + params[3] = (t_uint16)((unsigned int)way >> 16); + + if((error = cm_COMP_generic(coreId, params, sizeof(params) / sizeof(t_uint16), NMF_LOCK_CACHE)) != CM_OK) + return error; + } + } + + return CM_OK; +} + +PUBLIC t_cm_error cm_COMP_InstructionCacheUnlock( + t_nmf_core_id coreId, + t_uint32 mmdspAddr, + t_uint32 mmdspSize +) +{ + t_uint16 params[2]; + t_uint32 startAddr = cm_DSP_GetState(coreId)->locked_offset; + int way; + + for(way = 1; startAddr < mmdspAddr + mmdspSize; startAddr += MMDSP_CODE_CACHE_WAY_SIZE, way++) + { + if(mmdspAddr < startAddr + MMDSP_CODE_CACHE_WAY_SIZE) + { + t_cm_error error; + + // Marshall parameter + params[0] = (t_uint16)((unsigned int)way & 0xFFFF); + params[1] = (t_uint16)((unsigned int)way >> 16); + + if((error = cm_COMP_generic(coreId, params, sizeof(params) / sizeof(t_uint16), NMF_UNLOCK_CACHE)) != CM_OK) + return error; + } + } + + return CM_OK; +} + +/* private method */ +PRIVATE t_cm_error cm_COMP_generic( + t_nmf_core_id coreId, + t_event_params_handle paramArray, + t_uint32 paramNumber, + t_uint32 serviceIndex +) +{ + t_event_params_handle _xyuv_data; + t_cm_error error; + t_uint32 i; + + // wait for an event in fifo + if (OSAL_SEMAPHORE_WAIT_TIMEOUT(initializerDesc[coreId].fifoSemHandle) != SYNC_OK) { + cm_COMP_generatePanic(coreId); + return CM_MPC_NOT_RESPONDING; + } + + + // AllocEvent + if((_xyuv_data = cm_AllocEvent(initializerDesc[coreId].downlinkFifo)) == NULL) + { + ERROR("CM_INTERNAL_FIFO_OVERFLOW: service FIFO full\n", 0, 0, 0, 0, 0, 0); + error = CM_INTERNAL_FIFO_OVERFLOW; + goto unlock; + } + + // Copy param + for(i=0;i<paramNumber;i++) + _xyuv_data[i] = paramArray[i]; + + OSAL_LOCK_COM(); + + // Send Command + error = cm_PushEventTrace(initializerDesc[coreId].downlinkFifo, _xyuv_data, serviceIndex,0); + if(error == CM_OK) + initializerDesc[coreId].servicePending++; + +unlock: + OSAL_UNLOCK_COM(); + + return error; +} + +PRIVATE void cm_COMP_generatePanic(t_nmf_core_id coreId) +{ + const t_dsp_desc* pDspDesc = cm_DSP_GetState(coreId); + + if (pDspDesc->state != MPC_STATE_PANIC) { + cm_DSP_SetStatePanic(coreId); + OSAL_GeneratePanic(coreId, 0); + } +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/instantiater.c b/drivers/staging/nmf-cm/cm/engine/component/src/instantiater.c new file mode 100644 index 00000000000..92c28b63171 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/instantiater.c @@ -0,0 +1,829 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/component/inc/bind.h> +#include <cm/engine/component/inc/initializer.h> + +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/configuration/inc/configuration_status.h> + +#include <cm/engine/dsp/inc/dsp.h> + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/trace/inc/xtitrace.h> + +#include <cm/engine/memory/inc/domain.h> + +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/utils/inc/mem.h> +#include <cm/engine/utils/inc/convert.h> + +#include <cm/engine/power_mgt/inc/power.h> + + +t_nmf_table ComponentTable; /**< list (table) of components */ + +static t_uint32 cm_getMaxStackValue(t_component_instance *pComponent); +static t_uint16 getNumberOfInstance(t_component_instance* component); +static t_uint16 getNumberOfStart(t_component_instance* component); + + +t_cm_error cm_COMP_Init(void) { + t_cm_error error; + error = cm_initTable(&ComponentTable); + if (error == CM_OK) + error = cm_initTable(&Host2MpcBindingTable); + return error; +} + +void cm_COMP_Destroy(void) { + cm_destroyTable(&ComponentTable); + cm_destroyTable(&Host2MpcBindingTable); +} + +/** cm_addComponent - Add an internal handler to the list + * + * 1. Increase the size of the list if it's full + * 2. Search an empty entry + * 3. Add the element to the list + * 4. Compute and return the "user handle" (= t_cm_instance_handle) + */ +static t_cm_instance_handle cm_addComponent(t_component_instance *comp) +{ + OSAL_DisableServiceMessages(); + comp->instance = cm_addEntry(&ComponentTable, comp); + OSAL_EnableServiceMessages(); + + return comp->instance; +} + +/** cm_delComponent - remove the given component from the list + * + * 1. Check if the handle is valid + * 2. Search the entry and free it + */ +static void cm_delComponent(t_component_instance *comp) +{ + if (comp == NULL) + return; + + OSAL_DisableServiceMessages(); + cm_delEntry(&ComponentTable, comp->instance & INDEX_MASK); + OSAL_EnableServiceMessages(); +} + +/** cm_lookupComponent - search the component corresponding to + * the component instance. + * + * 1. Check if the instance is valid + * 2. Return a pointer to the component + */ +t_component_instance *cm_lookupComponent(const t_cm_instance_handle hdl) +{ + return cm_lookupEntry(&ComponentTable, hdl); +} + +static void cm_DestroyComponentMemory(t_component_instance *component) +{ + int i; + + /* + * Remove instance from list + */ + cm_delComponent(component); + + /* + * Destroy instance + */ + { + struct t_client_of_singleton* cur = component->clientOfSingleton; + + for( ; cur != NULL ; ) + { + struct t_client_of_singleton* tmp = cur; + cur = cur->next; + + OSAL_Free(tmp); + } + } + + for(i = 0; i < component->Template->requireNumber; i++) + { + OSAL_Free(component->interfaceReferences[i]); + } + + cm_StringRelease(component->pathname); + + cm_ELF_FreeInstance(component->Template->dspId, component->Template->memories, component->memories); + + cm_unloadComponent(component->Template); + OSAL_Free(component); +} + +/** + * Non-Require: + * - MMDSP could be sleep (Since we access it only through HSEM) + */ +void cm_delayedDestroyComponent(t_component_instance *component) { + int i; + + if (osal_debug_ops.component_destroy) + osal_debug_ops.component_destroy(component); + + /* + * Remove component from load map here + */ + cm_DSPABI_RemoveLoadMap( + component->domainId, + component->Template->name, + component->memories, + component->pathname, + component); + + // Generate XTI/STM trace + cm_TRC_traceLoadMap(TRACE_COMPONENT_COMMAND_REMOVE, component); + + /* + * disconnect interrupt handler if needed + */ + for(i = 0; i < component->Template->provideNumber; i++) + { + if(component->Template->provides[i].interruptLine) + { + cm_unbindInterfaceStaticInterrupt(component->Template->dspId, component->Template->provides[i].interruptLine); + } + } + + /* + * Update dsp stack size if needed + */ + if (component->Template->minStackSize > MIN_STACK_SIZE) + { + if (cm_EEM_isStackUpdateNeed(component->Template->dspId, component->priority, FALSE, component->Template->minStackSize)) + { + t_uint32 newStackValue; + t_uint32 maxComponentStackSize; + + maxComponentStackSize = cm_getMaxStackValue(component); + cm_EEM_UpdateStack(component->Template->dspId, component->priority, maxComponentStackSize, &newStackValue); + if (cm_DSP_GetState(component->Template->dspId)->state == MPC_STATE_BOOTED) + cm_COMP_UpdateStack(component->Template->dspId, newStackValue); + } + } + + cm_DestroyComponentMemory(component); +} + +/** + * Pre-Require: + * - MMDSP wakeup (when loading in TCM) + */ +t_cm_error cm_instantiateComponent(const char* templateName, + t_cm_domain_id domainId, + t_nmf_ee_priority priority, + const char* pathName, + t_elfdescription *elfhandle, + t_component_instance** refcomponent) +{ + t_nmf_core_id coreId = cm_DM_GetDomainCoreId(domainId); + t_dup_char templateNameDup; + t_component_template* template; + t_component_instance *component; + /* coverity[var_decl] */ + t_cm_error error; + int i, j, k; + + *refcomponent = NULL; + + templateNameDup = cm_StringDuplicate(templateName); + if(templateNameDup == NULL) + return CM_NO_MORE_MEMORY; + + /* + * Lookup in template list + */ + template = cm_lookupTemplate(coreId, templateNameDup); + if(template != NULL) + { + if(template->classe == SINGLETON) + { + // Return same handle for singleton component + struct t_client_of_singleton* cl; + + cm_StringRelease(templateNameDup); + + cl = cm_getClientOfSingleton(template->singletonIfAvaliable, TRUE, domainDesc[domainId].client); + if(cl == NULL) + return CM_NO_MORE_MEMORY; + cl->numberOfInstance++; + + *refcomponent = template->singletonIfAvaliable; + LOG_INTERNAL(1, "##### Singleton : New handle of %s/%x component on %s provItf=%d#####\n", + template->singletonIfAvaliable->pathname, template->singletonIfAvaliable, cm_getDspName(coreId), + template->singletonIfAvaliable->providedItfUsedCount, 0, 0); + return CM_OK; + } + } + + // Get the dataFile (identity if already pass as parameter) + if((elfhandle = cm_REP_getComponentFile(templateNameDup, elfhandle)) == NULL) + { + cm_StringRelease(templateNameDup); + return CM_COMPONENT_NOT_FOUND; + } + + // Load template + if((error = cm_loadComponent(templateNameDup, domainId, elfhandle, &template)) != CM_OK) + { + cm_StringRelease(templateNameDup); + return error; + } + + // templateNameDup no more used, release it + cm_StringRelease(templateNameDup); + + // Allocated component + component = (t_component_instance*)OSAL_Alloc_Zero( + sizeof(t_component_instance) + + sizeof(t_interface_reference*) * template->requireNumber); + if(component == NULL) + { + cm_unloadComponent(template); + return CM_NO_MORE_MEMORY; + } + + component->interfaceReferences = (t_interface_reference**)((char*)component + sizeof(t_component_instance)); + component->Template = template; + + /* + * Update linked list + */ + if (cm_addComponent(component) == 0) { + cm_unloadComponent(template); + OSAL_Free(component); + return CM_NO_MORE_MEMORY; + } + + // NOTE: From here use cm_DestroyComponentMemory + + component->pathname = pathName ? cm_StringDuplicate(pathName) : cm_StringReference(anonymousDup); + if(component->pathname == NULL) + { + cm_DestroyComponentMemory(component); + return CM_NO_MORE_MEMORY; + } + + LOG_INTERNAL(1, "\n##### Instantiate %s/%x (%s) component on %s at priority %d #####\n", component->pathname, component, template->name, cm_getDspName(coreId), priority, 0); + + if((error = cm_ELF_LoadInstance(domainId, elfhandle, template->memories, component->memories, template->classe == SINGLETON)) != CM_OK) + { + cm_DestroyComponentMemory(component); + return error; + } + + if((error = cm_ELF_relocatePrivateSegments( + component->memories, + elfhandle, + template)) != CM_OK) + { + cm_DestroyComponentMemory(component); + return error; + } + + cm_ELF_FlushInstance(coreId, template->memories, component->memories); + + /* + * Create a new component instance + */ + component->priority = priority; + component->thisAddress = 0xFFFFFFFF; + component->state = STATE_NONE; + + if(component->Template->classe == SINGLETON) + { // Return same handle for singleton component + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, TRUE, domainDesc[domainId].client); + if(cl == NULL) + { + cm_DestroyComponentMemory(component); + return CM_NO_MORE_MEMORY; + } + + cl->numberOfInstance = 1; + template->singletonIfAvaliable = component; + if (cm_DM_GetDomainCoreId(domainId) == SVA_CORE_ID) + component->domainId = DEFAULT_SVA_DOMAIN; + else + component->domainId = DEFAULT_SIA_DOMAIN; + } else { + component->domainId = domainId; + } + + if(component->memories[template->thisMemory->id] != INVALID_MEMORY_HANDLE) + cm_DSP_GetDspAddress(component->memories[template->thisMemory->id], &component->thisAddress); + else { + // In case of singleton or component without data + component->thisAddress = 0; + } + + /* + * Create empty required interfaces array and set method interface to Panic + */ + for(i = 0; i < template->requireNumber; i++) // For all required interface + { + component->interfaceReferences[i] = + (t_interface_reference*)OSAL_Alloc_Zero(sizeof(t_interface_reference) * template->requires[i].collectionSize); + if(component->interfaceReferences[i] == NULL) + { + cm_DestroyComponentMemory(component); + return CM_NO_MORE_MEMORY; + } + + for(j = 0; j < template->requires[i].collectionSize; j++) // ... and for each index in collection (set THIS&method for each client) + { + component->interfaceReferences[i][j].instance = NULL; + component->interfaceReferences[i][j].bfInfoID = BF_SYNCHRONOUS; // Just to memorize no Binding component used and unbind ToVoid happy ;-). + + if(template->classe == COMPONENT && template->requires[i].indexes != NULL) + { + // If component, fill THIS to itself to detect UNBINDED panic with rigth DSP + t_interface_require_index *requireindex = &template->requires[i].indexes[j]; + for(k = 0; k < requireindex->numberOfClient; k++) + { + t_uint32 *hostAddr; + + hostAddr = (t_uint32*)( + cm_DSP_GetHostLogicalAddress( + component->memories[requireindex->memories[k].memory->id]) + + requireindex->memories[k].offset * requireindex->memories[k].memory->memEntSize); + *hostAddr++ = (t_uint32)component->thisAddress; + } + } + } + } + + /* + * Inform debugger about new component + */ + if ((error = cm_DSPABI_AddLoadMap( + domainId, + template->name, + component->pathname, + component->memories, + component)) != CM_OK) + { + cm_DestroyComponentMemory(component); + return error; + } + + // Generate XTI/STM trace + cm_TRC_traceLoadMap(TRACE_COMPONENT_COMMAND_ADD, component); + + // NOTE: From here use cm_delayedDestroyComponent + + /* + * Relocate interrupt if this is an interrupt + */ + for(i = 0; i < template->provideNumber; i++) + { + if(template->provides[i].interruptLine) + { + if ((error = cm_bindInterfaceStaticInterrupt(coreId, + template->provides[i].interruptLine, + component, + template->provides[i].name)) != CM_OK) + { + cm_delayedDestroyComponent(component); + return error; + } + } + } + + /* + * For first instance of a component; Update ee stack size if needed + */ + if(template->classe != FIRMWARE && template->numberOfInstance == 1 && template->minStackSize > MIN_STACK_SIZE) + { + t_uint32 newStackValue; + + if (cm_EEM_isStackUpdateNeed(template->dspId, priority, TRUE, template->minStackSize)) + { + error = cm_EEM_UpdateStack(template->dspId, priority, template->minStackSize, &newStackValue); + if (error != CM_OK) + { + cm_delayedDestroyComponent(component); + return error; + } + cm_COMP_UpdateStack(template->dspId, newStackValue); + } + } + + + /* + * For component or first instance + */ + if(template->classe == SINGLETON || template->classe == COMPONENT) + { + /* + * Call init function generated by the compiler (one per .elf) + */ + LOG_INTERNAL(2, "constructor call(s) <%s>\n", template->name, 0, 0, 0, 0, 0); + if (cm_DSP_GetState(template->dspId)->state != MPC_STATE_BOOTED) + { + cm_delayedDestroyComponent(component); + return CM_MPC_NOT_RESPONDING; + } + else if ((error = cm_COMP_CallService( + (priority > cm_EEM_getExecutiveEngine(coreId)->instance->priority)?NMF_CONSTRUCT_SYNC_INDEX:NMF_CONSTRUCT_INDEX, + component, + template->LCCConstructAddress)) != CM_OK) + { + if (error == CM_MPC_NOT_RESPONDING) + ERROR("CM_MPC_NOT_RESPONDING: can't call constructor '%s'\n", component->pathname, 0, 0, 0, 0, 0); + cm_delayedDestroyComponent(component); + return error; + } + } + else + { + /* be sure everything is write into memory, not required elsewhere since will be done by cm_COMP_CallService */ + OSAL_mb(); + } + + // For firmware; Directly switch to STARTED state, don't need to start it + if (template->classe == FIRMWARE) + component->state = STATE_RUNNABLE; + else + component->state = STATE_STOPPED; + + if (osal_debug_ops.component_create) + osal_debug_ops.component_create(component); + + *refcomponent = component; + return CM_OK; +} + +struct t_client_of_singleton* cm_getClientOfSingleton(t_component_instance* component, t_bool createdIfNotExist, t_nmf_client_id clientId) +{ + struct t_client_of_singleton* cur = component->clientOfSingleton; + + for( ; cur != NULL ; cur = cur->next) + { + if(cur->clientId == clientId) + { + return cur; + } + } + + //if(createdIfNotExist) + { + cur = OSAL_Alloc(sizeof(struct t_client_of_singleton)); + if(cur != NULL) + { + cur->clientId = clientId; + cur->next = component->clientOfSingleton; + cur->numberOfBind = 0; + cur->numberOfInstance= 0; + cur->numberOfStart = 0; + component->clientOfSingleton = cur; + } + } + return cur; +} + +/** + * Non-Require: + * - MMDSP could be sleep (Since we access it only through HSEM) + */ +t_cm_error cm_startComponent(t_component_instance* component, t_nmf_client_id clientId) +{ + t_cm_error error; + char value[MAX_PROPERTY_VALUE_LENGTH]; + int i; + + /* + * Special code for SINGLETON handling + */ + if(component->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, FALSE, clientId); + if(cl != NULL) + cl->numberOfStart++; + // A singleton could be started twice, thus start it only if first client starter + if(getNumberOfStart(component) > 1) + return CM_OK; + + // Fall through and start really the singleton. + } + + if(component->state == STATE_RUNNABLE) + return CM_COMPONENT_NOT_STOPPED; + + // CM_ASSERT component->state == STATE_STOPPED + + /* + * Check that all required binding have been binded! + */ + for(i = 0; i < component->Template->requireNumber; i++) + { + int nb = component->Template->requires[i].collectionSize, j; + for(j = 0; j < nb; j++) + { + if(component->interfaceReferences[i][j].instance == NULL && + (component->Template->requires[i].requireTypes & (OPTIONAL_REQUIRE | INTRINSEC_REQUIRE)) == 0) + { + ERROR("CM_REQUIRE_INTERFACE_UNBINDED: Required interface '%s'.'%s' binded\n", component->pathname, component->Template->requires[i].name, 0, 0, 0, 0); + return CM_REQUIRE_INTERFACE_UNBINDED; + } + } + } + + component->state = STATE_RUNNABLE; + + /* + * Power on, HW resources if required + */ + if(cm_getComponentProperty( + component, + "hardware", + value, + sizeof(value)) == CM_OK) + { + error = cm_PWR_EnableMPC(MPC_PWR_HWIP, component->Template->dspId); + if(error != CM_OK) + return error; + } + + /* + * Call starter if available + */ + if(component->Template->LCCStartAddress != 0) + { + if (cm_DSP_GetState(component->Template->dspId)->state != MPC_STATE_BOOTED) + { + return CM_MPC_NOT_RESPONDING; + } + else if ((error = cm_COMP_CallService( + (component->priority > cm_EEM_getExecutiveEngine(component->Template->dspId)->instance->priority)?NMF_START_SYNC_INDEX:NMF_START_INDEX, + component, + component->Template->LCCStartAddress)) != CM_OK) + { + if (error == CM_MPC_NOT_RESPONDING) + ERROR("CM_MPC_NOT_RESPONDING: can't call starter '%s'\n", component->pathname, 0, 0, 0, 0, 0); + return error; + } + } + + return CM_OK; +} + +/** + * Non-Require: + * - MMDSP could be sleep (Since we access it only through HSEM) + */ +t_cm_error cm_stopComponent(t_component_instance* component, t_nmf_client_id clientId) +{ + char value[MAX_PROPERTY_VALUE_LENGTH]; + t_cm_error error = CM_OK; + t_bool isHwProperty; + + /* + * Special code for SINGLETON handling + */ + if(component->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, FALSE, clientId); + if(cl != NULL) + cl->numberOfStart--; + // A singleton could be started twice, thus stop it only if no more client starter + if(getNumberOfStart(component) > 0) + return CM_OK; + + // Fall through and stop really the singleton. + } + + /* + * Component life cycle sanity check + */ + if(component->state == STATE_STOPPED) + return CM_COMPONENT_NOT_STARTED; + + // CM_ASSERT component->state == STATE_RUNNABLE + component->state = STATE_STOPPED; + + isHwProperty = (cm_getComponentProperty( + component, + "hardware", + value, + sizeof(value)) == CM_OK); + + if (cm_DSP_GetState(component->Template->dspId)->state != MPC_STATE_BOOTED) + { + error = CM_MPC_NOT_RESPONDING; + } + else + { + /* + * Call stopper if available + */ + if(component->Template->LCCStopAddress != 0) + { + if ((error = cm_COMP_CallService( + isHwProperty ? NMF_STOP_SYNC_INDEX : NMF_STOP_INDEX, + component, + component->Template->LCCStopAddress)) != CM_OK) + { + if (error == CM_MPC_NOT_RESPONDING) + ERROR("CM_MPC_NOT_RESPONDING: can't call stopper '%s'\n", component->pathname, 0, 0, 0, 0, 0); + } + } + } + + /* + * Power on, HW resources if required + */ + if(isHwProperty) + { + cm_PWR_DisableMPC(MPC_PWR_HWIP, component->Template->dspId); + } + + return error; +} + +t_cm_error cm_destroyInstance(t_component_instance* component, t_destroy_state forceDestroy) +{ + int i, j; + + LOG_INTERNAL(1, "\n##### Destroy %s/%x (%s) component on %s #####\n", + component->pathname, component, component->Template->name, cm_getDspName(component->Template->dspId), 0, 0); + + /* + * Component life cycle sanity check; do it only when destroying last reference. + */ + if(forceDestroy == DESTROY_NORMAL) + { + if (component->state == STATE_RUNNABLE) + return CM_COMPONENT_NOT_STOPPED; + + // CM_ASSERT component->state == STATE_STOPPED + + // Check that all required binding have been unbound! + for(i = 0; i < component->Template->requireNumber; i++) + { + int nb = component->Template->requires[i].collectionSize; + for(j = 0; j < nb; j++) + { + if(component->interfaceReferences[i][j].instance != NULL) + { + ERROR("CM_COMPONENT_NOT_UNBINDED: Required interface %s/%x.%s still binded\n", + component->pathname, component, component->Template->requires[i].name, 0, 0, 0); + return CM_COMPONENT_NOT_UNBINDED; + } + } + } + + // Check that all provided bindings have been unbound! + if (component->providedItfUsedCount != 0) + { + unsigned idx; + + ERROR("CM_COMPONENT_NOT_UNBINDED: Still %d binding to %s/%x provided interface\n", + component->providedItfUsedCount, component->pathname, component, 0, 0, 0); + + /* Find which interface is still bound to gracefully print an error message */ + for (idx=0; idx<ComponentTable.idxMax; idx++) + { + if ((componentEntry(idx) == NULL) || (componentEntry(idx) == component)) + continue; + for (i = 0; i < componentEntry(idx)->Template->requireNumber; i++) + { + for (j = 0; j < componentEntry(idx)->Template->requires[i].collectionSize; j++) + { + if(componentEntry(idx)->interfaceReferences[i][j].instance == component + && component->Template->provides[componentEntry(idx)->interfaceReferences[i][j].provideIndex].interruptLine == 0) + { + ERROR(" -> %s/%x.%s still used by %s/%x.%s\n", + component->pathname, component, + component->Template->provides[componentEntry(idx)->interfaceReferences[i][j].provideIndex].name, + componentEntry(idx)->pathname, + componentEntry(idx), + componentEntry(idx)->Template->requires[i].name); + } + } + } + } + + return CM_COMPONENT_NOT_UNBINDED; + } + } + + // Sanity check finished, here, we will do the JOB whatever error + + if (cm_DSP_GetState(component->Template->dspId)->state == MPC_STATE_BOOTED) + { + /* + * Call destroy if available + */ + /* Call the destructor only if we don't want to force the destruction */ + if(forceDestroy != DESTROY_WITHOUT_CHECK_CALL && component->Template->LCCDestroyAddress != 0) + { + if (cm_COMP_CallService( + NMF_DESTROY_INDEX, + component, + component->Template->LCCDestroyAddress) != CM_OK) + { + ERROR("CM_MPC_NOT_RESPONDING: can't call destroy '%s'\n", component->pathname, 0, 0, 0, 0, 0); + } + } + else + { + cm_COMP_Flush(component->Template->dspId); + } + } + + cm_delayedDestroyComponent(component); + + return CM_OK; +} + +/** + * Pre-Require: + * - MMDSP wakeup (when accessing loadmap) + */ +t_cm_error cm_destroyInstanceForClient(t_component_instance* component, t_destroy_state forceDestroy, t_nmf_client_id clientId) +{ + /* + * Special code for SINGLETON handling + */ + if(component->Template->classe == SINGLETON) + { + struct t_client_of_singleton* cl = cm_getClientOfSingleton(component, FALSE, clientId); + int nbinstance; + if(cl != NULL) + cl->numberOfInstance--; + + // A singleton could be instantiate twice, thus destroy it only if no more client constructor + nbinstance = getNumberOfInstance(component); + if(nbinstance > 0) + { + LOG_INTERNAL(1, "##### Singleton : Delete handle of %s/%x (%s) component on %s [%d] provItf=%d #####\n", + component->pathname, component, component->Template->name, cm_getDspName(component->Template->dspId), + nbinstance, component->providedItfUsedCount); + return CM_OK; + } + + // Fall through + } + + return cm_destroyInstance(component, forceDestroy); +} + + +static t_uint32 cm_getMaxStackValue(t_component_instance *pComponent) +{ + t_nmf_executive_engine_id executiveEngineId = cm_EEM_getExecutiveEngine(pComponent->Template->dspId)->executiveEngineId; + t_uint32 res = MIN_STACK_SIZE; + unsigned int i; + + for (i=0; i<ComponentTable.idxMax; i++) + { + if ((componentEntry(i) != NULL) && + (componentEntry(i) != pComponent) && + (pComponent->Template->dspId == componentEntry(i)->Template->dspId) && + (executiveEngineId == SYNCHRONOUS_EXECUTIVE_ENGINE || componentEntry(i)->priority == pComponent->priority)) + { + if (componentEntry(i)->Template->minStackSize > res) + res = componentEntry(i)->Template->minStackSize; + } + } + + return res; +} + +static t_uint16 getNumberOfInstance(t_component_instance* component) +{ + t_uint16 instanceNumber = 0; + struct t_client_of_singleton* cur = component->clientOfSingleton; + + for( ; cur != NULL ; cur = cur->next) + { + instanceNumber += cur->numberOfInstance; + } + + return instanceNumber; +} + +static t_uint16 getNumberOfStart(t_component_instance* component) +{ + t_uint16 startNumber = 0; + struct t_client_of_singleton* cur = component->clientOfSingleton; + + for( ; cur != NULL ; cur = cur->next) + { + startNumber += cur->numberOfStart; + } + + return startNumber; +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/introspection.c b/drivers/staging/nmf-cm/cm/engine/component/src/introspection.c new file mode 100644 index 00000000000..7e2f7cd65d0 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/introspection.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/string.h> + +/* + * + */ +t_cm_error cm_getComponentProperty( + const t_component_instance *component, + const char *propName, + char value[MAX_PROPERTY_VALUE_LENGTH], + t_uint32 valueLength){ + t_component_template* template = component->Template; + int i; + + for(i = 0; i < template->propertyNumber; i++) { + if(cm_StringCompare(template->properties[i].name, propName, MAX_PROPERTY_NAME_LENGTH) == 0) { + cm_StringCopy( + value, + template->properties[i].value, + valueLength); + return CM_OK; + } + } + + return CM_NO_SUCH_PROPERTY; +} + +/** + * + */ +static t_attribute* cm_getAttributeDescriptor( + const t_component_instance *component, + const char *attrName) +{ + int i; + + for(i = 0; i < component->Template->attributeNumber; i++) + { + if(cm_StringCompare(component->Template->attributes[i].name, attrName, MAX_ATTRIBUTE_NAME_LENGTH) == 0) + { + return &component->Template->attributes[i]; + } + } + + return NULL; +} + +t_dsp_address cm_getAttributeMpcAddress( + const t_component_instance *component, + const char *attrName) +{ + t_attribute* attribute; + t_uint32 dspAddress; + + if((attribute = cm_getAttributeDescriptor(component, attrName)) == NULL) + return 0x0; + + cm_DSP_GetDspAddress(component->memories[attribute->memory.memory->id], &dspAddress); + + return (dspAddress + + attribute->memory.offset); +} + +t_cm_logical_address cm_getAttributeHostAddr( + const t_component_instance *component, + const char *attrName) +{ + t_attribute* attribute; + + if((attribute = cm_getAttributeDescriptor(component, attrName)) == NULL) + return 0x0; + + // TODO JPF: component->Template->attributes[i].memory.offset could be converted in byte during load + return cm_DSP_GetHostLogicalAddress(component->memories[attribute->memory.memory->id]) + + attribute->memory.offset * attribute->memory.memory->memEntSize; +} + + +t_cm_error cm_readAttribute( + const t_component_instance* component, + const char* attrName, + t_uint32* value) +{ + t_attribute* attribute; + t_cm_logical_address hostAddr; + + if((attribute = cm_getAttributeDescriptor(component, attrName)) == NULL) + { + ERROR("CM_NO_SUCH_ATTRIBUTE(%s, %s)\n", component->pathname, attrName, 0, 0, 0, 0); + return CM_NO_SUCH_ATTRIBUTE; + } + + // TODO JPF: component->Template->attributes[i].memory.offset could be converted in byte during load + hostAddr = cm_DSP_GetHostLogicalAddress(component->memories[attribute->memory.memory->id]) + + attribute->memory.offset * attribute->memory.memory->memEntSize; + + if(attribute->memory.memory->memEntSize != 2) + *value = *((t_uint32 *)hostAddr) & ~MASK_BYTE3; + else + *value = *((t_uint16 *)hostAddr); + + LOG_INTERNAL(3, "cm_readAttribute: [%s:%s, %x]=%x\n", + component->pathname, attrName, hostAddr, *value, 0, 0); + + return CM_OK; +} + +t_uint32 cm_readAttributeNoError( + const t_component_instance* component, + const char* attrName) +{ + t_uint32 value; + + if(cm_readAttribute(component, attrName, &value) != CM_OK) + value = 0; + + return value; +} + +t_cm_error cm_writeAttribute( + const t_component_instance* component, + const char* attrName, + t_uint32 value) +{ + t_attribute* attribute; + t_cm_logical_address hostAddr; + + if((attribute = cm_getAttributeDescriptor(component, attrName)) == NULL) + { + ERROR("CM_NO_SUCH_ATTRIBUTE(%s, %s)\n", component->pathname, attrName, 0, 0, 0, 0); + return CM_NO_SUCH_ATTRIBUTE; + } + + // TODO JPF: component->Template->attributes[i].memory.offset could be converted in byte during load + hostAddr = cm_DSP_GetHostLogicalAddress(component->memories[attribute->memory.memory->id]) + + attribute->memory.offset * attribute->memory.memory->memEntSize; + + if(attribute->memory.memory->memEntSize != 2) + *((t_uint32 *)hostAddr) = value & ~MASK_BYTE3; + else + *((t_uint16 *)hostAddr) = value; + + /* be sure attribute is write into memory */ + OSAL_mb(); + + LOG_INTERNAL(3, "cm_writeAttribute: [%s:%s, %x]=%x\n", + component->pathname, attrName, hostAddr, value, 0, 0); + + return CM_OK; +} + + +/** + * + */ +t_dsp_address cm_getFunction( + const t_component_instance* component, + const char* interfaceName, + const char* methodName) +{ + t_interface_provide_description itfProvide; + t_interface_provide* provide; + t_interface_provide_loaded* provideLoaded; + t_cm_error error; + int i; + + // Get interface description + if((error = cm_getProvidedInterface(component, interfaceName, &itfProvide)) != CM_OK) + return error; + + provide = &component->Template->provides[itfProvide.provideIndex]; + provideLoaded = &component->Template->providesLoaded[itfProvide.provideIndex]; + + for(i = 0; i < provide->interface->methodNumber; i++) + { + if(cm_StringCompare(provide->interface->methodNames[i], methodName, MAX_INTERFACE_METHOD_NAME_LENGTH) == 0) + { + return provideLoaded->indexesLoaded[itfProvide.collectionIndex][i].methodAddresses; + } + } + + return 0x0; +} + +/** + * + */ +PRIVATE t_uint8 compareItfName(const char* simplename, const char* complexname, int *collectionIndex) { + int i; + + // Search if simplename is a prefix of complexname ?? + for(i = 0; simplename[i] != 0; i++) { + if(simplename[i] != complexname[i]) + return 1; // NO + } + + // YES + if(complexname[i] == '[') { + // This is a collection + int value = 0; + i++; + if(complexname[i] < '0' || complexname[i] > '9') { + return 1; + } + for(; complexname[i] >= '0' && complexname[i] <= '9'; i++) { + value = value * 10 + (complexname[i] - '0'); + } + if(complexname[i++] != ']') + return 1; + *collectionIndex = value; + } else + *collectionIndex = -1; + + if(complexname[i] != 0) { + // Complexe name has not been fully parsed -> different name + return 1; + } + + return 0; +} + + +/** + * + */ +PUBLIC t_cm_error cm_getProvidedInterface(const t_component_instance* server, + const char* itfName, + t_interface_provide_description *itfProvide){ + int i; + + for(i = 0; i < server->Template->provideNumber; i++) + { + int collectionIndex; + if(compareItfName(server->Template->provides[i].name, itfName, &collectionIndex) == 0) + { + t_interface_provide *provide = &server->Template->provides[i]; + if(collectionIndex >= 0) + { + if(! (provide->provideTypes & COLLECTION_PROVIDE)) { + ERROR("CM_NO_SUCH_PROVIDED_INTERFACE(%s, %s)\n", + server->pathname, itfName, 0, 0, 0, 0); + goto out; + } + if(collectionIndex >= provide->collectionSize) { + ERROR("CM_NO_SUCH_PROVIDED_INTERFACE(%s, %s): out of range [0..%d[\n", + server->pathname, itfName, provide->collectionSize, + 0, 0, 0); + goto out; + } + } + else + { + if(provide->provideTypes & COLLECTION_PROVIDE) { + ERROR("CM_NO_SUCH_PROVIDED_INTERFACE(%s, %s): interface is a collection [0..%d[\n", + server->pathname, itfName, provide->collectionSize, + 0, 0, 0); + goto out; + } + collectionIndex = 0; + } + itfProvide->provideIndex = i; + itfProvide->server = server; + itfProvide->collectionIndex = collectionIndex; + itfProvide->origName = itfName; + return CM_OK; + } + } + + ERROR("CM_NO_SUCH_PROVIDED_INTERFACE(%s, %s)\n", server->pathname, itfName, 0, 0, 0, 0); +out: + itfProvide->provideIndex = 0; + itfProvide->server = NULL; + itfProvide->collectionIndex = 0; + itfProvide->origName = NULL; + return CM_NO_SUCH_PROVIDED_INTERFACE; +} + +/** + * + */ +t_cm_error cm_getRequiredInterface(const t_component_instance* client, + const char* itfName, + t_interface_require_description *itfRequire){ + int i; + + for(i = 0; i < client->Template->requireNumber; i++) { + int collectionIndex; + if(compareItfName(client->Template->requires[i].name, itfName, &collectionIndex) == 0) { + t_interface_require *require = &client->Template->requires[i]; + if(collectionIndex >= 0) { + if(! (require->requireTypes & COLLECTION_REQUIRE)) { + ERROR("CM_NO_SUCH_REQUIRED_INTERFACE(%s, %s)\n", + client->pathname, itfName, 0, 0, 0, 0); + return CM_NO_SUCH_REQUIRED_INTERFACE; + } + if(collectionIndex >= require->collectionSize) { + ERROR("CM_NO_SUCH_REQUIRED_INTERFACE(%s, %s): out of range [0..%d[\n", + client->pathname, itfName, require->collectionSize, + 0, 0, 0); + return CM_NO_SUCH_REQUIRED_INTERFACE; + } + } else { + if(require->requireTypes & COLLECTION_REQUIRE) { + ERROR("CM_NO_SUCH_REQUIRED_INTERFACE(%s, %s): interface is a collection [0..%d[\n", + client->pathname, itfName, require->collectionSize, + 0, 0, 0); + return CM_NO_SUCH_REQUIRED_INTERFACE; + } + collectionIndex = 0; + } + itfRequire->client = client; + itfRequire->requireIndex = i; + itfRequire->collectionIndex = collectionIndex; + itfRequire->origName = itfName; + return CM_OK; + } + } + + ERROR("CM_NO_SUCH_REQUIRED_INTERFACE(%s, %s)\n", client->pathname, itfName, 0, 0, 0, 0); + return CM_NO_SUCH_REQUIRED_INTERFACE; +} diff --git a/drivers/staging/nmf-cm/cm/engine/component/src/loader.c b/drivers/staging/nmf-cm/cm/engine/component/src/loader.c new file mode 100644 index 00000000000..3d81e8308f9 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/loader.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/component/inc/bind.h> + +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/convert.h> + +void START(void); +void END(char*); + +#undef NHASH +#define NHASH 79 //Use a prime number! +#define MULT 17 + +static t_component_template *templates[NB_CORE_IDS][NHASH]; + +static unsigned int templateHash(const char *str) +{ + unsigned int h = 0; + for(; *str; str++) + h = MULT * h + *str; + return h % NHASH; +} + +static void templateAdd(t_component_template *template) +{ + unsigned int h = templateHash(template->name); + + if(templates[template->dspId][h] != NULL) + templates[template->dspId][h]->prev = template; + template->next = templates[template->dspId][h]; + template->prev = NULL; + templates[template->dspId][h] = template; +} + +static void templateRemove(t_component_template *template) +{ + unsigned int h = templateHash(template->name); + + if(template->prev != NULL) + template->prev->next = template->next; + if(template->next != NULL) + template->next->prev = template->prev; + if(template == templates[template->dspId][h]) + templates[template->dspId][h] = template->next; +} + + +t_component_template* cm_lookupTemplate(t_nmf_core_id dspId, t_dup_char str) +{ + t_component_template *template; + + for(template = templates[dspId][templateHash(str)]; template != NULL; template = template->next) + { + if(str == template->name) + return template; + } + + return NULL; +} + +t_bool cm_isComponentOnCoreId(t_nmf_core_id coreId) { + t_uint32 i; + + for(i = 0; i < NHASH; i++) + { + if ((templates[coreId][i] != NULL) + && (templates[coreId][i]->classe != FIRMWARE)) // Skip firmware + return TRUE; + } + + return FALSE; +} + + +static t_dsp_address MemoryToDspAdress(t_component_template *template, t_memory_reference *memory) +{ + if(memory->memory == NULL) + return (t_dsp_address)memory->offset; + else + { + t_dsp_address address; + + cm_DSP_GetDspAddress(template->memories[memory->memory->id], &address); + + return (t_dsp_address)(address + memory->offset); + } +} + +/* + * Method callback + */ +t_uint32 cm_resolvSymbol( + void* context, + t_uint32 type, + t_dup_char symbolName, + char* reloc_addr) +{ + t_component_template *template = (t_component_template*)context; + t_component_instance* ee = cm_EEM_getExecutiveEngine(template->dspId)->instance; + int i, j; + + // Search if this method is provided by EE and resolve it directly + for(i = 0; i < ee->Template->provideNumber; i++) + { + t_interface_provide* provide = &ee->Template->provides[i]; + t_interface_provide_loaded* provideLoaded = &ee->Template->providesLoaded[i]; + + for(j = 0; j < provide->interface->methodNumber; j++) + { + if(provide->interface->methodNames[j] == symbolName) + { + return provideLoaded->indexesLoaded[0][j].methodAddresses; // Here we assume no collection provided !! + } + } + } + + // Lookup if the method is statically required, ands delay relocation when bind occur + for(i = 0; i < template->requireNumber; i++) + { + if((template->requires[i].requireTypes & STATIC_REQUIRE) == 0) + continue; + + for(j = 0; j < template->requires[i].interface->methodNumber; j++) + { + if(template->requires[i].interface->methodNames[j] == symbolName) + { + t_function_relocation* delayedRelocation = (t_function_relocation*)OSAL_Alloc(sizeof(t_function_relocation)); + if(delayedRelocation == NULL) + return 0xFFFFFFFE; + + delayedRelocation->type = type; + delayedRelocation->symbol_name = cm_StringReference(symbolName); + delayedRelocation->reloc_addr = reloc_addr; + delayedRelocation->next = template->delayedRelocation; + template->delayedRelocation = delayedRelocation; + + return 0xFFFFFFFF; + } + } + } + + //Symbol not found + return 0x0; +} + +/* + * Template Management + */ +t_cm_error cm_loadComponent( + t_dup_char templateName, + t_cm_domain_id domainId, + t_elfdescription* elfhandle, + t_component_template **reftemplate) +{ + t_nmf_core_id coreId = cm_DM_GetDomainCoreId(domainId); + t_cm_error error; + int i, j, k; + + /* + * Allocate new component template if first instance + */ + if(*reftemplate == NULL) + { + t_component_template *template; + + LOG_INTERNAL(1, "\n##### Load template %s on %s #####\n", templateName, cm_getDspName(coreId), 0, 0, 0, 0); + + /* + * Sanity check + */ + if(elfhandle->foundedTemplateName != templateName) + { + ERROR("CM_INVALID_ELF_FILE: template name %s != %s\n", templateName, elfhandle->foundedTemplateName, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } + + // Alloc & Reset variable in order to use unloadComponent either with partial constructed template + *reftemplate = template = (t_component_template*)OSAL_Alloc_Zero(sizeof(t_component_template)); + if(template == NULL) + return CM_NO_MORE_MEMORY; + template->name = cm_StringReference(elfhandle->foundedTemplateName); + + // Get information from elfhandle + template->descriptionAssociatedWithTemplate = elfhandle->temporaryDescription; + template->requireNumber = elfhandle->requireNumber; + template->requires = elfhandle->requires; + template->attributeNumber = elfhandle->attributeNumber; + template->attributes = elfhandle->attributes; + template->propertyNumber = elfhandle->propertyNumber; + template->properties = elfhandle->properties; + template->provideNumber = elfhandle->provideNumber; + template->provides = elfhandle->provides; + if(template->descriptionAssociatedWithTemplate) + { + elfhandle->requires = NULL; + elfhandle->attributes = NULL; + elfhandle->properties = NULL; + elfhandle->provides = NULL; + } + + // Compute simple information + template->numberOfInstance = 1; + template->dspId = coreId; + LOG_INTERNAL(3, "load<%x> = %s\n", (int)template, template->name, 0, 0, 0, 0); + switch(elfhandle->magicNumber) { + case MAGIC_COMPONENT: + template->classe = COMPONENT; + break; + case MAGIC_SINGLETON: + template->classe = SINGLETON; + break; + case MAGIC_FIRMWARE: + template->classe = FIRMWARE; + break; + } + template->minStackSize = elfhandle->minStackSize; + + /* + * Load shared memory from file + */ + // START(); + if((error = cm_ELF_LoadTemplate(domainId, elfhandle, template->memories, template->classe == SINGLETON)) != CM_OK) + goto out; + MMDSP_serializeMemories(elfhandle->instanceProperty, &template->codeMemory, &template->thisMemory); + // END("cm_ELF_LoadTemplate"); + + /* + * Copy LCC functions information + * Since MMDSP require Constructor & Destructor (for cache flush and debug purpose) to be called + * either if not provided by user for allowing defered breakpoint, we use Void method if not provided. + */ + template->LCCConstructAddress = MemoryToDspAdress(template, &elfhandle->memoryForConstruct); + template->LCCStartAddress = MemoryToDspAdress(template, &elfhandle->memoryForStart); + template->LCCStopAddress = MemoryToDspAdress(template, &elfhandle->memoryForStop); + template->LCCDestroyAddress = MemoryToDspAdress(template, &elfhandle->memoryForDestroy); + if(template->LCCConstructAddress == 0 && template->classe != FIRMWARE) + template->LCCConstructAddress = cm_EEM_getExecutiveEngine(coreId)->voidAddr; + + // Compute provide methodIndex + if(template->provideNumber != 0) + { + template->providesLoaded = + (t_interface_provide_loaded*)OSAL_Alloc_Zero(sizeof(t_interface_provide_loaded) * template->provideNumber); + if(template->providesLoaded == NULL) + goto oom; + + for(i = 0; i < template->provideNumber; i++) + { + template->providesLoaded[i].indexesLoaded = (t_interface_provide_index_loaded**)OSAL_Alloc_Zero( + sizeof(t_interface_provide_index_loaded*) * template->provides[i].collectionSize); + if(template->providesLoaded[i].indexesLoaded == NULL) + goto oom; + + if(template->provides[i].interface->methodNumber != 0) + { + for(j = 0; j < template->provides[i].collectionSize; j++) + { + template->providesLoaded[i].indexesLoaded[j] = (t_interface_provide_index_loaded*)OSAL_Alloc( + sizeof(t_interface_provide_index_loaded) * template->provides[i].interface->methodNumber); + if(template->providesLoaded[i].indexesLoaded[j] == NULL) + goto oom; + + for(k = 0; k < template->provides[i].interface->methodNumber; k++) + { + template->providesLoaded[i].indexesLoaded[j][k].methodAddresses = + MemoryToDspAdress(template, &template->provides[i].indexes[j][k].memory); + + LOG_INTERNAL(2, " [%d, %d] method '%s' @ %x\n", + j, k, template->provides[i].interface->methodNames[k], + template->providesLoaded[i].indexesLoaded[j][k].methodAddresses, 0, 0); + } + + } + } + } + } + + /* + * TODO + + if((error = elfhandle->errorOccured) != CM_OK) + goto out; + */ + + // START(); + if(template->classe != FIRMWARE) + { + if((error = cm_ELF_relocateSharedSegments( + template->memories, + elfhandle, + template)) != CM_OK) + goto out; + } + // END("cm_ELF_relocateSharedSegments"); + + cm_ELF_FlushTemplate(coreId, template->memories); + + templateAdd(template); + + return CM_OK; + oom: + error = CM_NO_MORE_MEMORY; + out: + cm_unloadComponent(template); + return error; + } + else + { + (*reftemplate)->numberOfInstance++; + } + + return CM_OK; +} + +PUBLIC t_cm_error cm_unloadComponent( + t_component_template *template) +{ + /* + * Destroy template if last instance + */ + if(--template->numberOfInstance == 0) { + t_function_relocation* reloc; + + LOG_INTERNAL(3, "unload<%s>\n", template->name, 0, 0, 0, 0, 0); + + templateRemove(template); + + // Free delayedRelocation + reloc = template->delayedRelocation; + while(reloc != NULL) + { + t_function_relocation *tofree = reloc; + reloc = reloc->next; + cm_StringRelease(tofree->symbol_name); + OSAL_Free(tofree); + } + + if(template->providesLoaded != NULL) + { + int i, j; + + for(i = 0; i < template->provideNumber; i++) + { + if(template->providesLoaded[i].indexesLoaded != NULL) + { + for(j = 0; j < template->provides[i].collectionSize; j++) + { + OSAL_Free(template->providesLoaded[i].indexesLoaded[j]); + } + OSAL_Free(template->providesLoaded[i].indexesLoaded); + } + } + + OSAL_Free(template->providesLoaded); + } + + if(template->descriptionAssociatedWithTemplate) + { + cm_ELF_ReleaseDescription( + template->requireNumber, template->requires, + template->attributeNumber, template->attributes, + template->propertyNumber, template->properties, + template->provideNumber, template->provides); + } + + // Free shared memories + cm_ELF_FreeTemplate(template->dspId, template->memories); + + cm_StringRelease(template->name); + + OSAL_Free(template); + } + + return CM_OK; +} + |