diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2011-06-15 16:09:37 +0200 |
---|---|---|
committer | said m bagheri <ebgheri@steludxu2848.(none)> | 2011-06-17 13:42:17 +0200 |
commit | ec939f287c27ea3a326a2988026d393bfeae4fd4 (patch) | |
tree | 31fbef4f7694b8a4a32d8d1fbdc9afbc2d62d102 | |
parent | 9e4e4a91750b5609e5988273e1a059088b6df7a0 (diff) |
ux500: Put NMF/CM driver in kernel source tree
Put all sources from NMF/CM driver
in kernel source tree instead of having a link within Android environment.
u8500 NMF/CM: Use deferrable timer in the DSP-monitor threads
Use deferrable timer in the threads monitoring the DSP load,
to not wake up ARM just for that.
u8500 NMF/CM: update to NMF 2.10.106
- Remove useless (userland only) files
- Fix several ER (Null pointer, issue in multiprocess environment)
u8500 NMF/CM: enable NMF/CM driver by default
Enable the NMF/CM driver in the default config for u8500
instead of relying on Android's makefile.
Signed-off-by: Pierre Peiffer <pierre.peiffer@stericsson.com>
staging: nmf-cm: Remove u8500 v1 support
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
staging: nmf-cm: Adding support for cyclic DMA jobs
NMF-CM gets support for setting up cyclic DMA jobs.
Start/stop of the DMA job will be controlled by the DSP.
ST-Ericsson ID: 338329
Signed-off-by: anneli lundblom <anneli.lundblom@stericsson.com>
u8500 NMF/CM: do not call MMDSP if it is out
Do not do any call to MMDSP if it is not or no more
booted.
Signed-off-by: Pierre Peiffer <pierre.peiffer@stericsson.com>
Fix in moduleparam.h for compilation pb
Signed-off-by: Philippe Langlais <philippe.langlais@linaro.org>
153 files changed, 28837 insertions, 1 deletions
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index 10d8667e5fb..e18179633df 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -222,6 +222,7 @@ CONFIG_DMADEVICES=y CONFIG_STE_DMA40=y CONFIG_STAGING=y CONFIG_U8500_MMIO=y +CONFIG_U8500_CM=y # CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_AUTOFS_FS=m CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 92298414c4a..8d7ebc30e12 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -28,6 +28,17 @@ config U8500_MMIO bool "ST-Ericsson MMIO (Camera) Driver" depends on ARCH_U8500 +config U8500_CM + tristate "U8500 Component Manager driver" + depends on UX500_SOC_DB8500 + help + This is the Component Manager driver. It is part of the + Nomadik Multiprocessing Framework. + + Note: This option allows the kernel developers to build + the driver in kernel to ease there life. By default, this driver + must be built outside this kernel source tree. + config STAGING_EXCLUDE_BUILD bool "Exclude Staging drivers from being built" if STAGING default y diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a0fb3ef3acd..5917ede01fe 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -73,3 +73,4 @@ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_CW1200) += cw1200/ obj-$(CONFIG_U8500_MMIO) += mmio/ +obj-$(CONFIG_U8500_CM) += nmf-cm/ diff --git a/drivers/staging/nmf-cm/Make.config b/drivers/staging/nmf-cm/Make.config new file mode 100644 index 00000000000..ccbc150158b --- /dev/null +++ b/drivers/staging/nmf-cm/Make.config @@ -0,0 +1,8 @@ +# Copyright (C) ST-Ericsson SA 2011. All rights reserved. +# This code is ST-Ericsson proprietary and confidential. +# Any use of the code for whatever purpose is subject to +# specific written permission of ST-Ericsson SA. + +#CM driver file to copy but not to compile +CMENGINESRC_COPY_NO_BUILD = cm/engine/elf/src/elfxx.c + diff --git a/drivers/staging/nmf-cm/Makefile b/drivers/staging/nmf-cm/Makefile new file mode 100644 index 00000000000..82fa97f81d1 --- /dev/null +++ b/drivers/staging/nmf-cm/Makefile @@ -0,0 +1,99 @@ +# +# Copyright (C) ST-Ericsson SA 2010 +# Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. +# License terms: GNU General Public License (GPL), version 2. +# + +# +# Rules to build kernel modules +# +ifndef MM_MAKEFILES_DIR + + # $(src): current relative dir; $(kbuild-dir): cur absolute dir + ifdef kbuild-dir + SRCDIR = $(realpath $(kbuild-dir)) + else + SRCDIR = $(realpath $(src)) + endif + include $(SRCDIR)/Make.config + ifndef FIXED_CPPFLAGS + # In Android env, we can not depend on files that are out of kernel tree. + # and thus we can't include $(SRCDIR)/../../../../mmenv/SharedARMFlags.mk + # where FIXED_CPPFLAGS is defined. + # So, define FIXED_CPPFLAGS here + FIXED_CPPFLAGS=-D__STN_8500=30 -DLINUX -D__ARM_LINUX + endif + EXTRA_CFLAGS := -I$(SRCDIR) $(FIXED_CPPFLAGS) + EXTRA_CFLAGS += -Wall -Werror + #EXTRA_CFLAGS += -DCM_DEBUG_ALLOC + + # + # CM object files to compile with + # + GENERIC_CM_FILES:=$(shell cd $(SRCDIR); find cm -name "*.c") + GENERIC_CM_FILES := $(filter-out $(CMENGINESRC_COPY_NO_BUILD), $(GENERIC_CM_FILES)) + + CM_OBJS := $(GENERIC_CM_FILES:.c=.o) + CM_OBJS += cmld.o cm_syscall.o osal-kernel.o cm_service.o configuration.o + CM_OBJS += cm_dma.o + + obj-$(CONFIG_U8500_CM) := cm.o + + #Note: build system prepends the $(PWD) directory to these objects paths + cm-objs := $(CM_OBJS) + +else + + # CM module is built in kernel in android env + # or as module otherwise (OSI env, ...) + export CONFIG_U8500_CM ?= m + + ifeq ($(findstring install,$(MAKECMDGOALS)),) + # If not only performing install then include needed files for build + include $(MM_MAKEFILES_DIR)/SharedARMFlags.mk + export FIXED_CPPFLAGS + -include $(MM_MAKEFILES_DIR)/KernelConfig.mk + + ifeq ($(findstring clean,$(MAKECMDGOALS)),) + ifndef KERNEL_BUILD_DIR + $(error KERNEL_BUILD_DIR not defined) + endif + endif + endif + + include $(MM_MAKEFILES_DIR)/SharedConfig.mk + + module: + $(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_BUILD_DIR) \ + M=$(PWD) INSTALL_HEADER_DIR=$(INSTALL_HEADER_DIR) \ + modules + + all: module + $(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_BUILD_DIR) \ + M=$(PWD) INSTALL_HEADER_DIR=$(INSTALL_HEADER_DIR) \ + INSTALL_MOD_PATH=$(PWD)/lib/$(PLATFORM) \ + modules_install + rm -f $(PWD)/lib/$(PLATFORM)/lib/modules/*/modules.* + + # + # Rules to clean and install + # + clean: + @rm -rf $(PLATFORM) $(CM_OBJS) .built-in.o.cmd .cm*o.cmd Module.symvers \ + .tmp_versions modules.order cm.ko cm.o cm.mod.* lib \ + $(foreach f,$(CM_OBJS), $(dir $f).$(notdir $f).cmd) + + realclean: clean + $(foreach platform, \ + $(shell grep property ../../component/component.xml | cut -d\" -f 4), \ + rm -rf $(platform);) + @rm -rf *~ + + install: + $(GEN_LN) -d lib/$(PLATFORM)/lib $(INSTALL_LIB_DIR)/lib + + uninstall: + $(GEN_LN) -r -d lib/$(PLATFORM)/lib $(INSTALL_LIB_DIR)/lib + +endif #ifdef KERNELRELEASE + diff --git a/drivers/staging/nmf-cm/cm/engine/api/channel_engine.h b/drivers/staging/nmf-cm/cm/engine/api/channel_engine.h new file mode 100644 index 00000000000..19353ee7328 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/channel_engine.h @@ -0,0 +1,101 @@ +/* + * 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. + */ +/*! + * \brief Communication Component Manager internal API type. + */ + +#ifndef CHANNEL_ENGINE_H +#define CHANNEL_ENGINE_H + +#include <nmf/inc/channel_type.h> +#include <nmf/inc/service_type.h> +#include <cm/engine/communication/inc/communication_type.h> + +/*! + * \brief Internal channel identification. + * + * Same as t_nmf_channel meaning but this the channel used internaly by + * OS Integration part + * + * \ingroup CM_OS_API + */ +typedef t_uint32 t_os_channel; + +/*! + * \brief Invalid value for os_channel + * + * Invalid value for os channel. + * + * \ingroup CM_OS_API + */ +#define NMF_OS_CHANNEL_INVALID_HANDLE 0xffffffff + +/*! + * \brief Structure used for storing required parameters for Interface Callback + * messages. + * + * This struture is used internally by CM_GetMessage() and CM_ExecuteMessage() as + * the message content in the given buffer. + * + * \ingroup CM_ENGINE_API + */ +typedef struct { + t_nmf_mpc2host_handle THIS; //!< Context of interface implementation + t_uint32 methodIndex; //!< Method index in interface + char params[1]; //!< Is of variable length concretely +} t_interface_data; + +/*! + * \brief Structure used for storing required parameters for Service Callback + * messages. + * + * This struture is used internally by CM_GetMessage() and CM_ExecuteMessage() as + * the message content in the given buffer. + * + * \ingroup CM_ENGINE_API + */ +typedef struct { + t_nmf_service_type type; //!< Type of the service message + t_nmf_service_data data; +} t_service_data; + +typedef enum { + MSG_INTERFACE, + MSG_SERVICE +} t_message_type; + +/*! + * \brief Structure used for storing required parameters for the internal NMF + * messages. + * + * This struture is used internally by CM_GetMessage() and CM_ExecuteMessage() as + * the message content in the given buffer. + * + * \ingroup CM_ENGINE_API + */ +typedef struct { + t_message_type type; //!< Type of the nmf message + union { + t_interface_data itf; + t_service_data srv; + } data; +} t_os_message; + +/*! + * \brief Structure used for storing required parameters for the internal NMF + * messages. + * + * This struture is used internally by CM_GetMessage() and CM_ExecuteMessage() as + * the message content in the given buffer. + * + * \ingroup CM_ENGINE_API + */ +typedef struct { + t_nmf_channel channel; //!< Channel (required to handle service message) + t_os_message osMsg; +} t_nmf_message; + +#endif /* CHANNEL_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/cm_engine.h b/drivers/staging/nmf-cm/cm/engine/api/cm_engine.h new file mode 100644 index 00000000000..0f4c1e4219e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/cm_engine.h @@ -0,0 +1,48 @@ +/* + * 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. + */ +/*! + * \brief CM Engine API. + * + * This file contains the Component Manager Engine API. + */ + +/*! + * \defgroup CM_ENGINE_MODULE CM Engine + */ +/*! + * \defgroup CM_ENGINE_API CM Engine API + * + * \note This API is not for user developers, this API is only an internal API. + * + * \warning All parameters in out from this API means that the parameter is a reference to a data that is complete by the call. + * + * This API is provided by CM Engine and shall be required by driver kernel part. + * \ingroup CM_ENGINE_MODULE + */ + +#ifndef CM_ENGINE_H_ +#define CM_ENGINE_H_ + +#include <cm/engine/api/configuration_engine.h> + +#include <cm/engine/api/component_engine.h> + +#include <cm/engine/api/memory_engine.h> + +#include <cm/engine/api/communication_engine.h> + +#include <cm/engine/api/perfmeter_engine.h> + +#include <cm/engine/api/executive_engine_mgt_engine.h> + +#include <cm/engine/api/repository_mgt_engine.h> + +#include <cm/engine/api/domain_engine.h> + +#include <cm/engine/api/migration_engine.h> + +#endif /*CM_ENGINE_H_*/ + diff --git a/drivers/staging/nmf-cm/cm/engine/api/communication_engine.h b/drivers/staging/nmf-cm/cm/engine/api/communication_engine.h new file mode 100644 index 00000000000..477a66a4002 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/communication_engine.h @@ -0,0 +1,73 @@ +/* + * 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. + */ +/*! + * \brief Communication User Engine API. + * + * This file contains the Communication Engine API for manipulating components. + * + */ +#ifndef COMMUNICATION_ENGINE_H_ +#define COMMUNICATION_ENGINE_H_ + +#include <cm/engine/communication/inc/communication_type.h> + +/*! + * \brief Allocate Event buffer where parameters will be marshalled. + * + * In order to optimize call, this method don't need to be exported to user space, + * but must be used by CM driver. + * + * See \ref HOST2MPC "Host->MPC binding" for seeing an integration example. + * + * \note This method is not called from user space!!! + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_event_params_handle CM_ENGINE_AllocEvent(t_cm_bf_host2mpc_handle host2mpcId); + +/*! + * \brief Push a event in Fifo. + * + * In order to optimize call, this method don't need to be exported to user space, + * but must be used by CM driver. + * + * See \ref HOST2MPC "Host->MPC binding" for seeing an integration example. + * + * \note This method is not called from user space!!! + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_PushEvent(t_cm_bf_host2mpc_handle host2mpcId, t_event_params_handle h, t_uint32 methodIndex); + +/*! + * \brief Push a event in Fifo. + * + * In order to optimize call, this method need to be exported to user space + * and must be implemented by CM driver. + * + * See \ref HOST2MPC "Host->MPC binding" for seeing an integration example. + * + * \note No implementation of this method is provided in kernel CM engine!!! + * + * \ingroup CM_ENGINE_API + */ +PUBLIC t_cm_error CM_ENGINE_PushEventWithSize(t_cm_bf_host2mpc_handle host2mpcId, t_event_params_handle h, t_uint32 size, t_uint32 methodIndex); + +/*! + * \brief Aknowledge a Fifo that the received event has been demarshalled. + * + * In order to optimize call, this method don't need to be exported to user space, + * but must be used by CM driver. + * + * See \ref MPC2HOST "MPC->Host binding" for seeing an integration example. + * + * \note This method is not called from user space!!! + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED void CM_ENGINE_AcknowledgeEvent(t_cm_bf_mpc2host_handle mpc2hostId); + +#endif /*COMMUNICATION_ENGINE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/api/component_engine.h b/drivers/staging/nmf-cm/cm/engine/api/component_engine.h new file mode 100644 index 00000000000..cbd61769597 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/component_engine.h @@ -0,0 +1,403 @@ +/* + * 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. + */ +/*! + * \brief Components Component Manager User Engine API. + * + * This file contains the Component Manager Engine API for manipulating components. + * + */ + +#ifndef COMPONENT_ENGINE_H_ +#define COMPONENT_ENGINE_H_ + +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/component/inc/component_type.h> +#include <cm/engine/communication/inc/communication_type.h> +#include <inc/nmf-limits.h> + +/*! + * \brief Instantiate a new component. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_InstantiateComponent( + const char templateName[MAX_TEMPLATE_NAME_LENGTH], //!< [in] Null terminated string (Max size=\ref MAX_TEMPLATE_NAME_LENGTH) + t_cm_domain_id domainId, //!< [in] Domain + t_nmf_client_id clientId, //!< [in] Client ID (aka PID) + t_nmf_ee_priority priority, //!< [in] Component priority + const char localName[MAX_COMPONENT_NAME_LENGTH], //!< [in] Null terminated string (Max size=\ref MAX_COMPONENT_NAME_LENGTH) + const char *dataFile, //!< [in] Optional reference on file where component is stored + t_cm_instance_handle *component //!< [out] component + ); + +/*! + * \brief Start a component. + * + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_StartComponent( + t_cm_instance_handle component, + t_nmf_client_id clientId); + +/*! + * \brief Stop a component. + * + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_StopComponent( + t_cm_instance_handle component, + t_nmf_client_id clientId); + +/*! + * \brief Destroy a component. + * + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_DestroyComponent( + t_cm_instance_handle component, + t_nmf_client_id clientId); + +/*! + * \brief Stop and destroy all components belonging to the given client. + * + * \param[in] client + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_FlushComponents( + t_nmf_client_id client); + +/*! + * \brief Bind two components together. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_BindComponent( + const t_cm_instance_handle client, //!< + const char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH], //!< Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + const t_cm_instance_handle server, //!< + const char providedItfServerName[MAX_INTERFACE_NAME_LENGTH], //!< Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + t_bool traced, //!< FALSE for synchronous binding, TRUE for traced one + t_nmf_client_id clientId, //!< Client ID + const char *dataFileTrace //!< Component file data in case on traced (Note: could be null if file already in cache) + ); + +/*! + * \brief Unbind a component. + * + * \param[in] client + * \param[in] requiredItfClientName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_UnbindComponent( + const t_cm_instance_handle client, + const char * requiredItfClientName, + t_nmf_client_id clientId); + +/*! + * \brief Bind a component to void (silently ignore a call). + * + * \param[in] client + * \param[in] requiredItfClientName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_BindComponentToVoid( + const t_cm_instance_handle client, + const char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH], + t_nmf_client_id clientId); + +/*! + * \brief Bind two components together in an asynchronous way + * (the components can be on the same MPC or on two different MPC) + * + * \param[in] client + * \param[in] requiredItfClientName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[in] server + * \param[in] providedItfServerName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[in] fifosize + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_BindComponentAsynchronous( + const t_cm_instance_handle client, + const char * requiredItfClientName, + const t_cm_instance_handle server, + const char * providedItfServerName, + t_uint32 fifosize, + t_cm_mpc_memory_type eventMemType, + t_nmf_client_id clientId, + const char *dataFileSkeletonOrEvent, + const char *dataFileStub); + +/*! + * \brief Unbind a component previously binded asynchronously + * + * \param[in] client + * \param[in] requiredItfClientName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentAsynchronous( + const t_cm_instance_handle client, + const char * requiredItfClientName, + t_nmf_client_id clientId); + +/*! + * \brief Bind the Host to a component. + * + * \param[in] server + * \param[in] providedItfServerName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[in] fifosize + * \param[out] host2mpcId + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_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 *host2mpcId, + t_nmf_client_id clientId, + const char *dataFileSkeleton); + +/*! + * \brief Unbind a component from the Host. + * + * \param[in] host2mpcId + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentFromCMCore( + t_cm_bf_host2mpc_handle host2mpcId); + +/*! + * \brief Bind a component to the Host, see \ref CM_ENGINE_BindComponentToCMCore. + * + * See \ref MPC2HOST "MPC->Host binding" for seeing an integration example. + * + * \note This method is not called from CM Proxy, its only there for wrapping purpose!!! + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_BindComponentToCMCore( + const t_cm_instance_handle client, + 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); + +/*! + * \brief Unbind a component to the Host, see \ref CM_ENGINE_UnbindComponentToCMCore. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_UnbindComponentToCMCore( + const t_cm_instance_handle client, + const char *requiredItfClientName, + t_nmf_mpc2host_handle *upLayerThis, + t_nmf_client_id clientId); + +/*! + * \brief Read a value on an attribute exported by a component instance. + * + * \param[in] component + * \param[in] attrName Null terminated string (Max size=\ref MAX_ATTRIBUTE_NAME_LENGTH). + * \param[out] value + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_ReadComponentAttribute( + const t_cm_instance_handle component, + const char* attrName, + t_uint24 *value); + +/*! + * \brief Get the older component. + * + * \param[in] client + * \param[out] headerComponent + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentListHeader( + const t_nmf_client_id client, + t_cm_instance_handle *headerComponent); + +/*! + * \brief Get the next component. + * + * \param[in] client + * \param[in] prevComponent + * \param[out] nextComponent + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentListNext( + const t_nmf_client_id client, + const t_cm_instance_handle prevComponent, + t_cm_instance_handle *nextComponent); + +/*! + * \brief Get a component description + * + * \param[in] component + * \param[in] templateNameLength + * \param[in] localNameLength + * \param[out] templateName Null terminated string (Size=templateNameLength, Max size=\ref MAX_TEMPLATE_NAME_LENGTH). + * \param[out] coreId + * \param[out] localName Null terminated string (Size=localNameLength, Max size=\ref MAX_COMPONENT_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentDescription( + const t_cm_instance_handle component, + char *templateName, + t_uint32 templateNameLength, + t_nmf_core_id *coreId, + char *localName, + t_uint32 localNameLength, + t_nmf_ee_priority *priority); + +/*! + * \brief Get number of interface required by a component. + * + * \param[in] component + * \param[out] numberRequiredInterfaces + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterfaceNumber( + const t_cm_instance_handle component, + t_uint8 *numberRequiredInterfaces); + +/*! + * \brief Return information about required interface. + * + * \param[in] component + * \param[in] index + * \param[in] itfNameLength + * \param[in] itfTypeLength + * \param[out] itfName Null terminated string (Size=itfNameLength, Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[out] itfType Null terminated string (Size=itfTypeLength, Max size=\ref MAX_INTERFACE_TYPE_NAME_LENGTH). + * \param[out] collectionSize + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterface( + const t_cm_instance_handle component, + const t_uint8 index, + char *itfName, + t_uint32 itfNameLength, + char *itfType, + t_uint32 itfTypeLength, + t_cm_require_state *requireState, + t_sint16 *collectionSize); + +/*! + * \brief Get the component binded to a required interface. + * + * \param[in] component + * \param[in] itfName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[in] serverItfNameLength + * \param[out] server + * \param[out] serverItfName Null terminated string (Size=serverItfNameLength, Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentRequiredInterfaceBinding( + const t_cm_instance_handle component, + const char *itfName, + t_cm_instance_handle *server, + char *serverItfName, + t_uint32 serverItfNameLength); + +/*! + * \brief Get number of interface provided by a component. + * + * \param[in] component + * \param[out] numberProvidedInterfaces + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentProvidedInterfaceNumber( + const t_cm_instance_handle component, + t_uint8 *numberProvidedInterfaces); + +/*! + * \brief Return information about provided interface. + * + * \param[in] component + * \param[in] index + * \param[in] itfNameLength + * \param[in] itfTypeLength + * \param[out] itfName Null terminated string (Size=itfNameLength, Max size=\ref MAX_INTERFACE_NAME_LENGTH). + * \param[out] itfType Null terminated string (Size=itfTypeLength, Max size=\ref MAX_INTERFACE_TYPE_NAME_LENGTH). + * \param[out] collectionSize + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentProvidedInterface( + const t_cm_instance_handle component, + const t_uint8 index, + char *itfName, + t_uint32 itfNameLength, + char *itfType, + t_uint32 itfTypeLength, + t_sint16 *collectionSize); + +/*! + * \brief Get number of properties of a component. + * + * \param[in] component + * \param[out] numberProperties + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyNumber( + const t_cm_instance_handle component, + t_uint8 *numberProperties); + +/*! + * \brief Return the name of a property. + * + * \param[in] component + * \param[in] index + * \param[in] propertyNameLength + * \param[out] propertyName Null terminated string (Size=propertyNameLength, Max size=\ref MAX_PROPERTY_NAME_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyName( + const t_cm_instance_handle component, + const t_uint8 index, + char *propertyName, + t_uint32 propertyNameLength); + +/*! + * \brief Get property value of a component. + * + * \param[in] component + * \param[in] propertyName + * \param[in] propertyValueLength + * \param[out] propertyValue Null terminated string (Size=propertyValueLength, Max size=\ref MAX_PROPERTY_VALUE_LENGTH). + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetComponentPropertyValue( + const t_cm_instance_handle component, + const char *propertyName, + char *propertyValue, + t_uint32 propertyValueLength); + +#endif /*COMPONENT_ENGINE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/api/configuration_engine.h b/drivers/staging/nmf-cm/cm/engine/api/configuration_engine.h new file mode 100644 index 00000000000..0336f62265e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/configuration_engine.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +/*! + * \brief Configuration Component Manager User Engine API. + * + * This file contains the Configuration CM Engine API for manipulating CM. + * + */ + +#ifndef CONFIGURATION_ENGINE_H +#define CONFIGURATION_ENGINE_H + +#include <cm/engine/configuration/inc/configuration_type.h> + +/*! + * \brief Dynamically set some debug parameters of the CM + * + * \param[in] aCmdID The command for the parameter to update + * \param[in] aParam The actual value to set for the given command + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_SetMode(t_cm_cmd_id aCmdID, t_sint32 aParam); + +#endif /* CONFIGURATION_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/control/configuration_engine.h b/drivers/staging/nmf-cm/cm/engine/api/control/configuration_engine.h new file mode 100644 index 00000000000..a9543a2af39 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/control/configuration_engine.h @@ -0,0 +1,193 @@ +/* + * 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. + */ +/*! + * \brief Configuration Component Manager User Engine API. + * + * This file contains the Configuration CM Engine API for manipulating CM. + */ + +#ifndef CONTROL_CONFIGURATION_ENGINE_H +#define CONTROL_CONFIGURATION_ENGINE_H + +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/memory/inc/memory_type.h> +#include <cm/engine/communication/inc/communication_type.h> + +/*****************************************************************************************/ +/* Component Manager dedicated (for Configuration purpose) structured types definition */ +/*****************************************************************************************/ + +/*! + * \brief Description of the Nomadik HW mapping configuration + * + * Describe the Nomadik mapping that is to say: + * - the ESRAM memory managed by the CM (The ESRAM address space SHALL BE declared as non cacheable, non bufferable inside host MMU table) + * - the mapping of the System HW Semaphore IP + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef struct { + t_nmf_memory_segment esramDesc; //!< Description of the ESRAM memory mapping into Nomadik SOC + t_cm_system_address hwSemaphoresMappingBaseAddr; //!< Description of the System HW Semaphores IP mapping into Nomadik SOC +} t_nmf_hw_mapping_desc; + +/*! + * @defgroup t_nmf_nomadik_version t_nmf_nomadik_version + * \brief Description of the various supported Nomadik SOC version + * @{ + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef t_uint8 t_nmf_nomadik_version; //!< Fake enumeration type +#define NOMADIK_8810 ((t_nmf_nomadik_version)0) //!< STn8810 chip (any cut) +#define NOMADIK_8815A0 ((t_nmf_nomadik_version)1) //!< STn8815 chip (cut A0) +#define NOMADIK_8815 ((t_nmf_nomadik_version)2) //!< STn8815 chip (other cuts) +#define NOMADIK_8820 ((t_nmf_nomadik_version)3) //!< STn8820 chip +#define NOMADIK_8500 ((t_nmf_nomadik_version)4) //!< STn8500 chip +/* @} */ + +/*! + * \brief Description of the configuration parameters of the Component Manager + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef struct { + t_nmf_coms_location comsLocation; //!< Configure where CM Communications objects are put (see \ref t_nmf_coms_location) +} t_nmf_config_desc; + +/*! + * @defgroup t_nmf_power_ctx t_nmf_power_ctx + * \brief Definition of the CM-engine context + * + * OS integrator uses this value to known the context where the associated OSAL routine is called + * + * @{ + * \ingroup CM_ENGINE_CONTROL_API + */ + +typedef t_uint32 t_nmf_power_ctx; //!< Fake enumeration type +#define PWR_FLUSH_REQ_INTERRUPT_CTX ((t_nmf_power_ctx)0x00) //!< Interrupt context - called by \ref CM_ProcessMpcEvent +#define PWR_FLUSH_REQ_NORMAL_CTX ((t_nmf_power_ctx)0x01) //!< Normal context (CM user call) + +/* @} */ + + +/****************************************************************************************************************/ +/* Component Manager dedicated (for Media Processors Cores Configuration purpose) structured types definition */ +/****************************************************************************************************************/ +/*! + * @defgroup t_nmf_executive_engine_id t_nmf_executive_engine_id + * \brief Identification of the Media Processor Executive Engine to deploy + * @{ + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef t_uint8 t_nmf_executive_engine_id; //!< Fake enumeration type +#define SYNCHRONOUS_EXECUTIVE_ENGINE ((t_nmf_executive_engine_id)0) //!< MPC Synchronous executive engine +#define HYBRID_EXECUTIVE_ENGINE ((t_nmf_executive_engine_id)1) //!< MPC Hybrid synchronous executive engine +/* @} */ + +/*! + * @defgroup t_nmf_semaphore_type_id t_nmf_semaphore_type_id + * \brief Definition of which type semaphore shall be used for the given Media Processor communication mechanism + * @{ + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef t_uint8 t_nmf_semaphore_type_id; //!< Fake enumeration type +#define LOCAL_SEMAPHORES ((t_nmf_semaphore_type_id)0) //!< Embedded MMDSP macrocell semaphore, so CM_ProcessMpcEvent(<coreId>) shall be called under ISR connected to local MMDSP IRQ0 +#define SYSTEM_SEMAPHORES ((t_nmf_semaphore_type_id)1) //!< Shared system HW Semaphores, so CM_ProcessMpcEvent(ARM_CORE_ID) shall be called under ISR connected to shared HW Sem Host IRQ +/* @} */ + + +/*! + * \brief Opaque type for allocator, returned at CM configuration. + */ +typedef t_uint32 t_cfg_allocator_id; + +/********************************************************************************/ +/* Configuration Component Manager API prototypes */ +/********************************************************************************/ + +/*! + * \brief Initialisation part + * + * This routine initialize and configure the Component Manager. + * + * \param[in] pNmfHwMappingDesc hardware mapping description + * \param[in] pNmfConfigDesc NMF (mainly CM) Configuration description + * + * \exception TBD + * \return exception number. + * + * \warning The ESRAM address space SHALL BE declared as non cacheable, non bufferable inside host MMU table + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC t_cm_error CM_ENGINE_Init( + const t_nmf_hw_mapping_desc *pNmfHwMappingDesc, + const t_nmf_config_desc *pNmfConfigDesc + ); + + +/*! + * \brief Media Processor core initialisation part + * + * This routine configures a given Media Processor core + * + * \param[in] coreId Media Processor identifier + * \param[in] executiveEngineId Media Processor Executive Engine identifier + * \param[in] semaphoreTypeId Media Processor semaphores (to be used by communication mechanism) identifier + * \param[in] nbYramBanks is the number of tcm ram banks to reserved for y memory + * \param[in] mediaProcessorMappingBaseAddr Media Processor mapping into host CPU addressable space + * \param[in] commDomain Domain for allocating communication FIFOs + * \param[in] eeDomain Domain for EE instantiation + * \param[in] sdramCodeAllocId Allocator Id for the SDRAM Code segment + * \param[in] sdramDataAllocId Allocator Id for the SDRAM Data segment + * + * \exception TBD + * \return exception number. + * + * \warning The Media Processor mapping address space SHALL BE declared as non cacheable, non bufferable inside host MMU table + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC t_cm_error CM_ENGINE_ConfigureMediaProcessorCore( + t_nmf_core_id coreId, + t_nmf_executive_engine_id executiveEngineId, + t_nmf_semaphore_type_id semaphoreTypeId, + t_uint8 nbYramBanks, + const t_cm_system_address *mediaProcessorMappingBaseAddr, + const t_cm_domain_id eeDomain, + const t_cfg_allocator_id sdramCodeAllocId, + const t_cfg_allocator_id sdramDataAllocId + ); + +/*! + * \brief Configure a memory segment for later + * + * \exception TBD + * \return TBD + * + * \warning + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC t_cm_error CM_ENGINE_AddMpcSdramSegment( + const t_nmf_memory_segment *pDesc, //!< [in] Memory segment description. + t_cfg_allocator_id *allocId, //!< [out] Identifier of the created allocator. + const char *memoryname //!< [in] Memory purpose name + ); + +/********************************************************************************/ +/* Destruction Component Manager API prototypes */ +/********************************************************************************/ +/*! + * \brief Destruction part + * + * This routine destroyes and releases all resources used by the Component Manager. + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC void CM_ENGINE_Destroy(void); + + +#endif /* CONTROL_CONFIGURATION_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/control/control_engine.h b/drivers/staging/nmf-cm/cm/engine/api/control/control_engine.h new file mode 100644 index 00000000000..1d823b27fc1 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/control/control_engine.h @@ -0,0 +1,26 @@ +/* + * 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. + */ +/*! + * \brief CM Engine API. + * + * This file contains the Component Manager Engine API. + */ +/*! + * \defgroup CM_ENGINE_CONTROL_API CM Engine Control API + * \note This API is not for OS integrator, it's only for low level system integration. + * \ingroup CM_ENGINE_MODULE + */ + +#ifndef CM_CONTROL_H_ +#define CM_CONTROL_H_ + +#include <cm/engine/api/control/configuration_engine.h> + +#include <cm/engine/api/control/irq_engine.h> + +#include <cm/engine/api/control/power_engine.h> + +#endif /*CM_CONTROL_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/api/control/irq_engine.h b/drivers/staging/nmf-cm/cm/engine/api/control/irq_engine.h new file mode 100644 index 00000000000..20313f13256 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/control/irq_engine.h @@ -0,0 +1,108 @@ +/* + * 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. + */ +/*! + * \brief NMF API for interrupt handler. + * + * This file contains the Component Manager API for interrupt handler. + */ +#ifndef CONTROL_IRQ_ENGINE_H +#define CONTROL_IRQ_ENGINE_H + +#include <share/inc/nmf.h> +#include <cm/inc/cm_type.h> +#include <nmf/inc/service_type.h> + +/*! + * \brief MPCs -> HOST communication handler + * + * This routine shall be integrated as interrupt handler into the OS + * + * If the given Media Processor Core has been configured (through CM_ConfigureMediaProcessorCore()) as using \ref LOCAL_SEMAPHORES, then + * the NMF communication mechanism will use the embedded MMDSP macrocell semaphore, + * so CM_ProcessMpcEvent(<\e coreId>) shall be called under ISR connected to local MMDSP IRQ0, with the related \e coreId as parameter. + * + * If the given Media Processor Core has been configured (through CM_ConfigureMediaProcessorCore()) as using \ref SYSTEM_SEMAPHORES, then + * the NMF communication mechanism will use the shared system HW Semaphores, + * so CM_ProcessMpcEvent(\ref ARM_CORE_ID) shall be called under ISR connected to shared HW Sem Host IRQ, with \ref ARM_CORE_ID as parameter. + * + * NB: A Media Processor Core belonging to the distribution pool shall be configured with \ref SYSTEM_SEMAPHORES + * + * \see t_nmf_semaphore_type_id description + * + * \param[in] coreId identification of the source of the interrupt + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC IMPORT_SHARED void CM_ProcessMpcEvent(t_nmf_core_id coreId); + +/*! + * \brief Service type + * + * \note We used an enumeration in structure since this description remain inside the kernel + * and we assume that everything in the kernel is compile with same compiler and option. + * + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef enum { // Allowed since i + CM_MPC_SERVICE_NONE = 0, //!< No service found + CM_MPC_SERVICE_PANIC = 1, //!< Panic service found + CM_MPC_SERVICE_PRINT = 2 //!< Print service found +} t_cm_service_type; + //!< Service description type +/*! + * \brief Service description data + * + * + * \ingroup CM_ENGINE_CONTROL_API + */ +typedef struct { + union { + t_nmf_panic_data panic; //!< Panic description + struct { + t_uint32 dspAddress; + t_uint32 value1; + t_uint32 value2; + } print; //!< Printf like description + } u; //!< Union of service description +} t_cm_service_description; + +/*! + * \brief MPC Panic handler + * + * This routine shall be called as interrupt handler into the OS. + * + * So CM_getPanicDescription shall be called under ISR connected to local MMDSP IRQ1, with the related \e coreId as parameter. + * + * \param[in] coreId identification of the source of the interrupt + * \param[out] srcType Pointer on service type + * \param[out] srcDescr Pointer on service description + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_getServiceDescription( + t_nmf_core_id coreId, + t_cm_service_type *srcType, + t_cm_service_description *srcDescr); + +/*! + * \brief Read a null terminated string inside an MPC + * + * This routine could be used to read the MPC string give as parameter during an CM_NMF_SERVICE_PRINT + * + * \param[in] coreId Identification of the code where read string + * \param[in] dspAddress Address of the string in the MPC + * \param[out] buffer Buffer pointer where returning null terminated string + * \param[in] bufferSize Buffer size + * + * \ingroup CM_ENGINE_CONTROL_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ReadMPCString( + t_nmf_core_id coreId, + t_uint32 dspAddress, + char * buffer, + t_uint32 bufferSize); + +#endif /* CONTROL_IRQ_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/domain_engine.h b/drivers/staging/nmf-cm/cm/engine/api/domain_engine.h new file mode 100644 index 00000000000..7cc6f33ed90 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/domain_engine.h @@ -0,0 +1,108 @@ +/* + * 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. + */ +/*! + * \brief Public Component Manager Memory User SYSCALL API. + * + * This file contains the Component Manager SYSCALL API for manipulating domains. + * + */ + +#ifndef __INC_DOMAIN_ENGINE_H +#define __INC_DOMAIN_ENGINE_H + +#include <cm/engine/memory/inc/domain_type.h> + +/*! + * \brief Create a domain. + * + * Create a memory domain for use in the CM for component instantiation and memory allocation. + * + * \param[in] client Id of the client. + * \param[in] domain Description of domain memories. + * \param[out] handle Idetifier of the created domain + * + * \exception CM_INVALID_DOMAIN_DEFINITION + * \exception CM_INTERNAL_DOMAIN_OVERFLOW + * \exception CM_OK + * + * \return Error code. + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_CreateMemoryDomain( + const t_nmf_client_id client, + const t_cm_domain_memory *domain, + t_cm_domain_id *handle + ); + +/*! + * \brief Create a scratch domain. + * + * Create a scratch memory domain. Scratch domains + * are used to perform overlapping allocations. + * + * \param[in] client Id of the client. + * \param[in] parentId Identifier of the parent domain. + * \param[in] domain Description of domain memories. + * \param[out] handle Idetifier of the created domain + * + * \exception CM_INVALID_DOMAIN_DEFINITION + * \exception CM_INTERNAL_DOMAIN_OVERFLOW + * \exception CM_NO_MORE_MEMORY + * \exception CM_OK + * + * \return Error code. + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_CreateMemoryDomainScratch( + const t_nmf_client_id client, + const t_cm_domain_id parentId, + const t_cm_domain_memory *domain, + t_cm_domain_id *handle + ); + +/*! + * \brief Destroy a memory domain. + + * \param[in] handle Domain identifier to destroy. + * + * \exception CM_INVALID_DOMAIN_HANDLE + * \exception CM_OK + * + * \return Error code. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_DestroyMemoryDomain( + t_cm_domain_id handle); + +/*! + * \brief Destroy all domains belonging to a given client. + * + * \param[in] client + * + * \return Error code. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_FlushMemoryDomains( + t_nmf_client_id client); + +/*! + * \brief Retrieve the coreId for a given domain. Utility. + + * \param[in] domainId Domain identifier. + * \param[out] coreId Core identifier. + * + * \exception CM_INVALID_DOMAIN_HANDLE Invalid domain handle + * \exception CM_OK + * + * \return Error code. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetDomainCoreId(const t_cm_domain_id domainId, t_nmf_core_id *coreId); + +#endif /* __INC_DOMAIN_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/executive_engine_mgt_engine.h b/drivers/staging/nmf-cm/cm/engine/api/executive_engine_mgt_engine.h new file mode 100644 index 00000000000..9cb8bc1481b --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/executive_engine_mgt_engine.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +/*! + * \brief CM executive engine management Engine API. + * + * This file contains the Component Manager executive engine management Engine API. + */ +#ifndef CM_EXECUTIVE_ENGINE_MANAGEMENT_ENGINE_H_ +#define CM_EXECUTIVE_ENGINE_MANAGEMENT_ENGINE_H_ + +#include <cm/inc/cm_type.h> + +/*! + * \brief Return executive engine handle for given core + * + * \param[in] coreId The core for which we want executive engine handle. + * \param[out] executiveEngineHandle executive engine instance (null if the executive engine is not loaded) + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetExecutiveEngineHandle( + t_cm_domain_id domainId, + t_cm_instance_handle *executiveEngineHandle); + +#endif /*CM_EXECUTIVE_ENGINE_MANAGEMENT_ENGINE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/api/memory_engine.h b/drivers/staging/nmf-cm/cm/engine/api/memory_engine.h new file mode 100644 index 00000000000..49c0c815669 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/memory_engine.h @@ -0,0 +1,98 @@ +/* + * 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. + */ +/*! + * \brief Public Component Manager Memory User Engine API. + * + * This file contains the Component Manager Engine API for manipulating memory. + * + */ + +#ifndef CM_MEMORY_ENGINE_H_ +#define CM_MEMORY_ENGINE_H_ + +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/memory/inc/memory_type.h> + +/*! + * \brief Allocate memory in a Media Processor Core memory + * + * \param[in] domainId + * \param[in] memType + * \param[in] size + * \param[in] memAlignment + * \param[out] pHandle + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_AllocMpcMemory( + t_cm_domain_id domainId, + t_nmf_client_id clientId, //!< [in] Client ID (aka PID) + t_cm_mpc_memory_type memType, + t_cm_size size, + t_cm_mpc_memory_alignment memAlignment, + t_cm_memory_handle *pHandle + ); + + +/*! + * \brief Free a MPC memory block. + * + * \param[in] handle + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_FreeMpcMemory(t_cm_memory_handle handle); + +/*! + * \brief Get the start address of the MPC memory block seen by the host CPU (physical and logical) + * + * The logical system address returned by this method is valid only in kernel space and the physical + * address is accessible only from kernel space too. + * + * \see OSMem "OS Memory management" for seeing an integration example. + * + * \param[in] handle + * \param[out] pSystemAddress + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemorySystemAddress( + t_cm_memory_handle handle, + t_cm_system_address *pSystemAddress); + +/*! + * \brief Get the start address of the memory block seen by the Media Processor Core + * + * \param[in] handle + * \param[out] pMpcAddress + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemoryMpcAddress( + t_cm_memory_handle handle, + t_uint32 *pMpcAddress); + +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemorySize( + t_cm_memory_handle handle, + t_uint32 *pSize); + +/*! + * \brief Get the memory status for given memory type of a given Media Processor Core + * + * \param[in] domainId + * \param[in] memType + * \param[out] pStatus + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemoryStatus( + t_cm_domain_id domainId, + t_cm_mpc_memory_type memType, + t_cm_allocator_status *pStatus); + + +#endif /* CM_MEMORY_ENGINE_H_ */ + diff --git a/drivers/staging/nmf-cm/cm/engine/api/migration_engine.h b/drivers/staging/nmf-cm/cm/engine/api/migration_engine.h new file mode 100644 index 00000000000..77a266d4459 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/migration_engine.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +#ifndef CM_MIGRATION_ENGINE_H +#define CM_MIGRATION_ENGINE_H + +#include <cm/inc/cm_type.h> +#include <cm/engine/memory/inc/domain_type.h> + +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_Migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst); + +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_Unmigrate(void); + +#endif /* CM_MIGRATION_ENGINE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/api/perfmeter_engine.h b/drivers/staging/nmf-cm/cm/engine/api/perfmeter_engine.h new file mode 100644 index 00000000000..bead49dc81e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/perfmeter_engine.h @@ -0,0 +1,41 @@ +/* + * 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. + */ +/*! + * \brief CM Performance Meter Engine API. + * + * This file contains the Component Manager Performance Meter Engine API. + */ +#ifndef CM_ENGINE_PERFMETER_ENGINE_H_ +#define CM_ENGINE_PERFMETER_ENGINE_H_ + +#include <cm/engine/perfmeter/inc/perfmeter_type.h> + +/*! + * \brief MPC cpu load + * + * \param[in] coreId identification of mpc from which we want cpu load + * \param[out] mpcLoadCounter will contain mpc cpu load counters value if success + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_getMpcLoadCounter( + t_nmf_core_id coreId, + t_cm_mpc_load_counter *mpcLoadCounter); + +/*! + * \brief MPC cpu load + * Same as \ref CM_ENGINE_getMpcLoadCounter() without lock + * + * \param[in] coreId identification of mpc from which we want cpu load + * \param[out] mpcLoadCounter will contain mpc cpu load counters value if success + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_GetMpcLoadCounter( + t_nmf_core_id coreId, + t_cm_mpc_load_counter *mpcLoadCounter); + +#endif /*CM_ENGINE_PERFMETER_ENGINE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/api/repository_mgt_engine.h b/drivers/staging/nmf-cm/cm/engine/api/repository_mgt_engine.h new file mode 100644 index 00000000000..3520f974be6 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/api/repository_mgt_engine.h @@ -0,0 +1,86 @@ +/* + * 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. + */ +/*! + * \brief Repository Component Manager User Engine API. + * + * This file contains the Component Manager Engine API for manipulating the components files. + */ + +#ifndef REPOSITORY_MGT_ENGINE_H_ +#define REPOSITORY_MGT_ENGINE_H_ + +#include <inc/nmf-limits.h> +#include <cm/engine/repository_mgt/inc/repository_type.h> + +/*! + * \brief Get the name(s) of the component(s) to load. + * + * \param[in] client Handle of the client component (optional) + * \param[in] requiredItfClientName Null terminated string (Max size=\ref MAX_INTERFACE_NAME_LENGTH) (optional). + * \param[in] server Handle of the server component (optional) + * \param[in] providedItfServerName Null terminated string (Max size==\ref MAX_INTERFACE_NAME_LENGTH) (optional). + * \param[out] fileList List of required component(s). + * \param[in,out] listSize Initial size of the list as input. Updated with the number of entries really used. + * \param[out] type Interface type of the client required or server provided interface. Null terminated string (Max size=\ref MAX_INTERFACE_TYPE_NAME_LENGTH) (optional) . + * \param[out] methodNumber Number of method in the interface type of the client required interface. (only used when called from CM_BindComponentToUser) (optional) + * + * \note It returns the component(s) name(s) to load, depending on the first four parameters. + * + * - If all 4 are NULL, it returns the name of the Executive Engine components to load + * - If 'client' is NULL, it returns the name of the required components for a Bind From CMCore. + * - If 'server' is NULL, it returns the name of the required components for a Bind To CMCore. + * - If none is NULL, it returns the name of the required components for an asynchronous binding + * + * The names are returned in fileList, whose initial size is specified in listSize. + * (sizeList must be the number of provided entries of \ref MAX_INTERFACE_TYPE_NAME_LENGTH length + * If not enough space is provided, CM_NO_MORE_MEMORY is returned + * + * sizeList is updated with the number entries really filled. + * + * This method is also used to retrieve the interface type when called from CM_BindComponentToUser and CM_BindComponentFromUser + * and the number of methods when called from CM_BindComponentToUser. + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetRequiredComponentFiles( + // IN + t_action_to_do action, + const t_cm_instance_handle client, + const char *requiredItfClientName, + const t_cm_instance_handle server, + const char *providedItfServerName, + // OUT component to be pushed + char fileList[][MAX_INTERFACE_TYPE_NAME_LENGTH], + // IN max component allowed to be pushed + t_uint32 listSize, + // OUT interface information + char type[MAX_INTERFACE_TYPE_NAME_LENGTH], + t_uint32 *methodNumber); + +/*! + * \brief Push a component into the CM Component Cache. + * + * \param[in] name Component name, null terminated string (Max size=\ref MAX_INTERFACE_TYPE_NAME_LENGTH) + * \param[in] data Pointer to _user_ data of the component. + * \param[in] size Size of the data. + * + * \note Push a component in the Component Cache + * The 'data' must be provided such a way that they can be freed by a call to OSAL_Free() + * The caller doesn't need and must NOT free the data, even in case of failure. + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_PushComponent(const char *name, const void *data, t_cm_size size); + +/*! + * \brief Remove a component from the CM Component Cache. + * + * \param[in] name Component name, null terminated string (Max size=\ref MAX_INTERFACE_TYPE_NAME_LENGTH) + * + * \ingroup CM_ENGINE_API + */ +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_ReleaseComponent (const char *name); + +#endif /*REPOSITORY_MGT_ENGINE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/communication/fifo/inc/nmf_fifo_arm.h b/drivers/staging/nmf-cm/cm/engine/communication/fifo/inc/nmf_fifo_arm.h new file mode 100644 index 00000000000..41c4f7a7ad6 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/communication/fifo/inc/nmf_fifo_arm.h @@ -0,0 +1,56 @@ +/* + * 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. + */ +/* + * + */ +#ifndef __INC_NMF_FIFO_ARM +#define __INC_NMF_FIFO_ARM + +#include <cm/inc/cm_type.h> +#include <share/communication/inc/nmf_fifo_desc.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/component/inc/instance.h> +#include <share/semaphores/inc/semaphores.h> +#include <cm/engine/memory/inc/domain.h> + +/* + * ARM Fifo descriptor (encapsulate the share one) + */ +typedef struct +{ + t_uint32 magic; + t_memory_handle chunkHandle; + t_nmf_core_id pusherCoreId; + t_nmf_core_id poperCoreId; + t_shared_addr dspAdress; + t_dsp_address_info dspAddressInfo; + t_nmf_fifo_desc *fifoDesc; //used for all fifo operations and systematically updated by the migrated offset (see cm_AllocEvent) + t_nmf_fifo_desc *fifoDescShadow; //shadow desc, is used to restore state after migration and perform the update of the real desc + + // ExtendedField + t_memory_handle extendedFieldHandle; + t_shared_field *extendedField; +} t_nmf_fifo_arm_desc; + +PUBLIC t_uint32 fifo_isFifoIdValid(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_nmf_fifo_arm_desc* fifo_alloc( + t_nmf_core_id pusherCoreId, t_nmf_core_id poperCoreId, + t_uint16 size_in_16bit, t_uint16 nbElem, t_uint16 nbExtendedSharedFields, + t_dsp_memory_type_id memType, t_dsp_memory_type_id memExtendedFieldType, t_cm_domain_id domainId); +PUBLIC void fifo_free(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_uint16 fifo_normalizeDepth(t_uint16 requestedDepth); + +PUBLIC t_shared_addr fifo_getAndAckNextElemToWritePointer(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_shared_addr fifo_getAndAckNextElemToReadPointer(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_shared_addr fifo_getNextElemToWritePointer(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_shared_addr fifo_getNextElemToReadPointer(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC void fifo_acknowledgeRead(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC void fifo_acknowledgeWrite(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC void fifo_coms_acknowledgeWriteAndInterruptGeneration(t_nmf_fifo_arm_desc *pArmFifo); + +PUBLIC t_cm_error fifo_params_setSharedField(t_nmf_fifo_arm_desc *pArmFifo, t_uint32 sharedFieldIndex, t_shared_field value); + +#endif /* __INC_NMF_FIFO_ARM */ diff --git a/drivers/staging/nmf-cm/cm/engine/communication/fifo/src/nmf_fifo_arm.c b/drivers/staging/nmf-cm/cm/engine/communication/fifo/src/nmf_fifo_arm.c new file mode 100644 index 00000000000..48d7f9e9f03 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/communication/fifo/src/nmf_fifo_arm.c @@ -0,0 +1,241 @@ +/* + * 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 <share/communication/inc/nmf_fifo_desc.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include "../inc/nmf_fifo_arm.h" + +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/trace/inc/trace.h> + +/* define value of fifo magic number */ +#define NMF_FIFO_MAGIC_NB 0xF1F0BEEF + +PRIVATE t_uint16 fifo_getCount( + t_uint16 writeIndex, + t_uint16 readIndex, + t_uint16 fifoSize +) +{ + if (writeIndex >= readIndex) {return writeIndex - readIndex;} + else {return fifoSize - readIndex + writeIndex;} +} + +PRIVATE t_uint16 fifo_incrementIndex( + t_uint16 index, + t_uint16 wrappingValue +) +{ + if (++index == wrappingValue) {index = 0;} + + return index; +} + +PUBLIC t_uint16 fifo_normalizeDepth(t_uint16 requestedDepth) +{ + /* with new implementation we don't align on power of two */ + return requestedDepth; +} + +PUBLIC t_nmf_fifo_arm_desc* fifo_alloc( + t_nmf_core_id pusherCoreId, t_nmf_core_id poperCoreId, + t_uint16 size_in_16bit, t_uint16 nbElem, t_uint16 nbExtendedSharedFields, + t_dsp_memory_type_id memType, t_dsp_memory_type_id memExtendedFieldType, t_cm_domain_id domainId) +{ + t_uint16 realNbElem = nbElem + 1;/* we need one more elem in new implementation */ + t_uint16 sizeToAlloc = sizeof(t_nmf_fifo_desc) + ((size_in_16bit<<1)*realNbElem); + t_nmf_fifo_arm_desc *pArmFifoDesc; + + pArmFifoDesc = (t_nmf_fifo_arm_desc*)OSAL_Alloc(sizeof (t_nmf_fifo_arm_desc)); + if (pArmFifoDesc == NULL) + goto errorde; + + pArmFifoDesc->chunkHandle = cm_DM_Alloc(domainId, memType, + (sizeToAlloc/2), CM_MM_ALIGN_2WORDS, TRUE); /* size in 16-bit since we use EXT16 memory */ + if (pArmFifoDesc->chunkHandle == INVALID_MEMORY_HANDLE) + goto errorsh; + + pArmFifoDesc->magic = NMF_FIFO_MAGIC_NB; + pArmFifoDesc->pusherCoreId = pusherCoreId; + pArmFifoDesc->poperCoreId = poperCoreId; + + pArmFifoDesc->fifoDesc = (t_nmf_fifo_desc *)cm_DSP_GetHostLogicalAddress(pArmFifoDesc->chunkHandle); + cm_DSP_GetDspAddress(pArmFifoDesc->chunkHandle, &pArmFifoDesc->dspAdress); + + pArmFifoDesc->fifoDescShadow = pArmFifoDesc->fifoDesc; + cm_DSP_GetDspDataAddressInfo(cm_DM_GetDomainCoreId(domainId), pArmFifoDesc->dspAdress, &pArmFifoDesc->dspAddressInfo); + + pArmFifoDesc->extendedFieldHandle = INVALID_MEMORY_HANDLE; + pArmFifoDesc->extendedField = NULL; + + pArmFifoDesc->fifoDesc->elemSize = size_in_16bit; + pArmFifoDesc->fifoDesc->fifoFullValue = nbElem; + pArmFifoDesc->fifoDesc->wrappingValue = realNbElem; + + pArmFifoDesc->fifoDesc->semId = cm_SEM_Alloc(pusherCoreId, poperCoreId); + pArmFifoDesc->fifoDesc->readIndex = 0; + pArmFifoDesc->fifoDesc->writeIndex = 0; + + LOG_INTERNAL(2, "\n##### Fifo alloc 0x%x (0x%x)\n\n", pArmFifoDesc, pArmFifoDesc->fifoDesc, 0, 0, 0, 0); + + if (nbExtendedSharedFields >= 1) + { + if(poperCoreId == ARM_CORE_ID) + { + /* Optimization: Don't put extended Field in DSP memory since use only by ARM if popper */ + pArmFifoDesc->extendedField = (t_shared_field*)OSAL_Alloc(nbExtendedSharedFields * sizeof(t_shared_field)); + if (pArmFifoDesc->extendedField == NULL) + goto errorex; + + pArmFifoDesc->fifoDesc->extendedField = (t_uint32)pArmFifoDesc->extendedField; + } + else + { + pArmFifoDesc->extendedFieldHandle = cm_DM_Alloc(domainId, memExtendedFieldType, + nbExtendedSharedFields * sizeof(t_shared_field) / 4, CM_MM_ALIGN_WORD, TRUE); + if (pArmFifoDesc->extendedFieldHandle == INVALID_MEMORY_HANDLE) + goto errorex; + + pArmFifoDesc->extendedField = (t_shared_field*)cm_DSP_GetHostLogicalAddress(pArmFifoDesc->extendedFieldHandle); + cm_DSP_GetDspAddress(pArmFifoDesc->extendedFieldHandle, (t_uint32*)&pArmFifoDesc->fifoDesc->extendedField); + } + + pArmFifoDesc->extendedField[EXTENDED_FIELD_BCTHIS_OR_TOP] = (t_shared_field)0; + } + + return pArmFifoDesc; + +errorex: + (void)cm_DM_Free(pArmFifoDesc->chunkHandle, TRUE); +errorsh: + OSAL_Free(pArmFifoDesc); +errorde: + return NULL; +} + +PUBLIC t_uint32 fifo_isFifoIdValid(t_nmf_fifo_arm_desc *pArmFifo) +{ + if (((t_uint32)pArmFifo & CM_MM_ALIGN_WORD) != 0) {return FALSE;} + if (pArmFifo->magic == NMF_FIFO_MAGIC_NB) {return TRUE;} + else {return FALSE;} +} + +PUBLIC void fifo_free(t_nmf_fifo_arm_desc *pArmFifo) +{ + CM_ASSERT(pArmFifo->pusherCoreId != ARM_CORE_ID || pArmFifo->poperCoreId != ARM_CORE_ID); + + pArmFifo->magic = ~NMF_FIFO_MAGIC_NB; + + if(pArmFifo->extendedFieldHandle != INVALID_MEMORY_HANDLE) + (void)cm_DM_Free(pArmFifo->extendedFieldHandle, TRUE); + else if(pArmFifo->extendedField != NULL) + OSAL_Free(pArmFifo->extendedField); + + (void)cm_DM_Free(pArmFifo->chunkHandle, TRUE); + OSAL_Free(pArmFifo); +} + +PUBLIC t_shared_addr fifo_getAndAckNextElemToWritePointer(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_shared_addr retValue; + + retValue = fifo_getNextElemToWritePointer(pArmFifo); + if (retValue != 0) + { + fifo_acknowledgeWrite(pArmFifo); + } + + return retValue; +} + +PUBLIC t_shared_addr fifo_getAndAckNextElemToReadPointer(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_shared_addr retValue; + + retValue = fifo_getNextElemToReadPointer(pArmFifo); + if (retValue != 0) + { + fifo_acknowledgeRead(pArmFifo); + } + + return retValue; +} + +PUBLIC t_shared_addr fifo_getNextElemToWritePointer(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_shared_addr retValue = 0; + t_nmf_fifo_desc *pDesc; + t_uint16 count; + + if ((NULL == pArmFifo) || (NULL == (pDesc = pArmFifo->fifoDesc))) + return 0; + + count = fifo_getCount(pDesc->writeIndex, pDesc->readIndex,pDesc->wrappingValue); + if (count < pDesc->fifoFullValue) + { + retValue = ((t_shared_addr)pDesc + sizeof(t_nmf_fifo_desc) + (pDesc->writeIndex*(pDesc->elemSize<<1))); + } + + return retValue; +} + +PUBLIC t_shared_addr fifo_getNextElemToReadPointer(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_shared_addr retValue = 0; + t_nmf_fifo_desc *pDesc; + t_uint16 count; + + if ((NULL == pArmFifo) || (NULL == (pDesc = pArmFifo->fifoDesc))) + return 0; + + count = fifo_getCount(pDesc->writeIndex, pDesc->readIndex,pDesc->wrappingValue); + if (count != 0) + { + retValue = ((t_shared_addr)pDesc+ sizeof(t_nmf_fifo_desc) + (pDesc->readIndex*(pDesc->elemSize<<1))); + } + + return retValue; +} + +PUBLIC void fifo_acknowledgeRead(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_nmf_fifo_desc *pDesc = pArmFifo->fifoDesc; + + pDesc->readIndex = fifo_incrementIndex(pDesc->readIndex, pDesc->wrappingValue); +} + +PUBLIC void fifo_acknowledgeWrite(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_nmf_fifo_desc *pDesc = pArmFifo->fifoDesc; + + pDesc->writeIndex = fifo_incrementIndex(pDesc->writeIndex, pDesc->wrappingValue); +} + +PUBLIC void fifo_coms_acknowledgeWriteAndInterruptGeneration(t_nmf_fifo_arm_desc *pArmFifo) +{ + t_nmf_fifo_desc *pDesc = pArmFifo->fifoDesc; + + fifo_acknowledgeWrite(pArmFifo); + //Be sure before generate irq that fifo has been updated + OSAL_mb(); + cm_SEM_GenerateIrq[pArmFifo->poperCoreId](pArmFifo->poperCoreId, pDesc->semId); + //cm_SEM_Take[pArmFifo->poperCoreId](pArmFifo->poperCoreId, pDesc->semId); + //cm_SEM_GiveWithInterruptGeneration[pArmFifo->poperCoreId](pArmFifo->poperCoreId, pDesc->semId); +} + +PUBLIC t_cm_error fifo_params_setSharedField(t_nmf_fifo_arm_desc *pArmFifo, t_uint32 sharedFieldIndex, t_shared_field value) +{ + pArmFifo->extendedField[sharedFieldIndex] = value; + + return CM_OK; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/communication/inc/communication.h b/drivers/staging/nmf-cm/cm/engine/communication/inc/communication.h new file mode 100644 index 00000000000..53ab87b7096 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/communication/inc/communication.h @@ -0,0 +1,44 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Components Management internal methods - Communication part. + * + */ +#ifndef __INC_NMF_COM +#define __INC_NMF_COM + +#include <cm/inc/cm_type.h> +#include <cm/engine/communication/fifo/inc/nmf_fifo_arm.h> +#include <cm/engine/memory/inc/memory.h> + +#include <cm/engine/communication/inc/communication_type.h> + +extern t_dsp_memory_type_id comsLocation; +extern t_dsp_memory_type_id paramsLocation; +extern t_dsp_memory_type_id extendedFieldLocation; + +PUBLIC t_cm_error cm_COM_Init(t_nmf_coms_location comsLocation); +PUBLIC t_cm_error cm_COM_AllocateMpc(t_nmf_core_id coreId); +PUBLIC void cm_COM_InitMpc(t_nmf_core_id coreId); +PUBLIC void cm_COM_FreeMpc(t_nmf_core_id coreId); + +PUBLIC t_cm_error cm_PushEventTrace(t_nmf_fifo_arm_desc*, t_event_params_handle h, t_uint32 methodIndex, t_uint32 isTrace); +PUBLIC t_cm_error cm_PushEvent(t_nmf_fifo_arm_desc *pArmFifo, t_event_params_handle h, t_uint32 methodIndex); +PUBLIC void cm_AcknowledgeEvent(t_nmf_fifo_arm_desc *pArmFifo); +PUBLIC t_event_params_handle cm_AllocEvent(t_nmf_fifo_arm_desc *pArmFifo); + +/*! + * \internal + * \brief Definition of custom value for userTHIS parameter of PostDfc OSAL call + * + * This value is used as 1st parameter of a pPostDfc call to indicate that a given interrupt is linked to an internal Component Manager event + */ +#define NMF_INTERNAL_USERTHIS ((void*)MASK_ALL32) + +typedef void (*t_callback_method)(t_nmf_core_id coreId, t_event_params_handle pParam); + +#endif /* __INC_NMF_COM */ diff --git a/drivers/staging/nmf-cm/cm/engine/communication/inc/communication_type.h b/drivers/staging/nmf-cm/cm/engine/communication/inc/communication_type.h new file mode 100644 index 00000000000..db426845a82 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/communication/inc/communication_type.h @@ -0,0 +1,61 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Communication Component Manager API type. + */ +#ifndef COMMUNICATION_TYPE_H_ +#define COMMUNICATION_TYPE_H_ + +#include <cm/inc/cm_type.h> + + +/*! + * \brief Buffer type used for (un)marshalling parameters. + * + * This buffer type is used for (un)marshalling paramaters. It can either be a + * shared memory buffer (ESRAM or SDRAM) or a pure host software memory (stack). + + * \ingroup CM_ENGINE_API + */ +typedef t_uint16 *t_event_params_handle; + +/*! + * \brief Component manager handle to Host -> MPC communication. + * + * \ingroup CM_ENGINE_API + */ +typedef t_uint32 t_cm_bf_host2mpc_handle; + +/*! + * \brief Component manager handle to MPC -> Host communication. + * + * \ingroup CM_ENGINE_API + */ +typedef t_uint32 t_cm_bf_mpc2host_handle; + +/*! + * \brief Component manager proxy handle to MPC -> Host skeleton context. + * + * \ingroup CM_ENGINE_API + */ +typedef t_uint32 t_nmf_mpc2host_handle; + +/*! + * @defgroup t_nmf_coms_location t_nmf_coms_location + * \brief Definition of the location of the internal CM communication objects + * + * @{ + * \ingroup CM_ENGINE_API + */ +typedef t_uint8 t_nmf_coms_location; //!< Fake enumeration type +#define COMS_IN_ESRAM ((t_nmf_coms_location)0) //!< All coms objects (coms and params fifos) will be in embedded RAM +#define COMS_IN_SDRAM ((t_nmf_coms_location)1) //!< All coms objects (coms and params fifos) will be in external RAM +/* @} */ + +#endif /*COMMUNICATION_TYPE_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/communication/src/communication.c b/drivers/staging/nmf-cm/cm/engine/communication/src/communication.c new file mode 100644 index 00000000000..8f48f02afc2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/communication/src/communication.c @@ -0,0 +1,326 @@ +/* + * 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. + */ +/** + * \internal + */ +#include <cm/inc/cm_type.h> +#include "../inc/communication.h" +#include <share/communication/inc/communication_fifo.h> +#include <cm/engine/api/control/irq_engine.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/component/inc/introspection.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/memory/inc/domain.h> +#include <cm/engine/memory/inc/migration.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/trace/inc/xtitrace.h> + +#include <cm/engine/component/inc/initializer.h> + +#define ARM_DSP_EVENT_FIFO_SIZE 16 + +t_dsp_memory_type_id comsLocation; +t_dsp_memory_type_id paramsLocation; +t_dsp_memory_type_id extendedFieldLocation; + +#define __DEBUG + +#ifdef __DEBUG +PRIVATE volatile t_uint32 armdspCounter = 0; +PRIVATE volatile t_uint32 armdspIrqCounter = 0; +PRIVATE volatile t_uint32 dsparmCounter = 0; +PRIVATE volatile t_uint32 dsparmIrqCounter = 0; +#endif /* __DEBUG */ + +t_nmf_fifo_arm_desc* mpc2mpcComsFifoId[NB_CORE_IDS][NB_CORE_IDS]; + +PRIVATE const t_callback_method internalHostJumptable[] = { + processAsyncAcknowledge, + processAsyncAcknowledge, + processAsyncAcknowledge, + processSyncAcknowledge, + processAsyncAcknowledge, + processAsyncAcknowledge, + processAsyncAcknowledge, + processSyncAcknowledge, + processAsyncAcknowledge, + processSyncAcknowledge, + processSyncAcknowledge +}; + +PUBLIC t_cm_error cm_COM_Init(t_nmf_coms_location _comsLocation) +{ + t_nmf_core_id coreId, localCoreId; + + /* + * Configure the default location of coms and params fifo (configuration by user) */ + switch(_comsLocation) + { + case COMS_IN_SDRAM: + comsLocation = SDRAM_EXT16; + paramsLocation = SDRAM_EXT16; + extendedFieldLocation = SDRAM_EXT24; + break; + case COMS_IN_ESRAM: + comsLocation = ESRAM_EXT16; + paramsLocation = ESRAM_EXT16; + extendedFieldLocation = ESRAM_EXT24; + break; + default: CM_ASSERT(0); + } + + for (coreId = ARM_CORE_ID; coreId < NB_CORE_IDS; coreId++) + { + for (localCoreId = ARM_CORE_ID; localCoreId < NB_CORE_IDS; localCoreId++) + { + mpc2mpcComsFifoId[coreId][localCoreId] = NULL; + } + } + + return CM_OK; +} + +PUBLIC t_cm_error cm_COM_AllocateMpc(t_nmf_core_id coreId) +{ + t_nmf_core_id localCoreId; + + /* + * Allocation of the coms fifo with neighbor MPCs + * if they are already initialized (known through initializedCoresMask) + */ + for (localCoreId = ARM_CORE_ID; localCoreId < NB_CORE_IDS; localCoreId++) + { + if (localCoreId == coreId) continue; /* no coms fifo with itself ;) */ + if(cm_DSP_GetState(localCoreId)->state != MPC_STATE_BOOTED) continue; + + /* + * coms fifo from other initialized MPCs to the given one + */ + if (mpc2mpcComsFifoId[coreId][localCoreId] != NULL) continue; /* coms fifo already allocated */ + + mpc2mpcComsFifoId[coreId][localCoreId] = fifo_alloc( + coreId, localCoreId, + EVENT_ELEM_SIZE_IN_BYTE/2, ARM_DSP_EVENT_FIFO_SIZE, + 0, comsLocation, extendedFieldLocation, cm_DSP_GetState(coreId)->domainEE + ); + if (mpc2mpcComsFifoId[coreId][localCoreId] == NULL) + goto oom; + + /* + * coms fifo from the given MPC to the other initialized ones + */ + if (mpc2mpcComsFifoId[localCoreId][coreId] != NULL) continue; /* coms fifo already allocated */ + + mpc2mpcComsFifoId[localCoreId][coreId] = fifo_alloc( + localCoreId, coreId, + EVENT_ELEM_SIZE_IN_BYTE/2, ARM_DSP_EVENT_FIFO_SIZE, + 0, comsLocation, extendedFieldLocation, cm_DSP_GetState(coreId)->domainEE + ); + if (mpc2mpcComsFifoId[localCoreId][coreId] == NULL) + goto oom; + } + + return CM_OK; +oom: + cm_COM_FreeMpc(coreId); + return CM_NO_MORE_MEMORY; +} + +PUBLIC void cm_COM_InitMpc(t_nmf_core_id coreId) +{ + // Here we assume that attribute are in XRAM, thus we don't need memory type + t_uint32* toNeighborsComsFifoIdSharedVar[NB_CORE_IDS]; + t_uint32* fromNeighborsComsFifoIdSharedVar[NB_CORE_IDS]; + + t_nmf_core_id localCoreId; + + /* + * Initialization of the core identifier of a given Executive Engine + * Used into communication scheme so the init is done here, will be moved MAY BE into EE loading module!!! + */ + cm_writeAttribute(cm_EEM_getExecutiveEngine(coreId)->instance, "semaphores/myCoreId", coreId); + + /* + * Initialization of the coms fifo with the Host for the given coreId + */ + for (localCoreId = FIRST_MPC_ID/* NOT ARM*/; localCoreId <= LAST_CORE_ID; localCoreId++) + { + // Note: This loop will also include coreId in order to fill + if(cm_DSP_GetState(localCoreId)->state != MPC_STATE_BOOTED) continue;/* no coms fifo initialisation with not booted MPC */ + + toNeighborsComsFifoIdSharedVar[localCoreId] = (t_uint32*)cm_getAttributeHostAddr(cm_EEM_getExecutiveEngine(localCoreId)->instance, "comms/toNeighborsComsFifoId"); + + fromNeighborsComsFifoIdSharedVar[localCoreId] = (t_uint32*)cm_getAttributeHostAddr(cm_EEM_getExecutiveEngine(localCoreId)->instance, "comms/fromNeighborsComsFifoId"); + } + + toNeighborsComsFifoIdSharedVar[coreId][ARM_CORE_ID] = mpc2mpcComsFifoId[coreId][ARM_CORE_ID]->dspAdress; + fromNeighborsComsFifoIdSharedVar[coreId][ARM_CORE_ID] = mpc2mpcComsFifoId[ARM_CORE_ID][coreId]->dspAdress; + + for (localCoreId = FIRST_MPC_ID/* NOT ARM*/; localCoreId <= LAST_CORE_ID; localCoreId++) + { + if (localCoreId == coreId) continue; /* no coms fifo with itself ;) */ + if(cm_DSP_GetState(localCoreId)->state != MPC_STATE_BOOTED) continue;/* no coms fifo initialisation with not booted MPC */ + + toNeighborsComsFifoIdSharedVar[coreId][localCoreId] = mpc2mpcComsFifoId[coreId][localCoreId]->dspAdress; + fromNeighborsComsFifoIdSharedVar[localCoreId][coreId] = mpc2mpcComsFifoId[coreId][localCoreId]->dspAdress; + + fromNeighborsComsFifoIdSharedVar[coreId][localCoreId] = mpc2mpcComsFifoId[localCoreId][coreId]->dspAdress; + toNeighborsComsFifoIdSharedVar[localCoreId][coreId] = mpc2mpcComsFifoId[localCoreId][coreId]->dspAdress; + } +} + +PUBLIC void cm_COM_FreeMpc(t_nmf_core_id coreId) +{ + t_nmf_core_id localCoreId; + + for (localCoreId = ARM_CORE_ID; localCoreId < NB_CORE_IDS; localCoreId++) + { + /* + * Free coms fifo from other initialized MPCs to the given one + */ + if ( mpc2mpcComsFifoId[coreId][localCoreId] != NULL) + { + fifo_free(mpc2mpcComsFifoId[coreId][localCoreId]); + mpc2mpcComsFifoId[coreId][localCoreId] = NULL; + } + + /* + * Free coms fifo from the given MPC to the other initialized ones + */ + if ( mpc2mpcComsFifoId[localCoreId][coreId] != NULL) + { + fifo_free(mpc2mpcComsFifoId[localCoreId][coreId]); + mpc2mpcComsFifoId[localCoreId][coreId] = NULL; + } + } +} + +PUBLIC t_event_params_handle cm_AllocEvent(t_nmf_fifo_arm_desc *pArmFifo) + +{ + t_uint32 retValue; + + //migration impacts the ARM-side address of the fifoDesc, + //thus translate the fifo desc adress systematically. + pArmFifo->fifoDesc = (t_nmf_fifo_desc*)cm_migration_translate(pArmFifo->dspAddressInfo.segmentType, (t_shared_addr)pArmFifo->fifoDescShadow); + + retValue = fifo_getAndAckNextElemToWritePointer(pArmFifo); + + return (t_event_params_handle)retValue; +} + +PUBLIC void cm_AcknowledgeEvent(t_nmf_fifo_arm_desc *pArmFifo) +{ + fifo_acknowledgeRead(pArmFifo); +} + +PUBLIC t_cm_error cm_PushEventTrace(t_nmf_fifo_arm_desc *pArmFifo, t_event_params_handle h, t_uint32 methodIndex, t_uint32 isTrace) +{ + t_uint32 retValue; + + retValue = fifo_getNextElemToWritePointer(mpc2mpcComsFifoId[ARM_CORE_ID][pArmFifo->poperCoreId]); + + if(retValue != 0x0) { + t_shared_field *pEvent = (t_shared_field *)retValue; + +#ifdef __DEBUG + armdspCounter++; +#endif /* __DEBUG */ + + pEvent[EVENT_ELEM_METHOD_IDX] = (t_shared_addr)methodIndex; + pEvent[EVENT_ELEM_PARAM_IDX] = pArmFifo->dspAdress + (((t_cm_logical_address)h - (t_cm_logical_address)pArmFifo->fifoDesc) >> 1); //note byte to half-word conversion + pEvent[EVENT_ELEM_EXTFIELD_IDX] = pArmFifo->fifoDesc->extendedField; + + if (isTrace) + { + cm_TRC_traceCommunication( + TRACE_COMMUNICATION_COMMAND_SEND, + ARM_CORE_ID, + pArmFifo->poperCoreId); + } + fifo_coms_acknowledgeWriteAndInterruptGeneration(mpc2mpcComsFifoId[ARM_CORE_ID][pArmFifo->poperCoreId]); + + return CM_OK; + } + + ERROR("CM_MPC_NOT_RESPONDING: FIFO COM full '%s'\n", 0, 0, 0, 0, 0, 0); + return CM_MPC_NOT_RESPONDING; +} + +PUBLIC t_cm_error cm_PushEvent(t_nmf_fifo_arm_desc *pArmFifo, t_event_params_handle h, t_uint32 methodIndex) +{ + return cm_PushEventTrace(pArmFifo,h,methodIndex,1); +} + +static void cmProcessMPCFifo(t_nmf_core_id coreId) +{ + t_shared_field *pEvent; + + while((pEvent = (t_shared_field *)fifo_getNextElemToReadPointer(mpc2mpcComsFifoId[coreId][ARM_CORE_ID])) != NULL) + { + t_event_params_handle pParamsAddr; + t_shared_field *pParamsFifoESFDesc; + + pParamsAddr = (t_event_params_handle)cm_DSP_ConvertDspAddressToHostLogicalAddress( + coreId, + pEvent[EVENT_ELEM_PARAM_IDX]); + pParamsFifoESFDesc = (t_shared_field *)pEvent[EVENT_ELEM_EXTFIELD_IDX]; +#ifdef __DEBUG + dsparmCounter++; +#endif /* __DEBUG */ + + if(pParamsFifoESFDesc[EXTENDED_FIELD_BCTHIS_OR_TOP] == (t_shared_field)NMF_INTERNAL_USERTHIS) + { + internalHostJumptable[pEvent[EVENT_ELEM_METHOD_IDX]](coreId, pParamsAddr); + } + else + { + cm_TRC_traceCommunication( + TRACE_COMMUNICATION_COMMAND_RECEIVE, + ARM_CORE_ID, + coreId); + + OSAL_PostDfc( + pParamsFifoESFDesc[EXTENDED_FIELD_BCTHIS_OR_TOP], + pEvent[EVENT_ELEM_METHOD_IDX], + pParamsAddr, + pParamsFifoESFDesc[EXTENDED_FIELD_BCDESC]); + } + + // [Pwr] mpc2hostComsFifoId value is checked to support the case where + // CM_PostCleanUpAndFlush method is called under interrupt context + // -> mpc2hostComsFifoId can be released. + if (mpc2mpcComsFifoId[coreId][ARM_CORE_ID] != NULL) + fifo_acknowledgeRead(mpc2mpcComsFifoId[coreId][ARM_CORE_ID]); + else + break; + } +} + +PUBLIC EXPORT_SHARED void CM_ProcessMpcEvent(t_nmf_core_id coreId) +{ +#ifdef __DEBUG + dsparmIrqCounter++; +#endif /* __DEBUG */ + + if (coreId != ARM_CORE_ID) + { + /* Acknowledge DSP communication interrupt */ + cm_DSP_AcknowledgeDspIrq(coreId, DSP2ARM_IRQ_0); + + cmProcessMPCFifo(coreId); + } + else + { + while((coreId = cm_HSEM_GetCoreIdFromIrqSrc()) <= LAST_MPC_ID) + cmProcessMPCFifo(coreId); + } +} + diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/bind.h b/drivers/staging/nmf-cm/cm/engine/component/inc/bind.h new file mode 100644 index 00000000000..325703e3367 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/bind.h @@ -0,0 +1,443 @@ +/* + * 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. + */ +/** + * \internal + * \brief Binding Factories internal API. + * + * \defgroup BF_COMMON Binding factories: Common API + * \defgroup BF_PRIMITIVE Binding Factories: Primitive API + * \defgroup BF_TRACE Binding Factories: Trace API + * \defgroup BF_ASYNCHRONOUS Binding Factories: Asynchronous API + * \defgroup BF_DISTRIBUTED Binding Factories: Distributed API + */ +#ifndef __INC_CM_BIND_H +#define __INC_CM_BIND_H + +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/communication/inc/communication.h> +#include <cm/engine/utils/inc/table.h> + +/** + * \internal + * \ingroup BF_COMMON + * + * \brief Identification number of prefedined Binding Factories + */ +typedef enum { + BF_SYNCHRONOUS, //!< Intra-DSP Synchronous Binding Factory Identifier + BF_TRACE, //!< Intra-DSP trace synchronous Binding Factory Identifier + BF_ASYNCHRONOUS, //!< Intra-DSP Asynchronous Binding Factory Identifier + BF_DSP2HOST, //!< DSP to Host Binding Factory Identifier + BF_HOST2DSP, //!< Host to DSP Binding Factory Identifier + BF_DSP2DSP, //!< DSP to DSP Binding Factory Identifier +} t_bf_info_ID; + +/*! + * \internal + * \brief Description of a provided interface + * + * \ingroup COMPONENT_INTERNAL + */ +typedef struct _t_interface_reference { + const t_component_instance *instance; //!< Component instance that provide this interface + t_uint8 provideIndex; //!< Index of the interface in the provide array + t_uint8 collectionIndex;//!< Index in the collection if provided interface is a collection + t_bf_info_ID bfInfoID; //!< Identification of BF used for creating binding + void* bfInfo; //!< Storage of the binding factory info +} t_interface_reference; + +/** + * \internal + * \ingroup BF_COMMON + * + * Make some basic sanity check for a client: + * - component stopped + * - Interface really required + * + * \param[in] client The client component instance handle. + * \param[in] requiredItfClientName The client required interface name + * \param[out] requiredItf return the required interface (avoid user searching) + */ +t_cm_error cm_checkValidClient( + const t_component_instance* client, + const char* requiredItfClientName, + t_interface_require_description *itfRequire, + t_bool *bindable); +/** + * \internal + * \ingroup BF_COMMON + * + * Make some basic sanity check for a server: + * - Interface really provided + * + * \param[in] server The server component instance handle. + * \param[in] providedItfServerName The server provided interface name + * \param[out] itf return the provided interface (avoid user searching) + */ +t_cm_error cm_checkValidServer( + const t_component_instance* server, + const char* providedItfServerName, + t_interface_provide_description *itfProvide); + +/** + * \internal + * \ingroup BF_COMMON + * + * Make some basic sanity check for a binding: + * - Sanity check for a server + * - Sanity check for a client (and potentially wait initialisation) + * - Provided and required interface matches + * + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[in] server The server component instance handle + * \param[in] providedItfServerName The server provided interface name + * \param[out] requiredItf return the required interface (avoid user searching) + * \param[out] itf return the provided interface (avoid user searching) + */ +t_cm_error cm_checkValidBinding( + const t_component_instance* client, + const char* requiredItfClientName, + const t_component_instance* server, + const char* requiredItfServerName, + t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide, + t_bool *bindable); + +/** + * \internal + * \ingroup BF_COMMON + * + * Make some basic sanity check for each unbinding: + * - Interface really required + * - Component stopped + * + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[out] itfRequire return the previously binded required interface (avoid user searching) + * \param[out] itfProvide return the previously binded provided interface (avoid user searching) + * \param[out] bfInfoID return the binding factory identifiant which done the previously bind + * \param[out] bfInfo return the binding factory information which done the previously bind + */ +t_cm_error cm_checkValidUnbinding( + const t_component_instance* client, + const char* requiredItfClientName, + t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide); + +/** + * \internal + * \ingroup BF_PRIMITIVE + * + * Create a primitive binding between a client to a server interface. + * + * \param[in] itfRequire The client required interface description + * \param[in] itfProvide The server provided interface description + */ +t_cm_error cm_bindInterface( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide); + +/** + * \internal + * \ingroup BF_PRIMITIVE + * + * Unbind a previously binded client. + * + * \param[in] itfRequire The client required interafce description + */ +void cm_unbindInterface( + const t_interface_require_description *itfRequire); + +/** + * \internal + * \ingroup BF_PRIMITIVE + * + * Get a server interface previouly binded to a client + * + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[out] itf The server interface + */ +t_cm_error cm_lookupInterface( + const t_interface_require_description *itfRequire, + t_interface_provide_description *itfProvide); + +/** + * \internal + * \ingroup BF_PRIMITIVE + * + * Create a void binding. + * + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + */ +t_cm_error cm_bindInterfaceToVoid( + const t_interface_require_description *itfRequire); + +/** + * \internal + * \ingroup BF_TRACE + * + * Trace synchronous binding factory Information + */ +typedef struct { + t_component_instance *traceInstance; //!< Trace binding component instance +} t_trace_bf_info; + +/** + * \internal + * \ingroup BF_TRACE + * + * Create a traced binding between a client to a server interface. + * + * \param[in] itfRequire The client required interface description + * \param[in] itfProvide The server provided interface description + */ +t_cm_error cm_bindInterfaceTrace( + const t_interface_require_description *itfRequire, + const t_interface_provide_description *itfProvide, + t_elfdescription *elfhandleTrace); + +/** + * \internal + * \ingroup BF_TRACE + * + * Unbind a previously binded client. + * + * \param[in] itfRequire The client required interafce description + */ +void cm_unbindInterfaceTrace( + const t_interface_require_description *itfRequire, + t_trace_bf_info *bfInfo); + + +/** + * \internal + * \ingroup BF_ASYNCHRONOUS + * + * Asynchronous binding factory Information + */ +typedef struct { + t_component_instance *eventInstance; //!< Event binding component instance + t_memory_handle dspfifoHandle; //!< Memory handle of allocated event fifo (pass to the event binding component) +} t_async_bf_info; + +/** + * \internal + * \ingroup BF_ASYNCHRONOUS + * + * Create a asynchronous binding between a client to a server interface. + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[in] itf The server interface + * \param[in] fifosize Number of waited event in the fifo + */ +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); +/** + * \internal + * \ingroup BF_ASYNCHRONOUS + * + * Destroy a asynchronous binding between a client to a server interface. + * \param[in] itfRequire the required interface + */ +void cm_unbindInterfaceAsynchronous( + const t_interface_require_description *itfRequire, + t_async_bf_info *bfInfo); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Stub information in distributed binding factory (client side) + */ +typedef struct { + t_component_instance *stubInstance; //!< Stub +} t_dspstub_bf_info; + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Skeleton information in distributed binding factory (server side) + */ +typedef struct { + t_component_instance *skelInstance; //!< Skeleton binding component instance + t_memory_handle dspfifoHandle; //!< Memory handle of allocated event fifo (pass to the event binding component) +} t_dspskel_bf_info; + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Host to DSP distributed binding factory Information + */ +typedef struct { + t_dspskel_bf_info dspskeleton; //!< Information about the DSP skeleton (server side) + t_nmf_fifo_arm_desc* fifo; //!< Handle of the fifo params + t_nmf_client_id clientId; //!< Client ID of the host client +} t_host2mpc_bf_info; + +/* + * Table of instantiated of host2mpc bindings + */ +extern t_nmf_table Host2MpcBindingTable; /**< list (table) of host2mpc bindings */ + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Create a Host to DSP distributed binding between a host client interface to a server interface. + * (Not manage in the same way as distributed binding since the Host programming model is not component aware). + * \param[in] itfServer The server interface + * \param[in] fifosize Number of waited event in the fifo + * \param[in] dspEventMemType The type of memory to use + * \param[in] bfInfo info structure + */ +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); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Destroy a Host to DSP distributed binding between a host client interface to a server interface. + * \param[in] bfInfo The Host to DSP distributed binding factory information + */ +void cm_unbindComponentFromCMCore( + t_host2mpc_bf_info *bfInfo); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * DSP to Host distributed binding factory Information + */ +typedef struct { + t_dspstub_bf_info dspstub; //!< Information about the DSP stub (client side) + t_nmf_fifo_arm_desc* fifo; //!< Handle of the fifo params + t_uint32 context; +} t_mpc2host_bf_info; + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Create a DSP to Host distributed binding between a client interface to a host server interface. + * (Not manage in the same way as distributed binding since the Host programming model is not component aware). + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[in] itfref The host server interface to be called + * \param[in] fifosize Number of waited event in the fifo + */ +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); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Destroy a DSP to Host distributed binding between a client interface to a server interface. + * \param[in] itfRequire The required interface + * \param[out] upLayerThis The 'THIS' context of upper layer + */ +void cm_unbindComponentToCMCore( + const t_interface_require_description *itfRequire, + t_mpc2host_bf_info *bfInfo); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Asynchronous distributed binding factory Information + */ +typedef struct { + t_nmf_fifo_arm_desc* fifo; //!< Handle of the fifo params + t_dspstub_bf_info dspstub; //!< Information about the DSP stub (client side) + t_dspskel_bf_info dspskeleton; //!< Information about the DSP skeleton (server side) +} t_mpc2mpc_bf_info; + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Create a asynchronous distributed binding between a client interface to a server interface. + * \param[in] client The client component instance handle + * \param[in] requiredItfClientName The client required interface name + * \param[in] itf The server interface + * \param[in] fifosize Number of waited event in the fifo + */ +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); + +/** + * \internal + * \ingroup BF_DISTRIBUTED + * + * Destroy a asynchronous distributed binding between a client interface to a server interface. + * \param[in] itfRequire The required interface + */ +void cm_unbindInterfaceDistributed( + const t_interface_require_description *itfRequire, + t_mpc2mpc_bf_info *bfInfo); + +/** + * \internal + * + * Bind a static interrupt to server provide interface name. + * \param[in] coreId The core to which component is loaded + * \param[in] interruptLine Interrupt line number to use + * \param[in] server Server instance that provide interrupt service + * \param[in] providedItfServerName Interface name hat provide interrupt service + */ +t_cm_error cm_bindInterfaceStaticInterrupt( + const t_nmf_core_id coreId, + const int interruptLine, + const t_component_instance *server, + const char* providedItfServerName); + +/** + * \internal + * + * Unbind a static interrupt. + * \param[in] coreId The core to which component is loaded + * \param[in] interruptLine Interrupt line number to use + */ +t_cm_error cm_unbindInterfaceStaticInterrupt( + const t_nmf_core_id coreId, + const int interruptLine); + +void cm_destroyRequireInterface(t_component_instance* component, t_nmf_client_id clientId); +void cm_registerSingletonBinding( + t_component_instance* component, + t_interface_require_description* itfRequire, + t_interface_provide_description* itfProvide, + t_nmf_client_id clientId); +t_bool cm_unregisterSingletonBinding( + t_component_instance* component, + t_interface_require_description* itfRequire, + t_interface_provide_description* itfProvide, + t_nmf_client_id clientId); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/component_type.h b/drivers/staging/nmf-cm/cm/engine/component/inc/component_type.h new file mode 100644 index 00000000000..35571dde06d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/component_type.h @@ -0,0 +1,65 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Components Component Manager API type. + * + * \defgroup COMPONENT CM Components API + * \ingroup CM_USER_API + */ + +#ifndef COMPONENT_TYPE_H_ +#define COMPONENT_TYPE_H_ + +#include <cm/inc/cm_type.h> +#include <nmf/inc/component_type.h> + +/*! + * @defgroup t_nmf_ee_priority t_nmf_ee_priority + * \brief Identification of the execution engine priority and sub priority. + * @{ + * \ingroup COMPONENT + */ +typedef t_uint32 t_nmf_ee_priority; //!< Fake enumeration type + +#define NMF_SCHED_BACKGROUND ((t_nmf_ee_priority)0) //!< Background priority +#define NMF_SCHED_NORMAL ((t_nmf_ee_priority)1) //!< Normal priority +#define NMF_SCHED_URGENT ((t_nmf_ee_priority)2) //!< Urgent priority +/* @} */ + + +/*! + * \brief Identification of host component returned during introspection + * + * \ingroup COMPONENT_INTROSPECTION + */ +#define NMF_HOST_COMPONENT ((t_cm_instance_handle)0xFFFFFFFF) + +/*! + * \brief Identification of void component returned during introspection + * + * \ingroup COMPONENT_INTROSPECTION + */ +#define NMF_VOID_COMPONENT ((t_cm_instance_handle)0xFFFFFFFE) + + +/*! + * @defgroup t_nmf_ee_priority t_nmf_ee_priority + * \brief Identification of the execution engine priority and sub priority. + * @{ + * \ingroup COMPONENT + */ +typedef t_uint8 t_cm_require_state; //!< Fake enumeration type + +#define CM_REQUIRE_STATIC ((t_cm_require_state)0) //!< Required interface is static +#define CM_REQUIRE_OPTIONAL ((t_cm_require_state)1) //!< Required interface is optional +#define CM_REQUIRE_COLLECTION ((t_cm_require_state)2) //!< Required interface is a collection + +/* @} */ + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/description.h b/drivers/staging/nmf-cm/cm/engine/component/inc/description.h new file mode 100644 index 00000000000..b7d3c34654d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/description.h @@ -0,0 +1,109 @@ +/* + * 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. + */ +#ifndef __INC_CM_COMPONENT_DESCRIPTION_H +#define __INC_CM_COMPONENT_DESCRIPTION_H + +#include <cm/engine/elf/inc/memory.h> +#include <cm/engine/utils/inc/string.h> + +#include <inc/nmf-limits.h> + +/*! + * \internal + * \brief Description of an interface + * \ingroup COMPONENT_INTERNAL + */ +typedef struct _t_interface_description { + t_dup_char type; //!< Type of the interface + t_uint16 referenceCounter; //!< Number of template referencing the interface + t_uint8 methodNumber; //!< Number of method in the interfaces + struct _t_interface_description* next; + t_dup_char methodNames[]; //!< Array of method names +} t_interface_description; + +/*! + * \internal + * \brief Description of a variable memory on a collection index + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_uint32 offset; //!< Offset in the memory + const t_elfmemory *memory; //!< Memory +} t_memory_reference; + +/*! + * \internal + * \brief Description of a required interface on a collection index + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_uint32 numberOfClient; //!< Number of interface descriptor really connected to this interface + t_memory_reference *memories; /*!< Memory where each interface reference descriptor resides + \note memories[numberOfClient] */ +} t_interface_require_index; + +/*! + * \internal + * \brief Description of a required interface + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_dup_char name; //!< Name of the interface + t_interface_description *interface; //!< Description of the interface + t_uint8 requireTypes; //!< Mask of t_elf_interface_require_type + t_uint8 collectionSize; //!< Size of the collection (1 if not a collection) + t_interface_require_index *indexes; /*!< Require information for each collection index + \note indexes[collectionSize] */ +} t_interface_require; + +/*! + * \internal + * \brief Description of a provided interface method on a collection index + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_uint32 methodAddresses; //!< Address of each method ; Available only when template loaded + t_memory_reference memory; //!< Memory of the method +} t_interface_provide_index; + +/*! + * \internal + * \brief Description of a provided interface + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_dup_char name; //!< Name of the interface + t_interface_description *interface; //!< Description of the interface + t_uint8 provideTypes; //!< Mask of t_elf_interface_provide_type + t_uint8 interruptLine; //!< Interrupt line if interrupt (0 if not) + t_uint8 collectionSize; //!< Size of the collection (1 if not a collection) + t_interface_provide_index **indexes; //!< Provide information for each collection index +} t_interface_provide; + +/*! + * \internal + * \brief Description of a attribute + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_dup_char name; //!< Name of the attribute + t_memory_reference memory; //!< Memory where the attribute reside +} t_attribute; + +/*! + * \internal + * \brief Description of a property + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + t_dup_char name; //!< Name of this attribute + t_dup_char value; //!< String of the value +} t_property; + + + + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/dspevent.h b/drivers/staging/nmf-cm/cm/engine/component/inc/dspevent.h new file mode 100644 index 00000000000..bb47363c0ae --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/dspevent.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_DSP_EVENT +#define __INC_DSP_EVENT + +#include <cm/inc/cm_type.h> +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/memory/inc/memory.h> + +/* value should be size of t_remote_event in mmdsp word */ +#define DSP_REMOTE_EVENT_SIZE_IN_DSPWORD 5 + +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); +void dspevent_destroyDspEventFifo(t_memory_handle handle); + +#endif /* __INC_DSP_EVENT */ diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/initializer.h b/drivers/staging/nmf-cm/cm/engine/component/inc/initializer.h new file mode 100644 index 00000000000..b4416f3ce20 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/initializer.h @@ -0,0 +1,29 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_NMF_INITIALIZER +#define __INC_NMF_INITIALIZER + +#include <cm/inc/cm_type.h> +#include <cm/engine/component/inc/instance.h> +#include <share/communication/inc/initializer.h> + +PUBLIC t_cm_error cm_COMP_INIT_Init(t_nmf_core_id coreId); +PUBLIC t_cm_error cm_COMP_CallService(int serviceIndex, t_component_instance *pComp, t_uint32 methodAddress); +PUBLIC void cm_COMP_INIT_Close(t_nmf_core_id coreId); +PUBLIC t_cm_error cm_COMP_UpdateStack(t_nmf_core_id coreId, t_uint32 stackSize); +PUBLIC t_cm_error cm_COMP_ULPForceWakeup(t_nmf_core_id coreId); +PUBLIC t_cm_error cm_COMP_ULPAllowSleep(t_nmf_core_id coreId); +PUBLIC t_cm_error cm_COMP_InstructionCacheLock(t_nmf_core_id coreId, t_uint32 mmdspAddr, t_uint32 mmdspSize); +PUBLIC t_cm_error cm_COMP_InstructionCacheUnlock(t_nmf_core_id coreId, t_uint32 mmdspAddr, t_uint32 mmdspSize); + + +PUBLIC void processAsyncAcknowledge(t_nmf_core_id coreId, t_event_params_handle pParam); +PUBLIC void processSyncAcknowledge(t_nmf_core_id coreId, t_event_params_handle pParam); + +#endif /* __INC_NMF_INITIALIZER */ diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/instance.h b/drivers/staging/nmf-cm/cm/engine/component/inc/instance.h new file mode 100644 index 00000000000..1bef76501de --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/instance.h @@ -0,0 +1,220 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Components Management internal methods - Instance API. + * + */ +#ifndef __INC_CM_INSTANCE_H +#define __INC_CM_INSTANCE_H + +#include <cm/engine/component/inc/template.h> +#include <cm/engine/repository_mgt/inc/repository_mgt.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/utils/inc/table.h> +#include <cm/engine/utils/inc/string.h> + +/*---------------------------------------------------------------------------- + * Component Instance API. + *----------------------------------------------------------------------------*/ +struct _t_interface_reference; + +/*! + * \internal + * \brief Component life cycle state + * + * \ingroup COMPONENT_INTERNAL + */ +typedef enum { + STATE_NONE, + STATE_STOPPED, + STATE_RUNNABLE, + // STATE_DESTROYED identified when component remove from component list +} t_component_state; + +struct t_client_of_singleton +{ + struct t_client_of_singleton *next; + t_nmf_client_id clientId; + t_uint16 numberOfInstance; + t_uint16 numberOfStart; + t_uint16 numberOfBind; +}; + +/*! + * \internal + * \brief Description of a component instance + * + * \ingroup COMPONENT_INTERNAL + */ +typedef struct t_component_instance { + t_dup_char pathname; //!< Path Name of this component in the components architecture + + t_component_state state; //!< Component state + t_nmf_ee_priority priority; //!< Executive engine component priority + t_component_template *template; //!< Component template + + t_uint32 thisAddress; //!< Cached value of cm_DSP_GetDspAddress(component->memories[data], &thisAddress); + + t_memory_handle memories[NUMBER_OF_MMDSP_MEMORY]; //!<Reference in different memory where datas are (YES, we fix implementation to MMDSP) + + struct _t_interface_reference **interfaceReferences; /*!< Interface references + (Share same index as template->u.p.requires) + type == targets[interface_index][collection_index] */ + + t_uint16 providedItfUsedCount; //!< Use count to reference the number of components binded to this once, ie count the number of provided interfaces in use + t_cm_instance_handle instance; //!< index of this component within the ComponentTable + t_cm_domain_id domainId; //!< Domain where the component has been installed + + struct t_client_of_singleton *clientOfSingleton; //!< Client of singleton list +} t_component_instance; + +t_component_template* cm_lookupTemplate(t_nmf_core_id dspId, t_dup_char str); + +/*! + * \internal + * \brief Load a component template. + * + * ... + * + * \param[in] templateName name of the template to load + * \param[in] coreId DSP where template must be loaded + * \praem[in] pRepComponent Pointer to the component entry stored in the Component Cache Repository + * \param[in, out] template reference to put the loaded template (null if first instance) + * + * \exception CM_COMPONENT_NOT_FOUND + * \exception CM_NO_MORE_MEMORY + * + * \return exception number. + * + * \warning For Component manager use only. + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_loadComponent( + t_dup_char templateName, + t_cm_domain_id domainId, + t_elfdescription* elfhandle, + t_component_template **reftemplate); + +/*! + * \internal + * \brief Unload a component template. + * + * ... + * + * \param[in] template template to be unloaded + * \praem[in] Private memories that has been created from component binary file + * + * \return exception number. + * + * \warning For Component manager use only. + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_unloadComponent( + t_component_template *template); + +/*! + * \internal + * \brief Instantiate a component. + * + * \ingroup COMPONENT_INTERNAL + */ +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); + +struct t_client_of_singleton* cm_getClientOfSingleton(t_component_instance* component, t_bool createdIfNotExist, t_nmf_client_id clientId); + +/*! + * \internal + * \brief Start a component. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_startComponent(t_component_instance* component, t_nmf_client_id clientId); + +/*! + * \internal + * \brief Stop a component. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_stopComponent(t_component_instance* component, t_nmf_client_id clientId); + +/*! + * \internal + */ +typedef enum { + DESTROY_NORMAL, + DESTROY_WITHOUT_CHECK, + DESTROY_WITHOUT_CHECK_CALL +} t_destroy_state; + +/*! + * \internal + * \brief Destroy a component instance. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_destroyInstance(t_component_instance* component, t_destroy_state forceDestroy); + +/*! + * \internal + * \brief Destroy a component instance. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_destroyInstanceForClient(t_component_instance* component, t_destroy_state forceDestroy, t_nmf_client_id clientId); + +/*! + * \internal + * \brief + * + * \ingroup COMPONENT_INTERNAL + */ +void cm_delayedDestroyComponent(t_component_instance *component); + +/*! + * \internal + * \brief + * + * \ingroup COMPONENT_INTERNAL + */ +t_component_instance *cm_lookupComponent(const t_cm_instance_handle hdl); + +/*! + * \internal + * \brief + * + * \ingroup COMPONENT_INTERNAL + */ +t_bool cm_isComponentOnCoreId(t_nmf_core_id coreId); + +/*! + * \internal + * \brief + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_COMP_Init(void); + +/*! + * \internal + * \brief + * + * \ingroup COMPONENT_INTERNAL + */ +void cm_COMP_Destroy(void); + +/* + * Table of instantiated components. + */ +extern t_nmf_table ComponentTable; /**< list (table) of components */ +#define componentEntry(i) ((t_component_instance *)ComponentTable.entries[i]) +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/introspection.h b/drivers/staging/nmf-cm/cm/engine/component/inc/introspection.h new file mode 100644 index 00000000000..cfb55c91779 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/introspection.h @@ -0,0 +1,109 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Components Management internal methods - Introspection. + * + */ +#ifndef __INC_CM_INTROSPECTION_H +#define __INC_CM_INTROSPECTION_H + +#include <cm/engine/component/inc/instance.h> + +/*! + * \internal + * \brief Description of a required interface reference + * + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + const t_component_instance *client; //!< Component that provide this interface + t_uint8 requireIndex; //!< Index of the interface in the require array + t_uint8 collectionIndex; //!< Index in the collection if required interface is a collection + const char* origName; //!< Name of the component interface +} t_interface_require_description; + +/*! + * \internal + * \brief Description of a provided interface + * + * \ingroup COMPONENT_INTERNAL + */ +typedef struct { + const t_component_instance *server; //!< Component that provide this interface + t_uint8 provideIndex; //!< Index of the interface in the provide array + t_uint8 collectionIndex; //!< Index in the collection if provided interface is a collection + const char* origName; //!< Name of the component interface +} t_interface_provide_description; + + +/*! + * \internal + * \brief Get property of a component. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_getComponentProperty( + const t_component_instance *component, + const char *propName, + char value[MAX_PROPERTY_VALUE_LENGTH], + t_uint32 valueLength); + + +t_dsp_address cm_getAttributeMpcAddress( + const t_component_instance *component, + const char *attrName); + +t_cm_logical_address cm_getAttributeHostAddr( + const t_component_instance *component, + const char *attrName); + +t_uint32 cm_readAttributeNoError( + const t_component_instance *component, + const char *attrName); + +t_cm_error cm_readAttribute( + const t_component_instance *component, + const char *attrName, + t_uint32 *value); + +t_cm_error cm_writeAttribute( + const t_component_instance *component, + const char *attrName, + t_uint32 value); + +/*! + * \internal + * \brief Get internal component symbol + * + * \ingroup COMPONENT_INTERNAL + */ +t_dsp_address cm_getFunction( + const t_component_instance* component, + const char* interfaceName, + const char* methodName); + +/*! + * \internal + * \brief Get interface provided by a component instance. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_getProvidedInterface(const t_component_instance* server, + const char* itfName, + t_interface_provide_description *itfProvide); + +/*! + * \internal + * \brief Get interface required by a component instance. + * + * \ingroup COMPONENT_INTERNAL + */ +t_cm_error cm_getRequiredInterface(const t_component_instance* server, + const char* itfName, + t_interface_require_description *itfRequire); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/nmfheaderabi.h b/drivers/staging/nmf-cm/cm/engine/component/inc/nmfheaderabi.h new file mode 100644 index 00000000000..59d2186f157 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/nmfheaderabi.h @@ -0,0 +1,154 @@ +/* + * 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. + */ +/*! + * \brief NMF component description ABI + * + * \defgroup NMF_HEADER NMF Component Description ABI + * The NMF component description ABI is stored in the nmf_segment in the ELF component file. + * The NMF component description section start by the t_elf_component_header structure. + * + * \warning <B>The format of this section is not fixed and is able to be changed without concerting.</B> + * \note You can use the nmfHeaderVersion to check if the format has changed. + * \note Each pointers in this section is relative to the beginning of the section and must be relocated before used. + * \ingroup NMF_ABI + */ +#ifndef __INC_CM_NMF_HEADERABI_H +#define __INC_CM_NMF_HEADERABI_H + +#include <cm/inc/cm_type.h> + +/*! + * \brief Description of a interface + * \ingroup NMF_HEADER + */ +typedef struct { + char *type; //!< Type of this Interface + t_uint8 methodNumber; //!< Number of method in the interfaces + t_uint8 reserved1, reserved2, reserved3; + char *methodNames[]; //!< Array of method names +} t_elf_interface_description; + +/*! + * \brief Description of required interface type (value could be combinated) + * \ingroup NMF_HEADER + */ +typedef enum { + COLLECTION_REQUIRE = 1, //!< Required interface is a collection + OPTIONAL_REQUIRE = 2, //!< Required interface if optional + STATIC_REQUIRE = 4, //!< Required interface is static + VIRTUAL_REQUIRE = 8, //!< Required interface is virtual (only for introspection purpose) + INTRINSEC_REQUIRE = 16 //!< Required interface is intrinsec (bind automatically done by runtime) +} t_elf_interface_require_type; + +/*! + * \brief Description of a required interface on a collection index + * \ingroup NMF_HEADER + */ +typedef struct { + t_uint32 numberOfClient; //!< Number of interface descriptor really connected to this interface + t_uint32 symbols[1]; /*!< Symbol of the real name of the attribute + \note Real type symbols[numberOfClient] + \note Use relocation in order to get symbol information */ +} t_elf_interface_require_index; + +/*! + * \brief Description of an interface required + * \ingroup NMF_HEADER + */ +typedef struct { + char *name; //!< name of the interface: offset in string segment + t_uint8 requireTypes; //!< Mask of t_elf_interface_require_type + t_uint8 collectionSize; //!< Size of the collection (1 if not a collection) + t_uint8 reserved1, reserved2; + t_elf_interface_description *interface; //!< Interface description + t_elf_interface_require_index indexes[]; /*!< Require information for each collection index + \note Real type: indexes[collectionSize], + available only if not static interface */ +} t_elf_required_interface; + +/*! + * \brief Description of provided interface type (value could be combinated) + * \ingroup NMF_HEADER + */ +typedef enum { + COLLECTION_PROVIDE = 1, //!< Provided interface is a collection + VIRTUAL_PROVIDE = 2 //!< Provided interface is virtual (only for introspection purpose) +} t_elf_interface_provide_type; + +/*! + * \brief Description of an interface provided + * \ingroup NMF_HEADER + */ +typedef struct { + char* name; //!< name of the interface: offset in string segment + t_uint8 provideTypes; //!< Mask of t_elf_interface_provide_type + t_uint8 interruptLine; //!< Interrupt line if interrupt (0 if not) + t_uint8 collectionSize; //!< Size of the collection (1 if not a collection) + t_uint8 reserved1; + t_elf_interface_description *interface; //!< Interface description + t_uint32 methodSymbols[]; /*!< Symbol of the real name of methods of the interface for each collection index + \note Real type: methodSymbols[collectionSize][methodNumber] + \note Use relocation in order to get symbol information*/ +} t_elf_provided_interface; + +/*! + * \brief Description of an attribute + * \ingroup NMF_HEADER + */ +typedef struct { + char* name; //!< Name of this attribute + t_uint32 symbols; /*!< Symbol of the real name of the attribute + \note Use relocation in order to get symbol information */ +} t_elf_attribute; + +/*! + * \brief Description of an property + * \ingroup NMF_HEADER + */ +typedef struct { + char* name; //!< Name of this attribute + char* value; //!< String of the value +} t_elf_property; + +#define MAGIC_COMPONENT 0x123 //!< Magic Number for a component \ingroup NMF_HEADER +#define MAGIC_SINGLETON 0x321 //!< Magic Number for a singleton component \ingroup NMF_HEADER +#define MAGIC_FIRMWARE 0x456 //!< Magic Number for Execution Engine Component \ingroup NMF_HEADER + +/*! + * \brief Description of a ELF component header + * + * The NMF component description section start by this structure. + * + * \ingroup NMF_HEADER + */ +typedef struct { + t_uint32 magic; //!< Magic Number + t_uint32 nmfVersion; //!< Version of the NMF Header + + char* templateName; //!< Name of the component template + + t_uint32 LCCConstruct; //!< Life cycle Constructor offset + t_uint32 LCCStart; //!< Life cycle Starter offset + t_uint32 LCCStop; //!< Life cycle Stopper offset + t_uint32 LCCDestroy; //!< Life cycle Destructer offset + + t_uint32 minStackSize; //!< Minimum stack size + + t_uint32 attributeNumber;//!< Number of attributes + t_elf_attribute *attributes; //!< Array of attributes (be careful, this reference must be relocated before use) + + t_uint32 propertyNumber; //!< Number of properties + t_elf_property *properties; //!< Array of properties (be careful, this reference must be relocated before use) + + t_uint32 provideNumber; //!< Number of interfaces provided + t_elf_provided_interface *provides; //!< Array of interfaces provided (be careful, this reference must be relocated before use) + + t_uint32 requireNumber; //!< Array of interfaces required + t_elf_required_interface *requires; //!< Array of interfaces required (be careful, this reference must be relocated before use) + +} t_elf_component_header; + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/component/inc/template.h b/drivers/staging/nmf-cm/cm/engine/component/inc/template.h new file mode 100644 index 00000000000..3e1a2c001e4 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/inc/template.h @@ -0,0 +1,89 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Components Management internal methods - Template API. + * + * \defgroup COMPONENT_INTERNAL Private component instances API + */ +#ifndef __INC_CM_TEMPLATE_H +#define __INC_CM_TEMPLATE_H + +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/component/inc/description.h> +#include <cm/engine/elf/inc/elfapi.h> +#include <cm/engine/utils/inc/string.h> + + +/*! + * \internal + * \brief Class of a component + * \ingroup COMPONENT_INTERNAL + */ +typedef enum { + COMPONENT, //!< Primitive component + SINGLETON, //!< Singleton component + FIRMWARE, //!< Firmware composite component +} t_component_classe; + +/*! + * \internal + * \brief Description of delayed relocation + * \ingroup COMPONENT_INTERNAL + */ +typedef struct _t_function_relocation { + t_dup_char symbol_name; + t_uint32 type; + char *reloc_addr; + struct _t_function_relocation *next; +} t_function_relocation; + +struct t_component_instance; + +/*! + * \internal + * \brief Description of a component template + * \ingroup COMPONENT_INTERNAL + */ +typedef struct _t_component_template { + t_dup_char name; //!< Template name (a.k.a component type) + + t_component_classe classe; //!< Class of the component + //TODO, juraj, remove dspId + t_nmf_core_id dspId; //!< Reference on DSP where template is loaded + + t_uint8 numberOfInstance; //!< Number of same instance (or singleton copy) create from this template + + t_uint8 propertyNumber; //!< Number of properties in this template + t_uint8 attributeNumber; //!< Number of attributes in this template + t_uint8 provideNumber; //!< Number of interface provided by this template + t_uint8 requireNumber; //!< Number of interface required by this template + + t_uint32 LCCConstructAddress; //!< Life cycle Constructor address + t_uint32 LCCStartAddress; //!< Life cycle Starter address + t_uint32 LCCStopAddress; //!< Life cycle Stopper address + t_uint32 LCCDestroyAddress; //!< Life cycle Destructer address + + t_uint32 minStackSize; //!< Minimum stack size + + t_memory_handle memories[NUMBER_OF_MMDSP_MEMORY]; //!< Reference in different memory where datas are (YES, we fix implementation to MMDSP) + const t_elfmemory *thisMemory; //!< Memory used to determine this + const t_elfmemory *codeMemory; //!< Memory used to determine code + + t_function_relocation *delayedRelocation; //!< List of reference that can't been relocatable while appropritae binding done. + + t_property *properties; //!< Array of properties in this template + t_attribute *attributes; //!< Array of attributes in this template + t_interface_provide *provides; //!< Array of interface provided by this template + t_interface_require *requires; //!< Array of interface required by this template + + t_bool descriptionAssociatedWithTemplate; + + struct _t_component_template *prev, *next; + struct t_component_instance *singletonIfAvaliable; +} t_component_template; + +#endif 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..8586fdfcbc8 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/binder.c @@ -0,0 +1,1310 @@ +/* + * 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]; + 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)provide->indexes[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)provide->indexes[itfLocalBC->collectionIndex][j].methodAddresses << 0) | + ((t_uint64)provide->indexes[itfLocalBC->collectionIndex][j+1].methodAddresses << 32); + hostAddr += 2; + } + + // Last word align if required + if(j < require->interface->methodNumber) + *hostAddr = provide->indexes[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, + provide->indexes[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) + 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->provides[0].indexes[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->provides[0].indexes[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..b141064c1c1 --- /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..07d20d0266e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/component_wrapper.c @@ -0,0 +1,1297 @@ +/* + * 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 */ + for (i=0; i<Host2MpcBindingTable.idxMax; i++) + { + t_host2mpc_bf_info* bfInfo; + OSAL_LOCK_COM(); + bfInfo = Host2MpcBindingTable.entries[i]; + if ((bfInfo != NULL) && (bfInfo->clientId == clientId)) { + cm_delEntry(&Host2MpcBindingTable, i); + OSAL_UNLOCK_COM(); + cm_unbindComponentFromCMCore(bfInfo); + } else + 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: + 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; +} + +/*=============================================================================== + * 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..0c055c7f6f9 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/dspevent.c @@ -0,0 +1,76 @@ +/* + * 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) + 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..7391669419e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/initializer.c @@ -0,0 +1,329 @@ +/* + * 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); + +/* + * 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; +} 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; + + 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]; + + + 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].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); + 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); + 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, + provide->indexes[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_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) + error = CM_MPC_NOT_RESPONDING; + } + + return error; +} + +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); + + OSAL_SemaphorePost(initializerDesc[coreId].fifoSemHandle,1); +} + +PUBLIC void processSyncAcknowledge(t_nmf_core_id coreId, t_event_params_handle pParam) +{ + cm_AcknowledgeEvent(initializerDesc[coreId].uplinkFifo); + + 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) + 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) + 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); + +unlock: + OSAL_UNLOCK_COM(); + + return error; +} + 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..2f517a98179 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/instantiater.c @@ -0,0 +1,819 @@ +/* + * 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; + + /* + * 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)) != 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->domainId = domainId; + 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(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; + + *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) + { + // The PRCMU seem not supporting the transition of asking HW IP on while DSP in retention + // -> Thus force wake up of the MMDSP before asking the transition + if ((error = cm_EEM_ForceWakeup(component->template->dspId)) != CM_OK) + return error; + + error = cm_PWR_EnableMPC(MPC_PWR_HWIP, component->template->dspId); + + cm_EEM_AllowSleep(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; + + /* + * 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; + + 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( + 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(cm_getComponentProperty( + component, + "hardware", + value, + sizeof(value)) == CM_OK) + { + 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); + } + } + } + + 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..a4e0a01a242 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/introspection.c @@ -0,0 +1,325 @@ +/* + * 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_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]; + + for(i = 0; i < provide->interface->methodNumber; i++) + { + if(cm_StringCompare(provide->interface->methodNames[i], methodName, MAX_INTERFACE_METHOD_NAME_LENGTH) == 0) + { + return provide->indexes[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..762f74c4479 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/component/src/loader.c @@ -0,0 +1,338 @@ +/* + * 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*); + +#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]; + + for(j = 0; j < provide->interface->methodNumber; j++) + { + if(provide->interface->methodNames[j] == symbolName) + { + return provide->indexes[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)) != 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 + for(i = 0; i < template->provideNumber; i++) + { + for(j = 0; j < template->provides[i].collectionSize; j++) + { + for(k = 0; k < template->provides[i].interface->methodNumber; k++) + { + template->provides[i].indexes[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->provides[i].indexes[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; + 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->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; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration.h b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration.h new file mode 100644 index 00000000000..7156769bb2d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration.h @@ -0,0 +1,40 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_CONFIGURATION_H_ +#define __INC_CONFIGURATION_H_ + +#include <cm/engine/api/control/configuration_engine.h> +#include <cm/engine/memory/inc/memory.h> +#include <inc/nmf-limits.h> +#include <cm/engine/dsp/inc/dsp.h> + +/******************************************************************************/ +/************************ FUNCTIONS PROTOTYPES ********************************/ +/******************************************************************************/ + +PUBLIC t_cm_error cm_CFG_ConfigureMediaProcessorCore(t_nmf_core_id coreId, + t_nmf_executive_engine_id executiveEngineId, + t_nmf_semaphore_type_id semaphoreTypeId, t_uint8 nbYramBanks, + const t_cm_system_address *mediaProcessorMappingBaseAddr, + const t_cm_domain_id eeDomain, + t_dsp_allocator_desc* sdramCodeAllocId, + t_dsp_allocator_desc* sdramDataAllocId + ); + +PUBLIC t_cm_error cm_CFG_AddMpcSdramSegment(const t_nmf_memory_segment *pDesc, + const char *memoryname, t_dsp_allocator_desc **allocDesc); + +PUBLIC t_cm_error cm_CFG_CheckMpcStatus(t_nmf_core_id coreId); + +void cm_CFG_ReleaseMpc(t_nmf_core_id coreId); + +PUBLIC t_cm_error cm_CFG_GetRequiredExecutiveEngineComponentNames( + char fileList[][MAX_INTERFACE_TYPE_NAME_LENGTH], t_uint32 listSize); + +#endif /* __INC_CONFIGURATION_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_status.h b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_status.h new file mode 100644 index 00000000000..0c75b9c49b0 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_status.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_CONFIGSTATUS_H_ +#define __INC_CONFIGSTATUS_H + +#include <cm/inc/cm_type.h> +#include <cm/engine/utils/inc/string.h> + +/* + * Variable to active intensive check + * + * \ingroup CM_CONFIGURATION_API + */ +extern t_sint32 cmIntensiveCheckState; + +/* + * Variable to active trace level + * + * \ingroup CM_CONFIGURATION_API + */ +extern t_sint32 cm_debug_level; + +/* + * Variable to active error break + * + * \ingroup CM_CONFIGURATION_API + */ +extern t_sint32 cm_error_break; + +/* + * Variable to activate Ulp + * + * \ingroup CM_CONFIGURATION_API + */ +extern t_bool cmUlpEnable; + +extern t_dup_char anonymousDup, eventDup, skeletonDup, stubDup, traceDup; + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_type.h b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_type.h new file mode 100644 index 00000000000..abfe452cf78 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/configuration/inc/configuration_type.h @@ -0,0 +1,82 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Configuration Component Manager API type. + */ +#ifndef CONFIGURATION_TYPE_H +#define CONFIGURATION_TYPE_H + +#include <cm/inc/cm_type.h> + +/*! + * @defgroup t_cm_cmd_id t_cm_cmd_id + * \brief Definition of the command ID + * \ingroup CM_CONFIGURATION_API + * + * CM_CMD_XXX designates the command ID used by the \ref CM_SetMode routine. + * + * \remarks Other command IDs are not yet implemented. + */ + +typedef t_uint32 t_cm_cmd_id; //!< Fake enumeration type \ingroup t_cm_cmd_id +#define CM_CMD_SYNC ((t_cm_cmd_id)0x01) //!< Synchronize on-going operations (no parameter) \ingroup t_cm_cmd_id + +#define CM_CMD_WARM_RESET ((t_cm_cmd_id)0x02) //!< Reset a part of the CM-engine (parameter indicates the part which must be reseted) \ingroup t_cm_cmd_id + +#define CM_CMD_PWR_MGR ((t_cm_cmd_id)0x10) //!< Enable/Disable the internal power management module (0=Disable, 1=Enable) \ingroup t_cm_cmd_id + +#define CM_CMD_DBG_MODE ((t_cm_cmd_id)0x40) //!< Enable/Disable DEBUG mode, Pwr Mgr is also disabled (0=Disable, 1=Enable) \ingroup t_cm_cmd_id + +#define CM_CMD_TRACE_ON ((t_cm_cmd_id)0x41) //!< Enable STM/XTI tracing and force network resetting and dumping \note Since MPC trace will be usable, you can enable them if not \ingroup t_cm_cmd_id +#define CM_CMD_TRACE_OFF ((t_cm_cmd_id)0x42) //!< Disable STM/XTI tracing \note Since MPC trace will not be usable, you can also disable them \ingroup t_cm_cmd_id + +#define CM_CMD_MPC_TRACE_ON ((t_cm_cmd_id)0x50) //!< Enable MPC STM/XTI tracing (param == coreId). \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id +#define CM_CMD_MPC_TRACE_OFF ((t_cm_cmd_id)0x51) //!< Disable MPC STM/XTI tracing (param == coreId) This is the default configuration. \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id + +#define CM_CMD_MPC_PRINT_OFF ((t_cm_cmd_id)0x52) //!< Set to OFF the level of MPC traces (param == coreId) \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id +#define CM_CMD_MPC_PRINT_ERROR ((t_cm_cmd_id)0x53) //!< Set to ERROR the level of MPC traces param == coreId) \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id +#define CM_CMD_MPC_PRINT_WARNING ((t_cm_cmd_id)0x54) //!< Set to WARNING the level of MPC traces param == coreId) \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id +#define CM_CMD_MPC_PRINT_INFO ((t_cm_cmd_id)0x55) //!< Set to INFO the level of MPC traces (param == coreId) \note This command is not execute if execution engine not started on the coreId This is the default configuration. \ingroup t_cm_cmd_id +#define CM_CMD_MPC_PRINT_VERBOSE ((t_cm_cmd_id)0x56) //!< Set to VERBOSE the level of MPC traces param == coreId) \note This command is not execute if execution engine not started on the coreId \ingroup t_cm_cmd_id + +/*! + * \brief Define the level of internal CM log traces + * + * Define the level of internal CM log traces (-1 to 3) + * -# <b>-1 </b> all internal LOG/ERROR traces are disabled + * -# <b> 0 </b> all internal LOG traces are disabled (<b>default/reset value</b>) + * -# <b> 1, 2, 3 </b> Most and most + * + * \ingroup t_cm_cmd_id + */ +#define CM_CMD_TRACE_LEVEL ((t_cm_cmd_id)0x80) + +/*! + * \brief Enable/Disable intensive internal check + * + * Enable/Disable intensive internal check (0=Disable, 1=Enable): + * - Component handle checking + * + * Must be used during the integration phase (additional process is time consuming). + * + * \ingroup t_cm_cmd_id + */ +#define CM_CMD_INTENSIVE_CHECK ((t_cm_cmd_id)0x100) + +/*! + * \brief Enable/Disable ulp mode + * + * Enable/Disable Ultra Low Power mode. + * + * \ingroup t_cm_cmd_id + */ +#define CM_CMD_ULP_MODE_ON ((t_cm_cmd_id)0x111) //!< Enable ULP mode \ingroup t_cm_cmd_id +#define CM_CMD_ULP_MODE_OFF ((t_cm_cmd_id)0x110) //!< Deprecated (must be removed in 2.10) !!! + +#endif /* CONFIGURATION_TYPE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration.c b/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration.c new file mode 100644 index 00000000000..f3242af5da8 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration.c @@ -0,0 +1,213 @@ +/* + * 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/configuration/inc/configuration.h> +#include <cm/engine/component/inc/initializer.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <cm/engine/communication/inc/communication.h> +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/repository_mgt/inc/repository_mgt.h> +#include <inc/nmf-limits.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/memory/inc/domain.h> + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/convert.h> + +#include <cm/engine/power_mgt/inc/power.h> + +t_sint32 cmIntensiveCheckState = 0; +t_sint32 cm_debug_level = 1; +t_sint32 cm_error_break = 0; +t_bool cmUlpEnable = FALSE; + + +#define MAX_EE_NAME_LENGTH 32 +typedef struct { + char eeName[MAX_EE_NAME_LENGTH]; + t_nmf_executive_engine_id executiveEngineId; + t_uint32 EEmemoryCount; +} t_cfg_mpc_desc; + +static t_cfg_mpc_desc cfgMpcDescArray[NB_CORE_IDS]; + +PUBLIC t_cm_error cm_CFG_ConfigureMediaProcessorCore( + t_nmf_core_id coreId, + t_nmf_executive_engine_id executiveEngineId, + t_nmf_semaphore_type_id semaphoreTypeId, + t_uint8 nbYramBanks, + const t_cm_system_address *mediaProcessorMappingBaseAddr, + const t_cm_domain_id eeDomain, + t_dsp_allocator_desc *sdramCodeAllocDesc, + t_dsp_allocator_desc *sdramDataAllocDesc) +{ + /* Process requested configuration (save it) */ + cfgMpcDescArray[coreId].EEmemoryCount = 0; + cfgMpcDescArray[coreId].executiveEngineId = executiveEngineId; + /* Build Executive Engine Name */ + switch(executiveEngineId) + { + case SYNCHRONOUS_EXECUTIVE_ENGINE: + cm_StringCopy(cfgMpcDescArray[coreId].eeName, "synchronous_", MAX_EE_NAME_LENGTH); + break; + case HYBRID_EXECUTIVE_ENGINE: + cm_StringCopy(cfgMpcDescArray[coreId].eeName, "hybrid_", MAX_EE_NAME_LENGTH); + break; + } + + switch(semaphoreTypeId) + { + case LOCAL_SEMAPHORES: + cm_StringConcatenate(cfgMpcDescArray[coreId].eeName, "lsem", MAX_EE_NAME_LENGTH); + break; + case SYSTEM_SEMAPHORES: + cm_StringConcatenate(cfgMpcDescArray[coreId].eeName, "hsem", MAX_EE_NAME_LENGTH); + break; + } + + cm_SEM_InitMpc(coreId, semaphoreTypeId); + + return cm_DSP_Add(coreId, nbYramBanks, mediaProcessorMappingBaseAddr, eeDomain, sdramCodeAllocDesc, sdramDataAllocDesc); +} + +// TODO JPF: Move in dsp.c +PUBLIC t_cm_error cm_CFG_AddMpcSdramSegment(const t_nmf_memory_segment *pDesc, const char* memoryname, t_dsp_allocator_desc **allocDesc) +{ + t_dsp_allocator_desc *desc; + if ( (pDesc == NULL) || + ((pDesc->systemAddr.logical & CM_MM_ALIGN_64BYTES) != 0) ) + return CM_INVALID_PARAMETER; + + //TODO, juraj, the right place and way to do this? + desc = (t_dsp_allocator_desc*)OSAL_Alloc(sizeof (t_dsp_allocator_desc)); + if (desc == 0) + return CM_NO_MORE_MEMORY; + + desc->allocDesc = cm_MM_CreateAllocator(pDesc->size, 0, memoryname); + if (desc->allocDesc == 0) { + OSAL_Free(desc); + return CM_NO_MORE_MEMORY; + } + desc->baseAddress = pDesc->systemAddr; + desc->referenceCounter = 0; + + *allocDesc = desc; + + return CM_OK; +} + +PUBLIC t_cm_error cm_CFG_CheckMpcStatus(t_nmf_core_id coreId) +{ + t_cm_error error; + + if (cm_DSP_GetState(coreId)->state == MPC_STATE_BOOTABLE) + { + /* Allocate coms fifo for a given MPC */ + if ((error = cm_COM_AllocateMpc(coreId)) != CM_OK) + return error; + + /* Launch EE */ + if ((error = cm_EEM_Init(coreId, + cfgMpcDescArray[coreId].eeName, + cfgMpcDescArray[coreId].executiveEngineId)) != CM_OK) + { + cm_COM_FreeMpc(coreId); + return error; + } + + /* Initialize coms fifo for a given MPC */ + cm_COM_InitMpc(coreId); + + /* Initialisation of the dedicated communication channel for component initialization */ + if((error = cm_COMP_INIT_Init(coreId)) != CM_OK) + { + cm_EEM_Close(coreId); + cm_COM_FreeMpc(coreId); + return error; + } + + cfgMpcDescArray[coreId].EEmemoryCount = cm_PWR_GetMPCMemoryCount(coreId); + + if(cmUlpEnable) + { + // We have finish boot, allow MMDSP to go in auto idle + cm_EEM_AllowSleep(coreId); + } + } + + if (cm_DSP_GetState(coreId)->state != MPC_STATE_BOOTED) + return CM_MPC_NOT_INITIALIZED; + + return CM_OK; +} + +void cm_CFG_ReleaseMpc(t_nmf_core_id coreId) +{ + t_uint32 memoryCount = cm_PWR_GetMPCMemoryCount(coreId); + + // If No more memory and no more component (to avoid switch off in case of component using no memory) + if( + cm_PWR_GetMode() == NORMAL_PWR_MODE && + memoryCount != 0 /* Just to see if there is something */ && + memoryCount == cfgMpcDescArray[coreId].EEmemoryCount && + cm_isComponentOnCoreId(coreId) == FALSE) + { + LOG_INTERNAL(1, "\n##### Shutdown %s #####\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + + (void)cm_EEM_ForceWakeup(coreId); + + /* remove ee from load map here */ + cm_COMP_INIT_Close(coreId); + cm_EEM_Close(coreId); + cm_COM_FreeMpc(coreId); + + cfgMpcDescArray[coreId].EEmemoryCount = 0; // For debug purpose + } +} + +/****************************************************************************/ +/* NAME: cm_CFG_GetRequiredExecutiveEngineComponentNames( */ +/* char *fileList[], */ +/* t_uint32 *listSize */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: retrieves the names of the required Executive Engine */ +/* component(s) to load. */ +/****************************************************************************/ +PUBLIC t_cm_error cm_CFG_GetRequiredExecutiveEngineComponentNames( + char fileList[][MAX_INTERFACE_TYPE_NAME_LENGTH], + t_uint32 listSize) +{ + t_nmf_core_id coreId; + t_uint32 nb=0; + + for (coreId = ARM_CORE_ID; coreId <= LAST_CORE_ID; coreId++) + { + if ((cm_DSP_GetState(coreId)->state == MPC_STATE_BOOTABLE) + && (cm_REP_lookupComponent(cfgMpcDescArray[coreId].eeName, NULL) != CM_OK)) + { + /* Check if we didn't already register this name in the list */ + int j, present=0; + for (j=0; j<nb; j++) { + if (cm_StringCompare(cfgMpcDescArray[coreId].eeName, fileList[j], MAX_EE_NAME_LENGTH) == 0) { + present = 1; + break; + } + } + if (present) + continue; + if (nb >= listSize) + return CM_NO_MORE_MEMORY; + cm_StringCopy(fileList[nb], cfgMpcDescArray[coreId].eeName, MAX_EE_NAME_LENGTH); + nb++; + } + } + return CM_OK; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration_wrapper.c b/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration_wrapper.c new file mode 100644 index 00000000000..34789752b7d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/configuration/src/configuration_wrapper.c @@ -0,0 +1,301 @@ +/* + * 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/configuration_engine.h> +#include <cm/engine/communication/inc/communication.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/memory/inc/chunk_mgr.h> +#include <cm/engine/repository_mgt/inc/repository_mgt.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/configuration/inc/configuration.h> +#include <cm/engine/power_mgt/inc/power.h> +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/component/inc/bind.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/api/executive_engine_mgt_engine.h> + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/trace/inc/xtitrace.h> + +t_dup_char anonymousDup, eventDup, skeletonDup, stubDup, traceDup; + +PUBLIC t_cm_error CM_ENGINE_Init( + const t_nmf_hw_mapping_desc *pNmfHwMappingDesc, + const t_nmf_config_desc *pNmfConfigDesc + ) +{ + t_cm_error error; + + // The purpose of that is just to not free/unfree some String frequently used + anonymousDup = cm_StringDuplicate("anonymous"); + eventDup = cm_StringDuplicate("event"); + skeletonDup = cm_StringDuplicate("skeleton"); + stubDup = cm_StringDuplicate("stub"); + traceDup = cm_StringDuplicate("trace"); + + if (( + error = cm_OSAL_Init() + ) != CM_OK) { return error; } + + if (( + error = cm_COMP_Init() + ) != CM_OK) { return error; } + + if (( + error = cm_PWR_Init() + ) != CM_OK) { return error; } + + cm_TRC_traceReset(); + + if (( + error = cm_DM_Init() + ) != CM_OK) {return error; } + + if (( + error = cm_SEM_Init(&pNmfHwMappingDesc->hwSemaphoresMappingBaseAddr) + ) != CM_OK) { return error; } + + if ((error = cm_COM_Init(pNmfConfigDesc->comsLocation)) != CM_OK) + return error; + + cm_DSP_Init(&pNmfHwMappingDesc->esramDesc); + + return CM_OK; +} + +PUBLIC void CM_ENGINE_Destroy(void) +{ + t_component_instance *instance; + t_cm_error error; + t_uint32 i; + + /* PP: Well, on Linux (and probably on Symbian too), this is called when driver is removed + * => the module (driver) can't be removed if there are some pending clients + * => all remaining components should have been destroyed in CM_ENGINE_FlushClient() + * => So, if we found some components here, we are in BIG trouble ... + */ + /* First, stop all remaining components */ + for (i=0; i<ComponentTable.idxMax; i++) + { + t_nmf_client_id clientId; + + if ((instance = componentEntry(i)) == NULL) + continue; + clientId = domainDesc[instance->domainId].client; + LOG_INTERNAL(0, "Found a remaining component %s (%s) when destroying the CM !!!\n", instance->pathname, instance->template->name, 0, 0, 0, 0); + 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 = instance->clientOfSingleton; + + clientId = instance->clientOfSingleton->clientId; + for( ; cl != NULL ; cl = cl->next) + { + if(cl == instance->clientOfSingleton) + { + 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 + } + else + { + cl->numberOfStart = 0; + cl->numberOfInstance = 0; + } + cl->numberOfBind = 0; + } + } + + // 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 (i=0; i<ComponentTable.idxMax; i++) + { + t_nmf_client_id clientId; + + if ((instance = componentEntry(i)) == NULL) + continue; + clientId = domainDesc[instance->domainId].client; + + 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; + } + + if(instance->template->classe == SINGLETON) + { + clientId = instance->clientOfSingleton->clientId; + } + + // 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); + } + } + + /* This will power off all ressources and destroy EE */ + cm_PWR_SetMode(NORMAL_PWR_MODE); + cm_DSP_Destroy(); + cm_DM_Destroy(); + /* Nothing to do about SEM */ + //cm_MM_Destroy(); + cm_REP_Destroy(); + cm_COMP_Destroy(); + cm_OSAL_Destroy(); + + cm_StringRelease(traceDup); + cm_StringRelease(stubDup); + cm_StringRelease(skeletonDup); + cm_StringRelease(eventDup); + cm_StringRelease(anonymousDup); +} + +PUBLIC t_cm_error CM_ENGINE_ConfigureMediaProcessorCore( + t_nmf_core_id coreId, + t_nmf_executive_engine_id executiveEngineId, + t_nmf_semaphore_type_id semaphoreTypeId, + t_uint8 nbYramBanks, + const t_cm_system_address *mediaProcessorMappingBaseAddr, + const t_cm_domain_id eeDomain, + const t_cfg_allocator_id sdramCodeAllocId, + const t_cfg_allocator_id sdramDataAllocId + ) +{ + return cm_CFG_ConfigureMediaProcessorCore( + coreId, + executiveEngineId, + semaphoreTypeId, + nbYramBanks, + mediaProcessorMappingBaseAddr, + eeDomain, + (t_dsp_allocator_desc*)sdramCodeAllocId, + (t_dsp_allocator_desc*)sdramDataAllocId + ); +} + +PUBLIC t_cm_error CM_ENGINE_AddMpcSdramSegment( + const t_nmf_memory_segment *pDesc, + t_cfg_allocator_id *id, + const char *memoryname + ) +{ + return cm_CFG_AddMpcSdramSegment(pDesc, memoryname == NULL ? "" : memoryname, (t_dsp_allocator_desc**)id); +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_SetMode(t_cm_cmd_id aCmdID, t_sint32 aParam) +{ + t_cm_error error = CM_OK; + int i; + + OSAL_LOCK_API(); + + switch(aCmdID) { + case CM_CMD_DBG_MODE: + cm_PWR_SetMode(( aParam==1 ) ? DISABLE_PWR_MODE : NORMAL_PWR_MODE); + switch(cm_PWR_GetMode()) + { + case NORMAL_PWR_MODE: + // Release the MPC (which will switch it off if no more used) + for (i=FIRST_MPC_ID; i<NB_CORE_IDS; i++) + { + cm_CFG_ReleaseMpc(i); + } + break; + case DISABLE_PWR_MODE: + // Force the load of the EE if not already done. + for (i=FIRST_MPC_ID; i<NB_CORE_IDS;i++) + { + if((error = cm_CFG_CheckMpcStatus(i)) != CM_OK) + break; + } + break; + } + break; + case CM_CMD_TRACE_LEVEL: + if (aParam<-1) cm_debug_level = -1; + else cm_debug_level = aParam; + break; + case CM_CMD_INTENSIVE_CHECK: + cmIntensiveCheckState = aParam; + break; + + case CM_CMD_TRACE_ON: + cm_trace_enabled = TRUE; + cm_TRC_Dump(); + break; + case CM_CMD_TRACE_OFF: + cm_trace_enabled = FALSE; + break; + + case CM_CMD_MPC_TRACE_ON: + cm_EEM_setTraceMode((t_nmf_core_id)aParam, 1); + break; + case CM_CMD_MPC_TRACE_OFF: + cm_EEM_setTraceMode((t_nmf_core_id)aParam, 0); + break; + + case CM_CMD_MPC_PRINT_OFF: + cm_EEM_setPrintLevel((t_nmf_core_id)aParam, 0); + break; + case CM_CMD_MPC_PRINT_ERROR: + cm_EEM_setPrintLevel((t_nmf_core_id)aParam, 1); + break; + case CM_CMD_MPC_PRINT_WARNING: + cm_EEM_setPrintLevel((t_nmf_core_id)aParam, 2); + break; + case CM_CMD_MPC_PRINT_INFO: + cm_EEM_setPrintLevel((t_nmf_core_id)aParam, 3); + break; + case CM_CMD_MPC_PRINT_VERBOSE: + cm_EEM_setPrintLevel((t_nmf_core_id)aParam, 4); + break; + + case CM_CMD_ULP_MODE_ON: + cmUlpEnable = TRUE; + break; + + default: + error = CM_INVALID_PARAMETER; + break; + } + + OSAL_UNLOCK_API(); + + return error; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/dsp/inc/dsp.h b/drivers/staging/nmf-cm/cm/engine/dsp/inc/dsp.h new file mode 100644 index 00000000000..5cd65289ff8 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/dsp/inc/dsp.h @@ -0,0 +1,454 @@ +/* + * 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. + */ +/*! + * \internal + * \brief DSP abstraction layer + * + * \defgroup DSP_INTERNAL Private DSP Abstraction Layer API. + * + */ +#ifndef __INC_CM_DSP_H +#define __INC_CM_DSP_H + +#include <cm/inc/cm_type.h> +#include <share/inc/nmf.h> +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/memory/inc/memory.h> +#include <share/semaphores/inc/semaphores.h> +#include <cm/engine/memory/inc/remote_allocator.h> + + +#define SxA_NB_BLOCK_RAM 8 /*32kworks (24-bit) */ + +#define SxA_LOCKED_WAY 1 + +/* + * Type defintion to handle dsp offset in word + */ +typedef t_uint32 t_dsp_offset; + +typedef t_uint32 t_dsp_address; + +typedef enum { + DSP2ARM_IRQ_0, + DSP2ARM_IRQ_1 +} t_mpc2host_irq_num; + +typedef enum { + ARM2DSP_IRQ_0, + ARM2DSP_IRQ_1, + ARM2DSP_IRQ_2, + ARM2DSP_IRQ_3 +} t_host2mpc_irq_num; + +typedef enum { + INTERNAL_XRAM24 = 0, /* 24-bit XRAM */ + INTERNAL_XRAM16 = 1, /* 16-bit XRAM */ + INTERNAL_YRAM24 = 2, /* 24-bit YRAM */ + INTERNAL_YRAM16 = 3, /* 16-bit YRAM */ + SDRAM_EXT24 = 4, /* 24-bit external "X" memory */ + SDRAM_EXT16 = 5, /* 16-bit external "X" memory */ + ESRAM_EXT24 = 6, /* ESRAM24 */ + ESRAM_EXT16 = 7, /* ESRAM16 */ + SDRAM_CODE = 8, /* Program memory */ + ESRAM_CODE = 9, /* ESRAM code */ + LOCKED_CODE = 10, /* For way locking */ + NB_DSP_MEMORY_TYPE, + DEFAULT_DSP_MEM_TYPE = MASK_ALL16 +} t_dsp_memory_type_id; + +typedef struct { + t_cm_allocator_desc *allocDesc; + t_cm_system_address baseAddress; + t_uint32 referenceCounter; +} t_dsp_allocator_desc; + +typedef struct { + t_cm_system_address base; + t_uint32 size; +} t_dsp_segment; + +typedef enum { +#if defined(__STN_8500) && (__STN_8500 > 10) + SDRAM_CODE_EE, + SDRAM_CODE_USER, + SDRAM_DATA_EE, + SDRAM_DATA_USER, + NB_MIGRATION_SEGMENT, + ESRAM_CODE_EE = NB_MIGRATION_SEGMENT, + ESRAM_CODE_USER, + ESRAM_DATA_EE, + ESRAM_DATA_USER, +#else + SDRAM_CODE_EE, + SDRAM_DATA_EE, + ESRAM_CODE_EE, + ESRAM_DATA_EE, +#endif + NB_DSP_SEGMENT_TYPE +} t_dsp_segment_type; + +typedef struct { + t_dsp_segment_type segmentType; + t_uint32 baseOffset; +} t_dsp_address_info; + +typedef enum { + MPC_STATE_UNCONFIGURED, + MPC_STATE_BOOTABLE, + MPC_STATE_BOOTED, + MPC_STATE_PANIC, +} t_dsp_state; + +typedef struct { + t_dsp_state state; + t_uint8 nbYramBank; + t_cm_domain_id domainEE; + t_dsp_allocator_desc *allocator[NB_DSP_MEMORY_TYPE]; + t_dsp_segment segments[NB_DSP_SEGMENT_TYPE]; + t_uint32 yram_offset; + t_uint32 yram_size; + t_uint32 locked_offset; + t_uint32 locked_size; +} t_dsp_desc; + +typedef struct { + t_nmf_core_id coreId; + t_dsp_memory_type_id memType; // Index in MPC desc allocator + t_cm_allocator_desc *alloc; +} t_dsp_chunk_info; + +PUBLIC const t_dsp_desc* cm_DSP_GetState(t_nmf_core_id coreId); +PUBLIC void cm_DSP_SetStatePanic(t_nmf_core_id coreId); + +PUBLIC void cm_DSP_Init(const t_nmf_memory_segment *pEsramDesc); +PUBLIC void cm_DSP_Destroy(void); + +/*! + * \brief Initialize the memory segments management of a given MPC + * + * \param[in] coreId Identifier of the DSP to initialize + * \param[in] pDspMapDesc DSP mapping into host space + * \param[in] memConf configuration of the DSP memories (standalone or shared) + * + * \retval t_cm_error + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_Add(t_nmf_core_id coreId, + t_uint8 nbYramBanks, + const t_cm_system_address *pDspMapDesc, + const t_cm_domain_id eeDomain, + t_dsp_allocator_desc *sdramCodeAllocDesc, + t_dsp_allocator_desc *sdramDataAllocDesc); + + + +/*! + * \brief Configure a given Media Processor Core + * + * This routine programs the configuration (caches, ahb wrapper, ...) registers of a given MPC. + * + * \param[in] coreId Identifier of the DSP to initialize + * + * \retval t_cm_error + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_Boot(t_nmf_core_id coreId); + +/*! + * \brief Boot a given DSP + * + * This routine allows after having initialized and loaded the EE into a given DSP to start it (boot it) + * + * \param[in] coreId identifier of the DSP to boot + * \param[in] panicReasonOffset offset of panic reason which will pass to NONE_PANIC when DSP booted. + * + * \retval t_cm_error + * + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_ConfigureAfterBoot(t_nmf_core_id coreId); + +PUBLIC void cm_DSP_Start(t_nmf_core_id coreId); + +PUBLIC void cm_DSP_Stop(t_nmf_core_id coreId); + +/*! + * \brief Shutdown a given DSP + * + * This routine allows to stop and shutdown a given DSP + * + * \param[in] coreId identifier of the DSP to shutdown + * + * \retval t_cm_error + * + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_Shutdown(t_nmf_core_id coreId); + +PUBLIC t_uint32 cm_DSP_ReadXRamWord(t_nmf_core_id coreId, t_uint32 dspOffset); +PUBLIC void cm_DSP_WriteXRamWord(t_nmf_core_id coreId, t_uint32 dspOffset, t_uint32 value); + +/*! + * \brief Convert a Dsp address (offset inside a given DSP memory segment) into the host address (logical) + * + * \param[in] coreId identifier of the given DSP + * \param[in] dspAddress dsp address to be converted + * \param[in] memType memory type identifier + * + * \retval t_cm_logical_address + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_logical_address cm_DSP_ConvertDspAddressToHostLogicalAddress(t_nmf_core_id coreId, t_shared_addr dspAddress); + +/*! + * \brief Acknowledge the local interrupt of a given DSP (when not using HW semaphore mechanisms) + * + * \param[in] coreId identifier of the given DSP + * \param[in] irqNum irq identifier + * + * \retval void + * + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_AcknowledgeDspIrq(t_nmf_core_id coreId, t_mpc2host_irq_num irqNum); + + +/* + * Memory Management API routines + */ + +/*! + * \brief Retrieve DSP information for a memory chunk. + * + * This function retrieves information stored in user-data of the allocated chunk. + * See also \ref{t_dsp_chunk_info}. + * + * \param[in] memHandle Handle to the allocated chunk. + * \param[out] info Dsp information structure. + * + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_GetDspChunkInfo(t_memory_handle memHandle, t_dsp_chunk_info *info); + +/*! + * \brief Get memory allocator for a given memory type on a DSP. + * + * \param[in] coreId Dsp identifier. + * \param[in] memType Memory type identifier. + * + * \retval reference to the allocator descriptor (or null) + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_allocator_desc* cm_DSP_GetAllocator(t_nmf_core_id coreId, t_dsp_memory_type_id memType); + +/*! + * \brief Get DSP internal memory (TCM) information for allocation. + * + * For DSP-internal memories (TCMX, Y 16/24), return the offset and size of the allocation zone (for domain + * mechanism) and the allocation memory type. + * + * \param[in] coreId Dsp identifier. + * \param[in] memType Memory type identifier. + * \param[out] mem_info Memory information structure. + * + * \retval CM_OK + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_GetInternalMemoriesInfo(t_cm_domain_id domainId, t_dsp_memory_type_id memType, + t_uint32 *offset, t_uint32 *size); + + +/*! + * \brief Convert word size to byte size. + * + * \param[in] memType Memory type identifier. + * \param[in] wordSize Word size to be converted. + * + * \retval Byte size. + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_uint32 cm_DSP_ConvertSize(t_dsp_memory_type_id memType, t_uint32 wordSize); + +/*! + * \brief Provide the Memory status of a given memory type for a given DSP + * + * \param[in] coreId dsp identifier. + * \param[in] memType Type of memory. + * \param[out] pStatus requested memory status + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_GetAllocatorStatus(t_nmf_core_id coreId, t_dsp_memory_type_id memType, t_uint32 offset, t_uint32 size, t_cm_allocator_status *pStatus); + +/*! + * \brief Provide DSP memory host shared address + * + * \param[in] memHandle Allocated block handle + * \param[out] pAddr Returned system address. + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_GetHostSystemAddress( t_memory_handle memHandle, t_cm_system_address *pAddr); + +/*! + * \brief Get physical address of a memory chunk. + * + * \param[in] memHandle Memory handle. + * + * \retval Physical address. + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_physical_address cm_DSP_GetPhysicalAdress(t_memory_handle memHandle); + +/*! + * \brief Return Logical Address of an allocated memory chunk. + * + * \param[in] memHandle Allocated chunk handle + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_logical_address cm_DSP_GetHostLogicalAddress(t_memory_handle memHandle); + +/*! + * \brief Provide DSP memory DSP address (offset inside a given DSP memory segment) + * + * \param[in] memHandle Allocated block handle + * \param[out] dspAddress allocated block address seen by the given DSP + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_GetDspAddress(t_memory_handle handle, t_uint32 *pDspAddress); + +/*! + * \brief Return the adress of the DSP base associated to the memory type. + * Caution, this information is valid only in normal state (not when migrated). + * + * \param[in] coreId DSP Identifier. + * \param[in] memType Type of memory. + * \param[out] pAddr Base address. + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_GetDspBaseAddress(t_nmf_core_id coreId, t_dsp_memory_type_id memType, t_cm_system_address *pAddr); + +/*! + * \brief Return DSP memory handle offset (offset inside a given DSP memory) + * + * \param[in] coreId dsp identifier. + * \param[in] memType Type of memory. + * \param[in] memHandle Allocated block handle + * + * \retval t_uint32: Offset of memory handle inside memory + * \ingroup DSP_INTERNAL + */ +PUBLIC t_uint32 cm_DSP_GetDspMemoryHandleOffset( + t_nmf_core_id coreId, + t_dsp_memory_type_id dspMemType, + t_memory_handle memHandle); + +/*! + * \brief Provide DSP memory handle size + * + * \param[in] memHandle Allocated block handle + * \param[out] pDspSize Size of the given memory handle + + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC void cm_DSP_GetDspMemoryHandleSize(t_memory_handle memHandle, t_uint32 *pDspSize); + +/*! + * \brief Resize xram allocator to reserve spave for stack. + * + * \param[in] coreId dsp identifier. + * \param[in] newStackSize New required stack size. + + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_setStackSize(t_nmf_core_id coreId, t_uint32 newStackSize); + +/*! + * \brief Allow to know if nbYramBanks parameter is valid for coreId. This api is need since use of nbYramBanks + * is deferred. + * + * \param[in] coreId dsp identifier. + * \param[in] nbYramBanks number of yramBanks to use. + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_IsNbYramBanksValid(t_nmf_core_id coreId, t_uint8 nbYramBanks); + +/*! + * \brief Allow to know stack base address according to coreId and nbYramBanks use. + * + * \param[in] coreId dsp identifier. + * \param[in] nbYramBanks number of yramBanks to use. + * + * \retval t_uint32 return stack address + * \ingroup DSP_INTERNAL + */ +PUBLIC t_uint32 cm_DSP_getStackAddr(t_nmf_core_id coreId); + +/*! + * \brief For a give dsp adress return the offset from the hardware base that the adress is relative to. + * + * \param[in] coreId DSP identifier. + * \param[in] adr DSP address. + * \param[out] info Info structure containing (hw base id, offset) + * + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_GetDspDataAddressInfo(t_nmf_core_id coreId, t_uint32 adr, t_dsp_address_info *info); + +/*! + * \brief Modify the mapping of a code hardware base. Used for memory migration. + * + * The function calculates the new hardware base so that in the DSP address-space, + * the source address will be mapped to the destination address. + * + * \param[in] coreId DSP Identifier. + * \param[in] hwSegment Identifier of the hardware segment (thus hardware base). + * \param[in] src Source address + * \param[in] dst Destination address + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_updateCodeBase(t_nmf_core_id coreId, t_dsp_segment_type hwSegment, t_cm_system_address src, t_cm_system_address dst); + +/*! + * \brief Modify the mapping of a data hardware base. Used for memory migration. + * + * The function calculates the new hardware base so that in the DSP address-space, + * the source address will be mapped to the destination address. + * + * \param[in] coreId DSP Identifier. + * \param[in] hwSegment Identifier of the hardware segment (thus hardware base). + * \param[in] src Source address + * \param[in] dst Destination address + * + * \retval t_cm_error + * \ingroup DSP_INTERNAL + */ +PUBLIC t_cm_error cm_DSP_updateDataBase(t_nmf_core_id coreId, t_dsp_segment_type hwSegment, t_cm_system_address src, t_cm_system_address dst); + +#endif /* __INC_CM_DSP_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/dsp/inc/semaphores_dsp.h b/drivers/staging/nmf-cm/cm/engine/dsp/inc/semaphores_dsp.h new file mode 100644 index 00000000000..1bb1c34cced --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/dsp/inc/semaphores_dsp.h @@ -0,0 +1,22 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_CM_SEMAPHORES_DSP_H +#define __INC_CM_SEMAPHORES_DSP_H + +#include <share/semaphores/inc/semaphores.h> +#include <cm/engine/dsp/inc/dsp.h> + +PUBLIC void cm_DSP_SEM_Take(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_DSP_SEM_Give(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_DSP_SEM_GenerateIrq(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_DSP_AssertDspIrq(t_nmf_core_id coreId, t_host2mpc_irq_num irqNum); + +PUBLIC void cm_DSP_AcknowledgeDspIrq(t_nmf_core_id coreId, t_mpc2host_irq_num irqNum); + +#endif /* __INC_CM_SEMAPHORES_DSP_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h b/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h new file mode 100644 index 00000000000..0ddc71d2c4f --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h @@ -0,0 +1,959 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_MMDSP_HWP_H +#define __INC_MMDSP_HWP_H + +#include <cm/inc/cm_type.h> + +#define MMDSP_NB_BLOCK_RAM 8 +#define MMDSP_RAM_BLOCK_SIZE 4096 /* 0x1000 */ +#define MMDSP_NB_TIMER 3 +#define MMDSP_NB_BIT_SEM 8 +#define MMDSP_NB_DMA_IF 8 +#define MMDSP_NB_DMA_CTRL 4 +#define MMDSP_NB_ITREMAP_REG 32 + +#define MMDSP_INSTRUCTION_WORD_SIZE (sizeof(t_uint64)) +#define MMDSP_ICACHE_LINE_SIZE_IN_INST (4) +#define MMDSP_ICACHE_LINE_SIZE (MMDSP_ICACHE_LINE_SIZE_IN_INST * MMDSP_INSTRUCTION_WORD_SIZE) + +#define MMDSP_DATA_WORD_SIZE (3) +#define MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE (sizeof(t_uint32)) +#define MMDSP_DATA_WORD_SIZE_IN_EXT24 (sizeof(t_uint32)) +#define MMDSP_DATA_WORD_SIZE_IN_EXT16 (sizeof(t_uint16)) +#define MMDSP_DCACHE_LINE_SIZE_IN_WORDS (8) +#define MMDSP_DCACHE_LINE_SIZE (MMDSP_DCACHE_LINE_SIZE_IN_WORDS * sizeof(t_uint32)) + +#define MMDSP_NB_IO 16 + +#define MMDSP_CODE_CACHE_WAY_SIZE 256 + +//#define MMDSP_ESRAM_DSP_BASE_ADDR 0xE0000 /* 64-bit words */ +//#define MMDSP_DATA24_DSP_BASE_ADDR 0x10000 +//#define MMDSP_DATA16_DSP_BASE_ADDR 0x800000 +//#define MMDSP_MMIO_DSP_BASE_ADDR 0xF80000 + +/* Specified according MMDSP & ELF convention */ +/* Note: Here we assume that ESRAM is less than 2MB */ +#define SDRAMTEXT_BASE_ADDR 0x00000000 +#define ESRAMTEXT_BASE_ADDR 0x000E0000 + +#define SDRAMMEM24_BASE_ADDR 0x00010000 +#define ESRAMMEM24_BASE_ADDR 0x00600000 /* ELF == 0x00400000 TODO: Update it in MMDSP ELF compiler */ +#define SDRAMMEM16_BASE_ADDR 0x00800000 +#define ESRAMMEM16_BASE_ADDR 0x00D80000 /* ELF == 0x00BC0000 TODO: Update it in MMDSP ELF compiler */ + +#define MMIO_BASE_ADDR 0x00F80000 + +/* + * Definition of indirect host registers + */ +#define IHOST_ICACHE_FLUSH_REG 0x0 +#define IHOST_ICACHE_FLUSH_CMD_ENABLE (t_uint64)MASK_BIT0 +#define IHOST_ICACHE_FLUSH_ALL_ENTRIES_CMD (t_uint64)0x0 +#if 0 +#define IHOST_ICACHE_INVALID_ALL_UNLOCKED_L2_LINES_CMD (t_uint64)0x8 +#define IHOST_ICACHE_INVALID_ALL_LOCKED_L2_LINES_CMD (t_uint64)0xA +#define IHOST_ICACHE_UNLOCK_ALL_LOCKED_L2_LINES_CMD (t_uint64)0xC +#define IHOST_ICACHE_LOCK_ALL_WAYS_LESSER_THAN_LOCK_V_CMD (t_uint64)0xE +#else +#define IHOST_ICACHE_INVALID_ALL_UNLOCKED_L2_LINES_CMD (t_uint64)0x10 +#define IHOST_ICACHE_INVALID_ALL_LOCKED_L2_LINES_CMD (t_uint64)0x12 +#define IHOST_ICACHE_UNLOCK_ALL_LOCKED_L2_LINES_CMD (t_uint64)0x14 +#define IHOST_ICACHE_LOCK_ALL_WAYS_LESSER_THAN_LOCK_V_CMD (t_uint64)0x16 +#define IHOST_ICACHE_FLUSH_BY_SERVICE (t_uint64)0x18 +#define IHOST_ICACHE_FLUSH_OUTSIDE_RANGE (t_uint64)0x1A +#endif + +#define IHOST_ICACHE_LOCK_V_REG 0x1 + +#define IHOST_ICACHE_MODE_REG 0x2 +#define IHOST_ICACHE_MODE_PERFMETER_ON (t_uint64)MASK_BIT0 +#define IHOST_ICACHE_MODE_PERFMETER_OFF (t_uint64)0x0 +#define IHOST_ICACHE_MODE_L2_CACHE_ON (t_uint64)MASK_BIT1 +#define IHOST_ICACHE_MODE_L2_CACHE_OFF (t_uint64)0x0 +#define IHOST_ICACHE_MODE_L1_CACHE_ON (t_uint64)MASK_BIT2 +#define IHOST_ICACHE_MODE_L1_CACHE_OFF (t_uint64)0x0 +#define IHOST_ICACHE_MODE_FILL_MODE_ON (t_uint64)MASK_BIT3 +#define IHOST_ICACHE_MODE_FILL_MODE_OFF (t_uint64)0x0 + +#define IHOST_CLEAR_PERFMETER_REG 0x3 +#define IHOST_CLEAR_PERFMETER_ON (t_uint64)0x1 +#define IHOST_CLEAR_PERFMETER_OFF (t_uint64)0x0 + +#define IHOST_PERF_HIT_STATUS_REG 0x4 + +#define IHOST_PERF_MISS_STATUS_REG 0x5 + +#define IHOST_FILL_START_WAY_REG 0x6 +#define IHOST_FILL_START_ADDR_VALUE_SHIFT 0U +#define IHOST_FILL_WAY_NUMBER_SHIFT 20U + +#define IHOST_PRG_BASE_ADDR_REG 0x7 +#define IHOST_PRG_BASE1_ADDR_SHIFT 0 +#define IHOST_PRG_BASE2_ADDR_SHIFT 32 + +#if defined(__STN_8500) && (__STN_8500>10) +#define IHOST_PRG_BASE_34_ADDR_REG 0x1A +#define IHOST_PRG_BASE3_ADDR_SHIFT 0 +#define IHOST_PRG_BASE4_ADDR_SHIFT 32 +#endif + +#if defined(__STN_8815) /* __STN_8815 */ +#define IHOST_PRG_AHB_CONF_REG 0x8 +#define IHOST_PRG_AHB_LOCKED_SHIFT 0U +#define IHOST_PRG_AHB_PROT_SHIFT 1U + +#define AHB_LOCKED_ON (t_uint64)1 +#define AHB_LOCKED_OFF (t_uint64)0 + +#define AHB_PROT_USER (t_uint64)0 +#define AHB_PROT_PRIVILEGED (t_uint64)MASK_BIT0 +#define AHB_PROT_NONBUFFERABLE (t_uint64)0 +#define AHB_PROT_BUFFERABLE (t_uint64)MASK_BIT1 +#define AHB_PROT_NONCACHEABLE (t_uint64)0 +#define AHB_PROT_CACHEABLE (t_uint64)MASK_BIT2 + + +#define IHOST_DATA_AHB_CONF_REG 0x9 +#define IHOST_DATA_AHB_LOCKED_SHIFT 0U +#define IHOST_DATA_AHB_PROT_SHIFT 1U +#else /* def __STN_8820 or __STN_8500 */ +#define IHOST_STBUS_ID_CONF_REG 0x8 +#define SAA_STBUS_ID 176 /* = 0xB0 */ +#define SVA_STBUS_ID 4 /* = 0x4 */ +#define SIA_STBUS_ID 180 /* = 0xB4 */ + +#define IHOST_STBUF_CONF_REG 0x9 /* RESERVED */ +#endif /* __STN_8820 or __STN_8500 */ + +#define IHOST_DATA_EXT_BUS_BASE_REG 0xA +#define IHOST_DATA_EXT_BUS_BASE_16_SHIFT 32ULL +#define IHOST_DATA_EXT_BUS_BASE_24_SHIFT 0ULL + +#define IHOST_EXT_MMIO_BASE_DATA_EXT_BUS_TOP_REG 0xB +#define IHOST_EXT_MMIO_DATA_EXT_BUS_TOP_SHIFT 0ULL +#define IHOST_EXT_MMIO_BASE_ADDR_SHIFT 32ULL + +#define IHOST_DATA_EXT_BUS_BASE2_REG 0xC +#define IHOST_DATA_EXT_BUS_BASE2_16_SHIFT 32ULL +#define IHOST_DATA_EXT_BUS_BASE2_24_SHIFT 0ULL + +#if defined(__STN_8500) && (__STN_8500>10) + +#define IHOST_DATA_EXT_BUS_BASE3_REG 0x1B +#define IHOST_DATA_EXT_BUS_BASE3_16_SHIFT 32ULL +#define IHOST_DATA_EXT_BUS_BASE3_24_SHIFT 0ULL + +#define IHOST_DATA_EXT_BUS_BASE4_REG 0x1C +#define IHOST_DATA_EXT_BUS_BASE4_16_SHIFT 32ULL +#define IHOST_DATA_EXT_BUS_BASE4_24_SHIFT 0ULL + +#endif + +#define IHOST_ICACHE_STATE_REG 0xD +#define IHOST_ICACHE_STATE_RESET 0x0 +#define IHOST_ICACHE_STATE_INITAGL2 0x1 +#define IHOST_ICACHE_STATE_READY_TO_START 0x2 +#define IHOST_ICACHE_STATE_WAIT_FOR_MISS 0x3 +#define IHOST_ICACHE_STATE_FILLDATARAM0 0x4 +#define IHOST_ICACHE_STATE_FILLDATARAM1 0x5 +#define IHOST_ICACHE_STATE_FILLDATARAM2 0x6 +#define IHOST_ICACHE_STATE_FILLDATARAM3 0x7 +#define IHOST_ICACHE_STATE_FLUSH 0x8 +#define IHOST_ICACHE_STATE_FILL_INIT 0x9 +#define IHOST_ICACHE_STATE_FILL_LOOP 0xA +#define IHOST_ICACHE_STATE_FILL_LOOP0 0xB +#define IHOST_ICACHE_STATE_FILL_LOOP1 0xC +#define IHOST_ICACHE_STATE_FILL_LOOP2 0xD +#define IHOST_ICACHE_STATE_FILL_LOOP3 0xE +#define IHOST_ICACHE_STATE_FILL_END 0xF +#define IHOST_ICACHE_STATE_SPECIFIC_FLUSH_R 0x10 +#define IHOST_ICACHE_STATE_SPECIFIC_FLUSH_W 0x11 +#define IHOST_ICACHE_STATE_SPECIFIC_FLUSH_END 0x12 +#define IHOST_ICACHE_STATE_OTHERS 0x1F + +#define IHOST_EN_EXT_BUS_TIMEOUT_REG 0xE +#define IHOST_TIMEOUT_ENABLE 1ULL +#define IHOST_TIMEOUT_DISABLE 0ULL + +#define IHOST_DATA2_1624_XA_BASE_REG 0xF +#define IHOST_DATA2_24_XA_BASE_SHIFT 0ULL +#define IHOST_DATA2_16_XA_BASE_SHIFT 32ULL +#if defined(__STN_8500) && (__STN_8500>10) +#define IHOST_DATA3_24_XA_BASE_SHIFT 8ULL +#define IHOST_DATA3_16_XA_BASE_SHIFT 40ULL +#define IHOST_DATA4_24_XA_BASE_SHIFT 16ULL +#define IHOST_DATA4_16_XA_BASE_SHIFT 48ULL +#endif + +#define IHOST_PERFMETERS_MODE_REG 0x10 + +#if defined(__STN_8815) /* __STN_8815 */ +#define IHOST_EXT_MMIO_AHB_CONF_REG 0x11 +#define IHOST_EXT_MMIO_AHB_LOCKED_SHIFT 0U +#define IHOST_EXT_MMIO_AHB_PROT_SHIFT 1U +#else /* def __STN_8820 or __STN_8500 */ +#define IHOST_EXT_MMIO_STBS_CONF_REG 0x11 /* RESERVED */ +#endif /* __STN_8820 or __STN_8500 */ + +#define IHOST_PRG_BASE_SEL_REG 0x12 +#define IHOST_PRG_BASE_SEL_OFF (t_uint64)0 +#define IHOST_PRG_BASE_SEL_ON (t_uint64)1 + +#define IHOST_PRG_BASE2_ACTIV_REG 0x13 +#define IHOST_PRG_BASE2_ACTIV_OFF (t_uint64)0 +#if defined(__STN_8500) && (__STN_8500>10) +/* TODO : for the moment just divide mmdsp in fix 4 spaces */ + #define IHOST_PRG_BASE2_ACTIV_ON (t_uint64)((((t_uint64)0xf0000>>10)<<48) | (((t_uint64)0xe0000>>10)<<32) | (((t_uint64)0x70000>>10)<<16) | 1) +#else + #define IHOST_PRG_BASE2_ACTIV_ON (t_uint64)1 +#endif + +#define IHOST_DATA_EXT_BUS_TOP_16_24_REG 0x14 +#define IHOST_DATA_EXT_BUS_TOP_24_SHIFT 0ULL +#define IHOST_DATA_EXT_BUS_TOP_16_SHIFT 32ULL + +#define IHOST_DATA_TOP_16_24_CHK_REG 0x16 +#define IHOST_DATA_TOP_16_24_CHK_OFF (t_uint64)0 +#define IHOST_DATA_TOP_16_24_CHK_ON (t_uint64)1 + +#define IHOST_EXT_BUS_TOP2_16_24_REG 0x15 +#define IHOST_DATA_EXT_BUS_TOP2_24_SHIFT 0ULL +#define IHOST_DATA_EXT_BUS_TOP2_16_SHIFT 32ULL + +#if defined(__STN_8500) && (__STN_8500>10) + +#define IHOST_EXT_BUS_TOP3_16_24_REG 0x1D +#define IHOST_DATA_EXT_BUS_TOP3_24_SHIFT 0ULL +#define IHOST_DATA_EXT_BUS_TOP3_16_SHIFT 32ULL + +#define IHOST_EXT_BUS_TOP4_16_24_REG 0x1E +#define IHOST_DATA_EXT_BUS_TOP4_24_SHIFT 0ULL +#define IHOST_DATA_EXT_BUS_TOP4_16_SHIFT 32ULL + +#endif + +#define IHOST_DATA_BASE2_ACTIV_REG 0x17 +#define IHOST_DATA_BASE2_ACTIV_OFF (t_uint64)0 +#define IHOST_DATA_BASE2_ACTIV_ON (t_uint64)1 + +#define IHOST_INST_BURST_SZ_REG 0x18 +#define IHOST_INST_BURST_SZ_ALWAYS_1_LINE (t_uint64)0x0 +#define IHOST_INST_BURST_SZ_ALWAYS_2_LINES (t_uint64)0x1 +#define IHOST_INST_BURST_SZ_AUTO (t_uint64)0x2 /* 2 lines for SDRAM [0, 0xE0000[, 1 line for ESRAM [0xE0000, 0xFFFFF] */ + +#define IHOST_ICACHE_END_CLEAR_REG 0x19 +#define IHOST_ICACHE_START_CLEAR_REG IHOST_FILL_START_WAY_REG + +/* + * Definition of value of the ucmd register + */ +#define MMDSP_UCMD_WRITE 0 +#define MMDSP_UCMD_READ 4 +#define MMDSP_UCMD_CTRL_STATUS_ACCESS 0x10 // (MASK_BIT4 | !MASK_BIT3 | !MASK_BIT0) +#define MMDSP_UCMD_DECREMENT_ADDR MASK_BIT5 +#define MMDSP_UCMD_INCREMENT_ADDR MASK_BIT1 + +/* + * Definition of value of the ubkcmd register + */ +#define MMDSP_UBKCMD_EXT_CODE_MEM_ACCESS_ENABLE MASK_BIT3 +#define MMDSP_UBKCMD_EXT_CODE_MEM_ACCESS_DISABLE 0 + +/* + * Definition of value of the clockcmd register + */ +#define MMDSP_CLOCKCMD_STOP_CLOCK MASK_BIT0 +#define MMDSP_CLOCKCMD_START_CLOCK 0 + +/* + * Definition of macros used to access indirect addressed host register + */ +#define WRITE_INDIRECT_HOST_REG(pRegs, addr, value64) \ +{ \ + (pRegs)->host_reg.emul_uaddrl = addr; \ + (pRegs)->host_reg.emul_uaddrm = 0; \ + (pRegs)->host_reg.emul_uaddrh = 0; \ + (pRegs)->host_reg.emul_udata[0] = ((value64 >> 0ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[1] = ((value64 >> 8ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[2] = ((value64 >> 16ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[3] = ((value64 >> 24ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[4] = ((value64 >> 32ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[5] = ((value64 >> 40ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[6] = ((value64 >> 48ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_udata[7] = ((value64 >> 56ULL) & MASK_BYTE0); \ + (pRegs)->host_reg.emul_ucmd = (MMDSP_UCMD_CTRL_STATUS_ACCESS | MMDSP_UCMD_WRITE); \ +} + +#define READ_INDIRECT_HOST_REG(pRegs, addr, value64) \ +{ \ + (pRegs)->host_reg.emul_udata[0] = 0; \ + (pRegs)->host_reg.emul_udata[1] = 0; \ + (pRegs)->host_reg.emul_udata[2] = 0; \ + (pRegs)->host_reg.emul_udata[3] = 0; \ + (pRegs)->host_reg.emul_udata[4] = 0; \ + (pRegs)->host_reg.emul_udata[5] = 0; \ + (pRegs)->host_reg.emul_udata[6] = 0; \ + (pRegs)->host_reg.emul_udata[7] = 0; \ + (pRegs)->host_reg.emul_uaddrl = addr; \ + (pRegs)->host_reg.emul_uaddrm = 0; \ + (pRegs)->host_reg.emul_uaddrh = 0; \ + (pRegs)->host_reg.emul_ucmd = (MMDSP_UCMD_CTRL_STATUS_ACCESS | MMDSP_UCMD_READ); \ + value64 = (((t_uint64)((pRegs)->host_reg.emul_udata[0])) << 0ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[1])) << 8ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[2])) << 16ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[3])) << 24ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[4])) << 32ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[5])) << 40ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[6])) << 48ULL) | \ + (((t_uint64)((pRegs)->host_reg.emul_udata[7])) << 56ULL); \ +} + +/* Common type to handle 64-bit modulo field in 32-bit mode */ +typedef struct { + t_uint32 value; + t_uint32 dummy; +} t_mmdsp_field_32; + +typedef struct { + t_uint16 value; + t_uint16 dummy; +} t_mmdsp_field_16; + +/* DCache registers */ +#define DCACHE_MODE_ENABLE MASK_BIT0 +#define DCACHE_MODE_DISABLE 0 +#define DCACHE_MODE_DIVIDE_PER_2 MASK_BIT1 +#define DCACHE_MODE_DIVIDE_PER_4 MASK_BIT2 +#define DCACHE_MODE_CHECK_TAG_ENABLE MASK_BIT3 +#define DCACHE_MODE_CHECK_TAG_DISABLE 0 +#define DCACHE_MODE_FORCE_LOCK_MODE MASK_BIT4 +#define DCACHE_MODE_LOCK_BIT MASK_BIT5 + +#define DCACHE_CONTROL_PREFETCH_LINE MASK_BIT0 +#define DCACHE_CONTROL_NON_BLOCKING_REFILL 0 +#define DCACHE_CONTROL_FAST_READ_DISABLE MASK_BIT1 +#define DCACHE_CONTROL_FAST_READ_ENABLE 0 +#define DCACHE_CONTROL_ON_FLY_FILL_ACCESS_OFF MASK_BIT2 +#define DCACHE_CONTROL_ON_FLY_FILL_ACCESS_ON 0 +#define DCACHE_CONTROL_BURST_1_WRAP8 MASK_BIT3 +#define DCACHE_CONTROL_BURST_2_WRAP4 0 +#define DCACHE_CONTROL_NOT_USE_DATA_BUFFER MASK_BIT4 +#define DCACHE_CONTROL_USE_DATA_BUFFER 0 +#define DCACHE_CONTROL_WRITE_POSTING_ENABLE MASK_BIT5 +#define DCACHE_CONTROL_WRITE_POSTING_DISABLE 0 + +#define DCACHE_CMD_NOP 0 +#define DCACHE_CMD_DISCARD_WAY 2 //see Dcache_way reg +#define DCACHE_CMD_DISCARD_LINE 3 //see Dcache_line reg +#define DCACHE_CMD_FREE_WAY 4 //see Dcache_way reg +#define DCACHE_CMD_FREE_LINE 5 //see Dchache_line reg +#define DCACHE_CMD_FLUSH 7 + +#define DCACHE_STATUS_CURRENT_WAY_MASK (MASK_BIT2 | MASK_BIT1 | MASK_BIT0) +#define DCACHE_STATUS_TAG_HIT_MASK MASK_BIT3 +#define DCACHE_STATUS_TAG_LOCKED_MASK MASK_BIT4 +#define DCACHE_STATUS_PROTECTION_ERROR_MASK MASK_BIT5 + +#define DCACHE_CPTRSEL_COUNTER_1_MASK (MASK_BIT3 | MASK_BIT2 | MASK_BIT1 | MASK_BIT0) +#define DCACHE_CPTRSEL_COUNTER_1_SHIFT 0 +#define DCACHE_CPTRSEL_COUNTER_2_MASK (MASK_BIT7 | MASK_BIT6 | MASK_BIT5 | MASK_BIT4) +#define DCACHE_CPTRSEL_COUNTER_2_SHIFT 4 +#define DCACHE_CPTRSEL_COUNTER_3_MASK (MASK_BIT11 | MASK_BIT10 | MASK_BIT9 | MASK_BIT8) +#define DCACHE_CPTRSEL_COUNTER_3_SHIFT 8 +#define DCACHE_CPTRSEL_XBUS_ACCESS_TO_CACHE_RAM 1 +#define DCACHE_CPTRSEL_CACHE_HIT 2 +#define DCACHE_CPTRSEL_LINE_MATCH 3 +#define DCACHE_CPTRSEL_XBUS_WS 4 +#define DCACHE_CPTRSEL_EXTMEM_WS 5 +#define DCACHE_CPTRSEL_CACHE_READ 6 +#define DCACHE_CPTRSEL_CACHE_WRITE 7 +#define DCACHE_CPTRSEL_TAG_HIT_READ 8 +#define DCACHE_CPTRSEL_TAG_LOCKED_ACCESS 9 +#define DCACHE_CPTRSEL_TAG_MEM_READ_CYCLE 10 +#define DCACHE_CPTRSEL_TAG_MEM_WRITE_CYCLE 11 + + +typedef volatile struct { + t_uint16 padding_1[5]; + t_uint16 mode; + t_uint16 control; + t_uint16 way; + t_uint16 line; + t_uint16 command; + t_uint16 status; + t_uint16 cptr1l; + t_uint16 cptr1h; + t_uint16 cptr2l; + t_uint16 cptr2h; + t_uint16 cptr3l; + t_uint16 cptr3h; + t_uint16 cptrsel; + t_uint16 flush_base_lsb; /* only on STn8820 and STn8500 */ + t_uint16 flush_base_msb; /* only on STn8820 and STn8500 */ + t_uint16 flush_top_lsb; /* only on STn8820 and STn8500 */ + t_uint16 flush_top_msb; /* only on STn8820 and STn8500 */ + t_uint16 padding_2[10]; +} t_mmdsp_dcache_regs_16; + +typedef volatile struct { + t_uint32 padding_1[5]; + t_uint32 mode; + t_uint32 control; + t_uint32 way; + t_uint32 line; + t_uint32 command; + t_uint32 status; + t_uint32 cptr1l; + t_uint32 cptr1h; + t_uint32 cptr2l; + t_uint32 cptr2h; + t_uint32 cptr3l; + t_uint32 cptr3h; + t_uint32 cptrsel; + t_uint32 flush_base_lsb; /* only on STn8820 and STn8500 */ + t_uint32 flush_base_msb; /* only on STn8820 and STn8500 */ + t_uint32 flush_top_lsb; /* only on STn8820 and STn8500 */ + t_uint32 flush_top_msb; /* only on STn8820 and STn8500 */ + t_uint32 padding_2[10]; +} t_mmdsp_dcache_regs_32; + +/* TIMER Registers */ +typedef volatile struct { + t_mmdsp_field_16 timer_msb; + t_mmdsp_field_16 timer_lsb; +} t_mmdsp_timer_regs_16; + +typedef volatile struct { + t_mmdsp_field_32 timer_msb; + t_mmdsp_field_32 timer_lsb; +} t_mmdsp_timer_regs_32; + + +/* DMA interface Registers */ +typedef volatile struct { + t_uint16 arm_dma_sreq; /* dma0: 5e800, dma1: +0x20 ...*/ + t_uint16 arm_dma_breq; /* ... 5e802 */ + t_uint16 arm_dma_lsreq; /* ... 5e804 */ + t_uint16 arm_dma_lbreq; + t_uint16 arm_dma_maskit; + t_uint16 arm_dma_it; + t_uint16 arm_dma_auto; + t_uint16 arm_dma_lauto; + t_uint16 dma_reserved[8]; +} t_mmdsp_dma_if_regs_16; + +typedef volatile struct { + t_uint32 arm_dma_sreq; /* dma0: 3a800, dma1: +0x40 ...*/ + t_uint32 arm_dma_breq; /* ... 3a804 */ + t_uint32 arm_dma_lsreq; /* ... 3a808 */ + t_uint32 arm_dma_lbreq; + t_uint32 arm_dma_maskit; + t_uint32 arm_dma_it; + t_uint32 arm_dma_auto; + t_uint32 arm_dma_lauto; + t_uint32 dma_reserved[8]; +} t_mmdsp_dma_if_regs_32; + +/* MMDSP DMA controller Registers */ +typedef volatile struct { + t_uint16 dma_ctrl; /* dma0: 0x5d400, dma1: +0x10 ... */ + t_uint16 dma_int_base; /* ... 0x5d402 */ + t_uint16 dma_int_length; /* ... 0x5d404 */ + t_uint16 dma_ext_baseh; + t_uint16 dma_ext_basel; + t_uint16 dma_count; + t_uint16 dma_ext_length; + t_uint16 dma_it_status; +} t_mmdsp_dma_ctrl_regs_16; + +typedef volatile struct { + t_uint32 dma_ctrl; /* dma0: 0x3a800, dma1: +0x20 ... */ + t_uint32 dma_int_base; /* ... 0x3a804 */ + t_uint32 dma_int_length; /* ... 0x3a808 */ + t_uint32 dma_ext_baseh; + t_uint32 dma_ext_basel; + t_uint32 dma_count; + t_uint32 dma_ext_length; + t_uint32 dma_it_status; +} t_mmdsp_dma_ctrl_regs_32; + +/* IO registers */ +typedef volatile struct { + t_mmdsp_field_16 io_bit[MMDSP_NB_IO]; + t_mmdsp_field_16 io_lsb; + t_mmdsp_field_16 io_msb; + t_mmdsp_field_16 io_all; + t_mmdsp_field_16 io_en; +} t_mmdsp_io_regs_16; + +typedef volatile struct { + t_mmdsp_field_32 io_bit[MMDSP_NB_IO]; + t_mmdsp_field_32 io_lsb; + t_mmdsp_field_32 io_msb; + t_mmdsp_field_32 io_all; + t_mmdsp_field_32 io_en; +} t_mmdsp_io_regs_32; + +/* HOST Registers bit mapping */ +#define HOST_GATEDCLK_ITREMAP MASK_BIT0 +#define HOST_GATEDCLK_SYSDMA MASK_BIT1 +#define HOST_GATEDCLK_INTEG_REGS MASK_BIT2 +#define HOST_GATEDCLK_TIMER_GPIO MASK_BIT3 +#define HOST_GATEDCLK_XBUSDMA MASK_BIT4 +#define HOST_GATEDCLK_STACKCTRL MASK_BIT5 +#define HOST_GATEDCLK_ITC MASK_BIT6 + +/* Only for STn8820 and STn8500 */ +#define HOST_PWR_DBG_MODE MASK_BIT0 +#define HOST_PWR_DC_STATUS (MASK_BIT1 | MASK_BIT2 | MASK_BIT3 | MASK_BIT4 | MASK_BIT5) +#define HOST_PWR_DE_STATUS MASK_BIT6 +#define HOST_PWR_STOV_STATUS MASK_BIT7 + +/* HOST Registers */ +typedef volatile struct { + t_uint16 ident; /*0x...60000*/ + t_uint16 identx[4]; /*0x...60002..8*/ + t_uint16 r5; /*0x...6000a*/ + t_uint16 r6; /*0x...6000c*/ + t_uint16 inte[2]; /*0x...6000e..10*/ + t_uint16 intx[2]; /*0x...60012..14*/ + t_uint16 int_ris[2]; /*0x...60016..18*/ + t_uint16 intpol; /*0x...6001a*/ + t_uint16 pwr; /*0x...6001c*/ /* only on STn8820 and STn8500 */ + t_uint16 gatedclk; /*0x...6001e*/ + t_uint16 softreset; /*0x...60020*/ + t_uint16 int_icr[2]; /*0x...60022..24*/ + t_uint16 cmd[4]; /*0x...60026..2c*/ + t_uint16 RESERVED4; + t_uint16 int_mis0; /*0x...60030*/ + t_uint16 RESERVED5; + t_uint16 RESERVED6; + t_uint16 RESERVED7; + t_uint16 i2cdiv; /*0x...60038*/ + t_uint16 int_mis1; /*0x...6003a*/ + t_uint16 RESERVED8; + t_uint16 RESERVED9; + t_uint16 emul_udata[8]; /*0x...60040..4e*/ + t_uint16 emul_uaddrl; /*0x...60050*/ + t_uint16 emul_uaddrm; /*0x...60052*/ + t_uint16 emul_ucmd; /*0x...60054*/ + t_uint16 emul_ubkcmd; /*0x...60056*/ + t_uint16 emul_bk2addl; /*0x...60058*/ + t_uint16 emul_bk2addm; /*0x...6005a*/ + t_uint16 emul_bk2addh; /*0x...6005c*/ + t_uint16 emul_mdata[3]; /*0x...6005e..62*/ + t_uint16 emul_maddl; /*0x...60064*/ + t_uint16 emul_maddm; /*0x...60066*/ + t_uint16 emul_mcmd; /*0x...60068*/ + t_uint16 emul_maddh; /*0x...6006a*/ + t_uint16 emul_uaddrh; /*0x...6006c*/ + t_uint16 emul_bk_eql; /*0x...6006e*/ + t_uint16 emul_bk_eqh; /*0x...60070*/ + t_uint16 emul_bk_combi; /*0x...60072*/ + t_uint16 emul_clockcmd; /*0x...60074*/ + t_uint16 emul_stepcmd; /*0x...60076*/ + t_uint16 emul_scanreg; /*0x...60078*/ + t_uint16 emul_breakcountl; /*0x...6007a*/ + t_uint16 emul_breakcounth; /*0x...6007c*/ + t_uint16 emul_forcescan; /*0x...6007e*/ + t_uint16 user_area[(0x200 - 0x80)>>1]; +} t_mmdsp_host_regs_16; + +typedef volatile struct { + t_uint32 ident; /*0x...60000*/ + t_uint32 identx[4]; /*0x...60004..10*/ + t_uint32 r5; /*0x...60014*/ + t_uint32 r6; /*0x...60018*/ + t_uint32 inte[2]; /*0x...6001c..20*/ + t_uint32 intx[2]; /*0x...60024..28*/ + t_uint32 int_ris[2]; /*0x...6002c..30*/ + t_uint32 intpol; /*0x...60034*/ + t_uint32 pwr; /*0x...60038*/ /* only on STn8820 and STn8500 */ + t_uint32 gatedclk; /*0x...6003c*/ + t_uint32 softreset; /*0x...60040*/ + t_uint32 int_icr[2]; /*0x...60044..48*/ + t_uint32 cmd[4]; /*0x...6004c..58*/ + t_uint32 RESERVED4; + t_uint32 int_mis0; /*0x...60060*/ + t_uint32 RESERVED5; + t_uint32 RESERVED6; + t_uint32 RESERVED7; + t_uint32 i2cdiv; /*0x...60070*/ + t_uint32 int_mis1; /*0x...60074*/ + t_uint32 RESERVED8; + t_uint32 RESERVED9; + t_uint32 emul_udata[8]; /*0x...60080..9c*/ + t_uint32 emul_uaddrl; /*0x...600a0*/ + t_uint32 emul_uaddrm; /*0x...600a4*/ + t_uint32 emul_ucmd; /*0x...600a8*/ + t_uint32 emul_ubkcmd; /*0x...600ac*/ + t_uint32 emul_bk2addl; /*0x...600b0*/ + t_uint32 emul_bk2addm; /*0x...600b4*/ + t_uint32 emul_bk2addh; /*0x...600b8*/ + t_uint32 emul_mdata[3]; /*0x...600bc..c4*/ + t_uint32 emul_maddl; /*0x...600c8*/ + t_uint32 emul_maddm; /*0x...600cc*/ + t_uint32 emul_mcmd; /*0x...600d0*/ + t_uint32 emul_maddh; /*0x...600d4*/ + t_uint32 emul_uaddrh; /*0x...600d8*/ + t_uint32 emul_bk_eql; /*0x...600dc*/ + t_uint32 emul_bk_eqh; /*0x...600e0*/ + t_uint32 emul_bk_combi; /*0x...600e4*/ + t_uint32 emul_clockcmd; /*0x...600e8*/ + t_uint32 emul_stepcmd; /*0x...600ec*/ + t_uint32 emul_scanreg; /*0x...600f0*/ + t_uint32 emul_breakcountl; /*0x...600f4*/ + t_uint32 emul_breakcounth; /*0x...600f8*/ + t_uint32 emul_forcescan; /*0x...600fc*/ + t_uint32 user_area[(0x400 - 0x100)>>2]; +} t_mmdsp_host_regs_32; + +/* MMIO blocks */ +#if defined(__STN_8820) || defined(__STN_8500) +typedef volatile struct { + t_uint16 RESERVED1[(0xD400-0x8000)>>1]; + + t_mmdsp_dma_ctrl_regs_16 dma_ctrl[MMDSP_NB_DMA_CTRL]; + + t_uint16 RESERVED2[(0xD800-0xD440)>>1]; + + t_mmdsp_dcache_regs_16 dcache; + + t_uint16 RESERVED3[(0xE000-0xD840)>>1]; + + t_mmdsp_io_regs_16 io; + + t_uint16 RESERVED4[(0x60-0x50)>>1]; + + t_mmdsp_timer_regs_16 timer[MMDSP_NB_TIMER]; + + t_uint16 RESERVED5[(0x410-0x78)>>1]; + + t_mmdsp_field_16 sem[MMDSP_NB_BIT_SEM]; + + t_uint16 RESERVED6[(0x450-0x430)>>1]; + + t_mmdsp_field_16 ipen; + t_uint16 itip_0; + t_uint16 itip_1; + t_uint16 itip_2; + t_uint16 itip_3; + t_uint16 itop_0; + t_uint16 itop_1; + t_uint16 itop_2; + t_uint16 itop_3; + t_uint16 RESERVED7[(0x8a-0x64)>>1]; + t_uint16 itip_4; + t_uint16 itop_4; + + t_uint16 RESERVED8[(0x7e0-0x48e)>>1]; + + t_mmdsp_field_16 id[4]; + t_mmdsp_field_16 idp[4]; + + t_mmdsp_dma_if_regs_16 dma_if[MMDSP_NB_DMA_IF]; + + t_uint16 RESERVED9[(0xC00-0x900)>>1]; + + t_mmdsp_field_16 emu_unit_maskit; + t_mmdsp_field_16 RESERVED[3]; + t_mmdsp_field_16 config_data_mem; + t_mmdsp_field_16 compatibility; + + t_uint16 RESERVED10[(0xF000-0xEC18)>>1]; + + t_uint16 stbus_if_config; + t_uint16 stbus_if_mode; + t_uint16 stbus_if_status; + t_uint16 stbus_if_security; + t_uint16 stbus_if_flush; + t_uint16 stbus_reserved; + t_uint16 stbus_if_priority; + t_uint16 stbus_msb_attribut; + + t_uint16 RESERVED11[(0xFC00-0xF010)>>1]; + + t_mmdsp_field_16 itremap_reg[MMDSP_NB_ITREMAP_REG]; + t_mmdsp_field_16 itmsk_l_reg; + t_mmdsp_field_16 itmsk_h_reg; + + t_uint16 RESERVED12[(0xfc9c - 0xfc88)>>1]; + + t_mmdsp_field_16 itmemo_l_reg; + t_mmdsp_field_16 itmeme_h_reg; + + t_uint16 RESERVED13[(0xfd00 - 0xfca4)>>1]; + + t_mmdsp_field_16 itremap1_reg[MMDSP_NB_ITREMAP_REG]; + + t_uint16 RESERVED14[(0x60000 - 0x5fd80)>>1]; +} t_mmdsp_mmio_regs_16; + + +typedef volatile struct { + t_uint32 RESERVED1[(0xa800)>>2]; + + t_mmdsp_dma_ctrl_regs_32 dma_ctrl[MMDSP_NB_DMA_CTRL]; + + t_uint32 RESERVED2[(0xb000-0xa880)>>2]; + + t_mmdsp_dcache_regs_32 dcache; + + t_uint32 RESERVED3[(0xc000-0xb080)>>2]; + + t_mmdsp_io_regs_32 io; + + t_uint32 RESERVED4[(0xc0-0xa0)>>2]; + + t_mmdsp_timer_regs_32 timer[MMDSP_NB_TIMER]; + + t_uint32 RESERVED5[(0x820-0x0f0)>>2]; + + t_mmdsp_field_32 sem[MMDSP_NB_BIT_SEM]; + + t_uint32 RESERVED6[(0x8a0-0x860)>>2]; + + t_mmdsp_field_32 ipen; + t_uint32 itip_0; + t_uint32 itip_1; + t_uint32 itip_2; + t_uint32 itip_3; + t_uint32 itop_0; + t_uint32 itop_1; + t_uint32 itop_2; + t_uint32 itop_3; + t_uint32 RESERVED7[(0x914-0x8c8)>>2]; + t_uint32 itip_4; + t_uint32 itop_4; + + t_uint32 RESERVED8[(0xcfc0-0xc91c)>>2]; + + t_mmdsp_field_32 id[4]; + t_mmdsp_field_32 idp[4]; + + t_mmdsp_dma_if_regs_32 dma_if[MMDSP_NB_DMA_IF]; + + t_uint32 RESERVED9[(0x800-0x200)>>2]; + + t_mmdsp_field_32 emu_unit_maskit; + t_mmdsp_field_32 RESERVED[3]; + t_mmdsp_field_32 config_data_mem; + t_mmdsp_field_32 compatibility; + + t_uint32 RESERVED10[(0xE000-0xD830)>>2]; + + t_uint32 stbus_if_config; + t_uint32 stbus_if_mode; + t_uint32 stbus_if_status; + t_uint32 stbus_if_security; + t_uint32 stbus_if_flush; + t_uint32 stbus_reserved; + t_uint32 stbus_if_priority; + t_uint32 stbus_msb_attribut; + + t_uint32 RESERVED11[(0xF800-0xE020)>>2]; + + t_mmdsp_field_32 itremap_reg[MMDSP_NB_ITREMAP_REG]; + t_mmdsp_field_32 itmsk_l_reg; + t_mmdsp_field_32 itmsk_h_reg; + + t_uint32 RESERVED12[(0xf938 - 0xf910)>>2]; + + t_mmdsp_field_32 itmemo_l_reg; + t_mmdsp_field_32 itmeme_h_reg; + + t_uint32 RESERVED13[(0xfa00 - 0xf948)>>2]; + + t_mmdsp_field_32 itremap1_reg[MMDSP_NB_ITREMAP_REG]; + + t_uint32 RESERVED14[(0x40000 - 0x3fb00)>>2]; +} t_mmdsp_mmio_regs_32; +#endif /* __STN_8820 or __STN_8500 */ + +#ifdef __STN_8815 +typedef volatile struct { + t_uint16 RESERVED1[(0xD400-0x8000)>>1]; + + t_mmdsp_dma_ctrl_regs_16 dma_ctrl[MMDSP_NB_DMA_CTRL]; + + t_uint16 RESERVED2[(0xD800-0xD440)>>1]; + + t_mmdsp_dcache_regs_16 dcache; + + t_uint16 RESERVED3[(0xE000-0xD840)>>1]; + + t_mmdsp_io_regs_16 io; + + t_uint16 RESERVED4[(0x60-0x50)>>1]; + + t_mmdsp_timer_regs_16 timer[MMDSP_NB_TIMER]; + + t_uint16 RESERVED5[(0x410-0x78)>>1]; + + t_mmdsp_field_16 sem[MMDSP_NB_BIT_SEM]; + + t_uint16 RESERVED6[(0x450-0x430)>>1]; + + t_mmdsp_field_16 ipen; + t_uint16 itip_0; + t_uint16 itip_1; + t_uint16 itip_2; + t_uint16 itip_3; + t_uint16 itop_0; + t_uint16 itop_1; + t_uint16 itop_2; + t_uint16 itop_3; + t_uint16 RESERVED7[(0x8a-0x64)>>1]; + t_uint16 itip_4; + t_uint16 itop_4; + + t_uint16 RESERVED8[(0x7e0-0x48e)>>1]; + + t_mmdsp_field_16 id[4]; + t_mmdsp_field_16 idp[4]; + + t_mmdsp_dma_if_regs_16 dma_if[MMDSP_NB_DMA_IF]; + + t_uint16 RESERVED9[(0xC00-0x900)>>1]; + + t_mmdsp_field_16 emu_unit_maskit; + t_mmdsp_field_16 RESERVED[3]; + t_mmdsp_field_16 config_data_mem; + t_mmdsp_field_16 compatibility; + + t_uint16 RESERVED10[(0xF000-0xEC18)>>1]; + + t_uint16 ahb_if_config; + t_uint16 ahb_if_mode; + t_uint16 ahb_if_status; + t_uint16 ahb_if_security; + t_uint16 ahb_if_flush; + + t_uint16 RESERVED11[(0xFC00-0xF00A)>>1]; + + t_mmdsp_field_16 itremap_reg[MMDSP_NB_ITREMAP_REG]; + t_mmdsp_field_16 itmsk_l_reg; + t_mmdsp_field_16 itmsk_h_reg; + + t_uint16 RESERVED12[(0xfc9c - 0xfc88)>>1]; + + t_mmdsp_field_16 itmemo_l_reg; + t_mmdsp_field_16 itmeme_h_reg; + + t_uint16 RESERVED13[(0xfd00 - 0xfca4)>>1]; + + t_mmdsp_field_16 itremap1_reg[MMDSP_NB_ITREMAP_REG]; + + t_uint16 RESERVED14[(0x60000 - 0x5fd80)>>1]; +} t_mmdsp_mmio_regs_16; + + +typedef volatile struct { + t_uint32 RESERVED1[(0xa800)>>2]; + + t_mmdsp_dma_ctrl_regs_32 dma_ctrl[MMDSP_NB_DMA_CTRL]; + + t_uint32 RESERVED2[(0xb000-0xa880)>>2]; + + t_mmdsp_dcache_regs_32 dcache; + + t_uint32 RESERVED3[(0xc000-0xb080)>>2]; + + t_mmdsp_io_regs_32 io; + + t_uint32 RESERVED4[(0xc0-0xa0)>>2]; + + t_mmdsp_timer_regs_32 timer[MMDSP_NB_TIMER]; + + t_uint32 RESERVED5[(0x820-0x0f0)>>2]; + + t_mmdsp_field_32 sem[MMDSP_NB_BIT_SEM]; + + t_uint32 RESERVED6[(0x8a0-0x860)>>2]; + + t_mmdsp_field_32 ipen; + t_uint32 itip_0; + t_uint32 itip_1; + t_uint32 itip_2; + t_uint32 itip_3; + t_uint32 itop_0; + t_uint32 itop_1; + t_uint32 itop_2; + t_uint32 itop_3; + t_uint32 RESERVED7[(0x914-0x8c8)>>2]; + t_uint32 itip_4; + t_uint32 itop_4; + + t_uint32 RESERVED8[(0xcfc0-0xc91c)>>2]; + + t_mmdsp_field_32 id[4]; + t_mmdsp_field_32 idp[4]; + + t_mmdsp_dma_if_regs_32 dma_if[MMDSP_NB_DMA_IF]; + + t_uint32 RESERVED9[(0x800-0x200)>>2]; + + t_mmdsp_field_32 emu_unit_maskit; + t_mmdsp_field_32 RESERVED[3]; + t_mmdsp_field_32 config_data_mem; + t_mmdsp_field_32 compatibility; + + t_uint32 RESERVED10[(0xE000-0xD830)>>2]; + + t_uint32 ahb_if_config; + t_uint32 ahb_if_mode; + t_uint32 ahb_if_status; + t_uint32 ahb_if_security; + t_uint32 ahb_if_flush; + + t_uint32 RESERVED11[(0xF800-0xE014)>>2]; + + t_mmdsp_field_32 itremap_reg[MMDSP_NB_ITREMAP_REG]; + t_mmdsp_field_32 itmsk_l_reg; + t_mmdsp_field_32 itmsk_h_reg; + + t_uint32 RESERVED12[(0xf938 - 0xf910)>>2]; + + t_mmdsp_field_32 itmemo_l_reg; + t_mmdsp_field_32 itmeme_h_reg; + + t_uint32 RESERVED13[(0xfa00 - 0xf948)>>2]; + + t_mmdsp_field_32 itremap1_reg[MMDSP_NB_ITREMAP_REG]; + + t_uint32 RESERVED14[(0x40000 - 0x3fb00)>>2]; +} t_mmdsp_mmio_regs_32; +#endif /* __STN_8815 */ + +/* Smart xx Accelerator memory map */ +typedef volatile struct { + t_uint32 mem24[MMDSP_NB_BLOCK_RAM*MMDSP_RAM_BLOCK_SIZE]; /* 0x0000 -> 0x20000 */ + + t_uint32 RESERVED1[(0x30000 - 0x20000)>>2]; + + t_mmdsp_mmio_regs_32 mmio_32; + + t_uint16 mem16[MMDSP_NB_BLOCK_RAM*MMDSP_RAM_BLOCK_SIZE]; /* 0x40000 -> 0x50000 */ + + t_uint32 RESERVED2[(0x58000 - 0x50000)>>2]; + + t_mmdsp_mmio_regs_16 mmio_16; + + t_mmdsp_host_regs_16 host_reg; + /* + union host_reg { + t_mmdsp_host_regs_16 reg16; + t_mmdsp_host_regs_32 reg32; + }; + */ +} t_mmdsp_hw_regs; + +#endif // __INC_MMDSP_HWP_H diff --git a/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_macros.h b/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_macros.h new file mode 100644 index 00000000000..b8911d27609 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/dsp/mmdsp/inc/mmdsp_macros.h @@ -0,0 +1,86 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_MMDSP_DSP_MACROS +#define __INC_MMDSP_DSP_MACROS + +#include <cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h> + +#define MMDSP_ENABLE_WRITE_POSTING(pRegs) \ +{ \ + (pRegs)->mmio_16.dcache.control |= DCACHE_CONTROL_WRITE_POSTING_ENABLE; \ +} + +#define MMDSP_FLUSH_DCACHE(pRegs) \ +{ /* Today, only full cache flush (clear all the ways) */ \ + (pRegs)->mmio_16.dcache.command = DCACHE_CMD_FLUSH; \ +} + +#define MMDSP_FLUSH_DCACHE_BY_SERVICE(pRegs, startAddr, endAddr) + +#define MMDSP_FLUSH_ICACHE(pRegs) \ +{ /* Flush the Instruction cache */ \ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_ICACHE_FLUSH_REG, (IHOST_ICACHE_FLUSH_ALL_ENTRIES_CMD | IHOST_ICACHE_FLUSH_CMD_ENABLE)); \ +} + +#ifndef __STN_8810 +#define MMDSP_FLUSH_ICACHE_BY_SERVICE(pRegs, startAddr, endAddr) \ +{ /* Flush the Instruction cache by service */ \ + /*t_uint64 start_clear_addr = startAddr & ~(MMDSP_ICACHE_LINE_SIZE_IN_INST - 1);*/ \ + t_uint64 start_clear_addr = (startAddr)>>2; \ + t_uint64 end_clear_addr = ((endAddr) + MMDSP_ICACHE_LINE_SIZE_IN_INST) & ~(MMDSP_ICACHE_LINE_SIZE_IN_INST - 1); \ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_ICACHE_START_CLEAR_REG, start_clear_addr); \ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_ICACHE_END_CLEAR_REG, end_clear_addr); \ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_ICACHE_FLUSH_REG, (IHOST_ICACHE_FLUSH_BY_SERVICE | IHOST_ICACHE_FLUSH_CMD_ENABLE)); \ +} +#else +#define MMDSP_FLUSH_ICACHE_BY_SERVICE(pRegs, startAddr, endAddr) {(void)pRegs; (void)startAddr; (void)endAddr; } +#endif + +#define MMDSP_RESET_CORE(pRegs) \ +{ /* Assert DSP core soft reset */ \ + (pRegs)->host_reg.softreset = 1; \ +} + +#define MMDSP_START_CORE(pRegs) \ +{ \ + /* Enable external memory access (set bit 3 of ubkcmd) */ \ + (pRegs)->host_reg.emul_ubkcmd |= MMDSP_UBKCMD_EXT_CODE_MEM_ACCESS_ENABLE; \ + \ + /* Start core clock */ \ + (pRegs)->host_reg.emul_clockcmd = MMDSP_CLOCKCMD_START_CLOCK; \ +} + +#define MMDSP_STOP_CORE(pRegs) \ +{ \ + /* Disable external memory access (reset bit 3 of ubkcmd) */ \ + (pRegs)->host_reg.emul_ubkcmd = MMDSP_UBKCMD_EXT_CODE_MEM_ACCESS_DISABLE; \ + \ + /* Stop core clock */ \ + (pRegs)->host_reg.emul_clockcmd = MMDSP_CLOCKCMD_STOP_CLOCK; \ +} + +#define MMDSP_ASSERT_IRQ(pRegs, irqNum) \ +{ \ + (pRegs)->host_reg.cmd[irqNum] = 1; \ +} + +#define MMDSP_ACKNOWLEDGE_IRQ(pRegs, irqNum) \ +{ \ + volatile t_uint16 dummy; \ + dummy =(pRegs)->host_reg.intx[irqNum]; \ +} + +#define MMDSP_WRITE_XWORD(pRegs, offset, value) \ +{ \ + (pRegs)->mem24[offset] = value; \ +} + +#define MMDSP_READ_XWORD(pRegs, offset) (pRegs)->mem24[offset] + +#endif /* __INC_MMDSP_DSP_MACROS */ diff --git a/drivers/staging/nmf-cm/cm/engine/dsp/src/dsp.c b/drivers/staging/nmf-cm/cm/engine/dsp/src/dsp.c new file mode 100644 index 00000000000..de4ea3b7ba5 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/dsp/src/dsp.c @@ -0,0 +1,1074 @@ +/* + * 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/dsp/inc/dsp.h> +#include <cm/engine/dsp/mmdsp/inc/mmdsp_macros.h> + +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <cm/engine/power_mgt/inc/power.h> +#include <cm/engine/memory/inc/migration.h> +#include <cm/engine/trace/inc/trace.h> + +#include <share/inc/nomadik_mapping.h> + +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/component/inc/component_type.h> + +static t_dsp_allocator_desc esramDesc; +static t_dsp_desc mpcDesc[NB_CORE_IDS]; +static t_mmdsp_hw_regs *pMmdspRegs[NB_CORE_IDS]; + +struct s_base_descr +{ + t_uint32 startAddress[2 /* DSP16 = 0, DSP24 = 1*/]; + t_dsp_segment_type segmentType; +}; + +#if defined(__STN_8500) && (__STN_8500 > 10) + +#define DATA_BASE_NUMBER 4 + +// In bytes +#define SDRAM_CODE_SPACE_SPLIT 0x8000 +#define ESRAM_CODE_SPACE_SPLIT 0x4000 +#define SDRAM_DATA_SPACE_SPLIT 0x40000 // This is the modulo constraint of mmdsp +#define ESRAM_DATA_SPACE_SPLIT 0x40000 + +// In MMDSP word +static const struct s_base_descr DATA_ADDRESS_BASE[DATA_BASE_NUMBER + 1 /* For guard */] = { + {{SDRAMMEM16_BASE_ADDR, SDRAMMEM24_BASE_ADDR}, SDRAM_DATA_EE}, + {{SDRAMMEM16_BASE_ADDR + (SDRAM_DATA_SPACE_SPLIT / 2), SDRAMMEM24_BASE_ADDR + (SDRAM_DATA_SPACE_SPLIT / 4)}, SDRAM_DATA_USER}, + {{ESRAMMEM16_BASE_ADDR, ESRAMMEM24_BASE_ADDR}, ESRAM_DATA_EE}, + {{ESRAMMEM16_BASE_ADDR + (ESRAM_DATA_SPACE_SPLIT / 2), ESRAMMEM24_BASE_ADDR + (ESRAM_DATA_SPACE_SPLIT / 4)}, ESRAM_DATA_USER}, + {{MMIO_BASE_ADDR, SDRAMMEM16_BASE_ADDR}, NB_DSP_SEGMENT_TYPE /* Not used*/} +}; + +#else + +#define DATA_BASE_NUMBER 2 + +// In MMDSP word +static const struct s_base_descr DATA_ADDRESS_BASE[DATA_BASE_NUMBER + 1 /* For guard */] = { + {{SDRAMMEM16_BASE_ADDR, SDRAMMEM24_BASE_ADDR}, SDRAM_DATA_EE}, + {{ESRAMMEM16_BASE_ADDR, ESRAMMEM24_BASE_ADDR}, ESRAM_DATA_EE}, + {{MMIO_BASE_ADDR, SDRAMMEM16_BASE_ADDR}, NB_DSP_SEGMENT_TYPE /* Not used*/} +}; + +#endif + +#if defined(__STN_8500) && (__STN_8500 > 10) +// In word +static const t_uint32 CODE_ADDRESS_BASE[4] = { + SDRAMTEXT_BASE_ADDR, + SDRAMTEXT_BASE_ADDR + (SDRAM_CODE_SPACE_SPLIT / 8), + ESRAMTEXT_BASE_ADDR, + ESRAMTEXT_BASE_ADDR + (ESRAM_CODE_SPACE_SPLIT / 8) +}; +#endif + +static void arm_Init(void); +static t_cm_error mmdsp_Init(const t_cm_system_address *dspSystemAddr, + t_uint8 nbXramBlocks, t_uint8 nbYramBlocks, + t_dsp_allocator_desc *sdramCodeDesc, + t_dsp_allocator_desc *sdramDataDesc, + t_cm_domain_id eeDomain, + t_dsp_desc *pDspDesc, + t_mmdsp_hw_regs **pRegs); +static t_cm_error mmdsp_Configure(t_nmf_core_id coreId, t_mmdsp_hw_regs *pRegs, const t_dsp_desc *pDspDesc); +static t_cm_error mmdsp_ConfigureAfterBoot(t_nmf_core_id coreId, t_uint8 nbXramBlocks, t_uint8 nbYramBlocks); +static void cm_DSP_SEM_Init(t_nmf_core_id coreId); + +PUBLIC const t_dsp_desc* cm_DSP_GetState(t_nmf_core_id coreId) +{ + return &mpcDesc[coreId]; +} +PUBLIC void cm_DSP_SetStatePanic(t_nmf_core_id coreId) +{ + mpcDesc[coreId].state = MPC_STATE_PANIC; +} + +PUBLIC void cm_DSP_Init(const t_nmf_memory_segment *pEsramDesc) +{ + t_nmf_core_id coreId; + int i; + + /* Create esram desc */ + esramDesc.allocDesc = cm_MM_CreateAllocator(pEsramDesc->size, 0, "esram"); + esramDesc.baseAddress = pEsramDesc->systemAddr; + esramDesc.referenceCounter = 1; // Don't free it with destroy mechanism + + /* Create ARM */ + arm_Init(); + + mpcDesc[ARM_CORE_ID].state = MPC_STATE_BOOTED; + + /* Reset MPC configuration */ + for (coreId = FIRST_MPC_ID; coreId <= LAST_CORE_ID; coreId++) + { + mpcDesc[coreId].state = MPC_STATE_UNCONFIGURED; + + for(i = 0; i < NB_DSP_MEMORY_TYPE; i++) + mpcDesc[coreId].allocator[i] = NULL; + } + +} + +PUBLIC void cm_DSP_Destroy(void) +{ + t_nmf_core_id coreId; + int i; + + for (coreId = ARM_CORE_ID; coreId <= LAST_CORE_ID; coreId++) + { + for(i = 0; i < NB_DSP_MEMORY_TYPE; i++) + { + if (mpcDesc[coreId].allocator[i] != NULL) + { + if(--mpcDesc[coreId].allocator[i]->referenceCounter == 0) + { + cm_MM_DeleteAllocator(mpcDesc[coreId].allocator[i]->allocDesc); + + OSAL_Free(mpcDesc[coreId].allocator[i]); + } + } + } + } + + cm_MM_DeleteAllocator(esramDesc.allocDesc); +} + + +PUBLIC t_cm_error cm_DSP_Add(t_nmf_core_id coreId, + t_uint8 nbYramBanks, + const t_cm_system_address *pDspMapDesc, + const t_cm_domain_id eeDomain, + t_dsp_allocator_desc *sdramCodeAllocDesc, + t_dsp_allocator_desc *sdramDataAllocDesc) +{ + t_cm_error error; + + /* checking nbYramBanks is valid */ + if (nbYramBanks >= SxA_NB_BLOCK_RAM) + return CM_MPC_INVALID_CONFIGURATION; + + if((error = cm_DM_CheckDomain(eeDomain, DOMAIN_NORMAL)) != CM_OK) + return error; + + mpcDesc[coreId].domainEE = eeDomain; + mpcDesc[coreId].nbYramBank = nbYramBanks; + mpcDesc[coreId].state = MPC_STATE_BOOTABLE; + + return mmdsp_Init( + pDspMapDesc, + SxA_NB_BLOCK_RAM, /* nb of data tcm bank minus one (reserved for cache) */ + nbYramBanks, + sdramCodeAllocDesc, + sdramDataAllocDesc, + eeDomain, + &mpcDesc[coreId], + &pMmdspRegs[coreId] + ); +} + +PUBLIC t_cm_error cm_DSP_Boot(t_nmf_core_id coreId) +{ + t_cm_error error; + + // Enable the associated power domain + if((error = cm_PWR_EnableMPC(MPC_PWR_CLOCK, coreId)) != CM_OK) + return error; + + cm_SEM_PowerOn[coreId](coreId); + + if((error = mmdsp_Configure( + coreId, + pMmdspRegs[coreId], + &mpcDesc[coreId])) != CM_OK) + { + cm_PWR_DisableMPC(MPC_PWR_CLOCK, coreId); + } + + // Put it in auto idle mode ; it's the default in Step 2 of power implementation + if((error = cm_PWR_EnableMPC(MPC_PWR_AUTOIDLE, coreId)) != CM_OK) + return error; + + return error; +} + +/* + * This method is required since MMDSP C bootstrap set some value that must be set differently !!! + */ +PUBLIC void cm_DSP_ConfigureAfterBoot(t_nmf_core_id coreId) +{ + mpcDesc[coreId].state = MPC_STATE_BOOTED; + + mmdsp_ConfigureAfterBoot(coreId, SxA_NB_BLOCK_RAM, mpcDesc[coreId].nbYramBank); + + cm_DSP_SEM_Init(coreId); +} + +PUBLIC void cm_DSP_Stop(t_nmf_core_id coreId) +{ + MMDSP_STOP_CORE(pMmdspRegs[coreId]); + + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } +} + +PUBLIC void cm_DSP_Start(t_nmf_core_id coreId) +{ + MMDSP_START_CORE(pMmdspRegs[coreId]); + + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } +} + +PUBLIC void cm_DSP_Shutdown(t_nmf_core_id coreId) +{ + MMDSP_FLUSH_DCACHE(pMmdspRegs[coreId]); + MMDSP_FLUSH_ICACHE(pMmdspRegs[coreId]); + + // Due to a hardware bug that breaks MTU when DSP are powered off, don't do that + // on mop500_ed for now +#if !defined(__STN_8500) || (__STN_8500 > 10) + MMDSP_RESET_CORE(pMmdspRegs[coreId]); + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } + MMDSP_STOP_CORE(pMmdspRegs[coreId]); + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } +#endif + + mpcDesc[coreId].state = MPC_STATE_BOOTABLE; + + cm_SEM_PowerOff[coreId](coreId); + + cm_PWR_DisableMPC(MPC_PWR_AUTOIDLE, coreId); + cm_PWR_DisableMPC(MPC_PWR_CLOCK, coreId); +} + +PUBLIC t_uint32 cm_DSP_ReadXRamWord(t_nmf_core_id coreId, t_uint32 dspOffset) +{ + t_uint32 value; + + value = pMmdspRegs[coreId]->mem24[dspOffset]; + + LOG_INTERNAL(3, "cm_DSP_ReadXRamWord: [%x]=%x\n", + dspOffset, value, + 0, 0, 0, 0); + + return value; +} + + +PUBLIC void cm_DSP_WriteXRamWord(t_nmf_core_id coreId, t_uint32 dspOffset, t_uint32 value) +{ + LOG_INTERNAL(3, "cm_DSP_WriteXRamWord: [%x]<-%x\n", + dspOffset, value, + 0, 0, 0, 0); + + pMmdspRegs[coreId]->mem24[dspOffset] = value; +} + +static void cm_DSP_SEM_Init(t_nmf_core_id coreId) +{ + pMmdspRegs[coreId]->mmio_16.sem[1].value = 1; +} + +PUBLIC void cm_DSP_SEM_Take(t_nmf_core_id coreId, t_semaphore_id semId) +{ + /* take semaphore */ + while(pMmdspRegs[coreId]->mmio_16.sem[1].value) ; +} + +PUBLIC void cm_DSP_SEM_Give(t_nmf_core_id coreId, t_semaphore_id semId) +{ + /* release semaphore */ + pMmdspRegs[coreId]->mmio_16.sem[1].value = 1; +} + +PUBLIC void cm_DSP_SEM_GenerateIrq(t_nmf_core_id coreId, t_semaphore_id semId) +{ + MMDSP_ASSERT_IRQ(pMmdspRegs[coreId], ARM2DSP_IRQ_0); +} + + +PUBLIC void cm_DSP_AssertDspIrq(t_nmf_core_id coreId, t_host2mpc_irq_num irqNum) +{ + MMDSP_ASSERT_IRQ(pMmdspRegs[coreId], irqNum); + return; +} + +PUBLIC void cm_DSP_AcknowledgeDspIrq(t_nmf_core_id coreId, t_mpc2host_irq_num irqNum) +{ + MMDSP_ACKNOWLEDGE_IRQ(pMmdspRegs[coreId], irqNum); + return; +} + +//TODO, juraj, cleanup INTERNAL_XRAM vs INTERNAL_XRAM16/24 +static const t_uint32 dspMemoryTypeId2OffsetShifter[NB_DSP_MEMORY_TYPE] = +{ + 2, /* INTERNAL_XRAM24: Internal X memory but seen by host as 32-bit memory */ + 2, /* INTERNAL_XRAM16: Internal X memory but seen by host as 16-bit memory */ + 2, /* INTERNAL_YRAM24: Internal Y memory but seen by host as 32-bit memory */ + 2, /* INTERNAL_YRAM16: Internal Y memory but seen by host as 16-bit memory */ + 2, /* SDRAM_EXT24: 24-bit external "X" memory */ + 1, /* SDRAM_EXT16: 16-bit external "X" memory */ + 2, /* ESRAM_EXT24: ESRAM24 */ + 1, /* ESRAM_EXT16: ESRAM16 */ + 3, /* SDRAM_CODE: Program memory */ + 3, /* ESRAM_CODE: ESRAM code */ + 3, /* LOCKED_CODE: ESRAM code */ +}; + +//TODO, juraj, use these values in mmdsp_Configure +static const t_uint32 dspMemoryTypeId2DspAddressOffset[NB_DSP_MEMORY_TYPE] = +{ + 0, /* INTERNAL_XRAM24 */ + 0, /* INTERNAL_XRAM16 */ + 0, /* INTERNAL_YRAM24 */ + 0, /* INTERNAL_YRAM16 */ + SDRAMMEM24_BASE_ADDR, /* SDRAM_EXT24: 24-bit external "X" memory */ + SDRAMMEM16_BASE_ADDR, /* SDRAM_EXT16: 16-bit external "X" memory */ + ESRAMMEM24_BASE_ADDR, /* ESRAM_EXT24: ESRAM24 */ + ESRAMMEM16_BASE_ADDR, /* ESRAM_EXT16: ESRAM16 */ + SDRAMTEXT_BASE_ADDR, /* SDRAM_CODE: Program memory */ + ESRAMTEXT_BASE_ADDR, /* ESRAM_CODE: ESRAM code */ + SDRAMTEXT_BASE_ADDR, /* ESRAM_CODE: ESRAM code */ +}; + +PUBLIC t_cm_allocator_desc* cm_DSP_GetAllocator(t_nmf_core_id coreId, t_dsp_memory_type_id memType) +{ + return mpcDesc[coreId].allocator[memType] ? mpcDesc[coreId].allocator[memType]->allocDesc : NULL; +} + +PUBLIC void cm_DSP_GetDspChunkInfo(t_memory_handle memHandle, t_dsp_chunk_info *info) +{ + t_uint16 userData; + + cm_MM_GetMemoryHandleUserData(memHandle, &userData, &info->alloc); + + info->coreId = (t_nmf_core_id) ((userData >> SHIFT_BYTE1) & MASK_BYTE0); + info->memType = (t_dsp_memory_type_id)((userData >> SHIFT_BYTE0) & MASK_BYTE0); +} + +PUBLIC t_cm_error cm_DSP_GetInternalMemoriesInfo(t_cm_domain_id domainId, t_dsp_memory_type_id memType, + t_uint32 *offset, t_uint32 *size) +{ + t_nmf_core_id coreId = domainDesc[domainId].domain.coreId; + + switch(memType) + { + case INTERNAL_XRAM24: + case INTERNAL_XRAM16: + *offset = 0; + *size = mpcDesc[coreId].yram_offset; + break; + case INTERNAL_YRAM24: + case INTERNAL_YRAM16: + *offset = mpcDesc[coreId].yram_offset; + *size = mpcDesc[coreId].yram_size; + break; + case LOCKED_CODE: + *offset = mpcDesc[coreId].locked_offset; + *size = mpcDesc[coreId].locked_size; + break; + case SDRAM_EXT24: + case SDRAM_EXT16: + *offset = domainDesc[domainId].domain.sdramData.offset; + *size = domainDesc[domainId].domain.sdramData.size; + break; + case ESRAM_EXT24: + case ESRAM_EXT16: + *offset = domainDesc[domainId].domain.esramData.offset; + *size = domainDesc[domainId].domain.esramData.size; + break; + case SDRAM_CODE: + *offset = domainDesc[domainId].domain.sdramCode.offset; + *size = domainDesc[domainId].domain.sdramCode.size; + + // update domain size to take into account .locked section + if(*offset + *size > mpcDesc[coreId].locked_offset) + *size = mpcDesc[coreId].locked_offset - *offset; + break; + case ESRAM_CODE: + *offset = domainDesc[domainId].domain.esramCode.offset; + *size = domainDesc[domainId].domain.esramCode.size; + break; + default: + //return CM_INVALID_PARAMETER; + //params are checked at the level above, so this should never occur + ERROR("Invalid memType\n",0,0,0,0,0,0); + *offset = 0; + *size = 0; + CM_ASSERT(0); + } + + return CM_OK; +} + + +PUBLIC t_uint32 cm_DSP_ConvertSize(t_dsp_memory_type_id memType, t_uint32 wordSize) +{ + return wordSize << dspMemoryTypeId2OffsetShifter[memType]; +} + +PUBLIC t_cm_logical_address cm_DSP_ConvertDspAddressToHostLogicalAddress(t_nmf_core_id coreId, t_shared_addr dspAddress) +{ + t_dsp_address_info info; + cm_DSP_GetDspDataAddressInfo(coreId, dspAddress, &info); + return mpcDesc[coreId].segments[info.segmentType].base.logical + info.baseOffset; +} + +PUBLIC t_cm_error cm_DSP_GetAllocatorStatus(t_nmf_core_id coreId, t_dsp_memory_type_id dspMemType, t_uint32 offset, t_uint32 size, t_cm_allocator_status *pStatus) +{ + t_cm_error error; + + if(mpcDesc[coreId].allocator[dspMemType] == NULL) + return CM_UNKNOWN_MEMORY_HANDLE; + + error = cm_MM_GetAllocatorStatus(cm_DSP_GetAllocator(coreId, dspMemType), offset, size, pStatus); + if (error != CM_OK) + return error; + + // complete status with stack sizes, for all dsps + //NOTE, well, surely this isn't very clean, as dsp and memory allocator are different things .. + { + t_uint8 i; + for (i = 0; i < NB_CORE_IDS; i++) { + //*(pStatus->stack[i].sizes) = *(eeState[i].currentStackSize); + pStatus->stack[i].sizes[0] = eeState[i].currentStackSize[0]; + pStatus->stack[i].sizes[1] = eeState[i].currentStackSize[1]; + pStatus->stack[i].sizes[2] = eeState[i].currentStackSize[2]; + } + } + + // Change bytes to words + pStatus->global.accumulate_free_memory = pStatus->global.accumulate_free_memory >> dspMemoryTypeId2OffsetShifter[dspMemType]; + pStatus->global.accumulate_used_memory = pStatus->global.accumulate_used_memory >> dspMemoryTypeId2OffsetShifter[dspMemType]; + pStatus->global.maximum_free_size = pStatus->global.maximum_free_size >> dspMemoryTypeId2OffsetShifter[dspMemType]; + pStatus->global.minimum_free_size = pStatus->global.minimum_free_size >> dspMemoryTypeId2OffsetShifter[dspMemType]; + + return error; +} + +PUBLIC void cm_DSP_GetHostSystemAddress(t_memory_handle memHandle, t_cm_system_address *pAddr) +{ + t_dsp_chunk_info chunk_info; + t_uint32 offset; //in bytes + + cm_DSP_GetDspChunkInfo(memHandle, &chunk_info); + + offset = cm_MM_GetOffset(memHandle); + + /* MMDSP mem16 array is very specific to host access, so .... */ + /* We compute by hand the Host System address to take into account the specifities of the mmdsp mem16 array */ + /* 1 dsp word = 2 host bytes AND mem16 array is "exported" by MMDSP External Bus wrapper at the 0x40000 offet */ + if (chunk_info.memType == INTERNAL_XRAM16 || chunk_info.memType == INTERNAL_YRAM16) { + offset = (offset >> 1) + FIELD_OFFSET(t_mmdsp_hw_regs, mem16); + } + + //TODO, juraj, calculate correct value here - based on segments desc etc.. + pAddr->logical = mpcDesc[chunk_info.coreId].allocator[chunk_info.memType]->baseAddress.logical + offset; + pAddr->physical = mpcDesc[chunk_info.coreId].allocator[chunk_info.memType]->baseAddress.physical + offset; +} + + +PUBLIC t_physical_address cm_DSP_GetPhysicalAdress(t_memory_handle memHandle) +{ + t_cm_system_address addr; + cm_DSP_GetHostSystemAddress(memHandle, &addr); + return addr.physical; +} + +PUBLIC t_cm_logical_address cm_DSP_GetHostLogicalAddress(t_memory_handle memHandle) +{ + t_cm_system_address addr; + cm_DSP_GetHostSystemAddress(memHandle, &addr); + return addr.logical; +} + +PUBLIC void cm_DSP_GetDspAddress(t_memory_handle memHandle, t_uint32 *pDspAddress) +{ + t_dsp_chunk_info chunk_info; + + cm_DSP_GetDspChunkInfo(memHandle, &chunk_info); + + *pDspAddress = + (cm_MM_GetOffset(memHandle) >> dspMemoryTypeId2OffsetShifter[chunk_info.memType]) + + dspMemoryTypeId2DspAddressOffset[chunk_info.memType]; +} + +PUBLIC t_cm_error cm_DSP_GetDspBaseAddress(t_nmf_core_id coreId, t_dsp_memory_type_id memType, t_cm_system_address *pAddr) +{ + cm_migration_check_state(coreId, STATE_NORMAL); + *pAddr = mpcDesc[coreId].allocator[memType]->baseAddress; + return CM_OK; +} + +PUBLIC void cm_DSP_GetDspMemoryHandleSize(t_memory_handle memHandle, t_uint32 *pDspSize) +{ + t_dsp_chunk_info chunk_info; + cm_DSP_GetDspChunkInfo(memHandle, &chunk_info); + *pDspSize = cm_MM_GetSize(memHandle) >> dspMemoryTypeId2OffsetShifter[chunk_info.memType]; +} + +PUBLIC t_cm_error cm_DSP_setStackSize(t_nmf_core_id coreId, t_uint32 newStackSize) +{ + t_uint8 nbXramBanks; + t_uint32 xramSize; + + /* compute size of xram allocator */ + nbXramBanks = SxA_NB_BLOCK_RAM - mpcDesc[coreId].nbYramBank; + + /* check first that required stack size is less then xram memory ....*/ + if (newStackSize >= nbXramBanks * 4 * ONE_KB) + return CM_NO_MORE_MEMORY; + + /* compute new xram allocator size */ + xramSize = nbXramBanks * 4 * ONE_KB - newStackSize; + + /* try to resize it */ + return cm_MM_ResizeAllocator(cm_DSP_GetAllocator(coreId, INTERNAL_XRAM24), + xramSize << dspMemoryTypeId2OffsetShifter[INTERNAL_XRAM24]); +} + +PUBLIC t_cm_error cm_DSP_IsNbYramBanksValid(t_nmf_core_id coreId, t_uint8 nbYramBanks) +{ + /* we use one bank for cache */ + t_uint8 nbOfRamBanksWithCacheReserved = SxA_NB_BLOCK_RAM; + + /* we want to keep at least one bank of xram */ + if (nbYramBanks < nbOfRamBanksWithCacheReserved) {return CM_OK;} + else {return CM_MPC_INVALID_CONFIGURATION;} +} + +PUBLIC t_uint32 cm_DSP_getStackAddr(t_nmf_core_id coreId) +{ + /* we use one bank for cache */ + //t_uint8 nbOfRamBanksWithCacheReserved = SxA_NB_BLOCK_RAM; + /* */ + //return ((nbOfRamBanksWithCacheReserved * MMDSP_RAM_BLOCK_SIZE * MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE) - mpcDesc[coreId].yram_offset); + return mpcDesc[coreId].yram_offset / MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE; +} + +static void arm_Init(void) +{ + mpcDesc[ARM_CORE_ID].allocator[INTERNAL_XRAM24] = 0; + mpcDesc[ARM_CORE_ID].allocator[INTERNAL_XRAM16] = 0; + + mpcDesc[ARM_CORE_ID].allocator[INTERNAL_YRAM24] = 0; + mpcDesc[ARM_CORE_ID].allocator[INTERNAL_YRAM16] = 0; + + mpcDesc[ARM_CORE_ID].allocator[SDRAM_CODE] = 0; + mpcDesc[ARM_CORE_ID].allocator[ESRAM_CODE] = 0; + + mpcDesc[ARM_CORE_ID].allocator[SDRAM_EXT16] = 0; + mpcDesc[ARM_CORE_ID].allocator[SDRAM_EXT24] = 0; + + mpcDesc[ARM_CORE_ID].allocator[ESRAM_EXT16] = &esramDesc; + mpcDesc[ARM_CORE_ID].allocator[ESRAM_EXT16]->referenceCounter++; + mpcDesc[ARM_CORE_ID].allocator[ESRAM_EXT24] = &esramDesc; + mpcDesc[ARM_CORE_ID].allocator[ESRAM_EXT24]->referenceCounter++; +} + +static void _init_Segment( + t_dsp_segment *seg, + const t_cm_system_address base, const t_uint32 arm_offset, + const t_uint32 size) +{ + seg->base.logical = base.logical + arm_offset; + seg->base.physical = base.physical + arm_offset; + seg->size = size; +} + +static t_cm_error mmdsp_Init( + const t_cm_system_address *dspSystemAddr, + t_uint8 nbXramBlocks, t_uint8 nbYramBlocks, + t_dsp_allocator_desc *sdramCodeDesc, + t_dsp_allocator_desc *sdramDataDesc, + t_cm_domain_id eeDomain, + t_dsp_desc *pDspDesc, + t_mmdsp_hw_regs **pRegs) +{ + t_cm_system_address xramSysAddr; + t_uint32 sizeInBytes; + + /* Initialize reference on hw ressources */ + *pRegs = (t_mmdsp_hw_regs *) dspSystemAddr->logical; + + /* Initialize memory segments management */ + xramSysAddr.logical = (t_cm_logical_address)(((t_mmdsp_hw_regs *)dspSystemAddr->logical)->mem24); + xramSysAddr.physical = (t_cm_physical_address)(((t_mmdsp_hw_regs *)dspSystemAddr->physical)->mem24); + + /* The last (x)ram block will be used by cache, so ... */ + /* And the NB_YRAM_BLOCKS last available block(s) will be used as YRAM */ + + /* XRAM*/ + pDspDesc->allocator[INTERNAL_XRAM16] = pDspDesc->allocator[INTERNAL_XRAM24] = (t_dsp_allocator_desc*)OSAL_Alloc(sizeof (t_dsp_allocator_desc)); + if (pDspDesc->allocator[INTERNAL_XRAM24] == NULL) + return CM_NO_MORE_MEMORY; + + pDspDesc->allocator[INTERNAL_XRAM24]->allocDesc = cm_MM_CreateAllocator( + ((nbXramBlocks-nbYramBlocks)*MMDSP_RAM_BLOCK_SIZE)*MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE, + 0, + "XRAM"); + pDspDesc->allocator[INTERNAL_XRAM24]->baseAddress = xramSysAddr; + pDspDesc->allocator[INTERNAL_XRAM24]->referenceCounter = 2; + + /* YRAM */ + pDspDesc->allocator[INTERNAL_YRAM16] = pDspDesc->allocator[INTERNAL_YRAM24] = (t_dsp_allocator_desc*)OSAL_Alloc(sizeof (t_dsp_allocator_desc)); + if (pDspDesc->allocator[INTERNAL_YRAM24] == 0) { + OSAL_Free(pDspDesc->allocator[INTERNAL_XRAM24]); + return CM_NO_MORE_MEMORY; + } + + pDspDesc->allocator[INTERNAL_YRAM24]->allocDesc = cm_MM_CreateAllocator( + (nbYramBlocks*MMDSP_RAM_BLOCK_SIZE)*MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE, + ((nbXramBlocks-nbYramBlocks)*MMDSP_RAM_BLOCK_SIZE)*MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE, + "YRAM"); + pDspDesc->allocator[INTERNAL_YRAM24]->baseAddress = xramSysAddr; /* use xram base address but offset is not null */ + pDspDesc->allocator[INTERNAL_YRAM24]->referenceCounter = 2; + + pDspDesc->yram_offset = ((nbXramBlocks-nbYramBlocks)*MMDSP_RAM_BLOCK_SIZE)*MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE; + pDspDesc->yram_size = (nbYramBlocks*MMDSP_RAM_BLOCK_SIZE)*MMDSP_DATA_WORD_SIZE_IN_HOST_SPACE; + + /* SDRAM & ESRAM */ + pDspDesc->allocator[SDRAM_CODE] = sdramCodeDesc; + pDspDesc->allocator[SDRAM_CODE]->referenceCounter++; + pDspDesc->allocator[ESRAM_CODE] = &esramDesc; + pDspDesc->allocator[ESRAM_CODE]->referenceCounter++; + + /* LOCKED CODE at end of SDRAM code*/ + pDspDesc->allocator[LOCKED_CODE] = sdramCodeDesc; + pDspDesc->allocator[LOCKED_CODE]->referenceCounter++; + + pDspDesc->locked_offset = cm_MM_GetAllocatorSize(pDspDesc->allocator[SDRAM_CODE]->allocDesc) - MMDSP_CODE_CACHE_WAY_SIZE * 8 * SxA_LOCKED_WAY; + pDspDesc->locked_size = MMDSP_CODE_CACHE_WAY_SIZE * 8 * SxA_LOCKED_WAY; + + /* Data_16/24 memory management */ + pDspDesc->allocator[SDRAM_EXT16] = sdramDataDesc; + pDspDesc->allocator[SDRAM_EXT16]->referenceCounter++; + pDspDesc->allocator[SDRAM_EXT24] = sdramDataDesc; + pDspDesc->allocator[SDRAM_EXT24]->referenceCounter++; + + pDspDesc->allocator[ESRAM_EXT16] = &esramDesc; + pDspDesc->allocator[ESRAM_EXT16]->referenceCounter++; + pDspDesc->allocator[ESRAM_EXT24] = &esramDesc; + pDspDesc->allocator[ESRAM_EXT24]->referenceCounter++; + + sizeInBytes = cm_MM_GetAllocatorSize(pDspDesc->allocator[SDRAM_CODE]->allocDesc); +#if defined(__STN_8500) && (__STN_8500 > 10) + _init_Segment(&pDspDesc->segments[SDRAM_CODE_EE], + pDspDesc->allocator[SDRAM_CODE]->baseAddress, + domainDesc[eeDomain].domain.sdramCode.offset, + domainDesc[eeDomain].domain.sdramCode.size); + _init_Segment(&pDspDesc->segments[SDRAM_CODE_USER], + pDspDesc->allocator[SDRAM_CODE]->baseAddress, + domainDesc[eeDomain].domain.sdramCode.offset + domainDesc[eeDomain].domain.sdramCode.size, + sizeInBytes - domainDesc[eeDomain].domain.sdramCode.size); +#else + _init_Segment(&pDspDesc->segments[SDRAM_CODE_EE], + pDspDesc->allocator[SDRAM_CODE]->baseAddress, + 0x0, + sizeInBytes); +#endif + + sizeInBytes = cm_MM_GetAllocatorSize(pDspDesc->allocator[ESRAM_CODE]->allocDesc); +#if defined(__STN_8500) && (__STN_8500 > 10) + _init_Segment(&pDspDesc->segments[ESRAM_CODE_EE], + pDspDesc->allocator[ESRAM_CODE]->baseAddress, + domainDesc[eeDomain].domain.esramCode.offset, + domainDesc[eeDomain].domain.esramCode.size); + _init_Segment(&pDspDesc->segments[ESRAM_CODE_USER], + pDspDesc->allocator[ESRAM_CODE]->baseAddress, + domainDesc[eeDomain].domain.esramCode.offset + domainDesc[eeDomain].domain.esramCode.size, + sizeInBytes - domainDesc[eeDomain].domain.esramCode.size); +#else + _init_Segment(&pDspDesc->segments[ESRAM_CODE_EE], + pDspDesc->allocator[ESRAM_CODE]->baseAddress, + 0x0, + sizeInBytes); +#endif + + //the difference in the following code is the segment size used to calculate the top!! + sizeInBytes = cm_MM_GetAllocatorSize(pDspDesc->allocator[SDRAM_EXT16]->allocDesc); +#if defined(__STN_8500) && (__STN_8500 > 10) + _init_Segment(&pDspDesc->segments[SDRAM_DATA_EE], + pDspDesc->allocator[SDRAM_EXT16]->baseAddress, + domainDesc[eeDomain].domain.sdramData.offset, + domainDesc[eeDomain].domain.sdramData.size); + _init_Segment(&pDspDesc->segments[SDRAM_DATA_USER], + pDspDesc->allocator[SDRAM_EXT16]->baseAddress, + domainDesc[eeDomain].domain.sdramData.offset + domainDesc[eeDomain].domain.sdramData.size, + sizeInBytes - domainDesc[eeDomain].domain.sdramData.size); +#else + _init_Segment(&pDspDesc->segments[SDRAM_DATA_EE], + pDspDesc->allocator[SDRAM_EXT16]->baseAddress, + 0x0, + sizeInBytes); +#endif + + sizeInBytes = cm_MM_GetAllocatorSize(pDspDesc->allocator[ESRAM_EXT16]->allocDesc); +#if defined(__STN_8500) && (__STN_8500 > 10) + _init_Segment(&pDspDesc->segments[ESRAM_DATA_EE], + pDspDesc->allocator[ESRAM_EXT16]->baseAddress, + domainDesc[eeDomain].domain.esramData.offset, + domainDesc[eeDomain].domain.esramData.size); + _init_Segment(&pDspDesc->segments[ESRAM_DATA_USER], + pDspDesc->allocator[ESRAM_EXT16]->baseAddress, + domainDesc[eeDomain].domain.esramData.offset + domainDesc[eeDomain].domain.esramData.size, + sizeInBytes - domainDesc[eeDomain].domain.esramData.size); +#else + _init_Segment(&pDspDesc->segments[ESRAM_DATA_EE], + pDspDesc->allocator[ESRAM_EXT16]->baseAddress, + 0x0, + sizeInBytes); +#endif + + return CM_OK; +} + +//TODO, juraj, reuse cm_DSP_UpdateBase functions +static t_cm_error mmdsp_Configure(t_nmf_core_id coreId, t_mmdsp_hw_regs *pRegs, const t_dsp_desc *pDspDesc) +{ + t_uint64 regValue; + static const t_uint64 coreId2stbusId[NB_CORE_IDS] = + { + 0, /* ARM_CORE_ID no meaning */ + SVA_STBUS_ID, /* SVA_CORE_ID */ + SIA_STBUS_ID /* SIA_CORE_ID */ + }; + + //t_cm_system_address sysAddr; + //t_cm_size sizeInBytes; + + /* Stop core (stop clock) */ + MMDSP_RESET_CORE(pRegs); + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } + MMDSP_STOP_CORE(pRegs); + { + volatile t_uint32 loopme = 0xfff; + while(loopme--) ; + } + +#if 0 + /* Reset DSP internal memory (xram) */ + { + t_uint32 *pSrc = (t_uint32 *)(pRegs->mem24); + t_uint32 tcmSize; + int i; + cm_MM_GetAllocatorSize(pDspDesc->allocator[INTERNAL_XRAM], &sizeInBytes); + tcmSize = sizeInBytes; + cm_MM_GetAllocatorSize(pDspDesc->allocator[INTERNAL_YRAM], &sizeInBytes); + tcmSize += sizeInBytes; + for (i = 0; i < (tcmSize/sizeof(t_uint32)); i++) + *(pSrc++) = 0; + } +#endif + + /* Configure all blocks as X only, except the Y ones (MOVED TO mmdsp_InitAfterBoot()) */ + + /* __STN_8815 --> __STN_8820 or __STN_8500 */ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_STBUS_ID_CONF_REG, coreId2stbusId[coreId]); + + /* Configure External Bus timeout reg */ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EN_EXT_BUS_TIMEOUT_REG, IHOST_TIMEOUT_ENABLE); + + /* Program memory management */ +#if defined(__STN_8500) && (__STN_8500 > 10) + { + const t_uint32 r0 = CODE_ADDRESS_BASE[1] >> 10; + const t_uint32 r1 = CODE_ADDRESS_BASE[2] >> 10; + const t_uint32 r2 = CODE_ADDRESS_BASE[3] >> 10; + const t_uint32 sdram0 = pDspDesc->segments[SDRAM_CODE_EE].base.physical; + const t_uint32 sdram1 = pDspDesc->segments[SDRAM_CODE_USER].base.physical; + const t_uint32 esram0 = pDspDesc->segments[ESRAM_CODE_EE].base.physical; + const t_uint32 esram1 = pDspDesc->segments[ESRAM_CODE_USER].base.physical; + + /* Bases for first two segments, going to sdram */ + regValue = ((t_uint64)(sdram1) << IHOST_PRG_BASE2_ADDR_SHIFT) + (t_uint64)sdram0; + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_PRG_BASE_ADDR_REG, regValue); + + /* Bases for second two segments, going to esram */ + regValue = ((t_uint64)(esram1) << IHOST_PRG_BASE4_ADDR_SHIFT) + (t_uint64)esram0; + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_PRG_BASE_34_ADDR_REG, regValue); + + /* Split mmdsp program adress-space and activate the mechanism */ + regValue = (t_uint64)((t_uint64)(r2) << 48 | (t_uint64)(r1) <<32 | (t_uint64)(r0) << 16 | 1); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_PRG_BASE2_ACTIV_REG, regValue); + } +#else + { + const t_uint32 sdram0 = pDspDesc->segments[SDRAM_CODE_EE].base.physical; + const t_uint32 esram0 = pDspDesc->segments[ESRAM_CODE_EE].base.physical; + + regValue = (t_uint64)sdram0 | ( ((t_uint64)esram0) << IHOST_PRG_BASE2_ADDR_SHIFT ); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_PRG_BASE_ADDR_REG, regValue); + + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_PRG_BASE2_ACTIV_REG, IHOST_PRG_BASE2_ACTIV_ON); + } +#endif + + /* Data_16/24 memory management */ +#if defined(__STN_8500) && (__STN_8500 > 10) + /* Segments 1 and 2 for 16/24 map to sdram continuously */ + /* Base 1 */ + regValue = (((t_uint64)pDspDesc->segments[SDRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE_24_SHIFT) | + (((t_uint64)pDspDesc->segments[SDRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE_REG, regValue); + /* Top 1 */ + regValue = (((t_uint64)(pDspDesc->segments[SDRAM_DATA_EE].base.physical + pDspDesc->segments[SDRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[SDRAM_DATA_EE].base.physical + pDspDesc->segments[SDRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_TOP_16_24_REG, regValue); + + /* Base 2 */ + regValue = (((t_uint64)pDspDesc->segments[SDRAM_DATA_USER].base.physical) << IHOST_DATA_EXT_BUS_BASE2_24_SHIFT) | + (((t_uint64)pDspDesc->segments[SDRAM_DATA_USER].base.physical) << IHOST_DATA_EXT_BUS_BASE2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE2_REG, regValue); + /* Top 2 */ + regValue = (((t_uint64)(pDspDesc->segments[SDRAM_DATA_USER].base.physical + pDspDesc->segments[SDRAM_DATA_USER].size - 1)) << IHOST_DATA_EXT_BUS_TOP2_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[SDRAM_DATA_USER].base.physical + pDspDesc->segments[SDRAM_DATA_USER].size - 1)) << IHOST_DATA_EXT_BUS_TOP2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EXT_BUS_TOP2_16_24_REG, regValue); + + /* Segments 3 and 4 for 16/24 map to esram continuously */ + /* Base 3 */ + regValue = (((t_uint64)pDspDesc->segments[ESRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE3_24_SHIFT) | + (((t_uint64)pDspDesc->segments[ESRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE3_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE3_REG, regValue); + /* Top 3 */ + regValue = (((t_uint64)(pDspDesc->segments[ESRAM_DATA_EE].base.physical + pDspDesc->segments[ESRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP3_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[ESRAM_DATA_EE].base.physical + pDspDesc->segments[ESRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP3_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EXT_BUS_TOP3_16_24_REG, regValue); + + /* Base 4 */ + regValue = (((t_uint64)pDspDesc->segments[ESRAM_DATA_USER].base.physical) << IHOST_DATA_EXT_BUS_BASE4_24_SHIFT) | + (((t_uint64)pDspDesc->segments[ESRAM_DATA_USER].base.physical) << IHOST_DATA_EXT_BUS_BASE4_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE4_REG, regValue); + /* Top 4 */ + regValue = (((t_uint64)(pDspDesc->segments[ESRAM_DATA_USER].base.physical + pDspDesc->segments[ESRAM_DATA_USER].size - 1)) << IHOST_DATA_EXT_BUS_TOP4_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[ESRAM_DATA_USER].base.physical + pDspDesc->segments[ESRAM_DATA_USER].size - 1)) << IHOST_DATA_EXT_BUS_TOP4_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EXT_BUS_TOP4_16_24_REG, regValue); + + /* Define base 2 thresholds/offset (1MB for each up segment) */ + regValue = ((t_uint64)DATA_ADDRESS_BASE[1].startAddress[1]>>SHIFT_HALFWORD1)<< IHOST_DATA2_24_XA_BASE_SHIFT; + regValue |= ((t_uint64)DATA_ADDRESS_BASE[1].startAddress[0]>>SHIFT_HALFWORD1)<< IHOST_DATA2_16_XA_BASE_SHIFT; + + /* Define base 3 thresholds/offset (1MB for each up segment) */ + regValue |= ((t_uint64)DATA_ADDRESS_BASE[2].startAddress[1]>>SHIFT_HALFWORD1)<< IHOST_DATA3_24_XA_BASE_SHIFT; + regValue |= ((t_uint64)DATA_ADDRESS_BASE[2].startAddress[0]>>SHIFT_HALFWORD1)<< IHOST_DATA3_16_XA_BASE_SHIFT; + + /* Define base 4 thresholds/offset (1MB for each up segment) */ + regValue |= ((t_uint64)DATA_ADDRESS_BASE[3].startAddress[1]>>SHIFT_HALFWORD1)<< IHOST_DATA4_24_XA_BASE_SHIFT; + regValue |= ((t_uint64)DATA_ADDRESS_BASE[3].startAddress[0]>>SHIFT_HALFWORD1)<< IHOST_DATA4_16_XA_BASE_SHIFT; + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA2_1624_XA_BASE_REG, regValue); + +#else + /* Program data24/16 base 1 */ + regValue = (((t_uint64)pDspDesc->segments[SDRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE_24_SHIFT) | + (((t_uint64)pDspDesc->segments[SDRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE_REG, regValue); + + /* Program data24/16 top 1 */ + regValue = (((t_uint64)(pDspDesc->segments[SDRAM_DATA_EE].base.physical + pDspDesc->segments[SDRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[SDRAM_DATA_EE].base.physical + pDspDesc->segments[SDRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_TOP_16_24_REG, regValue); + + /* Program data24/16 base 2 */ + regValue = (((t_uint64)pDspDesc->segments[ESRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE2_24_SHIFT) | + (((t_uint64)pDspDesc->segments[ESRAM_DATA_EE].base.physical) << IHOST_DATA_EXT_BUS_BASE2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_EXT_BUS_BASE2_REG, regValue); + + /* Program data24/16 top 2 */ + regValue = (((t_uint64)(pDspDesc->segments[ESRAM_DATA_EE].base.physical + pDspDesc->segments[ESRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP2_24_SHIFT) | + (((t_uint64)(pDspDesc->segments[ESRAM_DATA_EE].base.physical + pDspDesc->segments[ESRAM_DATA_EE].size - 1)) << IHOST_DATA_EXT_BUS_TOP2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EXT_BUS_TOP2_16_24_REG, regValue); + + /* Define base 2 thresholds/offset (1MB for each up segment) */ + regValue = ((t_uint64)(DATA_ADDRESS_BASE[1].startAddress[1]>>SHIFT_HALFWORD1))<< IHOST_DATA2_24_XA_BASE_SHIFT; // Top address minus ONE_MB => 256KW (24/32-bit) + regValue |= ((t_uint64)(DATA_ADDRESS_BASE[1].startAddress[0]>>SHIFT_HALFWORD1))<< IHOST_DATA2_16_XA_BASE_SHIFT; // Top address minus ONE_MB => 512KW (16-bit) + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA2_1624_XA_BASE_REG, regValue); +#endif + + /* Enable top check */ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_TOP_16_24_CHK_REG, IHOST_DATA_TOP_16_24_CHK_ON); + + /* Enable both bases */ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_DATA_BASE2_ACTIV_REG, IHOST_DATA_BASE2_ACTIV_ON); + + /* MMIO management */ + regValue = (((t_uint64)STM_BASE_ADDR) << IHOST_EXT_MMIO_BASE_ADDR_SHIFT) | + (((t_uint64)DMA_CTRL_END_ADDR) << IHOST_EXT_MMIO_DATA_EXT_BUS_TOP_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_EXT_MMIO_BASE_DATA_EXT_BUS_TOP_REG, regValue); + + /* Configure Icache */ + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_INST_BURST_SZ_REG, IHOST_INST_BURST_SZ_AUTO); + + regValue = (t_uint64)(IHOST_ICACHE_MODE_PERFMETER_OFF | IHOST_ICACHE_MODE_L2_CACHE_ON | + IHOST_ICACHE_MODE_L1_CACHE_ON | IHOST_ICACHE_MODE_FILL_MODE_OFF); + WRITE_INDIRECT_HOST_REG(pRegs, IHOST_ICACHE_MODE_REG, regValue); + + return CM_OK; +} + +PUBLIC t_cm_error cm_DSP_updateCodeBase( + t_nmf_core_id coreId, + t_dsp_segment_type hwSegment, + t_cm_system_address src, + t_cm_system_address dst + ) +{ +#if defined(__STN_8500) && (__STN_8500 > 10) + t_mmdsp_hw_regs *pRegs = pMmdspRegs[coreId]; + t_uint32 offset = src.physical - mpcDesc[coreId].segments[hwSegment].base.physical; + t_cm_system_address base; + t_uint32 altBase = 0; + t_uint64 regValue = 0; + t_uint8 reg = 0; + + base.physical = dst.physical - offset; + base.logical = dst.logical - offset; + + switch(hwSegment) { + case SDRAM_CODE_EE: + altBase = mpcDesc[coreId].segments[SDRAM_CODE_USER].base.physical; + regValue = ((t_uint64)(altBase) << IHOST_PRG_BASE2_ADDR_SHIFT) + (t_uint64)base.physical; + reg = IHOST_PRG_BASE_ADDR_REG; + break; + case SDRAM_CODE_USER: + altBase = mpcDesc[coreId].segments[SDRAM_CODE_EE].base.physical; + regValue = ((t_uint64)(base.physical) << IHOST_PRG_BASE2_ADDR_SHIFT) + (t_uint64)altBase; + reg = IHOST_PRG_BASE_ADDR_REG; + break; + case ESRAM_CODE_EE: + altBase = mpcDesc[coreId].segments[ESRAM_CODE_USER].base.physical; + regValue = ((t_uint64)(altBase) << IHOST_PRG_BASE4_ADDR_SHIFT) + (t_uint64)base.physical; + reg = IHOST_PRG_BASE_34_ADDR_REG; + break; + case ESRAM_CODE_USER: + altBase = mpcDesc[coreId].segments[ESRAM_CODE_EE].base.physical; + regValue = ((t_uint64)(base.physical) << IHOST_PRG_BASE4_ADDR_SHIFT) + (t_uint64)altBase; + reg = IHOST_PRG_BASE_34_ADDR_REG; + break; + default: + CM_ASSERT(0); + } + + LOG_INTERNAL(1, "##### DSP Code Base Update [%d]: 0x%x -> 0x%x (0x%x)\n", + hwSegment, mpcDesc[coreId].segments[hwSegment].base.physical, base.physical, base.logical, 0, 0); + + WRITE_INDIRECT_HOST_REG(pRegs, reg, regValue); + + mpcDesc[coreId].segments[hwSegment].base = base; +#endif + return CM_OK; +} + +PUBLIC t_cm_error cm_DSP_updateDataBase( + t_nmf_core_id coreId, + t_dsp_segment_type hwSegment, + t_cm_system_address src, + t_cm_system_address dst + ) +{ +#if defined(__STN_8500) && (__STN_8500 > 10) + t_mmdsp_hw_regs *pRegs = pMmdspRegs[coreId]; + t_uint32 offset = src.physical - mpcDesc[coreId].segments[hwSegment].base.physical; + t_cm_system_address base; + t_uint32 size = mpcDesc[coreId].segments[hwSegment].size; //in bytes + t_uint64 regValue; + t_uint8 reg = 0; + t_uint8 top = 0; + + base.physical = dst.physical - offset; + base.logical = dst.logical - offset; + + switch(hwSegment) { + case SDRAM_DATA_EE: + reg = IHOST_DATA_EXT_BUS_BASE_REG; + top = IHOST_DATA_EXT_BUS_TOP_16_24_REG; + break; + case SDRAM_DATA_USER: + reg = IHOST_DATA_EXT_BUS_BASE2_REG; + top = IHOST_EXT_BUS_TOP2_16_24_REG; + break; + case ESRAM_DATA_EE: + reg = IHOST_DATA_EXT_BUS_BASE3_REG; + top = IHOST_EXT_BUS_TOP3_16_24_REG; + break; + case ESRAM_DATA_USER: + reg = IHOST_DATA_EXT_BUS_BASE4_REG; + top = IHOST_EXT_BUS_TOP4_16_24_REG; + break; + default: + CM_ASSERT(0); + } + + LOG_INTERNAL(1, "##### DSP Data Base Update [%d]: 0x%x -> 0x%x (0x%x)\n", + hwSegment, mpcDesc[coreId].segments[hwSegment].base.physical, base.physical, base.logical, 0, 0); + + /* Program data24/16 base */ + regValue = (((t_uint64)(base.physical)) << IHOST_DATA_EXT_BUS_BASE2_24_SHIFT) | + (((t_uint64)(base.physical)) << IHOST_DATA_EXT_BUS_BASE2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, reg, regValue); + + /* Program data24/16 top */ + regValue = (((t_uint64)(base.physical + size - 1)) << IHOST_DATA_EXT_BUS_TOP2_24_SHIFT) | + (((t_uint64)(base.physical + size - 1)) << IHOST_DATA_EXT_BUS_TOP2_16_SHIFT); + WRITE_INDIRECT_HOST_REG(pRegs, top, regValue); + + mpcDesc[coreId].segments[hwSegment].base = base; +#endif + return CM_OK; +} + +PUBLIC t_cm_error cm_DSP_GetDspDataAddressInfo(t_nmf_core_id coreId, t_uint32 addr, t_dsp_address_info *info) +{ + t_uint32 i, j; + + for(j = 0; j < 2; j++) + { + for(i = 0; i < DATA_BASE_NUMBER; i++) + { + if(DATA_ADDRESS_BASE[i].startAddress[j] <= addr && addr < DATA_ADDRESS_BASE[i + 1].startAddress[j]) + { + info->segmentType = DATA_ADDRESS_BASE[i].segmentType; + info->baseOffset = (addr - DATA_ADDRESS_BASE[i].startAddress[j]) * (2 + j * 2); + + return CM_OK; + } + } + } + + CM_ASSERT(0); + //return CM_INVALID_PARAMETER; +} + +static t_cm_error mmdsp_ConfigureAfterBoot(t_nmf_core_id coreId, t_uint8 nbXramBlocks, t_uint8 nbYramBlocks) +{ + /* Configure all blocks as X only, except the Y ones */ + pMmdspRegs[coreId]->mmio_16.config_data_mem.value = (t_uint16)(~(((1U << nbYramBlocks) - 1) << (nbXramBlocks-nbYramBlocks))); + +#if defined(__STN_8500) && (__STN_8500 > 10) + /* enable write posting */ + MMDSP_ENABLE_WRITE_POSTING(pMmdspRegs[coreId]); +#endif + + return CM_OK; +} + + diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/bfd.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/bfd.h new file mode 100644 index 00000000000..2bccf9c073b --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/bfd.h @@ -0,0 +1,123 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf bfd relocation. + * + * \defgroup ELFLOADER MMDSP ELF loader. + */ +#ifndef __INC_CM_ELF_BFD_H +#define __INC_CM_ELF_BFD_H + +#include <cm/inc/cm_type.h> + +/* + * Relocation spcification + */ +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +struct reloc_howto_struct +{ + /* The type field has mainly a documentary use - the back end can + do what it wants with it, though normally the back end's + external idea of what a reloc number is stored + in this field. For example, a PC relative word relocation + in a coff environment has the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. To get the number of bytes operated + on by a type of relocation, use bfd_get_reloc_size. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + t_uint64 pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + void (*special_function)(void); + + /* The textual name of the relocation type. */ + char *name; + + /* Some formats record a relocation addend in the section contents + rather than with the relocation. For ELF formats this is the + distinction between USE_REL and USE_RELA (though the code checks + for USE_REL == 1/0). The value of this field is TRUE if the + addend is recorded with the section contents; when performing a + partial link (ld -r) the section contents (the data) will be + modified. The value of this field is FALSE if addends are + recorded with the relocation (in arelent.addend); when performing + a partial link the relocation will be modified. + All relocations for all ELF USE_RELA targets should set this field + to FALSE (values of TRUE should be looked on with suspicion). + However, the converse is not true: not all relocations of all ELF + USE_REL targets set this field to TRUE. Why this is so is peculiar + to each particular target. For relocs that aren't used in partial + links (e.g. GOT stuff) it doesn't matter what this is set to. */ + char partial_inplace; + + /* src_mask selects the part of the instruction (or data) to be used + in the relocation sum. If the target relocations don't have an + addend in the reloc, eg. ELF USE_REL, src_mask will normally equal + dst_mask to extract the addend from the section contents. If + relocations do have an addend in the reloc, eg. ELF USE_RELA, this + field should be zero. Non-zero values for ELF USE_RELA targets are + bogus as in those cases the value in the dst_mask part of the + section contents should be treated as garbage. */ + t_uint64 src_mask; + + /* dst_mask selects which parts of the instruction (or data) are + replaced with a relocated value. */ + t_uint64 dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs); this flag signals the fact. */ + char pcrel_offset; +}; + +#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/common.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/common.h new file mode 100644 index 00000000000..c51845d5f96 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/common.h @@ -0,0 +1,125 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf common definition. + */ +#ifndef __INC_CM_ELF_COMMON_H +#define __INC_CM_ELF_COMMON_H + +#include <cm/engine/component/inc/nmfheaderabi.h> +#include <cm/engine/elf/inc/elfabi.h> +#include <cm/engine/elf/inc/reloc.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/component/inc/description.h> +#include <cm/engine/utils/inc/string.h> + + +#define MAX_SEGMENT 20 // Just in order to not allocate them dynamically + +struct XXElf; + +/** + * \brief Structure used as database of pushed component. + */ +typedef struct { + t_instance_property instanceProperty; + t_uint32 magicNumber; //!< Magic Number + t_dup_char foundedTemplateName; + t_uint32 minStackSize; //!< Minimum stack size + + struct XXElf *ELF; + + t_elfSegment segments[NUMBER_OF_MMDSP_MEMORY]; + + t_bool temporaryDescription; + + t_memory_reference memoryForConstruct; + t_memory_reference memoryForStart; + t_memory_reference memoryForStop; + t_memory_reference memoryForDestroy; + + t_uint8 requireNumber; //!< Number of interface required by this template + t_uint8 attributeNumber; //!< Number of attributes in this template + t_uint8 propertyNumber; //!< Number of properties in this template + t_uint8 provideNumber; //!< Number of interface provided by this template + + t_interface_require *requires; //!< Array of interface required by this template + t_attribute *attributes; //!< Array of attributes in this template + t_property *properties; //!< Array of properties in this template + t_interface_provide *provides; //!< Array of interface provided by this template + +} t_elfdescription; + +/** + * \brief Temporary structure used as database when pushing component. + */ +typedef struct +{ + const char *elfdata; + const char *sectionData[50]; // YES it must be dynamic, but i'm tired. + + t_bool isExecutable; + + t_sint32 nmfSectionIndex; + const void *relaNmfSegment, *relaNmfSegmentEnd; + const void *relaNmfSegmentSymbols; + const char *relaNmfSegmentStrings; + + const t_elf_component_header*elfheader; + + +} t_tmp_elfdescription; + + +t_cm_error ELF64_LoadComponent( + t_uint16 e_machine, + const char *elfdata, + t_elfdescription **elfhandlePtr, + t_tmp_elfdescription *elftmp); +t_cm_error ELF64_ComputeSegment( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp); + +void ELF64_UnloadComponent( + t_elfdescription *elfhandle); + +t_cm_error ELF64_loadSegment( + t_elfdescription *elfhandle, + t_memory_handle *memory, + t_memory_property property); +t_cm_error ELF64_relocateSegments( + t_memory_handle *memories, + t_elfdescription *elf, + t_memory_property property, + void *cbContext); +t_cm_error ELF64_getRelocationMemory( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp, + t_uint32 offsetInNmf, + t_memory_reference *memory); + +const t_elfmemory* MMDSP_getMappingById(t_memory_id memId); +const t_elfmemory* MMDSP_getMappingByName(const char* sectionName, t_instance_property property); +void MMDSP_serializeMemories(t_instance_property property, + const t_elfmemory** codeMemory, const t_elfmemory** thisMemory); +void MMDSP_copySection(t_uint32 origAddr, t_uint32 remoteAddr, t_uint32 sizeInByte); +void MMDSP_bzeroSection(t_uint32 remoteAddr, t_uint32 sizeInByte); +void MMDSP_loadedSection(t_nmf_core_id coreId, t_memory_id memId, t_memory_handle handle); +void MMDSP_unloadedSection(t_nmf_core_id coreId, t_memory_id memId, t_memory_handle handle); + +void MMDSP_copyCode(t_uint64 * remoteAddr64, const char* origAddr, int nb); +void MMDSP_copyData24(t_uint32 * remoteAddr32, const char* origAddr, int nb); +void MMDSP_copyData16(t_uint16 * remoteAddr16, const char* origAddr, int nb); + +t_uint32 cm_resolvSymbol( + void* context, + t_uint32 type, + t_dup_char symbolName, + char* reloc_addr); + + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/elfabi.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/elfabi.h new file mode 100644 index 00000000000..cbcc6db3b9b --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/elfabi.h @@ -0,0 +1,539 @@ +/* + * 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. + */ +#ifndef _CM_ELF_H +#define _CM_ELF_H 1 + +typedef t_uint16 Elf32_Half; +typedef t_uint16 Elf64_Half; + +typedef t_uint32 Elf32_Word; +typedef t_sint32 Elf32_Sword; +typedef t_uint32 Elf64_Word; +typedef t_sint32 Elf64_Sword; + +typedef t_uint64 Elf32_Xword; +typedef t_sint64 Elf32_Sxword; +typedef t_uint64 Elf64_Xword; +typedef t_sint64 Elf64_Sxword; + +typedef t_uint32 Elf32_Addr; +typedef t_uint64 Elf64_Addr; + +typedef t_uint32 Elf32_Off; +typedef t_uint64 Elf64_Off; + +typedef t_uint16 Elf32_Section; +typedef t_uint16 Elf64_Section; + +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/********************************************* + * Header + *********************************************/ +#define EI_NIDENT (16) //!< Size of e_ident[] + +#define EI_MAG0 0 //!< File identification +#define ELFMAG0 0x7f + +#define EI_MAG1 1 //!< File identification +#define ELFMAG1 'E' + +#define EI_MAG2 2 //!< File identification +#define ELFMAG2 'L' + +#define EI_MAG3 3 //!< File identification +#define ELFMAG3 'F' + +#define EI_CLASS 4 //!< File class +#define ELFCLASSNONE 0 //!< Invalid class +#define ELFCLASS32 1 //!< 32-bit objects +#define ELFCLASS64 2 //!< 64-bit objects + +#define EI_DATA 5 //!< Data encoding +#define ELFDATANONE 0 //!< Invalid data encoding +#define ELFDATA2LSB 1 //!< 2's complement, little endian +#define ELFDATA2MSB 2 //!< 2's complement, big endian + +#define EI_VERSION 6 //!< File version + +#define EI_OSABI 7 //!< OS ABI identification +#define ELFOSABI_NONE 0 //!< No extension +#define ELFOSABI_HPUX 1 //!< HP-UX +#define ELFOSABI_NETBSD 2 //!< NetBSD +#define ELFOSABI_LINUX 3 //!< Linux +#define ELFOSABI_SOLARIS 6 //!< Sun Solaris +#define ELFOSABI_AIX 7 //!< AIX +#define ELFOSABI_IRIX 8 //!< IRIX +#define ELFOSABI_FREEBSD 9 //!< FreeBSD +#define ELFOSABI_TRU64 10 //!< Compaq TRU64 UNIX +#define ELFOSABI_MODESTO 11 //!< Novell Modesto +#define ELFOSABI_OPENBSD 12 //!< Open BSD +#define ELFOSABI_OPENVMS 13 //!< Open VMS +#define ELFOSABI_NSK 14 //!< HP Non-Stop-Kernel + +#define EI_ABIVERSION 8 //!< ABI version + +#define EI_PAD 9 //!< Start of padding byte + + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; //!< The initial bytes mark the file as an object file and provide machine-independent data with which to decode and interpret the file's contents + Elf32_Half e_type; //!< This member identifies the object file type + Elf32_Half e_machine; //!< This member's value specifies the required architecture for an individual file + Elf32_Word e_version; //!< This member identifies the object file version + Elf32_Addr e_entry; //!< This member gives the virtual address to which the system first transfers control, thus starting the process + Elf32_Off e_phoff; //!< This member holds the program header table's file offset in bytes + Elf32_Off e_shoff; //!< This member holds the section header table's file offset in bytes + Elf32_Word e_flags; //!< This member holds processor-specific flags associated with the file + Elf32_Half e_ehsize; //!< This member holds the ELF header's size in bytes + Elf32_Half e_phentsize; //!< This member holds the size in bytes of one entry in the file's program header table; all entries are the same size + Elf32_Half e_phnum; //!< This member holds the number of entries in the program header table + Elf32_Half e_shentsize; //!< This member holds a section header's size in bytes + Elf32_Half e_shnum; //!< This member holds the number of entries in the section header table + Elf32_Half e_shstrndx; //!< This member holds the section header table index of the entry associated with the section name string table +} Elf32_Ehdr; //!< 32bit Entry Header + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; //!< The initial bytes mark the file as an object file and provide machine-independent data with which to decode and interpret the file's contents + Elf64_Half e_type; //!< This member identifies the object file type + Elf64_Half e_machine; //!< This member's value specifies the required architecture for an individual file + Elf64_Word e_version; //!< This member identifies the object file version + Elf64_Addr e_entry; //!< This member gives the virtual address to which the system first transfers control, thus starting the process + Elf64_Off e_phoff; //!< This member holds the program header table's file offset in bytes + Elf64_Off e_shoff; //!< This member holds the section header table's file offset in bytes + Elf64_Word e_flags; //!< This member holds processor-specific flags associated with the file + Elf64_Half e_ehsize; //!< This member holds the ELF header's size in bytes + Elf64_Half e_phentsize; //!< This member holds the size in bytes of one entry in the file's program header table; all entries are the same size + Elf64_Half e_phnum; //!< This member holds the number of entries in the program header table + Elf64_Half e_shentsize; //!< This member holds a section header's size in bytes + Elf64_Half e_shnum; //!< This member holds the number of entries in the section header table + Elf64_Half e_shstrndx; //!< This member holds the section header table index of the entry associated with the section name string table +} Elf64_Ehdr; //!< 64bit Entry Header + +/* + * e_type + */ +#define ET_NONE 0 //!< No file type +#define ET_REL 1 //!< Relocatable file +#define ET_EXEC 2 //!< Executable file +#define ET_DYN 3 //!< Shared object file +#define ET_CORE 4 //!< Core file +#define ET_LOOS 0xfe00 //!< Operating system-specific +#define ET_HIOS 0xfeff //!< Operating system-specific +#define ET_LOPROC 0xff00 //!< Processor-specific +#define ET_HIPROC 0xffff //!< Processor-specific + +/* + * e_machine + */ +#define EM_NONE 0 //!< No machine +#define EM_M32 1 //!< AT&T WE 32100 +#define EM_SPARC 2 //!< SUN SPARC +#define EM_386 3 //!< Intel 80386 +#define EM_68K 4 //!< Motorola 68000 +#define EM_88K 5 //!< Motorola 88000 +#define EM_860 7 //!< Intel 80860 +#define EM_MIPS 8 //!< MIPS I architecture +#define EM_S370 9 //!< IBM System/370 +#define EM_MIPS_RS3_LE 10 //!< MIPS R3000 little-endian +#define EM_PARISC 15 //!< HPPA +#define EM_VPP500 17 //!< Fujitsu VPP500 +#define EM_SPARC32PLUS 18 //!< Enhanced instruction set SPARC +#define EM_960 19 //!< Intel 80960 +#define EM_PPC 20 //!< PowerPC +#define EM_PPC64 21 //!< 64-bit PowerPC +#define EM_S390 22 //!< IBM System/390 Processor +#define EM_V800 36 //!< NEC V800 +#define EM_FR20 37 //!< Fujitsu FR20 +#define EM_RH32 38 //!< TRW RH-32 +#define EM_RCE 39 //!< Motorola RCE +#define EM_ARM 40 //!< Advanced RISC Machines ARM +#define EM_FAKE_ALPHA 41 //!< Digital Alpha +#define EM_SH 42 //!< Hitachi SH +#define EM_SPARCV9 43 //!< SPARC Version 9 +#define EM_TRICORE 44 //!< Siemens TriCore embedded processor +#define EM_ARC 45 //!< Argonaut RISC Core, Argonaut Technologies Inc +#define EM_H8_300 46 //!< Hitachi H8/300 +#define EM_H8_300H 47 //!< Hitachi H8/300H +#define EM_H8S 48 //!< Hitachi H8S +#define EM_H8_500 49 //!< Hitachi H8/500 +#define EM_IA_64 50 //!< Intel IA-64 processor architecture +#define EM_MIPS_X 51 //!< Stanford MIPS-X +#define EM_COLDFIRE 52 //!< Motorola ColdFire +#define EM_68HC12 53 //!< Motorola M68HC12 +#define EM_MMA 54 //!< Fujitsu MMA Multimedia Accelerator +#define EM_PCP 55 //!< Siemens PCP +#define EM_NCPU 56 //!< Sony nCPU embedded RISC processor +#define EM_NDR1 57 //!< Denso NDR1 microprocessor +#define EM_STARCORE 58 //!< Motorola Start*Core processor +#define EM_ME16 59 //!< Toyota ME16 processor +#define EM_ST100 60 //!< STMicroelectronics ST100 processor +#define EM_TINYJ 61 //!< Advanced Logic Corp. TinyJ embedded processor family +#define EM_X86_64 62 //!< AMD x86-64 architecture +#define EM_PDSP 63 //!< Sony DSP Processor +#define EM_PDP10 64 //!< Digital Equipment Corp. PDP-10 +#define EM_PDP11 65 //!< Digital Equipment Corp. PDP-11 +#define EM_FX66 66 //!< Siemens FX66 microcontroller +#define EM_ST9PLUS 67 //!< STMicroelectronics ST9+ 8/16 bit microcontroller +#define EM_ST7 68 //!< STMicroelectronics ST7 8-bit microcontroller +#define EM_68HC16 69 //!< Motorola MC68HC16 Microcontroller +#define EM_68HC11 70 //!< Motorola MC68HC11 Microcontroller +#define EM_68HC08 71 //!< Motorola MC68HC08 Microcontroller +#define EM_68HC05 72 //!< Motorola MC68HC05 Microcontroller +#define EM_SVX 73 //!< Silicon Graphics SVx +#define EM_ST19 74 //!< STMicroelectronics ST19 8-bit microcontroller +#define EM_VAX 75 //!< Digital VAX +#define EM_CRIS 76 //!< Axis Communications 32-bit embedded processor +#define EM_JAVELIN 77 //!< Infifineon Technologies 32-bit embedded processor +#define EM_FIREPATH 78 //!< Element 14 64-bit DSP Processor +#define EM_ZSP 79 //!< LSI Logic 16-bit DSP Processor +#define EM_MMIX 80 //!< Donald Knuth's educational 64-bit processor +#define EM_HUANY 81 //!< Harvard University machine-independent object files +#define EM_PRISM 82 //!< SiTera Prism +#define EM_AVR 83 //!< Atmel AVR 8-bit microcontroller +#define EM_FR30 84 //!< Fujitsu FR30 +#define EM_D10V 85 //!< Mitsubishi D10V +#define EM_D30V 86 //!< Mitsubishi D30V +#define EM_V850 87 //!< NEC v850 +#define EM_M32R 88 //!< Mitsubishi M32R +#define EM_MN10300 89 //!< Matsushita MN10300 +#define EM_MN10200 90 //!< Matsushita MN10200 +#define EM_PJ 91 //!< picoJava +#define EM_OPENRISC 92 //!< OpenRISC 32-bit embedded processor +#define EM_ARC_A5 93 //!< ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5) +#define EM_XTENSA 94 //!< Tensilica Xtensa Architecture +#define EM_VIDEOCORE 95 //!< Alphamosaic VideoCore processor +#define EM_TMM_GPP 96 //!< Thompson Multimedia General Purpose Processor +#define EM_NS32K 97 //!< National Semiconductor 32000 series +#define EM_TPC 98 //!< Tenor Network TPC processor +#define EM_SNP1K 99 //!< Trebia SNP 1000 processor +#define EM_ST200 100 //!< STMicroelectronics (www.st.com) ST200 microcontroller +#define EM_IP2K 101 //!< Ubicom IP2xxx microcontroller family +#define EM_MAX 102 //!< MAX Processor +#define EM_CR 103 //!< National Semiconductor CompactRISC microprocessor +#define EM_F2MC16 104 //!< Fujitsu F2MC16 +#define EM_MSP430 105 //!< Texaxas Instruments embedded microcontroller msp430 +#define EM_BLACKFIN 106 //!< Analog Devices Blackfin (DSP) processor +#define EM_SE_C33 107 //!< S1C33 Family of Seiko Epspson processors +#define EM_SEP 108 //!< Sharp embedded microprocessor +#define EM_ARCA 109 //!< Arca RISC Microprocessor +#define EM_UNICORE 110 //!< Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University +#define EM_EXCESS 111 //!< eXcess: 16/32/64-bit configurable embedded CPU +#define EM_DXP 112 //!< Icera Semiconductor Inc. Deep Execution Processor +#define EM_ALTERA_NIOS2 113 //!< Altera Nios II soft-core processor +#define EM_CRX 114 //!< National Semiconductor CompactRISC CRX microprocessor +#define EM_XGATE 115 //!< Motorola XGATE embedded processor +#define EM_C166 116 //!< Infifineon C16x/XC16x processor +#define EM_M16C 117 //!< Renesas M16C series microprocessors +#define EM_DSPIC30F 118 //!< Microchip Technology dsPIC30F Digital Signal Controller +#define EM_CE 119 //!< Freescale Communication Engine RISC core +#define EM_M32C 120 //!< Renesas M32C series microprocessors +#define EM_TSK3000 131 //!< Altium TSK3000 core +#define EM_RS08 132 //!< Freescale RS08 embedded processor +#define EM_ECOG2 134 //!< Cyan Technology eCOG2 microprocessor +#define EM_SCORE7 135 //!< Sunplus S+core7 RISC processor +#define EM_DSP24 136 //!< New Japan Radio (NJR) 24-bit DSP Processor +#define EM_VIDEOCORE3 137 //!< Broadcom VideoCore III processor +#define EM_LATTICEMICO32 138 //!< RISC processor for Lattice FPGA architecture +#define EM_SE_C17 139 //!< Seiko Epspson C17 family +#define EM_TI_C6000 140 //!< The Texaxas Instruments TMS320C6000 DSP family +#define EM_TI_C2000 141 //!< The Texaxas Instruments TMS320C2000 DSP family +#define EM_TI_C5500 142 //!< The Texaxas Instruments TMS320C55x DSP family +#define EM_MMDSP_PLUS 160 //!< STMicroelectronics 64bit VLIW Data Signal Processor +#define EM_CYPRESS_M8C 161 //!< Cypress M8C microprocessor +#define EM_R32C 162 //!< Renesas R32C series microprocessors +#define EM_TRIMEDIA 163 //!< NXP Semiconductors TriMedia architecture family +#define EM_QDSP6 164 //!< QUALCOMM DSP6 Processor +#define EM_8051 165 //!< Intel 8051 and variants +#define EM_STXP7X 166 //!< STMicroelectronics STxP7x family of configurable and extensible RISC processors +#define EM_NDS32 167 //!< Andes Technology compact code size embedded RISC processor family +#define EM_ECOG1 168 //!< Cyan Technology eCOG1X family +#define EM_ECOG1X 168 //!< Cyan Technology eCOG1X family +#define EM_MAXQ30 169 //!< Dallas Semiconductor MAXQ30 Core Micro-controllers +#define EM_XIMO16 170 //!< New Japan Radio (NJR) 16-bit DSP Processor +#define EM_MANIK 171 //!< M2000 Reconfigurable RISC Microprocessor +#define EM_CRAYNV2 172 //!< Cray Inc. NV2 vector architecture +#define EM_RX 173 //!< Renesas RX family +#define EM_METAG 174 //!< Imagination Technologies META processor architecture +#define EM_MCST_ELBRUS 175 //!< MCST Elbrus general purpose hardware architecture +#define EM_ECOG16 176 //!< Cyan Technology eCOG16 family +#define EM_CR16 177 //!< National Semiconductor CompactRISC CR16 16-bit microprocessor +#define EM_ETPU 178 //!< Freescale Extended Time Processing Unit +#define EM_SLE9X 179 //!< Infifineon Technologies SLE9X core +#define EM_AVR32 185 //!< Atmel Corporation 32-bit microprocessor family +#define EM_STM8 186 //!< STMicroeletronics STM8 8-bit microcontroller +#define EM_TILE64 187 //!< Tilera TILE64 multicore architecture family +#define EM_TILEPRO 188 //!< Tilera TILEPro multicore architecture family +#define EM_MICROBLAZE 189 //!< Xilinx MicroBlaze 32-bit RISC soft processor core +#define EM_CUDA 190 //!< NVIDIA CUDA architecture +#define EM_TILEGX 191 //!< Tilera TILE-Gx multicore architecture family + +/* + * e_version (version) + */ +#define EV_NONE 0 //!< Invalid version +#define EV_CURRENT 1 //!< Current version + + +/********************************************* + * Section + *********************************************/ +typedef struct +{ + Elf32_Word sh_name; //!< This member specifies the name of the section + Elf32_Word sh_type; //!< This member categorizes the section's contents and semantics + Elf32_Word sh_flags; //!< Sections support 1-bit flags that describe miscellaneous attributes + Elf32_Addr sh_addr; //!< If the section will appear in the memory image of a process, this member gives the address at which the section's first byte should reside + Elf32_Off sh_offset; //!< This member's value gives the byte offset from the beginning of the file to the first byte in the section + Elf32_Word sh_size; //!< This member gives the section's size in bytes + Elf32_Word sh_link; //!< This member holds a section header table index link, whose interpretation depends on the section type + Elf32_Word sh_info; //!< This member holds extra information, whose interpretation depends on the section type + Elf32_Word sh_addralign; //!< Some sections have address alignment constraints + Elf32_Word sh_entsize; //!< Some sections hold a table of fixed-size entries, such as a symbol table +} Elf32_Shdr; //!< 32bit Section header + +typedef struct +{ + Elf64_Word sh_name; //!< This member specifies the name of the section + Elf64_Word sh_type; //!< This member categorizes the section's contents and semantics + Elf64_Xword sh_flags; //!< Sections support 1-bit flags that describe miscellaneous attributes + Elf64_Addr sh_addr; //!< If the section will appear in the memory image of a process, this member gives the address at which the section's first byte should reside + Elf64_Off sh_offset; //!< This member's value gives the byte offset from the beginning of the file to the first byte in the section + Elf64_Xword sh_size; //!< This member gives the section's size in bytes + Elf64_Word sh_link; //!< This member holds a section header table index link, whose interpretation depends on the section type + Elf64_Word sh_info; //!< This member holds extra information, whose interpretation depends on the section type + Elf64_Xword sh_addralign; //!< Some sections have address alignment constraints + Elf64_Xword sh_entsize; //!< Some sections hold a table of fixed-size entries, such as a symbol table +} Elf64_Shdr; //!< 64bit Section header + +/* + * Special Section Indexes + */ +#define SHN_UNDEF 0 //!< This value marks an undefined, missing, irrelevant, or otherwise meaningless section reference +#define SHN_LORESERVE 0xff00 //!< This value specifies the lower bound of the range of reserved indexes +#define SHN_LOPROC 0xff00 //!< Values in this inclusive range are reserved for processor-specific semantics +#define SHN_HIPROC 0xff1f //!< Values in this inclusive range are reserved for processor-specific semantics +#define SHN_LOOS 0xff20 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define SHN_HIOS 0xff3f //!< Values in this inclusive range are reserved for operating system-specific semantics +#define SHN_ABS 0xfff1 //!< This value specifies absolute values for the corresponding reference +#define SHN_COMMON 0xfff2 //!< Symbols defined relative to this section are common symbols +#define SHN_XINDEX 0xffff //!< This value is an escape value +#define SHN_HIRESERVE 0xffff //!< This value specifies the upper bound of the range of reserved indexes + +/* + * sh_type + */ +#define SHT_NULL 0 //!< This value marks the section header as inactive +#define SHT_PROGBITS 1 //!< The section holds information defined by the program +#define SHT_SYMTAB 2 //!< These sections hold a symbol table +#define SHT_STRTAB 3 //!< The section holds a string table +#define SHT_RELA 4 //!< The section holds relocation entries with explicit addends, such as type Elf32_Rela for the 32-bit class of object files or type Elf64_Rela for the 64-bit class of object files +#define SHT_HASH 5 //!< The section holds a symbol hash table +#define SHT_DYNAMIC 6 //!< The section holds information for dynamic linking +#define SHT_NOTE 7 //!< The section holds information that marks the file in some way +#define SHT_NOBITS 8 //!< A section of this type occupies no space in the file but otherwise resembles SHT_PROGBITS +#define SHT_REL 9 //!< The section holds relocation entries without explicit addends, such as type Elf32_Rel for the 32-bit class of object files or type Elf64_Rel for the 64-bit class of object files +#define SHT_SHLIB 10 //!< This section type is reserved but has unspecified semantics +#define SHT_DYNSYM 11 //!< +#define SHT_INIT_ARRAY 14 //!< This section contains an array of pointers to initialization functions +#define SHT_FINI_ARRAY 15 //!< This section contains an array of pointers to termination functions +#define SHT_PREINIT_ARRAY 16 //!< This section contains an array of pointers to functions that are invoked before all other initialization functions +#define SHT_GROUP 17 //!< This section defines a section group +#define SHT_SYMTAB_SHNDX 18 //!< This section is associated with a section of type SHT_SYMTAB and is required if any of the section header indexes referenced by that symbol table contain the escape value SHN_XINDEX +#define SHT_LOOS 0x60000000 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define SHT_HIOS 0x6fffffff //!< Values in this inclusive range are reserved for operating system-specific semantics +#define SHT_LOPROC 0x70000000 //!< Values in this inclusive range are reserved for processor-specific semantics +#define SHT_HIPROC 0x7fffffff //!< Values in this inclusive range are reserved for processor-specific semantics +#define SHT_LOUSER 0x80000000 //!< This value specifies the upper bound of the range of indexes reserved for application programs +#define SHT_HIUSER 0x8fffffff //!< This value specifies the upper bound of the range of indexes reserved for application programs + +/* + * sh_flags + */ +#define SHF_WRITE 0x1 //!< The section contains data that should be writable during process execution +#define SHF_ALLOC 0x2 //!< The section occupies memory during process execution +#define SHF_EXECINSTR 0x4 //!< The section contains executable machine instructions +#define SHF_MERGE 0x10 //!< The data in the section may be merged to eliminate duplication +#define SHF_STRINGS 0x20 //!< The data elements in the section consist of null-terminated character strings +#define SHF_INFO_LINK 0x40 //!< The sh_info field of this section header holds a section header table index +#define SHF_LINK_ORDER 0x80 //!< This flag adds special ordering requirements for link editors +#define SHF_OS_NONCONFORMING 0x100 //!< This section requires special OS-specific processing (beyond the standard linking rules) to avoid incorrect behavior +#define SHF_GROUP 0x200 //!< This section is a member (perhaps the only one) of a section group +#define SHF_TLS 0x400 //!< This section holds Thread-Local Storage, meaning that each separate execution flow has its own distinct instance of this data +#define SHF_MASKOS 0x0ff00000 //!< All bits included in this mask are reserved for operating system-specific semantics +#define SHF_MASKPROC 0xf0000000 //!< All bits included in this mask are reserved for processor-specific semantics + + +/********************************************* + * Symbol + *********************************************/ +typedef struct +{ + Elf32_Word st_name; //!< This member holds an index into the object file's symbol string table, which holds the character representations of the symbol names + Elf32_Addr st_value; //!< This member gives the value of the associated symbol + Elf32_Word st_size; //!< Many symbols have associated sizes + unsigned char st_info; //!< This member specifies the symbol's type and binding attributes + unsigned char st_other; //!< This member currently specifies a symbol's visibility + Elf32_Section st_shndx; //!< Every symbol table entry is defined in relation to some section +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; //!< This member holds an index into the object file's symbol string table, which holds the character representations of the symbol names + unsigned char st_info; //!< This member specifies the symbol's type and binding attributes + unsigned char st_other; //!< This member currently specifies a symbol's visibility + Elf64_Section st_shndx; //!< Every symbol table entry is defined in relation to some section + Elf64_Addr st_value; //!< This member gives the value of the associated symbol + Elf64_Xword st_size; //!< Many symbols have associated sizes +} Elf64_Sym; + +/* + * st_info + */ +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#define ELF64_ST_BIND(i) ((i)>>4) +#define ELF64_ST_TYPE(i) ((i)&0xf) +#define ELF64_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + + +/* st_info (symbol binding) */ +#define STB_LOCAL 0 //!< Local symbols are not visible outside the object file containing their definition +#define STB_GLOBAL 1 //!< Global symbols are visible to all object files being combined +#define STB_WEAK 2 //!< Weak symbols resemble global symbols, but their definitions have lower precedence +#define STB_LOOS 10 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define STB_HIOS 12 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define STB_LOPROC 13 //!< Values in this inclusive range are reserved for processor-specific semantics +#define STB_HIPROC 15 //!< Values in this inclusive range are reserved for processor-specific semantics + +/* st_info (symbol type) */ +#define STT_NOTYPE 0 //!< The symbol's type is not specified +#define STT_OBJECT 1 //!< The symbol is associated with a data object, such as a variable, an array, and so on +#define STT_FUNC 2 //!< The symbol is associated with a function or other executable code +#define STT_SECTION 3 //!< The symbol is associated with a section +#define STT_FILE 4 //!< Conventionally, the symbol's name gives the name of the source file associated with the object file +#define STT_COMMON 5 //!< The symbol labels an uninitialized common block +#define STT_TLS 6 //!< The symbol specifies a Thread-Local Storage entity +#define STT_LOOS 10 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define STT_HIOS 12 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define STT_LOPROC 13 //!< Values in this inclusive range are reserved for processor-specific semantics +#define STT_HIPROC 15 //!< Values in this inclusive range are reserved for processor-specific semantics + +/* + * st_other + */ +#define ELF32_ST_VISIBILITY(o) ((o)&0x3) +#define ELF64_ST_VISIBILITY(o) ((o)&0x3) + + +#define STV_DEFAULT 0 //!< The visibility of symbols with the STV_DEFAULT attribute is as specified by the symbol's binding type +#define STV_INTERNAL 1 //!< A symbol defined in the current component is protected if it is visible in other components but not preemptable, meaning that any reference to such a symbol from within the defining component must be resolved to the definition in that component, even if there is a definition in another component that would preempt by the default rules +#define STV_HIDDEN 2 //!< A symbol defined in the current component is hidden if its name is not visible to other components +#define STV_PROTECTED 3 //!< The meaning of this visibility attribute may be defined by processor supplements to further constrain hidden symbols + + +/********************************************* + * Relocation + *********************************************/ +typedef struct +{ + Elf32_Addr r_offset; //!< This member gives the location at which to apply the relocation action + Elf32_Word r_info; //!< This member gives both the symbol table index with respect to which the relocation must be made, and the type of relocation to apply +} Elf32_Rel; //!< 32bits Relocation Entries + +typedef struct +{ + Elf64_Addr r_offset; //!< This member gives the location at which to apply the relocation action + Elf64_Xword r_info; //!< This member gives both the symbol table index with respect to which the relocation must be made, and the type of relocation to apply +} Elf64_Rel; //!< 32bits Relocation Entries + +typedef struct +{ + Elf32_Addr r_offset; //!< This member gives the location at which to apply the relocation action + Elf32_Word r_info; //!< This member gives both the symbol table index with respect to which the relocation must be made, and the type of relocation to apply + Elf32_Sword r_addend; //!< This member specifies a constant addend used to compute the value to be stored into the relocatable field +} Elf32_Rela; //!< 32bits Relocation Addend Entries + +typedef struct +{ + Elf64_Addr r_offset; //!< This member gives the location at which to apply the relocation action + Elf64_Xword r_info; //!< This member gives both the symbol table index with respect to which the relocation must be made, and the type of relocation to apply + Elf64_Sxword r_addend; //!< This member specifies a constant addend used to compute the value to be stored into the relocatable field +} Elf64_Rela; //!< 32bits Relocation Addend Entries + + +/* + * r_info + */ +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) (((s)<<32)+((t)&0xffffffffL)) + + + +/********************************************* + * Program + *********************************************/ +typedef struct +{ + Elf32_Word p_type; //!< This member tells what kind of segment this array element describes or how to interpret the array element's information + Elf32_Off p_offset; //!< This member gives the offset from the beginning of the file at which the first byte of the segment resides + Elf32_Addr p_vaddr; //!< This member gives the virtual address at which the first byte of the segment resides in memory + Elf32_Addr p_paddr; //!< On systems for which physical addressing is relevant, this member is reserved for the segment's physical address + Elf32_Word p_filesz; //!< This member gives the number of bytes in the file image of the segment; it may be zero + Elf32_Word p_memsz; //!< This member gives the number of bytes in the memory image of the segment; it may be zero + Elf32_Word p_flags; //!< This member gives flags relevant to the segment + Elf32_Word p_align; //!< As ``Program Loading'' describes in this chapter of the processor supplement, loadable process segments must have congruent values for p_vaddr and p_offset, modulo the page size +} Elf32_Phdr; //!< 32bits Program header + +typedef struct +{ + Elf64_Word p_type; //!< This member tells what kind of segment this array element describes or how to interpret the array element's information + Elf64_Word p_flags; //!< This member gives flags relevant to the segment + Elf64_Off p_offset; //!< This member gives the offset from the beginning of the file at which the first byte of the segment resides + Elf64_Addr p_vaddr; //!< This member gives the virtual address at which the first byte of the segment resides in memory + Elf64_Addr p_paddr; //!< On systems for which physical addressing is relevant, this member is reserved for the segment's physical address + Elf64_Xword p_filesz; //!< This member gives the number of bytes in the file image of the segment; it may be zero + Elf64_Xword p_memsz; //!< This member gives the number of bytes in the memory image of the segment; it may be zero + Elf64_Xword p_align; //!< As ``Program Loading'' describes in this chapter of the processor supplement, loadable process segments must have congruent values for p_vaddr and p_offset, modulo the page size +} Elf64_Phdr; //!< 64bits Program header + +/* + * p_type + */ +#define PT_NULL 0 //!< The array element is unused; other members' values are undefined +#define PT_LOAD 1 //!< The array element specifies a loadable segment, described by p_filesz and p_memsz +#define PT_DYNAMIC 2 //!< The array element specifies dynamic linking information +#define PT_INTERP 3 //!< The array element specifies the location and size of a null-terminated path name to invoke as an interpreter +#define PT_NOTE 4 //!< The array element specifies the location and size of auxiliary information +#define PT_SHLIB 5 //!< This segment type is reserved but has unspecified semantics +#define PT_PHDR 6 //!< The array element, if present, specifies the location and size of the program header table itself, both in the file and in the memory image of the program +#define PT_TLS 7 //!< The array element specifies the Thread-Local Storage template +#define PT_LOOS 0x60000000 //!< Values in this inclusive range are reserved for operating system-specific semantics +#define PT_HIOS 0x6fffffff //!< Values in this inclusive range are reserved for operating system-specific semantics +#define PT_LOPROC 0x70000000 //!< Values in this inclusive range are reserved for processor-specific semantics +#define PT_HIPROC 0x7fffffff //!< Values in this inclusive range are reserved for processor-specific semantics + +/* + * p_flags + */ +#define PF_X (1 << 0) //!< Execute +#define PF_W (1 << 1) //!< Write +#define PF_R (1 << 2) //!< Read +#define PF_MASKOS 0x0ff00000 //!< Unspecified +#define PF_MASKPROC 0xf0000000 //!< Unspecified + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/elfapi.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/elfapi.h new file mode 100644 index 00000000000..564086db26c --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/elfapi.h @@ -0,0 +1,123 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf loder internal methods. + * + * \defgroup ELFLOADER MMDSP ELF loader. + */ +#ifndef __INC_CM_ELFLOADER_H +#define __INC_CM_ELFLOADER_H + +#include <cm/engine/elf/inc/common.h> + +/*! + * \internal + * \brief ELF Parsing & checking + * \ingroup ELFLOADER + */ +t_cm_error cm_ELF_CheckFile( + const char *elfdata, + t_bool temporaryDescription, + t_elfdescription **elfhandlePtr); + +void cm_ELF_ReleaseDescription( + t_uint32 requireNumber, t_interface_require *requires, + t_uint32 attributeNumber, t_attribute *attributes, + t_uint32 propertyNumber, t_property *properties, + t_uint32 provideNumber, t_interface_provide *provides); + +/*! + * \internal + * \brief ELF closing + * \ingroup ELFLOADER + */ +void cm_ELF_CloseFile( + t_bool temporaryDescription, + t_elfdescription *elfhandle); + +/*! + * \internal + * \brief Load a component template shared memories. + * + * \note In case of error, part of memory could have been allocated and must be free by calling cm_DSPABI_FreeTemplate. + */ +t_cm_error cm_ELF_LoadTemplate( + t_cm_domain_id domainId, + t_elfdescription *elfhandle, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]); + +/*! + * \internal + * \brief Clean cache memory of a component template shared code. + */ +void cm_ELF_FlushTemplate( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]); + +void cm_ELF_FlushInstance( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]); + +/*! + * \internal + * \brief Load a component instance private memories. + * + * \note In case of error, part of memory could have been allocated and must be free by calling cm_DSPABI_FreeInstance. + */ +t_cm_error cm_ELF_LoadInstance( + t_cm_domain_id domainId, + t_elfdescription *elfhandle, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]); + +void cm_ELF_FreeInstance( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]); +void cm_ELF_FreeTemplate( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]); + + +t_cm_error cm_ELF_relocateSharedSegments( + t_memory_handle *memories, + t_elfdescription *elfhandle, + void *cbContext); +t_cm_error cm_ELF_relocatePrivateSegments( + t_memory_handle *memories, + t_elfdescription *elfhandle, + void *cbContext); +void cm_ELF_performRelocation( + t_uint32 type, + const char *symbol_name, + t_uint32 symbol_addr, + char *reloc_addr); +t_cm_error cm_ELF_GetMemory( + t_elfdescription *elf, + t_tmp_elfdescription *elftmp, + t_uint32 address, + t_memory_purpose purpose, + t_memory_reference *memory); + + +#include <cm/engine/component/inc/component_type.h> + +t_cm_error cm_DSPABI_AddLoadMap( + t_cm_domain_id domainId, + const char* templateName, + const char* localname, + t_memory_handle *memories, + void *componentHandle); +t_cm_error cm_DSPABI_RemoveLoadMap( + t_cm_domain_id domainId, + const char* templateName, + t_memory_handle *memories, + const char* localname, + void *componentHandle); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/memory.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/memory.h new file mode 100644 index 00000000000..9eab94f173c --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/memory.h @@ -0,0 +1,77 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf memory. + */ +#ifndef __INC_CM_ELF_MEMORY_H +#define __INC_CM_ELF_MEMORY_H + +#include <cm/engine/dsp/inc/dsp.h> + +/** + * \brief Memory identifier + */ +typedef t_uint8 t_memory_id; + +/** + * \brief Memory property + */ +typedef enum { + MEM_FOR_MULTIINSTANCE, + MEM_FOR_SINGLETON, + MEM_FOR_LAST +} t_instance_property; + +/** + * \brief Memory prupose (for processor with different address space for code and data/ + */ +typedef enum { + MEM_CODE, + MEM_DATA +} t_memory_purpose; + +/** + * \brief Memory property + */ +typedef enum { + MEM_PRIVATE, + MEM_SHARABLE, +} t_memory_property; + +/** + * \brief Elf memory mapping description + */ +typedef struct +{ + t_memory_id id; + t_dsp_memory_type_id dspMemType; + t_uint32 startAddr; + t_cm_memory_alignment memAlignement; + t_memory_property property; + t_memory_purpose purpose; + t_uint8 fileEntSize; + t_uint8 memEntSize; + char* memoryName; +} t_elfmemory; + +#define NUMBER_OF_MMDSP_MEMORY 15 + +/* + * \brief Elf segment description + */ +typedef struct { + // Data in Bytes + t_uint32 sumSize; + t_bool sumSizeSetted; + t_cm_logical_address hostAddr; // Valid only if section Load in memory + t_uint32 maxAlign; + // Data in word + t_uint32 mpcAddr; // Valid only if section Load in memory +} t_elfSegment; + + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp-loadmap.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp-loadmap.h new file mode 100644 index 00000000000..78b00388802 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp-loadmap.h @@ -0,0 +1,49 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf writer internal methods. + * + * \defgroup LOADMAP MMDSP ELF writer (a linker in fact). + */ +#ifndef __INC_CM_LOADMAP_H +#define __INC_CM_LOADMAP_H + +#include <cm/inc/cm_type.h> + +/* + * Align with loadmap : + * https://codex.cro.st.com/wiki/index.php?pagename=Specification%2FLoadmap%2Fv1.2&group_id=310 + */ +#define LOADMAP_MAGIC_NUMBER 0xFBBF + +#define LOADMAP_VERSION_MSB 1 +#define LOADMAP_VERSION_LSB 2 + +struct LoadMapItem +{ + const char* pSolibFilename; // Filename of shared library object + void* pAddrProg; // Load address of program section + void* pAddrEmbProg; // Load address of embedded program section + void* pThis; // Data base address of component instance + void* pARMThis; // ARM component debug ID + const char* pComponentName; // Pretty name of the component instance, NULL if none. + struct LoadMapItem* pNextItem;// Pointer on the next list item, NULL if last one. + void* pXROM; // Start address of XROM + void* pYROM; // Start address of YROM + + void* memHandle; // handle of allocated memory for this structure and name, local field not use by mmdsp +}; + +struct LoadMapHdr +{ + t_uint16 nMagicNumber; // Equal to 0xFBBF. + t_uint16 nVersion; // The version of the load map format. + t_uint32 nRevision; // A counter incremented at each load map list modification. + struct LoadMapItem* pFirstItem;// Pointer on the first item, NULL if no shared library loaded. +}; + +#endif /* __INC_CM_LOADMAP_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp.h new file mode 100644 index 00000000000..1662def6c1a --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/mmdsp.h @@ -0,0 +1,31 @@ +/* + * 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. + */ +/*! + * \internal + * \brief MMDSP elf. + */ +#ifndef __INC_CM_ELF_MMDSP_H +#define __INC_CM_ELF_MMDSP_H + +#include <cm/engine/elf/inc/common.h> + +#define CODE_MEMORY_INDEX 0 +#define ECODE_MEMORY_INDEX 7 + +#define XROM_MEMORY_INDEX 1 +#define YROM_MEMORY_INDEX 2 +#define PRIVATE_DATA_MEMORY_INDEX 8 +#define SHARE_DATA_MEMORY_INDEX 1 + +/* + * Relocation + */ +#define R_MMDSP_IMM16 5 +#define R_MMDSP_IMM20_16 6 +#define R_MMDSP_IMM20_4 7 +#define R_MMDSP_24 13 + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/mpcal.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/mpcal.h new file mode 100644 index 00000000000..718b7f61ceb --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/mpcal.h @@ -0,0 +1,20 @@ +/* + * 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. + */ +/*! + * \internal + * \brief MPC Abraction Layer. + * + * \defgroup MPCAL MPC Abraction Layer. + */ +#ifndef __INC_CM_DSP_MPCAL_H +#define __INC_CM_DSP_MPCAL_H + +#include <cm/inc/cm_type.h> +#include <share/inc/nmf.h> + +#include <cm/engine/elf/inc/common.h> + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/inc/reloc.h b/drivers/staging/nmf-cm/cm/engine/elf/inc/reloc.h new file mode 100644 index 00000000000..b38be48d689 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/inc/reloc.h @@ -0,0 +1,35 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Elf relocation. + */ +#ifndef __INC_CM_ELF_RELOC_H +#define __INC_CM_ELF_RELOC_H + + +void MMDSP_performRelocation( + t_uint32 type, + const char* symbol_name, + t_uint32 symbol_addr, + char* reloc_addr, + const char* inPlaceAddr, + t_uint32 reloc_offset); + +/* + * + * Return: + * 0x0 returned if symbol not found + * 0xFFFFFFFE returned if out of memory + * 0xFFFFFFFF returned if symbol found in static required binding + */ +typedef t_uint32 (*CBresolvSymbol)( + void* context, + t_uint32 type, + const char* symbolName, + char* reloc_addr); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/elf64.c b/drivers/staging/nmf-cm/cm/engine/elf/src/elf64.c new file mode 100644 index 00000000000..2e0f5928ffd --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/elf64.c @@ -0,0 +1,47 @@ +/* + * 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/elf/inc/common.h> +#include <cm/engine/elf/inc/elfabi.h> + +#include <cm/engine/utils/inc/swap.h> +#include <cm/engine/trace/inc/trace.h> + +typedef Elf64_Half ElfXX_Half; +typedef Elf64_Word ElfXX_Word; +typedef Elf64_Addr ElfXX_Addr; +typedef Elf64_Off ElfXX_Off; + +typedef Elf64_Xword ElfXX_Xword; + +typedef Elf64_Ehdr ElfXX_Ehdr; +typedef Elf64_Shdr ElfXX_Shdr; +typedef Elf64_Sym ElfXX_Sym; +typedef Elf64_Rela ElfXX_Rela; + +#undef ELFXX_R_SYM +#define ELFXX_R_SYM ELF64_R_SYM +#undef ELFXX_R_TYPE +#define ELFXX_R_TYPE ELF64_R_TYPE +#undef ELFXX_R_INFO +#define ELFXX_R_INFO ELF64_R_INFO + +// TODO Here we assume big endian (MMDSP !) +static Elf64_Half swapHalf(Elf64_Half half) +{ + return (Elf64_Half)swap16(half); +} + +static Elf64_Word swapWord(Elf64_Word word) +{ + return (Elf64_Word)swap32(word); +} + +static Elf64_Xword swapXword(Elf64_Xword xword) +{ + return (Elf64_Xword)swap64(xword); +} + +#include "elfxx.c" diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/elfload.c b/drivers/staging/nmf-cm/cm/engine/elf/src/elfload.c new file mode 100644 index 00000000000..2efe6edbf69 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/elfload.c @@ -0,0 +1,749 @@ +/* + * 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/elf/inc/elfapi.h> +#include <cm/engine/elf/inc/mpcal.h> +#include <cm/inc/cm_def.h> + +//#include <cm/engine/component/inc/introspection.h> + +#include <cm/engine/utils/inc/mem.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/swap.h> +#include <cm/engine/utils/inc/string.h> + +static void* getElfHeaderReference(t_tmp_elfdescription *elftmp, void* hdrref) +{ + if(hdrref != NULL) + return (void*)((int)swap32((t_uint32)hdrref) + (int)elftmp->elfheader); + else + return NULL; +} + +static t_dup_char copyElfString(t_tmp_elfdescription *elftmp, char* idx) +{ + return cm_StringDuplicate((char*)getElfHeaderReference(elftmp, (void*)idx)); +} + +static t_cm_error getMemoryOffset( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp, + t_memory_purpose purpose, + const t_uint32 *addressInNmf, + t_memory_reference *memory) { + + if(elftmp->isExecutable) { + return cm_ELF_GetMemory(elfhandle, elftmp, + swap32(*addressInNmf), + purpose, + memory); + } else { + return ELF64_getRelocationMemory(elfhandle, elftmp, + (t_uint32)addressInNmf - (t_uint32)elftmp->elfheader, + memory); + } +} + +static t_cm_error getAdressForExecutableOffsetElsewhere( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp, + const t_uint32 *addressInNmf, + t_memory_reference *memory) { + t_uint32 address; + + address = swap32(*addressInNmf); + if(address == 0xFFFFFFFF) + { + memory->offset = 0x0; + memory->memory = NULL; + return CM_OK; + } + + if(elftmp->isExecutable) + { + memory->offset = address; + memory->memory = NULL; + return CM_OK; + } + + // Error log in elfhandle by previous call will be check in loadTemplate + return ELF64_getRelocationMemory(elfhandle, elftmp, + (t_uint32)addressInNmf - (t_uint32)elftmp->elfheader, + memory); +} + +/* + * Interface Management + */ +static t_interface_description* interfaceList = NULL; + +static t_interface_description* getInterfaceDescription(t_tmp_elfdescription *elftmp, t_elf_interface_description* elfitf) { + t_dup_char itfType; + t_interface_description* itf; + int i; + + itfType = copyElfString(elftmp, elfitf->type); + if(itfType == NULL) + return NULL; + + // Search if interfane already loaded + for(itf = interfaceList; itf != NULL; itf = itf->next) { + if(itf->type == itfType) { + // TODO Sanity check + + itf->referenceCounter++; + cm_StringRelease(itfType); + return itf; + } + } + + // Create a new interface if not exists + itf = (t_interface_description*)OSAL_Alloc_Zero(sizeof(t_interface_description) + sizeof(char*) * (elfitf->methodNumber /*- 1*/)); + if(itf == NULL) + goto out_itf_type; + itf->referenceCounter = 1; + itf->type = itfType; + itf->methodNumber = elfitf->methodNumber; + for(i = 0; i < itf->methodNumber; i++) { + itf->methodNames[i] = copyElfString(elftmp, elfitf->methodNames[i]); + if(itf->methodNames[i] == NULL) + goto out_method; + } + + // Put it in Top + itf->next = interfaceList; + interfaceList = itf; + + return itf; + +out_method: + for(i = 0; i < itf->methodNumber; i++) + cm_StringRelease(itf->methodNames[i]); + OSAL_Free(itf); +out_itf_type: + cm_StringRelease(itfType); + return NULL; +} + +static void releaseInterfaceDescription(t_interface_description* itf) { + if(itf == NULL) + return; + + if(--itf->referenceCounter == 0) { + int i; + + // Remove it from list + if(interfaceList == itf) { + interfaceList = interfaceList->next; + } else { + t_interface_description* prev = interfaceList; + while(prev->next != itf) + prev = prev->next; + prev->next = itf->next; + } + + // Destroy interface description + for(i = 0; i < itf->methodNumber; i++) { + cm_StringRelease(itf->methodNames[i]); + } + cm_StringRelease(itf->type); + OSAL_Free(itf); + } +} + + +t_cm_error cm_ELF_CheckFile( + const char *elfdata, + t_bool temporaryDescription, + t_elfdescription **elfhandlePtr) +{ + t_elfdescription *elfhandle; + t_tmp_elfdescription elftmp; + t_cm_error error; + t_uint32 version; + t_uint32 compatibleVersion; + int i, j, k; + + /* + * Sanity check + */ + if (elfdata[EI_MAG0] != ELFMAG0 || + elfdata[EI_MAG1] != ELFMAG1 || + elfdata[EI_MAG2] != ELFMAG2 || + elfdata[EI_MAG3] != ELFMAG3 || + elfdata[EI_CLASS] != ELFCLASS64) + { + ERROR("CM_INVALID_ELF_FILE: component file is not a MMDSP ELF file\n", 0, 0, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } + + /* + * Create elf data + */ + if((error = ELF64_LoadComponent(EM_MMDSP_PLUS, elfdata, elfhandlePtr, &elftmp)) != CM_OK) + return error; + + elfhandle = *elfhandlePtr; + + elfhandle->temporaryDescription = temporaryDescription; + + version = swap32(elftmp.elfheader->nmfVersion); + + compatibleVersion = (VERSION_MAJOR(version) == VERSION_MAJOR(NMF_VERSION)); + if(compatibleVersion) + { + switch(VERSION_MINOR(NMF_VERSION)) + { + case 10: // Compatible with 2.9, 2.10 + compatibleVersion = + (VERSION_MINOR(version) == 9) || + (VERSION_MINOR(version) == 10); + break; + default: // Strict compatibility 2.x == 2.x + compatibleVersion = (VERSION_MINOR(version) == VERSION_MINOR(NMF_VERSION)); + } + } + + if(! compatibleVersion) + { + ERROR("CM_INVALID_ELF_FILE: incompatible version for Component %d.%d.x != CM:%d.%d.x\n", + VERSION_MAJOR(version), VERSION_MINOR(version), + VERSION_MAJOR(NMF_VERSION), VERSION_MINOR(NMF_VERSION), 0, 0); + error = CM_INVALID_ELF_FILE; + goto onerror; + } + + + /* + * Commented since to many noise !!!! + if(VERSION_PATCH(version) != VERSION_PATCH(NMF_VERSION)) + { + WARNING("CM_INVALID_ELF_FILE: incompatible version, Component:%d.%d.%d != CM:%d.%d.%d\n", + VERSION_MAJOR(version), VERSION_MINOR(version), VERSION_PATCH(version), + VERSION_MAJOR(NMF_VERSION), VERSION_MINOR(NMF_VERSION), VERSION_PATCH(NMF_VERSION)); + } + */ + + if((error = ELF64_ComputeSegment(elfhandle, &elftmp)) != CM_OK) + goto onerror; + + // + elfhandle->foundedTemplateName = copyElfString(&elftmp, elftmp.elfheader->templateName); + if(elfhandle->foundedTemplateName == NULL) + goto oom; + elfhandle->minStackSize = swap32(elftmp.elfheader->minStackSize); + + // Get Life-cycle memory + if((error = getAdressForExecutableOffsetElsewhere(elfhandle, &elftmp, &elftmp.elfheader->LCCConstruct, &elfhandle->memoryForConstruct)) != CM_OK) + goto onerror; + if((error = getAdressForExecutableOffsetElsewhere(elfhandle, &elftmp, &elftmp.elfheader->LCCStart, &elfhandle->memoryForStart)) != CM_OK) + goto onerror; + if((error = getAdressForExecutableOffsetElsewhere(elfhandle, &elftmp, &elftmp.elfheader->LCCStop, &elfhandle->memoryForStop)) != CM_OK) + goto onerror; + if((error = getAdressForExecutableOffsetElsewhere(elfhandle, &elftmp, &elftmp.elfheader->LCCDestroy, &elfhandle->memoryForDestroy)) != CM_OK) + goto onerror; + + // Copy attributes information + elfhandle->attributeNumber = swap32(elftmp.elfheader->attributeNumber); + if(elfhandle->attributeNumber > 0) + { + elfhandle->attributes = + (t_attribute*)OSAL_Alloc_Zero(sizeof(t_attribute) * elfhandle->attributeNumber); + if(elfhandle->attributes == NULL) + goto oom; + + if(elfhandle->attributeNumber > 0) + { + t_elf_attribute *attributes = (t_elf_attribute*)getElfHeaderReference(&elftmp, (void*)elftmp.elfheader->attributes); + + for(i = 0; i < elfhandle->attributeNumber; i++) + { + elfhandle->attributes[i].name = copyElfString(&elftmp, attributes[i].name); + if(elfhandle->attributes[i].name == NULL) + goto oom; + + if((error = getMemoryOffset(elfhandle, &elftmp, + MEM_DATA, + &attributes[i].symbols, + &elfhandle->attributes[i].memory)) != CM_OK) + goto onerror; + LOG_INTERNAL(2, " attribute %s mem=%s offset=%x\n", + elfhandle->attributes[i].name, + elfhandle->attributes[i].memory.memory->memoryName, + elfhandle->attributes[i].memory.offset, + 0, 0, 0); + } + } + } + + // Copy properties information + elfhandle->propertyNumber = swap32(elftmp.elfheader->propertyNumber); + if(elfhandle->propertyNumber > 0) + { + elfhandle->properties = + (t_property*)OSAL_Alloc_Zero(sizeof(t_property) * elfhandle->propertyNumber); + if(elfhandle->properties == NULL) + goto oom; + + if(elfhandle->propertyNumber > 0) + { + t_elf_property *properties = (t_elf_property*)getElfHeaderReference(&elftmp, (void*)elftmp.elfheader->properties); + + for(i = 0; i < elfhandle->propertyNumber; i++) + { + elfhandle->properties[i].name = copyElfString(&elftmp, properties[i].name); + if(elfhandle->properties[i].name == NULL) + goto oom; + + elfhandle->properties[i].value = copyElfString(&elftmp, properties[i].value); + if(elfhandle->properties[i].value == NULL) + goto oom; + + LOG_INTERNAL(3, " property %s = %s\n", + elfhandle->properties[i].name, + elfhandle->properties[i].value, + 0, 0, 0, 0); + } + } + } + + // Copy requires information + elfhandle->requireNumber = swap32(elftmp.elfheader->requireNumber); + if(elfhandle->requireNumber > 0) + { + char *ref = getElfHeaderReference(&elftmp, (void*)elftmp.elfheader->requires); + + elfhandle->requires = (t_interface_require*)OSAL_Alloc_Zero(sizeof(t_interface_require) * elfhandle->requireNumber); + if(elfhandle->requires == NULL) + goto oom; + + for(i = 0; i < elfhandle->requireNumber; i++) + { + t_elf_required_interface *require = (t_elf_required_interface*)ref; + t_elf_interface_description *interface = (t_elf_interface_description*)getElfHeaderReference(&elftmp, (void*)require->interface); + + elfhandle->requires[i].name = copyElfString(&elftmp, require->name); + if(elfhandle->requires[i].name == NULL) + goto oom; + + elfhandle->requires[i].requireTypes = require->requireTypes; + elfhandle->requires[i].collectionSize = require->collectionSize; + elfhandle->requires[i].interface = getInterfaceDescription(&elftmp, interface); + if(elfhandle->requires[i].interface == NULL) + goto oom; + + LOG_INTERNAL(2, " require %s <%s> %x\n", + elfhandle->requires[i].name, + elfhandle->requires[i].interface->type, + elfhandle->requires[i].requireTypes, 0, 0, 0); + CM_ASSERT(elfhandle->requires[i].collectionSize != 0); + + ref += sizeof(t_elf_required_interface); + + if((elfhandle->requires[i].requireTypes & VIRTUAL_REQUIRE) == 0 && + (elfhandle->requires[i].requireTypes & STATIC_REQUIRE) == 0) + { + elfhandle->requires[i].indexes = + (t_interface_require_index*)OSAL_Alloc_Zero(sizeof(t_interface_require_index) * elfhandle->requires[i].collectionSize); + if(elfhandle->requires[i].indexes == NULL) + goto oom; + + for(j = 0; j < elfhandle->requires[i].collectionSize; j++) + { + t_elf_interface_require_index* index = (t_elf_interface_require_index*)ref; + + elfhandle->requires[i].indexes[j].numberOfClient = swap32(index->numberOfClient); + if(elfhandle->requires[i].indexes[j].numberOfClient != 0) + { + elfhandle->requires[i].indexes[j].memories = + (t_memory_reference*)OSAL_Alloc(sizeof(t_memory_reference) * elfhandle->requires[i].indexes[j].numberOfClient); + if(elfhandle->requires[i].indexes[j].memories == NULL) + goto oom; + + for(k = 0; k < elfhandle->requires[i].indexes[j].numberOfClient; k++) { + if((error = getMemoryOffset(elfhandle,&elftmp, + MEM_DATA, + &index->symbols[k], + &elfhandle->requires[i].indexes[j].memories[k])) != CM_OK) + goto onerror; + LOG_INTERNAL(2, " [%d, %d] mem=%s offset=%x\n", + j, k, + elfhandle->requires[i].indexes[j].memories[k].memory->memoryName, + elfhandle->requires[i].indexes[j].memories[k].offset, + 0, 0); + } + } + + ref += sizeof(index->numberOfClient) + elfhandle->requires[i].indexes[j].numberOfClient * sizeof(index->symbols[0]); + } + } + } + } + + // Copy provides informations + elfhandle->provideNumber = swap32(elftmp.elfheader->provideNumber); + if(elfhandle->provideNumber != 0) + { + elfhandle->provides = + (t_interface_provide*)OSAL_Alloc_Zero(sizeof(t_interface_provide) * elfhandle->provideNumber); + if(elfhandle->provides == NULL) + goto oom; + + if(elfhandle->provideNumber > 0) + { + char *ref = getElfHeaderReference(&elftmp, (void*)elftmp.elfheader->provides); + + for(i = 0; i < elfhandle->provideNumber; i++) + { + t_elf_provided_interface *provide = (t_elf_provided_interface*)ref; + t_elf_interface_description *interface = (t_elf_interface_description*)getElfHeaderReference(&elftmp, (void*)provide->interface); + + elfhandle->provides[i].name = copyElfString(&elftmp, provide->name); + if(elfhandle->provides[i].name == NULL) + goto oom; + + elfhandle->provides[i].provideTypes = provide->provideTypes; + elfhandle->provides[i].interruptLine = provide->interruptLine; + elfhandle->provides[i].collectionSize = provide->collectionSize; + elfhandle->provides[i].interface = getInterfaceDescription(&elftmp, interface); + if(elfhandle->provides[i].interface == NULL) + goto oom; + + LOG_INTERNAL(2, " provide %s <%s>\n", + elfhandle->provides[i].name, + elfhandle->provides[i].interface->type, + 0,0, 0, 0); + CM_ASSERT(elfhandle->provides[i].collectionSize != 0); + + ref += sizeof(t_elf_required_interface); + + { + t_uint32 *methodSymbols = (t_uint32*)ref; + + elfhandle->provides[i].indexes = (t_interface_provide_index**)OSAL_Alloc_Zero( + sizeof(t_interface_provide_index*) * elfhandle->provides[i].collectionSize); + if(elfhandle->provides[i].indexes == NULL) + goto oom; + + if(elfhandle->provides[i].interface->methodNumber != 0) + { + for(j = 0; j < elfhandle->provides[i].collectionSize; j++) + { + elfhandle->provides[i].indexes[j] = (t_interface_provide_index*)OSAL_Alloc( + sizeof(t_interface_provide_index) * elfhandle->provides[i].interface->methodNumber); + if(elfhandle->provides[i].indexes[j] == NULL) + goto oom; + + for(k = 0; k < elfhandle->provides[i].interface->methodNumber; k++) + { + if((error = getAdressForExecutableOffsetElsewhere(elfhandle, &elftmp, + methodSymbols++, + &elfhandle->provides[i].indexes[j][k].memory)) != CM_OK) + goto onerror; + + if(elfhandle->provides[i].indexes[j][k].memory.memory != NULL) + LOG_INTERNAL(2, " [%d, %d] method '%s' mem=%s offset=%x\n", + j, k, + elfhandle->provides[i].interface->methodNames[k], + elfhandle->provides[i].indexes[j][k].memory.memory->memoryName, + elfhandle->provides[i].indexes[j][k].memory.offset, + 0); + else + LOG_INTERNAL(2, " [%d, %d] method '%s' address=%x\n", + j, k, + elfhandle->provides[i].interface->methodNames[k], + elfhandle->provides[i].indexes[j][k].memory.offset, + 0, 0); + } + } + } + + ref += elfhandle->provides[i].collectionSize * elfhandle->provides[i].interface->methodNumber * sizeof(methodSymbols[0]); + } + } + } + } + + return CM_OK; + +oom: + error = CM_NO_MORE_MEMORY; +onerror: + cm_ELF_CloseFile(temporaryDescription, elfhandle); + *elfhandlePtr = NULL; + return error; +} + +void cm_ELF_ReleaseDescription( + t_uint32 requireNumber, t_interface_require *requires, + t_uint32 attributeNumber, t_attribute *attributes, + t_uint32 propertyNumber, t_property *properties, + t_uint32 provideNumber, t_interface_provide *provides) +{ + int i, j; + + // Free provides (Number set when array allocated) + if(provides != NULL) + { + for(i = 0; i < provideNumber; i++) + { + if(provides[i].indexes != NULL) + { + for(j = 0; j < provides[i].collectionSize; j++) + { + OSAL_Free(provides[i].indexes[j]); + } + OSAL_Free(provides[i].indexes); + } + releaseInterfaceDescription(provides[i].interface); + cm_StringRelease(provides[i].name); + } + OSAL_Free(provides); + } + + // Free requires (Number set when array allocated) + if(requires != NULL) + { + for(i = 0; i < requireNumber; i++) + { + if(requires[i].indexes != 0) + { + for(j = 0; j < requires[i].collectionSize; j++) + { + OSAL_Free(requires[i].indexes[j].memories); + } + OSAL_Free(requires[i].indexes); + } + releaseInterfaceDescription(requires[i].interface); + cm_StringRelease(requires[i].name); + } + OSAL_Free(requires); + } + + // Free properties (Number set when array allocated) + if(properties != NULL) + { + for(i = 0; i < propertyNumber; i++) + { + cm_StringRelease(properties[i].value); + cm_StringRelease(properties[i].name); + } + OSAL_Free(properties); + } + + // Free Attributes (Number set when array allocated) + if(attributes != NULL) + { + for(i = 0; i < attributeNumber; i++) + { + cm_StringRelease(attributes[i].name); + } + OSAL_Free(attributes); + } +} + +void cm_ELF_CloseFile( + t_bool temporaryDescription, + t_elfdescription *elfhandle) +{ + if(elfhandle == NULL) + return; + + if(temporaryDescription && ! elfhandle->temporaryDescription) + return; + + // Release description if not moved to template + cm_ELF_ReleaseDescription( + elfhandle->requireNumber, elfhandle->requires, + elfhandle->attributeNumber, elfhandle->attributes, + elfhandle->propertyNumber, elfhandle->properties, + elfhandle->provideNumber, elfhandle->provides); + + cm_StringRelease(elfhandle->foundedTemplateName); + + ELF64_UnloadComponent(elfhandle); +} + + +static t_cm_error allocSegment( + t_cm_domain_id domainId, + t_elfdescription *elfhandle, + t_memory_handle memories[NUMBER_OF_MMDSP_MEMORY], + t_memory_property property) { + t_memory_id memId; + const t_elfmemory *thisMemory; //!< Memory used to determine this + const t_elfmemory *codeMemory; //!< Memory used to determine code + + MMDSP_serializeMemories(elfhandle->instanceProperty, &codeMemory, &thisMemory); + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + const t_elfmemory* mapping; + + if(elfhandle->segments[memId].sumSize == 0x0) + continue; + + mapping = MMDSP_getMappingById(memId); + + if( + (mapping->property == property && elfhandle->instanceProperty != MEM_FOR_SINGLETON) || + (property == MEM_SHARABLE && elfhandle->instanceProperty == MEM_FOR_SINGLETON) ) + { + // Allocate segment + memories[memId] = cm_DM_Alloc(domainId, mapping->dspMemType, + elfhandle->segments[memId].sumSize / mapping->fileEntSize, + mapping->memAlignement, TRUE); + + if(memories[memId] == INVALID_MEMORY_HANDLE) + { + ERROR("CM_NO_MORE_MEMORY(%s): %x too big\n", mapping->memoryName, elfhandle->segments[memId].sumSize / mapping->fileEntSize, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + // Get reference in memory + elfhandle->segments[memId].hostAddr = cm_DSP_GetHostLogicalAddress(memories[memId]); + + cm_DSP_GetDspAddress(memories[memId], &elfhandle->segments[memId].mpcAddr); + + // Log it + LOG_INTERNAL(1, "\t%s%s: 0x%x..+0x%x (0x%x)\n", + mapping->memoryName, + (thisMemory == mapping) ? "(THIS)" : "", + elfhandle->segments[memId].mpcAddr, + elfhandle->segments[memId].sumSize / mapping->fileEntSize, + elfhandle->segments[memId].hostAddr, 0); + } + else if(property == MEM_PRIVATE) // Since we allocate private segment, if not allocate, it's a share one + { + // In order to allow further relocation based on cached address like mpcAddr & hostAddr, + // initialize them also ! + + // Get reference in memory + elfhandle->segments[memId].hostAddr = cm_DSP_GetHostLogicalAddress(memories[memId]); + + cm_DSP_GetDspAddress(memories[memId], &elfhandle->segments[memId].mpcAddr); + } + } + + return CM_OK; +} + +/* + * Note: in case of error, part of memory could have been allocated and must be free by calling cm_DSPABI_FreeTemplate + */ +t_cm_error cm_ELF_LoadTemplate( + t_cm_domain_id domainId, + t_elfdescription *elfhandle, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_cm_error error; + + if((error = allocSegment(domainId, elfhandle, sharedMemories, MEM_SHARABLE)) != CM_OK) + return error; + + // Load each readonly segment + if((error = ELF64_loadSegment(elfhandle, sharedMemories, MEM_SHARABLE)) != CM_OK) + return error; + + return CM_OK; +} + +t_cm_error cm_ELF_LoadInstance( + t_cm_domain_id domainId, + t_elfdescription *elfhandle, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_memory_id memId; + t_cm_error error; + + // Erase whole memories to make free in case of error + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + privateMemories[memId] = sharedMemories[memId]; + } + + if((error = allocSegment(domainId, elfhandle, privateMemories, MEM_PRIVATE)) != CM_OK) + return error; + + // Load each writable memory + if((error = ELF64_loadSegment(elfhandle, privateMemories, MEM_PRIVATE)) != CM_OK) + return error; + + return CM_OK; +} + +void cm_ELF_FlushTemplate( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_memory_id memId; + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + if(sharedMemories[memId] != INVALID_MEMORY_HANDLE) + MMDSP_loadedSection( + coreId, memId, + sharedMemories[memId]); + } +} + +void cm_ELF_FlushInstance( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_memory_id memId; + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + if(privateMemories[memId] != INVALID_MEMORY_HANDLE && privateMemories[memId] != sharedMemories[memId]) + MMDSP_loadedSection( + coreId, memId, + privateMemories[memId]); + } +} + +void cm_ELF_FreeInstance( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY], + t_memory_handle privateMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_memory_id memId; + + if(privateMemories == NULL) + return; + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + if(privateMemories[memId] != INVALID_MEMORY_HANDLE && privateMemories[memId] != sharedMemories[memId]) + { + MMDSP_unloadedSection(coreId, memId, privateMemories[memId]); + cm_DM_Free(privateMemories[memId], TRUE); + } + } +} + +void cm_ELF_FreeTemplate( + t_nmf_core_id coreId, + t_memory_handle sharedMemories[NUMBER_OF_MMDSP_MEMORY]) +{ + t_memory_id memId; + + if(sharedMemories == NULL) + return; + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + if(sharedMemories[memId] != INVALID_MEMORY_HANDLE) + { + MMDSP_unloadedSection(coreId, memId, sharedMemories[memId]); + cm_DM_Free(sharedMemories[memId], TRUE); + } + } +} diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/elfmmdsp.c b/drivers/staging/nmf-cm/cm/engine/elf/src/elfmmdsp.c new file mode 100644 index 00000000000..452d0f1b175 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/elfmmdsp.c @@ -0,0 +1,575 @@ +/* + * 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/elf/inc/mmdsp.h> +#include <cm/engine/elf/inc/bfd.h> +#include <cm/engine/elf/inc/mpcal.h> + +#include <cm/engine/component/inc/initializer.h> + +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/utils/inc/swap.h> +#include <cm/engine/trace/inc/trace.h> + +#include <cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h> + +static const t_elfmemory mmdspMemories[NUMBER_OF_MMDSP_MEMORY] = { + {0, SDRAM_CODE, SDRAMTEXT_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_CODE, 8, 8, "SDRAM_CODE"}, /* 0: Program memory */ + {1, INTERNAL_XRAM24, 0, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 4, "XROM"}, /* 1: Internal X memory */ + {2, INTERNAL_YRAM24, 0, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 4, "YROM"}, /* 2: Y memory */ + {3, SDRAM_EXT24, SDRAMMEM24_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 4, "SDR0M24"}, /* 5: SDRAM24 */ + {4, SDRAM_EXT16, SDRAMMEM16_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 2, "SDROM16"}, /* 6: SDRAM16 */ + {5, ESRAM_EXT24, ESRAMMEM24_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 4, "ESROM24"}, /* 8: ESRAM24 */ + {6, ESRAM_EXT16, ESRAMMEM16_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_DATA, 3, 2, "ESROM16"}, /* 9: ESRAM16 */ + {7, ESRAM_CODE, ESRAMTEXT_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_CODE, 8, 8, "ESRAM_CODE"}, /*10: ESRAM code */ + {8, INTERNAL_XRAM24, 0, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 4, "XRAM"}, /* 1: Internal X memory */ + {9, INTERNAL_YRAM24, 0, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 4, "YRAM"}, /* 2: Y memory */ + {10, SDRAM_EXT24, SDRAMMEM24_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 4, "SDRAM24"}, /* 5: SDRAM24 */ + {11, SDRAM_EXT16, SDRAMMEM16_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 2, "SDRAM16"}, /* 6: SDRAM16 */ + {12, ESRAM_EXT24, ESRAMMEM16_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 4, "ESRAM24"}, /* 8: ESRAM24 */ + {13, ESRAM_EXT16, ESRAMMEM16_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_PRIVATE, MEM_DATA, 3, 2, "ESRAM16"}, /* 9: ESRAM16 */ + {14, LOCKED_CODE, SDRAMTEXT_BASE_ADDR, CM_MM_ALIGN_2WORDS, MEM_SHARABLE, MEM_CODE, 8, 8, "LOCKED_CODE"}, /* : .locked */ +}; + +#define MAX_ELFSECTIONNAME 10 +struct memoryMapping { + char *elfSectionName; + t_uint32 memoryIndex[MEM_FOR_LAST]; // memoryIndex[t_instance_property] +}; + +static const struct memoryMapping mappingmem0[] = { + {"mem0.0", {0, 0}}, + {"mem0.1", {0, 0}}, + {"mem0.2", {0, 0}} +}; +static const struct memoryMapping mappingmem10 = + {"mem10", {7, 7}}; +static const struct memoryMapping mappinglocked = + {".locked", {14, 14}}; +static const struct memoryMapping mappingmem1[] = { + {"", {0xff, 0xff}}, + {"mem1.1", {1, 1}}, + {"mem1.2", {8, 1}}, + {"mem1.3", {1, 1}}, + {"mem1.4", {8, 1}}, + {"mem1.stack", {8, 1}} +}; +static const struct memoryMapping mappingmem2[] = { + {"", {0xff, 0xff}}, + {"mem2.1", {2, 2}}, + {"mem2.2", {9, 2}}, + {"mem2.3", {2, 2}}, + {"mem2.4", {9, 2}} +}; +static const struct memoryMapping mappingmem5[] = { + {"", {0xff, 0xff}}, + {"mem5.1", {3, 3}}, + {"mem5.2", {10, 3}}, + {"mem5.3", {3, 3}}, + {"mem5.4", {10, 3}} +}; +static const struct memoryMapping mappingmem6[] = { + {"", {0xff, 0xff}}, + {"mem6.1", {4, 4}}, + {"mem6.2", {11, 4}}, + {"mem6.3", {4, 4}}, + {"mem6.4", {11, 4}} +}; +static const struct memoryMapping mappingmem8[] = { + {"", {0xff, 0xff}}, + {"mem8.1", {5, 5}}, + {"mem8.2", {12, 5}}, + {"mem8.3", {5, 5}}, + {"mem8.4", {12, 5}} +}; +static const struct memoryMapping mappingmem9[] = { + {"", {0xff, 0xff}}, + {"mem9.1", {6, 6}}, + {"mem9.2", {13, 6}}, + {"mem9.3", {6, 6}}, + {"mem9.4", {13, 6}} +}; + +static const struct { + const struct memoryMapping* mapping; + unsigned int number; +} hashMappings[10] = { + {mappingmem0, sizeof(mappingmem0) / sizeof(mappingmem0[0])}, + {mappingmem1, sizeof(mappingmem1) / sizeof(mappingmem1[0])}, + {mappingmem2, sizeof(mappingmem2) / sizeof(mappingmem2[0])}, + {0x0, 0}, + {0x0, 0}, + {mappingmem5, sizeof(mappingmem5) / sizeof(mappingmem5[0])}, + {mappingmem6, sizeof(mappingmem6) / sizeof(mappingmem6[0])}, + {0x0, 0}, + {mappingmem8, sizeof(mappingmem8) / sizeof(mappingmem8[0])}, + {mappingmem9, sizeof(mappingmem9) / sizeof(mappingmem9[0])}, +}; + +const t_elfmemory* MMDSP_getMappingById(t_memory_id memId) +{ + return &mmdspMemories[memId]; +} + +const t_elfmemory* MMDSP_getMappingByName(const char* sectionName, t_instance_property property) +{ + if(sectionName[0] == 'm' && sectionName[1] == 'e' && sectionName[2] == 'm') + { + if(sectionName[4] == '.') + { + if(sectionName[5] >= '0' && sectionName[5] <= '9') + { + if(sectionName[3] >= '0' && sectionName[3] <= '9') + { + unsigned int m, sm; + + m = sectionName[3] - '0'; + sm = sectionName[5] - '0'; + if(sm < hashMappings[m].number) + return &mmdspMemories[hashMappings[m].mapping[sm].memoryIndex[property]]; + } + } else if(sectionName[3] == '1' && sectionName[5] == 's') + return &mmdspMemories[mappingmem1[5].memoryIndex[property]]; + } + else if(sectionName[3] == '1' && sectionName[4] == '0') + return &mmdspMemories[mappingmem10.memoryIndex[property]]; + } + else if(sectionName[0] == '.' && sectionName[1] == 'l' && sectionName[2] == 'o' && sectionName[3] == 'c' && + sectionName[4] == 'k' && sectionName[5] == 'e' && sectionName[6] == 'd') + { + return &mmdspMemories[mappinglocked.memoryIndex[property]]; + } + + return NULL; +} + +void MMDSP_serializeMemories(t_instance_property property, + const t_elfmemory** codeMemory, const t_elfmemory** thisMemory) { + // Return meory reference + *codeMemory = &mmdspMemories[0]; + if(property == MEM_FOR_SINGLETON) + { + *thisMemory = &mmdspMemories[1]; + } + else + { + *thisMemory = &mmdspMemories[8]; + } +} + +void MMDSP_copyCode(t_uint64 * remoteAddr64, const char* origAddr, int nb) +{ + int m; + + // Linux allow unaligned access +#ifdef LINUX + t_uint64 *origAddr64 = (t_uint64*)origAddr; +#else + __packed t_uint64 *origAddr64 = (__packed t_uint64*)origAddr; +#endif + + for (m = 0; m < nb; m += 8) + { + *remoteAddr64++ = swap64(*origAddr64++); + } +} + +void MMDSP_copyData24(t_uint32 * remoteAddr32, const char* origAddr, int nb) +{ + int m; + + for (m = 0; m < nb; m+=4) + { + t_uint32 value1; + + value1 = (*origAddr++ << 16); + value1 |= (*origAddr++ << 8); + value1 |= (*origAddr++ << 0); + *remoteAddr32++ = value1; + } +} + +void MMDSP_copyData16(t_uint16 * remoteAddr16, const char* origAddr, int nb) +{ + int m; + + for (m = 0; m < nb; m+=2) + { + t_uint16 value1; + + origAddr++; // Skip this byte (which is put in elf file for historical reason) + value1 = (*origAddr++ << 8); + value1 |= (*origAddr++ << 0); + *remoteAddr16++ = value1; + } +} + +#if 0 +__asm void MMDSP_copyCode(void* dst, const void* src, int nb) +{ + PUSH {r4-r8, lr} + SUBS r2,r2,#0x20 + BCC l4 + +l5 + SETEND BE + LDR r4, [r1], #0x4 + LDR r3, [r1], #0x4 + LDR r6, [r1], #0x4 + LDR r5, [r1], #0x4 + LDR r8, [r1], #0x4 + LDR r7, [r1], #0x4 + LDR lr, [r1], #0x4 + LDR r12, [r1], #0x4 + + SETEND LE + STM r0!,{r3-r8,r12, lr} + SUBS r2,r2,#0x20 + BCS l5 + +l4 + LSLS r12,r2,#28 + + SETEND BE + LDRCS r4, [r1], #0x4 + LDRCS r3, [r1], #0x4 + LDRCS r6, [r1], #0x4 + LDRCS r5, [r1], #0x4 + SETEND LE + STMCS r0!,{r3-r6} + + SETEND BE + LDRMI r4, [r1], #0x4 + LDRMI r3, [r1], #0x4 + SETEND LE + STMMI r0!,{r3-r4} + + POP {r4-r8, pc} +} +#endif + +#ifdef LINUX +static void PLD5(int r) +{ + asm volatile ( + "PLD [r0, #0x20] \n\t" + "PLD [r0, #0x40] \n\t" + "PLD [r0, #0x60] \n\t" + "PLD [r0, #0x80] \n\t" + "PLD [r0, #0xA0]" ); +} + +static void PLD1(int r) +{ + asm volatile ( + "PLD [r0, #0xC0]" ); +} +#else /* Symbian, Think -> We assume ARMCC */ +static __asm void PLD5(int r) +{ + PLD [r0, #0x20] + PLD [r0, #0x40] + PLD [r0, #0x60] + PLD [r0, #0x80] + PLD [r0, #0xA0] + + bx lr +} + +static __asm void PLD1(int r) +{ + PLD [r0, #0xC0] + + bx lr +} +#endif + +#if 0 +__asm void COPY(void* dst, const void* src, int nb) +{ + PUSH {r4-r8, lr} + SUBS r2,r2,#0x20 + BCC l4a + PLD [r1, #0x20] + PLD [r1, #0x40] + PLD [r1, #0x60] + PLD [r1, #0x80] + PLD [r1, #0xA0] + +l5a + PLD [r1, #0xC0] + LDM r1!,{r3-r8,r12,lr} + STM r0!,{r3-r8,r12,lr} + SUBS r2,r2,#0x20 + BCS l5a + +l4a + LSLS r12,r2,#28 + LDMCS r1!,{r3,r4,r12,lr} + STMCS r0!,{r3,r4,r12,lr} + LDMMI r1!,{r3,r4} + STMMI r0!,{r3,r4} + POP {r4-r8,lr} + LSLS r12,r2,#30 + LDRCS r3,[r1],#4 + STRCS r3,[r0],#4 + BXEQ lr +l6b + LSLS r2,r2,#31 + LDRHCS r3,[r1],#2 + LDRBMI r2,[r1],#1 + STRHCS r3,[r0],#2 + STRBMI r2,[r0],#1 + BX lr +} +#endif + + +void MMDSP_copySection(t_uint32 origAddr, t_uint32 remoteAddr, t_uint32 sizeInByte) { + t_uint32 endAddr = remoteAddr + sizeInByte; + + PLD5(origAddr); + + // Align on 32bits + if((remoteAddr & 0x3) != 0) + { + *(t_uint16*)remoteAddr = *(t_uint16*)origAddr; + remoteAddr += sizeof(t_uint16); + origAddr += sizeof(t_uint16); + } + + // Align on 64bits + if((remoteAddr & 0x7) != 0 && (remoteAddr <= endAddr - sizeof(t_uint32))) + { + *(t_uint32*)remoteAddr = *(t_uint32*)origAddr; + remoteAddr += sizeof(t_uint32); + origAddr += sizeof(t_uint32); + } + + // 64bits burst access + for(; remoteAddr <= endAddr - sizeof(t_uint64); remoteAddr += sizeof(t_uint64), origAddr += sizeof(t_uint64)) + { + PLD1(origAddr); + *(volatile t_uint64*)remoteAddr = *(t_uint64*)origAddr; + } + + // Remain 32bits access + if(remoteAddr <= endAddr - sizeof(t_uint32)) + { + *(t_uint32*)remoteAddr = *(t_uint32*)origAddr; + remoteAddr += sizeof(t_uint32); + origAddr += sizeof(t_uint32); + } + + // Remain 16bits access + if(remoteAddr <= endAddr - sizeof(t_uint16)) + *(t_uint16*)remoteAddr = *(t_uint16*)origAddr; +} + + +void MMDSP_bzeroSection(t_uint32 remoteAddr, t_uint32 sizeInByte) { + t_uint32 endAddr = remoteAddr + sizeInByte; + + // Align on 32bits + if((remoteAddr & 0x3) != 0) + { + *(t_uint16*)remoteAddr = 0; + remoteAddr += sizeof(t_uint16); + } + + // Align on 64bits + if((remoteAddr & 0x7) != 0 && (remoteAddr <= endAddr - sizeof(t_uint32))) + { + *(t_uint32*)remoteAddr = 0; + remoteAddr += sizeof(t_uint32); + } + + // 64bits burst access + for(; remoteAddr <= endAddr - sizeof(t_uint64); remoteAddr += sizeof(t_uint64)) + *(volatile t_uint64*)remoteAddr = 0ULL; + + // Remain 32bits access + if(remoteAddr <= endAddr - sizeof(t_uint32)) + { + *(t_uint32*)remoteAddr = 0; + remoteAddr += sizeof(t_uint32); + } + + // Remain 16bits access + if(remoteAddr <= endAddr - sizeof(t_uint16)) + *(t_uint16*)remoteAddr = 0; +} + +void MMDSP_loadedSection(t_nmf_core_id coreId, t_memory_id memId, t_memory_handle handle) +{ + if(mmdspMemories[memId].purpose == MEM_CODE) + { + OSAL_CleanDCache(cm_DSP_GetHostLogicalAddress(handle), cm_MM_GetSize(handle)); + } + + if(memId == LOCKED_CODE) + { + t_uint32 DspAddress, DspSize; + + cm_DSP_GetDspMemoryHandleSize(handle, &DspSize); + cm_DSP_GetDspAddress(handle, &DspAddress); + + cm_COMP_InstructionCacheLock(coreId, DspAddress, DspSize); + } +} + +void MMDSP_unloadedSection(t_nmf_core_id coreId, t_memory_id memId, t_memory_handle handle) +{ + if(memId == LOCKED_CODE) + { + t_uint32 DspAddress, DspSize; + + cm_DSP_GetDspMemoryHandleSize(handle, &DspSize); + cm_DSP_GetDspAddress(handle, &DspAddress); + + cm_COMP_InstructionCacheUnlock(coreId, DspAddress, DspSize); + } + +} + +static struct reloc_howto_struct elf64_mmdsp_howto_table[] = +{ + HOWTO (R_MMDSP_IMM20_16, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 8, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0x0, /* special_function */ + "R_MMDSP_IMM20_16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0000000000ffff00, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 4-bit absolute relocation for splitted 20 bits immediate, shifted by 56 */ + + HOWTO (R_MMDSP_IMM20_4, /* type */ + 16, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 4, /* bitsize */ + FALSE, /* pc_relative */ + 56, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0x0, /* special_function */ + "R_MMDSP_IMM20_4", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0f00000000000000LL, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_MMDSP_24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0x0, /* special_function */ + "R_MMDSP_24", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_MMDSP_IMM16, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 8, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0x0, /* special_function */ + "R_MMDSP_IMM16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0000000000ffff00, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + +static const char* lastInPlaceAddr = 0; +static long long lastInPlaceValue; + +void MMDSP_performRelocation( + t_uint32 type, + const char* symbol_name, + t_uint32 symbol_addr, + char* reloc_addr, + const char* inPlaceAddr, + t_uint32 reloc_offset) { + int i; + + for(i = 0; i < sizeof(elf64_mmdsp_howto_table) / sizeof(elf64_mmdsp_howto_table[0]); i++) + { + struct reloc_howto_struct* howto = &elf64_mmdsp_howto_table[i]; + if(howto->type == type) + { + t_uint64 relocation; + + LOG_INTERNAL(2, "reloc '%s:0x%x' type %s at 0x%x (0x%x)\n", + symbol_name ? symbol_name : "??", symbol_addr, + howto->name, + reloc_offset, reloc_addr, 0); + + relocation = symbol_addr; + + if (howto->pc_relative) { + // Not handle yet + } + + if (howto->complain_on_overflow != complain_overflow_dont) { + // Not handle yet + } + + relocation >>= howto->rightshift; + + relocation <<= howto->bitpos; + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) { + case 2: { + long x = *(long*)inPlaceAddr; + + // CM_ASSERT(*(long*)inPlaceAddr == *(long*)reloc_addr); + + DOIT (x); + *(long*)reloc_addr = x; + } + break; + case 4: { + long long x; + if(lastInPlaceAddr == inPlaceAddr) + { + x = lastInPlaceValue; + } + else + { + // CM_ASSERT(*(__packed long long*)inPlaceAddr == *(long long*)reloc_addr); + x = *(long long*)inPlaceAddr; + lastInPlaceAddr = inPlaceAddr; + } + + DOIT (x); + *(long long*)reloc_addr = lastInPlaceValue = x; + } + break; + default: + CM_ASSERT(0); + } + + return; + } + } + + ERROR("Relocation type %d not supported for '%s'\n", type, symbol_name, 0, 0, 0, 0); +} diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/elfrelocate.c b/drivers/staging/nmf-cm/cm/engine/elf/src/elfrelocate.c new file mode 100644 index 00000000000..b08ac6a361e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/elfrelocate.c @@ -0,0 +1,79 @@ +/* + * 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/elf/inc/bfd.h> +#include <cm/engine/elf/inc/mpcal.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/string.h> + +t_cm_error cm_ELF_relocateSharedSegments( + t_memory_handle *memories, + t_elfdescription *elfhandle, + void *cbContext) +{ + return ELF64_relocateSegments( + memories, + elfhandle, + MEM_SHARABLE, + cbContext); +} + +t_cm_error cm_ELF_relocatePrivateSegments( + t_memory_handle *memories, + t_elfdescription *elfhandle, + void *cbContext) +{ + return ELF64_relocateSegments( + memories, + elfhandle, + MEM_PRIVATE, + cbContext); +} + +void cm_ELF_performRelocation( + t_uint32 type, + const char* symbol_name, + t_uint32 symbol_addr, + char* reloc_addr) +{ + MMDSP_performRelocation( + type, + symbol_name, + symbol_addr, + reloc_addr, + reloc_addr, + 0xBEEF); + + OSAL_CleanDCache((t_uint32)reloc_addr, 8); +} + +t_cm_error cm_ELF_GetMemory( + t_elfdescription *elf, + t_tmp_elfdescription *elftmp, + t_uint32 address, + t_memory_purpose purpose, + t_memory_reference *memory) { + t_memory_id memId; + + for(memId = 0; memId < NUMBER_OF_MMDSP_MEMORY; memId++) + { + const t_elfmemory* mem = MMDSP_getMappingById(memId); + + if(mem->purpose == purpose && // Memory correspond + elf->segments[mem->id].sumSize != 0 && // Segment allocated + (elf->segments[mem->id].mpcAddr <= address) && + (address < elf->segments[mem->id].mpcAddr + elf->segments[mem->id].sumSize / mem->fileEntSize)) { + memory->memory = mem; + memory->offset = address - elf->segments[mem->id].mpcAddr; + return CM_OK; + } + } + + ERROR("Memory %x,%d not found\n", address, purpose, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; +} diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/elfxx.c b/drivers/staging/nmf-cm/cm/engine/elf/src/elfxx.c new file mode 100644 index 00000000000..4a2976a6bc1 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/elfxx.c @@ -0,0 +1,591 @@ +/* + * 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/elf/inc/mpcal.h> + +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/utils/inc/mem.h> + + +static t_uint32 max(t_uint32 a, t_uint32 b) +{ + return (a >= b) ? a : b; +} +/* +static t_uint32 min(t_uint32 a, t_uint32 b) +{ + return (a <= b) ? a : b; +} +*/ + +struct XXrelocation +{ + t_uint32 st_value; + ElfXX_Half st_shndx; + Elf64_Sxword r_addend; + t_uint32 OffsetInElf; + t_uint32 type; + + t_dup_char symbol_name; // Valid only if st_shndx == SHN_UNDEF +}; + +struct XXSection { + ElfXX_Word sh_type; /* Section type */ + t_uint32 sh_size; /* Section size in bytes */ + ElfXX_Word sh_info; /* Additional section information */ + ElfXX_Word sh_link; /* Link to another section */ + t_uint32 sh_addralign; /* Some sections have address alignment constraints */ + t_uint32 sh_addr; /* Section addr */ + ElfXX_Xword sh_flags; /* Section flags */ + + const char *data; + t_uint32 trueDataSize; /* Valid if different from sh_size */ + const char *sectionName; + + t_uint32 offsetInSegment; + const t_elfmemory *meminfo; + + t_uint32 relocationNumber; + struct XXrelocation *relocations; +}; + +struct XXElf { + t_uint32 e_shnum; + struct XXSection sectionss[1]; +}; + +t_cm_error ELF64_LoadComponent( + t_uint16 e_machine, + const char *elfdata, + t_elfdescription **elfhandlePtr, + t_tmp_elfdescription *elftmp) +{ + t_elfdescription *elfhandle; + const ElfXX_Ehdr *header = (ElfXX_Ehdr*)elfdata; + const ElfXX_Shdr *sections; + const char *strings; + struct XXElf* ELF; + int i, nb; + + elftmp->elfdata = elfdata; + + /* Sanity check */ + if (swapHalf(header->e_machine) != e_machine) + { + ERROR("This is not a executable for such MPC\n", 0, 0, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } + + // Cache elf file informations + nb = swapHalf(header->e_shnum); + elftmp->isExecutable = (swapHalf(header->e_type) == ET_EXEC); + + elfhandle = (t_elfdescription*)OSAL_Alloc_Zero( + sizeof(t_elfdescription) + sizeof(struct XXElf) + sizeof(struct XXSection) * (nb - 1)); + if(elfhandle == NULL) + return CM_NO_MORE_MEMORY; + + ELF = elfhandle->ELF = (struct XXElf*)(elfhandle + 1); + + ELF->e_shnum = nb; + + sections = (ElfXX_Shdr*)&elfdata[swapXword(header->e_shoff)]; + // Compute and swap section infromation + for(i = 0; i < ELF->e_shnum; i++) + { + ELF->sectionss[i].sh_type = swapWord(sections[i].sh_type); + ELF->sectionss[i].sh_info = swapWord(sections[i].sh_info); + ELF->sectionss[i].sh_link = swapWord(sections[i].sh_link); + ELF->sectionss[i].sh_size = (t_uint32)swapXword(sections[i].sh_size); + ELF->sectionss[i].sh_addralign = (t_uint32)swapXword(sections[i].sh_addralign); + ELF->sectionss[i].sh_addr = (t_uint32)swapXword(sections[i].sh_addr); + ELF->sectionss[i].sh_flags = swapXword(sections[i].sh_flags); + + elftmp->sectionData[i] = &elfdata[(t_uint32)swapXword(sections[i].sh_offset)]; + } + + /* + * search nmf_segment + */ + strings = elftmp->sectionData[swapHalf(header->e_shstrndx)]; + for(i = 0; i < ELF->e_shnum; i++) + { + ELF->sectionss[i].sectionName = &strings[swapWord(sections[i].sh_name)]; + + // Found nmf_segment to see if it's + if(cm_StringCompare("nmf_segment", ELF->sectionss[i].sectionName, 11) == 0) { + elftmp->nmfSectionIndex = i; + elftmp->elfheader = (const t_elf_component_header*)elftmp->sectionData[i]; + } + } + + if(elftmp->nmfSectionIndex == 0) + { + ERROR("This is not a NMF component\n", 0, 0, 0, 0, 0, 0); + goto invalid; + } + + /* + * Determine component type + */ + elfhandle->magicNumber = swap32(elftmp->elfheader->magic); + switch(elfhandle->magicNumber) { + case MAGIC_COMPONENT: + elfhandle->instanceProperty = MEM_FOR_MULTIINSTANCE; + break; + case MAGIC_SINGLETON: + case MAGIC_FIRMWARE: + elfhandle->instanceProperty = MEM_FOR_SINGLETON; + break; + } + + // Copy content + for(i = 0; i < ELF->e_shnum; i++) + { + ELF->sectionss[i].meminfo = MMDSP_getMappingByName( + ELF->sectionss[i].sectionName, + elfhandle->instanceProperty); + + if(ELF->sectionss[i].meminfo != NULL) + ELF->sectionss[i].trueDataSize = (ELF->sectionss[i].sh_size / ELF->sectionss[i].meminfo->fileEntSize) * ELF->sectionss[i].meminfo->memEntSize; + + if(ELF->sectionss[i].sh_size != 0 && + ELF->sectionss[i].sh_type == SHT_PROGBITS && + (ELF->sectionss[i].sh_flags & SHF_ALLOC) != 0) + { + const char* elfAddr = elftmp->sectionData[i]; + + ELF->sectionss[i].data = OSAL_Alloc(ELF->sectionss[i].trueDataSize); + if(ELF->sectionss[i].data == NULL) + goto oom; + + if(ELF->sectionss[i].meminfo->purpose == MEM_CODE) + { + MMDSP_copyCode( + (t_uint64*)ELF->sectionss[i].data, + elfAddr, + ELF->sectionss[i].trueDataSize); + } + else if(ELF->sectionss[i].meminfo->purpose == MEM_DATA && + // Always 3 for data ELF->sectionss[i].meminfo->fileEntSize == 3 && + ELF->sectionss[i].meminfo->memEntSize == 4) + { + MMDSP_copyData24( + (t_uint32*)ELF->sectionss[i].data, + elfAddr, + ELF->sectionss[i].trueDataSize); + } + else if(ELF->sectionss[i].meminfo->purpose == MEM_DATA && + // Always 3 for data ELF->sectionss[i].meminfo->fileEntSize == 3 && + ELF->sectionss[i].meminfo->memEntSize == 2) + { + MMDSP_copyData16( + (t_uint16*)ELF->sectionss[i].data, + elfAddr, + ELF->sectionss[i].trueDataSize); + } + else + CM_ASSERT(0); + } + } + + // Copy relocation + // Loop on all relocation section + for(i=0; i < ELF->e_shnum; i++) + { + int sh_info; + + // Does this section is a relocation table (only RELA supported) + if((ELF->sectionss[i].sh_type != SHT_RELA) || + ELF->sectionss[i].sh_size == 0) continue; + + // Copy only relocation for loaded section + sh_info = ELF->sectionss[i].sh_info; + if(ELF->sectionss[sh_info].meminfo != NULL) + { + const ElfXX_Sym* symtab; + const char* strtab; + ElfXX_Rela* rel_start; + int n; + + ELF->sectionss[sh_info].relocationNumber = ELF->sectionss[i].sh_size / sizeof(ElfXX_Rela); + ELF->sectionss[sh_info].relocations = (struct XXrelocation*)OSAL_Alloc_Zero(sizeof(struct XXrelocation) * ELF->sectionss[sh_info].relocationNumber); + if(ELF->sectionss[sh_info].relocations == NULL) + goto oom; + + symtab = (ElfXX_Sym *)elftmp->sectionData[ELF->sectionss[i].sh_link]; + strtab = elftmp->sectionData[ELF->sectionss[ELF->sectionss[i].sh_link].sh_link]; + rel_start = (ElfXX_Rela*)elftmp->sectionData[i]; + for(n = 0; n < ELF->sectionss[sh_info].relocationNumber; n++, rel_start++) + { + struct XXrelocation* relocation = &ELF->sectionss[sh_info].relocations[n]; + ElfXX_Xword r_info = swapXword(rel_start->r_info); + int strtab_index = ELFXX_R_SYM(r_info); + const char* symbol_name = &strtab[swapWord(symtab[strtab_index].st_name)]; + + relocation->st_shndx = swapHalf(symtab[strtab_index].st_shndx); + relocation->st_value = (t_uint32)swapXword(symtab[strtab_index].st_value); + relocation->r_addend = swapXword(rel_start->r_addend); + relocation->OffsetInElf = (t_uint32)swapXword(rel_start->r_offset) / ELF->sectionss[sh_info].meminfo->fileEntSize; + relocation->type = ELFXX_R_TYPE(r_info); + + switch(relocation->st_shndx) { + case SHN_UNDEF: + relocation->symbol_name = cm_StringDuplicate(symbol_name + 1); /* Remove '_' prefix */ + if(relocation->symbol_name == NULL) + goto oom; + break; + case SHN_COMMON: + ERROR("SHN_COMMON not handle for %s\n", symbol_name, 0, 0, 0, 0, 0); + goto invalid; + } + } + } + } + + *elfhandlePtr = elfhandle; + return CM_OK; +invalid: + ELF64_UnloadComponent(elfhandle); + return CM_INVALID_ELF_FILE; +oom: + ELF64_UnloadComponent(elfhandle); + return CM_NO_MORE_MEMORY; +} + +t_cm_error ELF64_ComputeSegment( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp) +{ + struct XXElf* ELF = elfhandle->ELF; + int i; + + for(i = 0; i < ELF->e_shnum; i++) + { + ELF->sectionss[i].offsetInSegment = 0xFFFFFFFF; + + if(ELF->sectionss[i].sh_type == SHT_PROGBITS || ELF->sectionss[i].sh_type == SHT_NOBITS) { + // This is a loadable memory (memory size could be zero since we can have symbol on it)... + const t_elfmemory* meminfo = ELF->sectionss[i].meminfo; + + if(meminfo != NULL) { + // Which correspond to MPC memory + + if(elftmp->isExecutable) + { + if(! elfhandle->segments[meminfo->id].sumSizeSetted) + { + CM_ASSERT(ELF->sectionss[i].sh_addr >= meminfo->startAddr * meminfo->fileEntSize); + + elfhandle->segments[meminfo->id].sumSizeSetted = TRUE; + elfhandle->segments[meminfo->id].sumSize = ELF->sectionss[i].sh_addr - meminfo->startAddr * meminfo->fileEntSize; + } + else + CM_ASSERT(elfhandle->segments[meminfo->id].sumSize == ELF->sectionss[i].sh_addr - meminfo->startAddr * meminfo->fileEntSize); + } + else + { + while(elfhandle->segments[meminfo->id].sumSize % ELF->sectionss[i].sh_addralign != 0) + elfhandle->segments[meminfo->id].sumSize++; + } + + elfhandle->segments[meminfo->id].maxAlign = max(elfhandle->segments[meminfo->id].maxAlign, ELF->sectionss[i].sh_addralign); + ELF->sectionss[i].offsetInSegment = elfhandle->segments[meminfo->id].sumSize / meminfo->fileEntSize; + elfhandle->segments[meminfo->id].sumSize += ELF->sectionss[i].sh_size; + } + } else if(ELF->sectionss[i].sh_type == SHT_RELA && ELF->sectionss[i].sh_info == elftmp->nmfSectionIndex) { + int secsym = ELF->sectionss[i].sh_link; + elftmp->relaNmfSegment = (ElfXX_Rela*)elftmp->sectionData[i]; + elftmp->relaNmfSegmentEnd = (ElfXX_Rela*)((t_uint32)elftmp->relaNmfSegment + ELF->sectionss[i].sh_size); + elftmp->relaNmfSegmentSymbols = (ElfXX_Sym*)elftmp->sectionData[secsym]; + elftmp->relaNmfSegmentStrings = elftmp->sectionData[ELF->sectionss[secsym].sh_link]; + } + } + + return CM_OK; +} + +void ELF64_UnloadComponent( + t_elfdescription *elfhandle) +{ + struct XXElf* ELF = elfhandle->ELF; + int i, n; + + for(i = 0; i < ELF->e_shnum; i++) + { + if(ELF->sectionss[i].relocations != NULL) + { + for(n = 0; n < ELF->sectionss[i].relocationNumber; n++) + cm_StringRelease(ELF->sectionss[i].relocations[n].symbol_name); + OSAL_Free(ELF->sectionss[i].relocations); + } + + OSAL_Free((void*)ELF->sectionss[i].data); + } + OSAL_Free(elfhandle); +} + +t_cm_error ELF64_loadSegment( + t_elfdescription *elfhandle, + t_memory_handle *memory, + t_memory_property property) +{ + struct XXElf* ELF = elfhandle->ELF; + int i; + + /* + * Copy ELF data in this segment + */ + for(i = 0; i < ELF->e_shnum; i++) + { + const t_elfmemory* mapping = ELF->sectionss[i].meminfo; + + if(mapping == NULL) + continue; + if((! (ELF->sectionss[i].sh_flags & SHF_ALLOC)) || (ELF->sectionss[i].sh_size == 0)) + continue; + + // This is a loadable memory ... + if( + (mapping->property == property && elfhandle->instanceProperty != MEM_FOR_SINGLETON) || + (property == MEM_SHARABLE && elfhandle->instanceProperty == MEM_FOR_SINGLETON) ) + { + // Where memory exist and waited share/private correspond + t_uint32 remoteData = elfhandle->segments[mapping->id].hostAddr + + ELF->sectionss[i].offsetInSegment * mapping->memEntSize; + + if(ELF->sectionss[i].sh_type != SHT_NOBITS) + { + LOG_INTERNAL(2, "loadSection(%s, 0x%x, 0x%x, 0x%08x)\n", + ELF->sectionss[i].sectionName, remoteData, ELF->sectionss[i].trueDataSize, + (t_uint32)ELF->sectionss[i].data, 0, 0); + + MMDSP_copySection((t_uint32)ELF->sectionss[i].data, remoteData, ELF->sectionss[i].trueDataSize); + } + else + { + LOG_INTERNAL(2, "bzeroSection(%s, 0x%x, 0x%x)\n", + ELF->sectionss[i].sectionName, remoteData, ELF->sectionss[i].trueDataSize, 0, 0, 0); + + MMDSP_bzeroSection(remoteData, ELF->sectionss[i].trueDataSize); + } + } + } + + return CM_OK; +} + + + +static const t_elfmemory* getSectionAddress( + t_memory_handle *memories, + t_elfdescription *elfhandle, + t_uint32 sectionIdx, + t_uint32 *sectionOffset, + t_cm_logical_address *sectionAddr) { + struct XXElf* ELF = elfhandle->ELF; + const t_elfmemory* mapping = ELF->sectionss[sectionIdx].meminfo; + + if(mapping != NULL) { + *sectionOffset = (elfhandle->segments[mapping->id].mpcAddr + + ELF->sectionss[sectionIdx].offsetInSegment); + + *sectionAddr = (t_cm_logical_address)(elfhandle->segments[mapping->id].hostAddr + + ELF->sectionss[sectionIdx].offsetInSegment * mapping->memEntSize); + } + + return mapping; +} + +static t_uint32 getSymbolAddress( + t_memory_handle *memories, + t_elfdescription *elfhandle, + t_uint32 symbolSectionIdx, + t_uint32 symbolOffet) { + struct XXElf* ELF = elfhandle->ELF; + const t_elfmemory* mapping = ELF->sectionss[symbolSectionIdx].meminfo; + + if(mapping == NULL) + return 0xFFFFFFFF; + // CM_ASSERT(elfhandle->segments[mapping->id].sumSize != 0); + // CM_ASSERT(elfhandle->sections[symbolSectionIdx].offsetInSegment != 0xFFFFFFFF); + + return elfhandle->segments[mapping->id].mpcAddr + + ELF->sectionss[symbolSectionIdx].offsetInSegment + + symbolOffet; +} + +#if 0 +t_bool ELFXX_getSymbolLocation( + const t_mpcal_memory *mpcalmemory, + t_elfdescription *elf, + char *symbolName, + const t_elfmemory **memory, + t_uint32 *offset) { + const ElfXX_Ehdr *header = (ElfXX_Ehdr*)elf->elfdata; + const ElfXX_Shdr *sections = (ElfXX_Shdr*)&elf->elfdata[swapXword(header->e_shoff)]; + const char *strings = &elf->elfdata[swapXword(sections[swapHalf(header->e_shstrndx)].sh_offset)]; + int len = cm_StringLength(symbolName, 256); // TO BE FIXED + int i; + + for(i = 0; i < ELF->e_shnum; i++) + { + ElfXX_Sym* symtab; + const char* strtab; + unsigned int size, j; + + if(ELF->sectionss[i].sh_type != SHT_SYMTAB && ELF->sectionss[i].sh_type != SHT_DYNSYM) continue; + + // Section is a symbol table + symtab = (ElfXX_Sym*)&elf->elfdata[swapXword(sections[i].sh_offset)]; + strtab = &elf->elfdata[swapXword(sections[swapWord(sections[i].sh_link)].sh_offset)]; + size = ELF->sectionss[i].sh_size / (unsigned int)swapXword(sections[i].sh_entsize); + + for(j = 0; j < size; j++) { + const char* foundName = &strtab[swapWord(symtab[j].st_name)]; + + if(cm_StringCompare(symbolName, foundName, len) == 0) { + if(swapHalf(symtab[j].st_shndx) != SHN_UNDEF) { + int sectionIdx = (int)swapHalf(symtab[j].st_shndx); + ElfXX_Xword sh_flags = swapXword(sections[sectionIdx].sh_flags); + + *memory = mpcalmemory->getMappingByName(&strings[swapWord(sections[sectionIdx].sh_name)], + sh_flags & SHF_WRITE ? MEM_RW : (sh_flags & SHF_EXECINSTR ? MEM_X : MEM_RO)); + *offset = (t_uint32)swapXword(symtab[j].st_value); + + return 1; + } + } + } + } + return 0; +} +#endif + +t_cm_error ELF64_relocateSegments( + t_memory_handle *memories, + t_elfdescription *elfhandle, + t_memory_property property, + void *cbContext) { + struct XXElf* ELF = elfhandle->ELF; + int sec, n; + + // Loop on all relocation section + for(sec=0; sec < ELF->e_shnum; sec++) + { + t_cm_logical_address sectionAddr = 0; + t_uint32 sectionOffset = 0; + const t_elfmemory* mapping; + + if(ELF->sectionss[sec].relocations == NULL) + continue; + + // Relocate only section in memory + mapping = getSectionAddress(memories, + elfhandle, + sec, + §ionOffset, + §ionAddr); + if(mapping == NULL) + continue; + + if( + (mapping->property == property && elfhandle->instanceProperty != MEM_FOR_SINGLETON) || + (property == MEM_SHARABLE && elfhandle->instanceProperty == MEM_FOR_SINGLETON) ) + { + LOG_INTERNAL(2, "relocSection(%s)\n", ELF->sectionss[sec].sectionName, 0, 0, 0, 0, 0); + + for(n = 0; n < ELF->sectionss[sec].relocationNumber; n++) + { + struct XXrelocation* relocation = &ELF->sectionss[sec].relocations[n]; + t_uint32 symbol_addr; + char* relocAddr = (char*)(sectionAddr + relocation->OffsetInElf * mapping->memEntSize); + + switch(relocation->st_shndx) { + case SHN_ABS: // Absolute external reference + symbol_addr = relocation->st_value; + break; + case SHN_UNDEF: // External reference + // LOG_INTERNAL(0, "cm_resolvSymbol(%d, %s)\n", relocation->type, relocation->symbol_name, 0,0, 0, 0); + symbol_addr = cm_resolvSymbol(cbContext, + relocation->type, + relocation->symbol_name, + relocAddr); + if(symbol_addr == 0x0) { // Not defined symbol + ERROR("Symbol %s not found\n", relocation->symbol_name, 0, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } else if(symbol_addr == 0xFFFFFFFE) { // OOM + return CM_NO_MORE_MEMORY; + } else if(symbol_addr == 0xFFFFFFFF) { // Defined inside static binding + continue; + } + break; + default: // Internal reference in loaded section + symbol_addr = getSymbolAddress( + memories, + elfhandle, + (t_uint32)relocation->st_shndx, + relocation->st_value); + if(symbol_addr == 0xFFFFFFFF) { + ERROR("Symbol in section %s+%d not loaded\n", + ELF->sectionss[relocation->st_shndx].sectionName, + relocation->st_value, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } + break; + } + + symbol_addr += relocation->r_addend; + + MMDSP_performRelocation( + relocation->type, + relocation->symbol_name, + symbol_addr, + relocAddr, + ELF->sectionss[sec].data + relocation->OffsetInElf * mapping->memEntSize, + sectionOffset + relocation->OffsetInElf); + } + } + } + + return CM_OK; +} + +t_cm_error ELF64_getRelocationMemory( + t_elfdescription *elfhandle, + t_tmp_elfdescription *elftmp, + t_uint32 offsetInNmf, + t_memory_reference *memory) { + struct XXElf* ELF = elfhandle->ELF; + const ElfXX_Rela* rel_start; + const ElfXX_Sym* relaNmfSegmentSymbols = (ElfXX_Sym*)elftmp->relaNmfSegmentSymbols; + + for(rel_start = (ElfXX_Rela*)elftmp->relaNmfSegment; rel_start < (ElfXX_Rela*)elftmp->relaNmfSegmentEnd; rel_start++) + { + if((t_uint32)swapXword(rel_start->r_offset) == offsetInNmf) + { + int strtab_index = ELFXX_R_SYM(swapXword(rel_start->r_info)); + int sectionIdx = (int)swapHalf(relaNmfSegmentSymbols[strtab_index].st_shndx); + + memory->memory = ELF->sectionss[sectionIdx].meminfo; + + if(memory->memory != NULL) { + memory->offset = ( + ELF->sectionss[sectionIdx].offsetInSegment + // Offset in Segment + (t_uint32)swapXword(relaNmfSegmentSymbols[strtab_index].st_value) + // Offset in Elf Section + (t_uint32)swapXword(rel_start->r_addend)); // Addend + + return CM_OK; + } else { + const char* symbol_name = &elftmp->relaNmfSegmentStrings[swapWord(relaNmfSegmentSymbols[strtab_index].st_name)]; + ERROR("Symbol %s not found\n", symbol_name, 0, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; + } + } + } + + ERROR("Unknown relocation error\n", 0, 0, 0, 0, 0, 0); + return CM_INVALID_ELF_FILE; +} diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/mmdsp-debug.c b/drivers/staging/nmf-cm/cm/engine/elf/src/mmdsp-debug.c new file mode 100644 index 00000000000..0853e2d25b5 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/mmdsp-debug.c @@ -0,0 +1,287 @@ +/* + * 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/elf/inc/mmdsp-loadmap.h> +#include <cm/engine/elf/inc/mmdsp.h> +#include <cm/engine/dsp/inc/semaphores_dsp.h> +#include <cm/engine/dsp/mmdsp/inc/mmdsp_hwp.h> + +#include <cm/engine/power_mgt/inc/power.h> + +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/component/inc/component_type.h> +#include <inc/nmf-limits.h> + +#define LOADMAP_SEMAPHORE_USE_NB 7 + +static t_memory_handle headerHandle[NB_CORE_IDS] = {INVALID_MEMORY_HANDLE, }; +static struct LoadMapHdr *headerAddresses[NB_CORE_IDS] = {0, }; +static t_uint32 headerOffsets[NB_CORE_IDS] = {0, }; + +t_cm_error cm_DSPABI_AddLoadMap( + t_cm_domain_id domainId, + const char* templateName, + const char* localname, + t_memory_handle *memories, + void *componentHandle) +{ + t_nmf_core_id coreId = cm_DM_GetDomainCoreId(domainId); + + if (headerHandle[coreId] == 0) /* Create loadmap header */ + { + headerHandle[coreId] = cm_DM_Alloc(domainId, SDRAM_EXT16, + sizeof(struct LoadMapHdr)/2, CM_MM_ALIGN_2WORDS, TRUE); + if (headerHandle[coreId] == INVALID_MEMORY_HANDLE) + return CM_NO_MORE_MEMORY; + + headerAddresses[coreId] = (struct LoadMapHdr*)cm_DSP_GetHostLogicalAddress(headerHandle[coreId]); + + headerAddresses[coreId]->nMagicNumber = LOADMAP_MAGIC_NUMBER; + headerAddresses[coreId]->nVersion = (LOADMAP_VERSION_MSB<<8)|(LOADMAP_VERSION_LSB); + headerAddresses[coreId]->nRevision = 0; + headerAddresses[coreId]->pFirstItem = 0; + + //Register Header into XRAM:2 + cm_DSP_GetDspAddress(headerHandle[coreId], &headerOffsets[coreId]); + cm_DSP_WriteXRamWord(coreId, 2, headerOffsets[coreId]); + } + + // update Header nRevision field + headerAddresses[coreId]->nRevision++; + + /* + * Build loadmap entry + */ + { + t_memory_handle handle; + struct LoadMapItem* pItem; + t_uint32 dspentry; + unsigned char* pos; + t_uint32 fnlen, lnlen; + t_uint32 fnlenaligned, lnlenaligned; + t_uint32 address; + t_uint32 postStringLength; + int i; + + postStringLength = cm_StringLength(".elf", 16); + fnlenaligned = fnlen = cm_StringLength(templateName, MAX_COMPONENT_FILE_PATH_LENGTH) + postStringLength + 2; + if((fnlenaligned % 2) != 0) fnlenaligned++; + lnlenaligned = lnlen = cm_StringLength(localname, MAX_TEMPLATE_NAME_LENGTH); + if((lnlenaligned % 2) != 0) lnlenaligned++; + + // Allocate new loap map + handle = cm_DM_Alloc(domainId, SDRAM_EXT16, + sizeof(struct LoadMapItem)/2 + (1 + fnlenaligned/2) + (1 + lnlenaligned/2), + CM_MM_ALIGN_2WORDS, TRUE); + if (handle == INVALID_MEMORY_HANDLE) + return CM_NO_MORE_MEMORY; + + pItem = (struct LoadMapItem*)cm_DSP_GetHostLogicalAddress(handle); + cm_DSP_GetDspAddress(handle, &dspentry); + + // Link this new loadmap with the previous one + if(headerAddresses[coreId]->pFirstItem == NULL) + headerAddresses[coreId]->pFirstItem = (struct LoadMapItem *)dspentry; + else + { + struct LoadMapItem* curItem; + + curItem = headerAddresses[coreId]->pFirstItem; + curItem = (struct LoadMapItem*)(((t_uint32)curItem - headerOffsets[coreId]) * 2 + (t_uint32)headerAddresses[coreId]); // To ARM address + while(curItem->pNextItem != NULL) + { + curItem = curItem->pNextItem; + curItem = (struct LoadMapItem*)(((t_uint32)curItem - headerOffsets[coreId]) * 2 + (t_uint32)headerAddresses[coreId]); // To ARM address + } + curItem->pNextItem = (struct LoadMapItem *)dspentry; + } + + // DSP Address of the string at the end of the load map + pos = (unsigned char*)pItem + sizeof(struct LoadMapItem); + + /* + * Set SolibFilename address information + * -> string = "./origfilename" + */ + pItem->pSolibFilename = (char*)(dspentry + sizeof(struct LoadMapItem) / 2); + *(t_uint16*)pos = fnlen; + pos += 2; + *pos++ = '.'; + *pos++ = '\\'; + for(i = 0; i < fnlen - 2 - postStringLength; i++) + { + *pos++ = (templateName[i] == '.') ? '\\' : templateName[i]; + } + *pos++ = '.'; + *pos++ = 'e'; + *pos++ = 'l'; + *pos++ = 'f'; + // add padding if needed + if ((t_uint32)pos & 1) + *pos++ = '\0'; + + /* + * Set Component Name address information + */ + if (lnlen != 0) + { + pItem->pComponentName = (char*)(dspentry + sizeof(struct LoadMapItem) / 2 + 1 + fnlenaligned / 2); + + *(t_uint16*)pos = lnlen; + pos += 2; + for(i = 0; i < lnlenaligned; i++) + { + // If not aligned null ending copied + *pos++ = localname[i]; + } + } + else + { + pItem->pComponentName = 0; + } + + /* + * Set PROG information + */ + if(memories[CODE_MEMORY_INDEX] == INVALID_MEMORY_HANDLE) + address = 0; + else + cm_DSP_GetDspAddress(memories[CODE_MEMORY_INDEX], &address); + pItem->pAddrProg = (void*)address; + + /* + * Set ERAMCODE information + */ + if(memories[ECODE_MEMORY_INDEX] == INVALID_MEMORY_HANDLE) + address = 0; + else + cm_DSP_GetDspAddress(memories[ECODE_MEMORY_INDEX], &address); + pItem->pAddrEmbProg = (void*)address; + + /* + * Set THIS information + */ + if(memories[PRIVATE_DATA_MEMORY_INDEX] != INVALID_MEMORY_HANDLE) { + // Standard component + cm_DSP_GetDspAddress(memories[PRIVATE_DATA_MEMORY_INDEX], &address); + } else if(memories[SHARE_DATA_MEMORY_INDEX] != INVALID_MEMORY_HANDLE) { + // Singleton component where data are shared (simulate THIS with shared memory) + cm_DSP_GetDspAddress(memories[SHARE_DATA_MEMORY_INDEX], &address); + } else { + // Component without data (take unique identifier -> arbitrary take host component handle) + address = (t_uint32)componentHandle; + } + pItem->pThis = (void*)address; + + /* + * Set ARM THIS information + */ + pItem->pARMThis = componentHandle; + + /* + * Set Link to null (end of list) + */ + pItem->pNextItem = 0; + + /* + * Set XROM information + */ + if(memories[XROM_MEMORY_INDEX] == INVALID_MEMORY_HANDLE) + address = 0; + else + cm_DSP_GetDspAddress(memories[XROM_MEMORY_INDEX], &address); + pItem->pXROM = (void*)address; + + /* + * Set YROM information + */ + if(memories[YROM_MEMORY_INDEX] == INVALID_MEMORY_HANDLE) + address = 0; + else + cm_DSP_GetDspAddress(memories[YROM_MEMORY_INDEX], &address); + pItem->pYROM = (void*)address; + + /* + * Set memory handle (not used externally) + */ + pItem->memHandle = (void*)handle; + } + + OSAL_mb(); + + return CM_OK; +} + +t_cm_error cm_DSPABI_RemoveLoadMap( + t_cm_domain_id domainId, + const char* templateName, + t_memory_handle *memories, + const char* localname, + void *componentHandle) +{ + struct LoadMapItem* curItem, **prevItemReference; + t_nmf_core_id coreId = cm_DM_GetDomainCoreId(domainId); + + CM_ASSERT (headerHandle[coreId] != INVALID_MEMORY_HANDLE); + + /* parse list until we find this */ + prevItemReference = &headerAddresses[coreId]->pFirstItem; + curItem = *prevItemReference; + while(curItem != NULL) + { + curItem = (struct LoadMapItem*)(((t_uint32)curItem - headerOffsets[coreId]) * 2 + (t_uint32)headerAddresses[coreId]); // To ARM address + + if(curItem->pARMThis == componentHandle) + break; + + prevItemReference = &curItem->pNextItem; + curItem = *prevItemReference; + } + + + // Remove component from loadmap if founded + if(curItem != NULL) + { + /* take local semaphore */ + cm_DSP_SEM_Take(coreId,LOADMAP_SEMAPHORE_USE_NB); + + /* remove element from list */ + *prevItemReference = curItem->pNextItem; + + /* update nRevision field in header */ + headerAddresses[coreId]->nRevision++; + + /* If this is the last item, deallocate !!! */ + if(headerAddresses[coreId]->pFirstItem == NULL) + { + // Deallocate memory + cm_DM_Free(headerHandle[coreId], TRUE); + headerHandle[coreId] = INVALID_MEMORY_HANDLE; + + //Register Header into XRAM:2 + cm_DSP_WriteXRamWord(coreId, 2, 0); + } + + /* deallocate memory */ + cm_DM_Free((t_memory_handle)curItem->memHandle, TRUE); + + /* be sure memory is updated before releasing local semaphore */ + OSAL_mb(); + + /* release local semaphore */ + cm_DSP_SEM_Give(coreId,LOADMAP_SEMAPHORE_USE_NB); + } + else + { + ERROR("Component not in LoadMap %s, memory corruption????\n", localname, 0, 0, 0, 0, 0); + } + + return CM_OK; +} diff --git a/drivers/staging/nmf-cm/cm/engine/elf/src/mpcal.c b/drivers/staging/nmf-cm/cm/engine/elf/src/mpcal.c new file mode 100644 index 00000000000..93d910a5ed6 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/elf/src/mpcal.c @@ -0,0 +1,6 @@ +/* + * 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/elf/inc/mpcal.h> diff --git a/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h b/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h new file mode 100644 index 00000000000..3f995982088 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h @@ -0,0 +1,42 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_EE_MGT_H +#define __INC_EE_MGT_H + +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/dsp/inc/dsp.h> + +typedef struct { + t_component_instance *instance; + t_nmf_executive_engine_id executiveEngineId; + t_uint32 currentStackSize[NMF_SCHED_URGENT + 1]; + t_uint32 voidAddr; + t_uint32 traceState; + t_uint32 printLevel; + t_uint32 nbOfForceWakeup; +} t_ee_state; + +//TODO, juraj, this should be done more properly, like accessor method, instead making this global variable.. +extern t_ee_state eeState[NB_CORE_IDS]; + +/******************************************************************************/ +/************************ FUNCTIONS PROTOTYPES ********************************/ +/******************************************************************************/ + +PUBLIC t_cm_error cm_EEM_Init(t_nmf_core_id coreId, const char *eeName, t_nmf_executive_engine_id executiveEngineId); +PUBLIC void cm_EEM_Close(t_nmf_core_id coreId); +PUBLIC t_uint32 cm_EEM_isStackUpdateNeed(t_nmf_core_id coreId, t_nmf_ee_priority priority, t_uint32 isInstantiate, t_uint32 needMinStackSize); +PUBLIC t_cm_error cm_EEM_UpdateStack(t_nmf_core_id coreId, t_nmf_ee_priority priority, t_uint32 needMinStackSize, t_uint32 *pNewStackValue); +PUBLIC t_ee_state* cm_EEM_getExecutiveEngine(t_nmf_core_id coreId); +PUBLIC void cm_EEM_setTraceMode(t_nmf_core_id coreId, t_uint32 state); +PUBLIC void cm_EEM_setPrintLevel(t_nmf_core_id coreId, t_uint32 level); +t_cm_error cm_EEM_ForceWakeup(t_nmf_core_id coreId); +void cm_EEM_AllowSleep(t_nmf_core_id coreId); + +#endif /* __INC_EE_MGT_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/src/executive_engine_mgt.c b/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/src/executive_engine_mgt.c new file mode 100644 index 00000000000..14889ec6e4d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/executive_engine_mgt/src/executive_engine_mgt.c @@ -0,0 +1,349 @@ +/* + * 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. + */ +/*----------------------------------------------------------------------------* + * This module provides functions that allow to manage DSPs' Firmwares. * + ******************************************************************************/ + + +/******************************************************************* Includes + ****************************************************************************/ + +#include "../inc/executive_engine_mgt.h" +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/utils/inc/convert.h> +#include <cm/engine/component/inc/initializer.h> +#include <cm/engine/power_mgt/inc/power.h> +#include <cm/engine/perfmeter/inc/mpcload.h> + +#include <share/communication/inc/nmf_service.h> + +t_ee_state eeState[NB_CORE_IDS]; + +/****************************************************************** Functions + ****************************************************************************/ + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetExecutiveEngineHandle( + t_cm_domain_id domainId, + t_cm_instance_handle *executiveEngineHandle) +{ + t_nmf_core_id coreId; + + if (cm_DM_CheckDomain(domainId, DOMAIN_NORMAL) != CM_OK) { + return CM_INVALID_DOMAIN_HANDLE; + } + + coreId = cm_DM_GetDomainCoreId(domainId); + //in case someone ask for ee on component manager !!!! + if (coreId == ARM_CORE_ID) {*executiveEngineHandle = 0;} + else {*executiveEngineHandle = eeState[coreId].instance->instance;} + + return CM_OK; +} + +PUBLIC t_cm_error cm_EEM_Init( + t_nmf_core_id coreId, + const char *eeName, + t_nmf_executive_engine_id executiveEngineId) +{ + t_rep_component *pRepComponent; + t_cm_error error; + t_uint32 i; + + eeState[coreId].instance = (t_component_instance *)0; + eeState[coreId].executiveEngineId = executiveEngineId; + for(i = NMF_SCHED_BACKGROUND; i < NMF_SCHED_URGENT + 1;i++) + { + eeState[coreId].currentStackSize[i] = MIN_STACK_SIZE; + } + + // Try to load component file + if((error = cm_REP_lookupComponent(eeName, &pRepComponent)) != CM_OK) + { + if (error == CM_COMPONENT_NOT_FOUND) + ERROR("CM_COMPONENT_NOT_FOUND: Execution Engine %s\n", eeName, 0, 0, 0, 0, 0); + return error; + } + + // Set to 1 during bootstrap since MMDSP forceWakeup is to one also in order to not go in idle state + // while configuration not finish !!! + eeState[coreId].nbOfForceWakeup = 1; + + if ((error = cm_DSP_Boot(coreId)) != CM_OK) + return error; + + if((error = cm_instantiateComponent( + eeName, + cm_DSP_GetState(coreId)->domainEE, + NMF_SCHED_URGENT, + eeName, + pRepComponent->elfhandle, + &eeState[coreId].instance)) != CM_OK) + { + cm_DSP_Shutdown(coreId); + return error; + } + + /* Get Void Function */ + eeState[coreId].voidAddr = cm_getFunction(eeState[coreId].instance, "helper", "Void"); + + /* allocate xram space for stack */ + if (executiveEngineId == SYNCHRONOUS_EXECUTIVE_ENGINE) + { + error = cm_DSP_setStackSize(coreId, MIN_STACK_SIZE); + } + else + { + error = cm_DSP_setStackSize(coreId, (NMF_SCHED_URGENT + 1) * MIN_STACK_SIZE); + } + if (error != CM_OK) + { + cm_delayedDestroyComponent(eeState[coreId].instance); + eeState[coreId].instance = (t_component_instance *)0; + cm_DSP_Shutdown(coreId); + return error; + } + + /* allocate sdram memory to share perfmeters data */ + error = cm_PFM_allocatePerfmeterDataMemory(coreId, cm_DSP_GetState(coreId)->domainEE); + if (error != CM_OK) { + cm_delayedDestroyComponent(eeState[coreId].instance); + eeState[coreId].instance = (t_component_instance *)0; + cm_DSP_Shutdown(coreId); + return error; + } + + /* set initial stack value */ + cm_writeAttribute(eeState[coreId].instance, "rtos/scheduler/topOfStack", cm_DSP_getStackAddr(coreId)); + + /* set myCoreId for trace */ + cm_writeAttribute(eeState[coreId].instance, "xti/myCoreId", coreId - 1); + +#if defined(__STN_8500) && (__STN_8500 > 10) + /* set myCoreId for prcmu if exist */ + cm_writeAttribute(eeState[coreId].instance, "sleep/prcmu/myCoreId", coreId + 1); +#endif + + /* go go go ... */ + cm_DSP_Start(coreId); + + /* Waiting for End Of Boot */ + //TODO : remove infinite while loop + //TODO : to be paranoiac, add a read to serviceReasonOffset before starting core and check value is MPC_SERVICE_BOOT as it should be + { + while(cm_readAttributeNoError(eeState[coreId].instance, "rtos/commonpart/serviceReason") == MPC_SERVICE_BOOT) + { + volatile t_uint32 i; + for (i=0; i < 1000; i++); + } + } + + /* set some attributes after boot to avoid being erase by mmdsp boot */ + cm_writeAttribute(eeState[coreId].instance, "xti/traceActive", eeState[coreId].traceState); + cm_writeAttribute(eeState[coreId].instance, "rtos/commonpart/printLevel", eeState[coreId].printLevel); + + cm_DSP_ConfigureAfterBoot(coreId); + + return CM_OK; +} + +/****************************************************************************/ +/* NAME: cm_EEM_Close */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Inform us that ee for coreId has been destroyed */ +/* */ +/* PARAMETERS: id: dsp identifier */ +/* */ +/* RETURN: none */ +/* */ +/****************************************************************************/ +PUBLIC void cm_EEM_Close(t_nmf_core_id coreId) +{ + cm_DSP_setStackSize(coreId, 0); + cm_delayedDestroyComponent(eeState[coreId].instance); + eeState[coreId].instance = (t_component_instance *)0; + cm_PFM_deallocatePerfmeterDataMemory(coreId); + + cm_DSP_Shutdown(coreId); +} + +/****************************************************************************/ +/* NAME: cm_EEM_isStackUpdateNeed( */ +/* t_nmf_core_id id, */ +/* t_nmf_ee_priority priority, */ +/* t_uint32 isInstantiate, */ +/* t_uint32 needMinStackSize */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Return a boolean to inform if a ee stack size update is need*/ +/* when instantiate or destroying a component */ +/****************************************************************************/ +PUBLIC t_uint32 cm_EEM_isStackUpdateNeed( + t_nmf_core_id coreId, + t_nmf_ee_priority priority, + t_uint32 isInstantiate, + t_uint32 needMinStackSize) +{ + /* in case of SYNCHRONOUS_EXECUTIVE_ENGINE we only use currentStackSize[NMF_SCHED_BACKGROUND] */ + if (eeState[coreId].executiveEngineId == SYNCHRONOUS_EXECUTIVE_ENGINE) {priority = NMF_SCHED_BACKGROUND;} + if (isInstantiate) + { + if (needMinStackSize > eeState[coreId].currentStackSize[priority]) {return TRUE;} + } + else + { + if (needMinStackSize == eeState[coreId].currentStackSize[priority]) {return TRUE;} + } + + return FALSE; +} + +/****************************************************************************/ +/* NAME: cm_EEM_UpdateStack( */ +/* t_nmf_core_id id, */ +/* t_nmf_ee_priority priority, */ +/* t_uint32 needMinStackSize, */ +/* t_uint32 *pNewStackValue */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: If cm_EEM_isStackUpdateNeed() has return true then caller */ +/* must inform EEM about new stack value for priority. */ +/* cm_EEM_UpdateStack() will return new global stack size to */ +/* provide to ee. */ +/****************************************************************************/ +PUBLIC t_cm_error cm_EEM_UpdateStack( + t_nmf_core_id coreId, + t_nmf_ee_priority priority, + t_uint32 needMinStackSize, + t_uint32 *pNewStackValue) +{ + t_cm_error error; + t_uint32 recoveryStackSize = eeState[coreId].currentStackSize[priority]; + t_uint32 i; + + /* in case of SYNCHRONOUS_EXECUTIVE_ENGINE we only use currentStackSize[NMF_SCHED_BACKGROUND] */ + if (eeState[coreId].executiveEngineId == SYNCHRONOUS_EXECUTIVE_ENGINE) {priority = NMF_SCHED_BACKGROUND;} + eeState[coreId].currentStackSize[priority] = needMinStackSize; + if (eeState[coreId].executiveEngineId == SYNCHRONOUS_EXECUTIVE_ENGINE) {*pNewStackValue = needMinStackSize;} + else + { + *pNewStackValue = 0; + for(i = NMF_SCHED_BACKGROUND; i < NMF_SCHED_URGENT + 1;i++) + { + *pNewStackValue += eeState[coreId].currentStackSize[i]; + } + } + + /* try to increase size of stack by modifying xram allocator size */ + error = cm_DSP_setStackSize(coreId, *pNewStackValue); + if (error != CM_OK) { + eeState[coreId].currentStackSize[priority] = recoveryStackSize; + } else { + LOG_INTERNAL(1, "\n##### Stack update: size=%d, prio=%d on %s #####\n", *pNewStackValue, priority, cm_getDspName(coreId), 0, 0, 0); + } + + return error; +} + +/****************************************************************************/ +/* NAME: t_nmf_executive_engine_id( */ +/* t_nmf_core_id id */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: return executive engine load on id core. */ +/****************************************************************************/ +PUBLIC t_ee_state * cm_EEM_getExecutiveEngine(t_nmf_core_id coreId) +{ + return &eeState[coreId]; +} + +/****************************************************************************/ +/* NAME: cm_EEM_setTraceMode( */ +/* t_nmf_core_id id, */ +/* t_uint32 state */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: activate/deactivate trace for ee running on id. In case ee */ +/* is not yet load then information is store. */ +/****************************************************************************/ +PUBLIC void cm_EEM_setTraceMode(t_nmf_core_id coreId, t_uint32 state) +{ + eeState[coreId].traceState = state; + if (eeState[coreId].instance) + { + if(cm_EEM_ForceWakeup(coreId) == CM_OK) + { + cm_writeAttribute(eeState[coreId].instance, "xti/traceActive", eeState[coreId].traceState); + + cm_EEM_AllowSleep(coreId); + } + } +} + +/****************************************************************************/ +/* NAME: cm_EEM_setPrintLevel( */ +/* t_nmf_core_id id, */ +/* t_uint32 level */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: set print level for ee running on id. In case ee */ +/* is not yet load then information is store. */ +/****************************************************************************/ +PUBLIC void cm_EEM_setPrintLevel(t_nmf_core_id coreId, t_uint32 level) +{ + eeState[coreId].printLevel = level; + if (eeState[coreId].instance) + { + if(cm_EEM_ForceWakeup(coreId) == CM_OK) + { + cm_writeAttribute(eeState[coreId].instance, "rtos/commonpart/printLevel", eeState[coreId].printLevel); + + cm_EEM_AllowSleep(coreId); + } + } +} + +t_cm_error cm_EEM_ForceWakeup(t_nmf_core_id coreId) +{ + if(eeState[coreId].nbOfForceWakeup++ == 0) + { + t_cm_error error; + + LOG_INTERNAL(2, "ARM: Try to wake up\n", 0, 0, 0, 0, 0, 0); + + if (cm_DSP_GetState(coreId)->state != MPC_STATE_BOOTED) + { + return CM_MPC_NOT_RESPONDING; + } + else if ((error = cm_COMP_ULPForceWakeup(coreId)) != CM_OK) + { + if (error == CM_MPC_NOT_RESPONDING) { + ERROR("CM_MPC_NOT_RESPONDING: DSP %s can't be wakeup'ed\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + cm_DSP_SetStatePanic(coreId); + } + return error; + } + } + return CM_OK; +} + +void cm_EEM_AllowSleep(t_nmf_core_id coreId) +{ + if(--eeState[coreId].nbOfForceWakeup == 0) + { + LOG_INTERNAL(2, "ARM: Allow sleep\n", 0, 0, 0, 0, 0, 0); + + if (cm_DSP_GetState(coreId)->state != MPC_STATE_BOOTED) + { + } + else if (cm_COMP_ULPAllowSleep(coreId) != CM_OK) + { + ERROR("CM_MPC_NOT_RESPONDING: DSP %s can't be allow sleep'ed\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + } + } +} diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/chunk_mgr.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/chunk_mgr.h new file mode 100644 index 00000000000..340301a9259 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/chunk_mgr.h @@ -0,0 +1,41 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef CHUNK_MGR_H_ +#define CHUNK_MGR_H_ + +#include <cm/engine/memory/inc/remote_allocator.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +t_cm_error allocChunkPool(void); +t_cm_error fillChunkPool(void); +void freeChunkPool(void); + +/***************************************************************************/ +/* + * allocChunk + * param current : Pointer on chunck to free + * + * Add a chunk in the chunck list + * + */ +/***************************************************************************/ +t_cm_chunk* allocChunk(void); + +/***************************************************************************/ +/* + * freeChunk + * param current : Pointer on chunck to free + * + * Remove a chunk in the chunck list + * + */ +/***************************************************************************/ +void freeChunk(t_cm_chunk *chunk); + +#endif /*CHUNK_MGR_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/domain.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/domain.h new file mode 100644 index 00000000000..bf75915c259 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/domain.h @@ -0,0 +1,154 @@ +/* + * 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. + */ +/***************************************************************************/ +/* file : domain.h + * author : NMF team + * version : 1.0 + * + * brief : NMF domain definitions + */ +/***************************************************************************/ + +#ifndef DOMAIN_H_ +#define DOMAIN_H_ + +#include <cm/inc/cm_type.h> +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/dsp/inc/dsp.h> + +/*! + * \brief Domain type. + * \internal + * \ingroup CM_DOMAIN_API + */ +typedef enum { + DOMAIN_ANY = 0, + DOMAIN_NORMAL, + DOMAIN_SCRATCH_PARENT, + DOMAIN_SCRATCH_CHILD +} t_cm_domain_type; + +/*! + * \brief Domain descriptor. Holds offsets for all memory types present in the system. + * \internal + * \ingroup CM_DOMAIN_API + */ +typedef struct { + t_cm_domain_memory domain; // the actual memory ranges + t_cm_domain_type type; // domain type + t_uint32 refcount; // reference counter for scratch domain dependencies + t_nmf_client_id client; // client id for cleaning + + union { + struct { + t_memory_handle handle; // memory handle of the allocated chunk the covers the esram-data scratch region + } parent; + struct { + t_cm_allocator_desc *alloc; //allocator descriptor for the scratch domain + t_cm_domain_id parent_ref; //parent domain reference + } child; + } scratch; +} t_cm_domain_desc; + +#ifdef DEBUG +#define DOMAIN_DEBUG(handle) \ + handle = handle & ~0xc0; +#else +#define DOMAIN_DEBUG(handle) +#endif + +/*! + * \brief Domain descriptor array. + */ +extern t_cm_domain_desc domainDesc[]; + +typedef struct { + t_cm_domain_id parentId; + t_cm_domain_id domainId; + t_cm_allocator_desc *allocDesc; +} t_cm_domain_scratch_desc; + +extern t_cm_domain_scratch_desc domainScratchDesc[]; + +typedef struct { + t_cm_system_address sdramCode; + t_cm_system_address sdramData; + t_cm_system_address esramCode; + t_cm_system_address esramData; +} t_cm_domain_info; + +/*! + * \brief Init of the domain subsystem. + */ +PUBLIC t_cm_error cm_DM_Init(void); + +/*! + * \brief Clean-up of the domain subsystem. + */ +PUBLIC void cm_DM_Destroy(void); + +/*! + * \brief Domain creation. + * + * Allocates in slot in the domain descriptors array and copies segment infos from the domain + * parameter to the descriptor. The resulting handle is returned via @param handle. + * + * Returns: CM_DOMAIN_INVALID in case of error, otherwise CM_OK. + */ +PUBLIC t_cm_error cm_DM_CreateDomain(const t_nmf_client_id client, const t_cm_domain_memory *domain, t_cm_domain_id *handle); + +/*! + * \brief Scratch (or overlap) domain creation. + * + * Create a scratch domain, ie domain where allocation may overlap. + */ +PUBLIC t_cm_error cm_DM_CreateDomainScratch(const t_nmf_client_id client, const t_cm_domain_id parentId, const t_cm_domain_memory *domain, t_cm_domain_id *handle); + +/* ! + * \brief Retrieve the coreId from a given domain. Utility. + */ +PUBLIC t_nmf_core_id cm_DM_GetDomainCoreId(const t_cm_domain_id domainId); + +/*! + * \brief Destroy all domains belonging to a given client. + */ +PUBLIC t_cm_error cm_DM_DestroyDomains(const t_nmf_client_id client); + +/*! + * \brief Destroy a given domain. + */ +PUBLIC t_cm_error cm_DM_DestroyDomain(t_cm_domain_id handle); + +/*! + * \brief Check if the handle is valid. + */ +PUBLIC t_cm_error cm_DM_CheckDomain(t_cm_domain_id handle, t_cm_domain_type type); +PUBLIC t_cm_error cm_DM_CheckDomainWithClient(t_cm_domain_id handle, t_cm_domain_type type, t_nmf_client_id client); + +/*! + * \brief Memory allocation in a given domain, for a given memory type (see CM_AllocMpcMemory). + */ +PUBLIC t_memory_handle cm_DM_Alloc(t_cm_domain_id domainId, t_dsp_memory_type_id memType, t_uint32 size, t_cm_mpc_memory_alignment memAlignment, t_bool powerOn); + +/*! + * \brief Memory free using a given domain handle + */ +PUBLIC void cm_DM_FreeWithInfo(t_memory_handle memHandle, t_nmf_core_id *coreId, t_dsp_memory_type_id *memType, t_bool powerOff); + +/*! + * \brief Memory free using a given domain handle + */ +PUBLIC void cm_DM_Free(t_memory_handle memHandle, t_bool powerOff); + +/*! + * \brief Wrapper function for CM_GetMpcMemoryStatus. + */ +PUBLIC t_cm_error cm_DM_GetAllocatorStatus(t_cm_domain_id domainId, t_dsp_memory_type_id memType, t_cm_allocator_status *pStatus); + +PUBLIC t_cm_error cm_DM_GetDomainAbsAdresses(t_cm_domain_id domainId, t_cm_domain_info *info); + +#endif /* DOMAIN_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/domain_type.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/domain_type.h new file mode 100644 index 00000000000..712d077d894 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/domain_type.h @@ -0,0 +1,61 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/***************************************************************************/ +/* file : domain.h + * author : NMF team + * version : 1.0 + * + * brief : NMF domain definitions + */ +/***************************************************************************/ + +#ifndef DOMAIN_TYPE_H_ +#define DOMAIN_TYPE_H_ + +#include <cm/inc/cm_type.h> +#include <cm/engine/memory/inc/memory_type.h> + +/*! + * \brief Domain identifier + * \ingroup CM_DOMAIN_API + */ +typedef t_uint8 t_cm_domain_id; + +/*! + * \brief Client identifier + * 0 (zero) is considered as an invalid or 'NO' client identifier + * \ingroup CM_DOMAIN_API + */ +typedef t_uint32 t_nmf_client_id; +// TO BE REMOVED LATER, I guess, when default domains will be removed (PP) +#define NMF_CORE_CLIENT (t_nmf_client_id)-1 +#define NMF_CURRENT_CLIENT (t_nmf_client_id)0 + +typedef struct { + t_uint32 offset; //!< offset relativ to segment start in memory (in bytes) + t_uint32 size; //!< size in bytes of the domain segment +} t_cm_domain_segment; + +/*! + * \brief Domain memory description structure + * \ingroup CM_DOMAIN_API + */ +typedef struct { + t_nmf_core_id coreId; //!< MMDSP Core Id for this domain (used for TCM-X and TCM-Y at instantiate) + t_cm_domain_segment esramCode; //!< ESRAM code segment + t_cm_domain_segment esramData; //!< ESRAM data segment + t_cm_domain_segment sdramCode; //!< SDRAM code segment + t_cm_domain_segment sdramData; //!< SDRAM data segment +} t_cm_domain_memory; + +#define INIT_DOMAIN_SEGMENT {0, 0} +#define INIT_DOMAIN {MASK_ALL8, INIT_DOMAIN_SEGMENT, INIT_DOMAIN_SEGMENT, INIT_DOMAIN_SEGMENT, INIT_DOMAIN_SEGMENT} + + +#endif /* DOMAIN_TYPE_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/memory.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/memory.h new file mode 100644 index 00000000000..c6d1fb2dfff --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/memory.h @@ -0,0 +1,19 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Internal Memory Management API. + * + * \defgroup MEMORY_INTERNAL Private Memory API. + * + */ +#ifndef __INC_MEMORY_H +#define __INC_MEMORY_H + +#include <cm/engine/api/control/configuration_engine.h> +#include <cm/engine/memory/inc/remote_allocator.h> + +#endif /* __INC_MEMORY_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/memory_type.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/memory_type.h new file mode 100644 index 00000000000..91246f1ec0e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/memory_type.h @@ -0,0 +1,152 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Public Component Manager Memory API type. + * + * This file contains the Component Manager API type for manipulating memory. + */ +#ifndef __INC_MEMORY_TYPE_H +#define __INC_MEMORY_TYPE_H + +#include <cm/inc/cm_type.h> + +/*! + * @defgroup t_cm_mpc_memory_type t_cm_mpc_memory_type + * \brief Definition of symbols used to reference the various type of Media Processor Core adressable memory + * @{ + * \ingroup MEMORY + */ +typedef t_uint8 t_cm_mpc_memory_type; //!< Fake enumeration type +#define CM_MM_MPC_TCM16_X ((t_cm_mpc_memory_type)0) +#define CM_MM_MPC_TCM24_X ((t_cm_mpc_memory_type)1) +#define CM_MM_MPC_ESRAM16 ((t_cm_mpc_memory_type)2) +#define CM_MM_MPC_ESRAM24 ((t_cm_mpc_memory_type)3) +#define CM_MM_MPC_SDRAM16 ((t_cm_mpc_memory_type)4) +#define CM_MM_MPC_SDRAM24 ((t_cm_mpc_memory_type)5) +#define CM_MM_MPC_TCM16_Y ((t_cm_mpc_memory_type)6) +#define CM_MM_MPC_TCM24_Y ((t_cm_mpc_memory_type)7) +#define CM_MM_MPC_TCM16 CM_MM_MPC_TCM16_X +#define CM_MM_MPC_TCM24 CM_MM_MPC_TCM24_X + +/* @} */ + +/*! + * @defgroup t_cm_memory_alignment t_cm_memory_alignment + * \brief Definition of symbols used to constraint the alignment of the allocated memory + * @{ + * \ingroup MEMORY + */ +typedef t_uint16 t_cm_memory_alignment; //!< Fake enumeration type +#define CM_MM_ALIGN_NONE ((t_cm_memory_alignment)0x00000000) +#define CM_MM_ALIGN_BYTE ((t_cm_memory_alignment)CM_MM_ALIGN_NONE) +#define CM_MM_ALIGN_HALFWORD ((t_cm_memory_alignment)0x00000001) +#define CM_MM_ALIGN_WORD ((t_cm_memory_alignment)0x00000003) +#define CM_MM_ALIGN_2WORDS ((t_cm_memory_alignment)0x00000007) +#define CM_MM_ALIGN_16BYTES ((t_cm_memory_alignment)0x0000000F) +#define CM_MM_ALIGN_4WORDS ((t_cm_memory_alignment)0x0000000F) +#define CM_MM_ALIGN_AHB_BURST ((t_cm_memory_alignment)0x0000000F) +#define CM_MM_ALIGN_32BYTES ((t_cm_memory_alignment)0x0000001F) +#define CM_MM_ALIGN_8WORDS ((t_cm_memory_alignment)0x0000001F) +#define CM_MM_ALIGN_64BYTES ((t_cm_memory_alignment)0x0000003F) +#define CM_MM_ALIGN_16WORDS ((t_cm_memory_alignment)0x0000003F) +#define CM_MM_ALIGN_128BYTES ((t_cm_memory_alignment)0x0000007F) +#define CM_MM_ALIGN_32WORDS ((t_cm_memory_alignment)0x0000007F) +#define CM_MM_ALIGN_256BYTES ((t_cm_memory_alignment)0x000000FF) +#define CM_MM_ALIGN_64WORDS ((t_cm_memory_alignment)0x000000FF) +#define CM_MM_ALIGN_512BYTES ((t_cm_memory_alignment)0x000001FF) +#define CM_MM_ALIGN_128WORDS ((t_cm_memory_alignment)0x000001FF) +#define CM_MM_ALIGN_1024BYTES ((t_cm_memory_alignment)0x000003FF) +#define CM_MM_ALIGN_256WORDS ((t_cm_memory_alignment)0x000003FF) +#define CM_MM_ALIGN_2048BYTES ((t_cm_memory_alignment)0x000007FF) +#define CM_MM_ALIGN_512WORDS ((t_cm_memory_alignment)0x000007FF) +#define CM_MM_ALIGN_4096BYTES ((t_cm_memory_alignment)0x00000FFF) +#define CM_MM_ALIGN_1024WORDS ((t_cm_memory_alignment)0x00000FFF) +#define CM_MM_ALIGN_65536BYTES ((t_cm_memory_alignment)0x0000FFFF) +#define CM_MM_ALIGN_16384WORDS ((t_cm_memory_alignment)0x0000FFFF) +/* @} */ + +/*! + * @defgroup t_cm_mpc_memory_alignment t_cm_mpc_memory_alignment + * \brief Definition of symbols used to constraint the alignment of the allocated mpc memory + * @{ + * \ingroup MEMORY + */ +typedef t_uint16 t_cm_mpc_memory_alignment; //!< Fake enumeration type +#define CM_MM_MPC_ALIGN_NONE ((t_cm_mpc_memory_alignment)0x00000000) +#define CM_MM_MPC_ALIGN_HALFWORD ((t_cm_mpc_memory_alignment)0x00000001) +#define CM_MM_MPC_ALIGN_WORD ((t_cm_mpc_memory_alignment)0x00000003) +#define CM_MM_MPC_ALIGN_2WORDS ((t_cm_mpc_memory_alignment)0x00000007) +#define CM_MM_MPC_ALIGN_4WORDS ((t_cm_mpc_memory_alignment)0x0000000F) +#define CM_MM_MPC_ALIGN_8WORDS ((t_cm_mpc_memory_alignment)0x0000001F) +#define CM_MM_MPC_ALIGN_16WORDS ((t_cm_mpc_memory_alignment)0x0000003F) +#define CM_MM_MPC_ALIGN_32WORDS ((t_cm_mpc_memory_alignment)0x0000007F) +#define CM_MM_MPC_ALIGN_64WORDS ((t_cm_mpc_memory_alignment)0x000000FF) +#define CM_MM_MPC_ALIGN_128WORDS ((t_cm_mpc_memory_alignment)0x000001FF) +#define CM_MM_MPC_ALIGN_256WORDS ((t_cm_mpc_memory_alignment)0x000003FF) +#define CM_MM_MPC_ALIGN_512WORDS ((t_cm_mpc_memory_alignment)0x000007FF) +#define CM_MM_MPC_ALIGN_1024WORDS ((t_cm_mpc_memory_alignment)0x00000FFF) +#define CM_MM_MPC_ALIGN_65536BYTES ((t_cm_mpc_memory_alignment)0x0000FFFF) +#define CM_MM_MPC_ALIGN_16384WORDS ((t_cm_mpc_memory_alignment)0x0000FFFF) +/* @} */ + +/*! + * \brief Identifier of a memory handle + * \ingroup MEMORY + */ +typedef t_uint32 t_cm_memory_handle; + +/*! + * \brief Description of a memory segment + * + * <=> allocable addressable space + * \ingroup MEMORY + */ +typedef struct { + t_cm_system_address systemAddr; //!< Logical AND physical segment start address + t_uint32 size; //!< segment size (in bytes) +} t_nmf_memory_segment; +#define INIT_MEMORY_SEGMENT {{0, 0}, 0} + +/*! + * \brief Definition of structure used for an allocator status + * \ingroup MEMORY + */ +typedef struct +{ + struct { + t_uint32 size; //!< size of the allocator + /* Block counters */ + t_uint16 used_block_number; //!< used block number + t_uint16 free_block_number; //!< free block number + + /* Free memory min/max */ + t_uint32 maximum_free_size; //!< maximum free size + t_uint32 minimum_free_size; //!< minimum free size + + /* Accumulation of free and used memory */ + t_uint32 accumulate_free_memory; //!< accumulate free memory + t_uint32 accumulate_used_memory; //!< accumulate used memory + } global; + + struct { + t_uint32 size; //!< size of the domain + t_uint32 maximum_free_size; //!< maximum free size in the given domain + t_uint32 minimum_free_size; //!< minimum free size in the given domain + t_uint32 accumulate_free_memory; //all free memory of the given domain + t_uint32 accumulate_used_memory; //all used memory of the given domain + } domain; + + struct { + t_uint32 sizes[3]; + } stack[NB_CORE_IDS]; + +} t_cm_allocator_status; + +#endif /* __INC_MEMORY_TYPE_H */ + diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/migration.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/migration.h new file mode 100644 index 00000000000..824d25374b3 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/migration.h @@ -0,0 +1,32 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Migration API. + * + * \defgroup + * + */ +#ifndef __INC_MIGRATION_H +#define __INC_MIGRATION_H + +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/dsp/inc/dsp.h> + +typedef enum { + STATE_MIGRATED = 1, + STATE_NORMAL = 0, +} t_cm_migration_state; + +PUBLIC t_cm_error cm_migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst); + +PUBLIC t_cm_error cm_unmigrate(void); + +PUBLIC t_uint32 cm_migration_translate(t_dsp_segment_type segmentType, t_uint32 addr); + +PUBLIC void cm_migration_check_state(t_nmf_core_id coreId, t_cm_migration_state expected); + +#endif /* __INC_MIGRATION_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator.h new file mode 100644 index 00000000000..e639c94cb46 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator.h @@ -0,0 +1,262 @@ +/* + * 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. + */ +/** + * \internal + * + * \note: In this module, we assume that parameters were checked !! + */ +#ifndef __REMOTE_ALLOCATOR_H_ +#define __REMOTE_ALLOCATOR_H_ + +/* + * Include + */ +#include <cm/inc/cm_type.h> +#include <cm/engine/memory/inc/memory_type.h> + + +/* + * Description of the memory block status + */ +typedef enum { + MEM_USED = 0, /* Memory block is used */ + MEM_FREE = 1 /* Memory block is free */ +} t_mem_status; + +/* + * Chunk structure. + */ +struct cm_allocator_desc; +typedef struct chunk_struct +{ + /* Double linked list of chunks */ + struct chunk_struct *prev; + struct chunk_struct *next; + + /* Double linked list of free memory */ + struct chunk_struct *prev_free_mem; + struct chunk_struct *next_free_mem; + + /* Offset of the block memory */ + t_uint32 offset; + + /* Size of the block memory */ + t_cm_size size; + + /* Status of the block memory */ + t_mem_status status; + + /* User data */ + t_uint16 userData; + + /* Alloc debug info*/ + t_uint32 domainId; + + /* Alloc desc backlink */ + struct cm_allocator_desc *alloc; +} t_cm_chunk; + +/*! + * \brief Identifier of an internal memory handle + * \ingroup MEMORY_INTERNAL + */ +typedef t_cm_chunk* t_memory_handle; + +#define INVALID_MEMORY_HANDLE ((t_cm_chunk*)NULL) + + +/* + * Context structure + */ +#define BINS 63 + +//TODO, juraj, add memType to alloc struct ? +typedef struct cm_allocator_desc { + const char *pAllocName; /* Name of the allocator */ + t_uint32 size; /* Size of the allocator */ + t_cm_chunk *chunks; /* Array of chunk */ + t_cm_chunk *free_mem_chunks[BINS]; /* List of free memory */ + struct cm_allocator_desc* next; /* List of allocator */ +} t_cm_allocator_desc; + +int bin_index(unsigned int sz); + +/* + * Functions + */ +/*! + * \brief Create a new allocator for a piece of memory (hw mapped (xram, yram)) + * Any further allocation into this piece of memory will return an offset inside it. + * (a constant offset value can be added to this offset) + * + * \retval t_cm_allocator_desc* new memory allocator identifier + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_cm_allocator_desc* cm_MM_CreateAllocator( + t_cm_size size, //!< [in] Size of the addressable space in bytes + t_uint32 offset, //!< [in] Constant offset to add to each allocated block base address + const char* name //!< [in] Name of the allocator + ); + +/*! + * \brief Free a memory allocator descriptor + * + * \retval t_cm_error + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_cm_error cm_MM_DeleteAllocator( + t_cm_allocator_desc* alloc //!< [in] Identifier of the memory allocator to be freed + ); + + +/*! + * \brief Resize an allocator to the size value. + * + * \retval t_cm_error + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_cm_error cm_MM_ResizeAllocator( + t_cm_allocator_desc* alloc, //!< [in] Identifier of the memory allocator used to allocate the piece of memory + t_cm_size size //!< [in] Size of the addressable space in allocDesc granularity + ); + +/*! + * \brief Check validity of a user handle + */ +t_cm_error cm_MM_getValidMemoryHandle(t_cm_memory_handle handle, t_memory_handle* validHandle); + +/*! + * \brief Wrapper routine to allocate some memory into a given allocator + * + * \retval t_memory_handle handle on the new allocated piece of memory + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_memory_handle cm_MM_Alloc( + t_cm_allocator_desc* alloc, //!< [in] Identifier of the memory allocator + t_cm_size size, //!< [in] Size of the addressable space + t_cm_memory_alignment memAlignment, //!< [in] Alignment constraint + t_uint32 seg_offset, //!< [in] Offset of range where allocating + t_uint32 seg_size, //!< [in] Size of range where allocating + t_uint32 domainId + ); + + +/*! + * \brief Routine to reallocate memory for a given handle + * + * Routine to reallocate memory for a given handle. The chunk can be extended or shrinked in both + * directions - top and bottom, depending on the offset and size arguments. + * + * \retval t_memory_handle handle on the reallocated piece of memory + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_memory_handle cm_MM_Realloc( + t_cm_allocator_desc* alloc, + const t_cm_size size, + const t_uint32 offset, + const t_cm_memory_alignment memAlignment, + const t_memory_handle handle); +/*! + * \brief Frees the allocated chunk + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC void cm_MM_Free( + t_cm_allocator_desc* alloc, //!< [in] Identifier of the memory allocator + t_memory_handle memHandle //!< [in] Memory handle to free + ); + + +/*! + * \brief Get the allocator status + * + * \param[in] alloc Identifier of the memory allocator + * \param[out] pStatus Status of the allocator + * + * \retval t_cm_error + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_cm_error cm_MM_GetAllocatorStatus(t_cm_allocator_desc* alloc, t_uint32 offset, t_uint32 size, t_cm_allocator_status *pStatus); + +/*! + * \brief Returns the offset into a given memory allocator of an allocated piece of memory + * + * \param[in] memHandle handle on the given memory + * + * \retval t_uint32 offset into the given memory allocator + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_uint32 cm_MM_GetOffset(t_memory_handle memHandle); + + +/*! + * \brief Returns the size in word size for a given memory allocator of an allocated piece of memory + * + * \param[in] memHandle handle on the given memory + * + * \retval t_uint32 size in wordsize for the given memory allocator + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_uint32 cm_MM_GetSize(t_memory_handle memHandle); + +/*! + * \brief Returns the size in bytes for a given memory allocator + * + * \param[in] allocDesc Identifier of the memory allocator + * \retval size + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC t_uint32 cm_MM_GetAllocatorSize(t_cm_allocator_desc* allocDesc); + + +/*! + * \brief Set the user data of an allocated piece of memory + * + * \param[in] memHandle handle on the given memory + * \param[in] userData UsedData of the given memory piece + * + * \retval t_cm_error + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC void cm_MM_SetMemoryHandleUserData (t_memory_handle memHandle, t_uint16 userData); + + +/*! + * \brief Return the user data of an allocated piece of memory + * + * \param[in] memHandle handle on the given memory + * \param[out] pUserData returned UsedData of the given memory piece + * + * \retval t_cm_error + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC void cm_MM_GetMemoryHandleUserData(t_memory_handle memHandle, t_uint16 *pUserData, t_cm_allocator_desc **alloc); + +/*! + * \brief Dump chunkd in the range of [start:end] + * + * \param[in] alloc Allocator descriptor + * \param[in] start Range start + * \param[in] end Range end + * + * \retval void + * + * \ingroup MEMORY_INTERNAL + */ +PUBLIC void cm_MM_DumpMemory(t_cm_allocator_desc* alloc, t_uint32 start, t_uint32 end); + +#endif /* _REMOTE_ALLOCATOR_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator_utils.h b/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator_utils.h new file mode 100644 index 00000000000..ce99e4d7a94 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/inc/remote_allocator_utils.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef REMOTE_ALLOCATOR_UTILS_H_ +#define REMOTE_ALLOCATOR_UTILS_H_ + +#include <cm/engine/memory/inc/remote_allocator.h> +#include <cm/engine/memory/inc/chunk_mgr.h> + +typedef enum { + FREE_CHUNK_BEFORE, + FREE_CHUNK_AFTER, +} t_mem_split_position; + + +PUBLIC void updateFreeList(t_cm_allocator_desc* alloc, t_cm_chunk* chunk); + +PUBLIC void linkChunk(t_cm_chunk* prev,t_cm_chunk* add); +PUBLIC void unlinkChunk(t_cm_allocator_desc* alloc,t_cm_chunk* current); + +PUBLIC void unlinkFreeMem(t_cm_allocator_desc* alloc,t_cm_chunk* current); +PUBLIC void linkFreeMemBefore(t_cm_chunk* add, t_cm_chunk* next); +PUBLIC void linkFreeMemAfter(t_cm_chunk* prev,t_cm_chunk* add); + +PUBLIC void mergeChunk(t_cm_allocator_desc* alloc,t_cm_chunk *c,t_cm_chunk *destroy); +PUBLIC t_cm_chunk* splitChunk(t_cm_allocator_desc* alloc, t_cm_chunk *chunk, t_uint32 offset, t_mem_split_position position); + +#endif /*REMOTE_ALLOCATOR_UTILS_H_*/ diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/chunk_mgr.c b/drivers/staging/nmf-cm/cm/engine/memory/src/chunk_mgr.c new file mode 100644 index 00000000000..26c00cdeb77 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/chunk_mgr.c @@ -0,0 +1,94 @@ +/* + * 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 + */ +#include <cm/inc/cm_type.h> +#include "../inc/chunk_mgr.h" +#include <cm/engine/trace/inc/trace.h> + +#define CHUNKS_PER_PAGE 500 +#define CHUNK_THRESOLD 5 + +struct t_page_chuncks { + struct t_page_chuncks *nextPage; + // unsigned int freeChunkInPage; + t_cm_chunk chunks[CHUNKS_PER_PAGE]; +}; + +static struct t_page_chuncks *firstPage; + +static unsigned int freeChunks; +static t_cm_chunk *firstFreeChunk; + +t_cm_chunk* allocChunk() +{ + t_cm_chunk* chunk = firstFreeChunk; + + firstFreeChunk = chunk->next; + + chunk->next_free_mem = 0; + chunk->prev_free_mem = 0; + chunk->prev = 0; + chunk->next = 0; + chunk->status = MEM_FREE; + // chunk->offset = 0; + // chunk->size = 0; + // chunk->alloc = 0; + // chunk->userData = 0; + + freeChunks--; + + return chunk; +} + +void freeChunk(t_cm_chunk* chunk) +{ + // Link chunk in free list + chunk->next = firstFreeChunk; + firstFreeChunk = chunk; + + // Increase counter + freeChunks++; +} + +t_cm_error allocChunkPool(void) +{ + struct t_page_chuncks* newPage; + int i; + + newPage = (struct t_page_chuncks*)OSAL_Alloc(sizeof(struct t_page_chuncks)); + if(newPage == NULL) + return CM_NO_MORE_MEMORY; + + // Link page + newPage->nextPage = firstPage; + firstPage = newPage; + + // Put chunk in free list + for(i = 0; i < CHUNKS_PER_PAGE; i++) + freeChunk(&newPage->chunks[i]); + + return CM_OK; +} + +t_cm_error fillChunkPool(void) +{ + if(freeChunks < CHUNK_THRESOLD) + return allocChunkPool(); + + return CM_OK; +} + +void freeChunkPool(void) +{ + while(firstPage != NULL) + { + struct t_page_chuncks* tofree = firstPage; + firstPage = firstPage->nextPage; + OSAL_Free(tofree); + } +} diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/domain.c b/drivers/staging/nmf-cm/cm/engine/memory/src/domain.c new file mode 100644 index 00000000000..61cb25b39ec --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/domain.c @@ -0,0 +1,590 @@ +/* + * 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 <inc/nmf-limits.h> + +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/memory/inc/migration.h> +#include <cm/engine/memory/inc/chunk_mgr.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/power_mgt/inc/power.h> + +/* + * domain_memory structure is all we need + */ +#define MAX_USER_DOMAIN_NB 64 +#define MAX_SCRATCH_DOMAIN_NB 16 + +t_cm_domain_desc domainDesc[MAX_USER_DOMAIN_NB]; +t_cm_domain_scratch_desc domainScratchDesc[MAX_SCRATCH_DOMAIN_NB]; + +static t_cm_allocator_desc *cm_DM_getAllocator(t_cm_domain_id domainId, t_dsp_memory_type_id memType); +static void cm_DM_DomainError(const t_cm_domain_id parentId, const t_nmf_client_id client); + +#define INIT_DOMAIN_STRUCT(domainDesc) do { \ + domainDesc.client = 0; \ + domainDesc.type = DOMAIN_NORMAL; \ + domainDesc.refcount = 0; \ + domainDesc.domain.coreId = MASK_ALL8; \ + domainDesc.domain.esramCode.offset = 0; \ + domainDesc.domain.esramCode.size = 0; \ + domainDesc.domain.esramData.offset = 0; \ + domainDesc.domain.esramData.size = 0; \ + domainDesc.domain.sdramCode.offset = 0; \ + domainDesc.domain.sdramCode.size = 0; \ + domainDesc.domain.sdramData.offset = 0; \ + domainDesc.domain.sdramData.size = 0; \ + domainDesc.scratch.parent.handle = 0; \ + domainDesc.scratch.child.alloc = 0; \ + domainDesc.scratch.child.parent_ref = 0; \ + } while (0) + +#define FIND_DOMAIN_ID(domainId) \ + { \ + domainId = 0; \ + while (domainDesc[domainId].client != 0 && domainId < MAX_USER_DOMAIN_NB) { \ + domainId++; \ + } \ + if (domainId >= MAX_USER_DOMAIN_NB) { \ + return CM_INTERNAL_DOMAIN_OVERFLOW; \ + } \ + } + +#define FIND_SCRATCH_DOMAIN_ID(domainId) \ + { \ + domainId = 0; \ + while (domainScratchDesc[domainId].allocDesc != 0 && domainId < MAX_SCRATCH_DOMAIN_NB) { \ + domainId++; \ + } \ + if (domainId >= MAX_SCRATCH_DOMAIN_NB) { \ + return CM_INTERNAL_DOMAIN_OVERFLOW; \ + } \ + } + +PUBLIC t_cm_error cm_DM_CheckDomain(t_cm_domain_id handle, t_cm_domain_type type) +{ + if ((handle <= 3) + || (handle >= MAX_USER_DOMAIN_NB)) { //remember, domain[0-3] are reserved + return CM_INVALID_DOMAIN_HANDLE; + } + + if (domainDesc[handle].client == 0) { + return CM_INVALID_DOMAIN_HANDLE; + } + + if (type != DOMAIN_ANY) { + if (domainDesc[handle].type != type) { + return CM_INVALID_DOMAIN_HANDLE; + } + } + + return CM_OK; +} + +PUBLIC t_cm_error cm_DM_CheckDomainWithClient(t_cm_domain_id handle, t_cm_domain_type type, t_nmf_client_id client) +{ + t_cm_error error; + + if((error = cm_DM_CheckDomain(handle, type)) != CM_OK) + return error; + +#ifdef CHECK_TO_BE_REACTIVATED_IN_2_11 + if(domainDesc[handle].client != client) + { + ERROR("CM_DOMAIN_VIOLATION: domain %d created by client %d not usable by client %d.", handle, domainDesc[handle].client, client, 0, 0, 0); + return CM_DOMAIN_VIOLATION; + } +#endif + + return CM_OK; +} + +PUBLIC t_cm_error cm_DM_Init(void) +{ + t_cm_error error; + + int i = 0; + for(i = 0; i < MAX_USER_DOMAIN_NB; i++) { + INIT_DOMAIN_STRUCT(domainDesc[i]); + } + + //domains[0-3] are reserved - allows to catch some cases of incorrect usage, + //especially when user uses coreId instead of domainId, ie id = 1, 2, 3 + domainDesc[0].client = NMF_CORE_CLIENT; + domainDesc[1].client = NMF_CORE_CLIENT; + domainDesc[2].client = NMF_CORE_CLIENT; + domainDesc[3].client = NMF_CORE_CLIENT; + + for(i = 0; i < MAX_SCRATCH_DOMAIN_NB; i++) { + domainScratchDesc[i].domainId = 0; + domainScratchDesc[i].parentId = 0; + domainScratchDesc[i].allocDesc = 0; + } + + // Alloc twice for having comfortable chunk + if((error = allocChunkPool()) != CM_OK) + return error; + if((error = allocChunkPool()) != CM_OK) + { + freeChunkPool(); + return error; + } + + return CM_OK; +} + +PUBLIC void cm_DM_Destroy(void) +{ + //cm_DM_Init(); + freeChunkPool(); +} + +PUBLIC t_nmf_core_id cm_DM_GetDomainCoreId(const t_cm_domain_id domainId) +{ + + return domainDesc[domainId].domain.coreId; +} + +#if 0 +static t_uint32 cm_DM_isSegmentOverlaping(const t_cm_domain_segment *d0, const t_cm_domain_segment *d1) +{ + t_uint32 min0 = d0->offset; + t_uint32 max0 = d0->offset + d0->size; + t_uint32 min1 = d1->offset; + t_uint32 max1 = d1->offset + d1->size; + + if ( (min0 < min1) && (min1 < max0) ){ /* min0 < min1 < max0 OR min1 in [min0:max0] */ + return 1; + } + if ( (min1 < min0) && (min0 <= max1) ){ /* min1 < min0 < max0 OR min0 in [min1:max1] */ + return 1; + } + + return 0; +} +{ + ... + + t_uint32 i; + //check non-overlapp with other domains + for (i = 0; i < MAX_USER_DOMAIN_NB; i++) { + if (domainDesc[i].client != 0) { + if (cm_DM_isSegmentOverlaping(&domainDesc[i].domain.esramData, &domain->esramData)) { + return CM_DOMAIN_OVERLAP; + } + /* + if (cm_DM_isSegmentOverlaping(&domainDesc[i].domain.esramData, &domain->esramData)) { + return CM_DOMAIN_OVERLAP; + } + */ + } + } + + ... +} +#endif + +PUBLIC t_cm_error cm_DM_CreateDomain(const t_nmf_client_id client, const t_cm_domain_memory *domain, t_cm_domain_id *handle) +{ + t_cm_domain_id domainId; + FIND_DOMAIN_ID(domainId); + + if (client == 0) + return CM_INVALID_PARAMETER; + + if (domain->coreId > LAST_CORE_ID) + return CM_INVALID_DOMAIN_DEFINITION; + + //FIXME, juraj, check invalid domain definition + domainDesc[domainId].client = client; + domainDesc[domainId].domain = *domain; + + *handle = domainId; + + return CM_OK; +} + +//TODO, juraj, add assert to cm_MM_GetOffset(), if domain is scratch parent +PUBLIC t_cm_error cm_DM_CreateDomainScratch(const t_nmf_client_id client, const t_cm_domain_id parentId, const t_cm_domain_memory *domain, t_cm_domain_id *handle) +{ + t_cm_error error; + t_memory_handle memhandle; + t_cm_allocator_desc *alloc; + t_uint32 parentMin, parentMax; + t_uint32 scratchMin, scratchMax; + + /* check if the parent domain exists */ + /* parent could be DOMAIN_NORMAL (1st call) or DOMAIN_SCRATCH_PARENT (other calls) */ + if ((error = cm_DM_CheckDomain(parentId, DOMAIN_ANY)) != CM_OK) { + return error; + } + + parentMin = domainDesc[parentId].domain.esramData.offset; + parentMax = domainDesc[parentId].domain.esramData.offset + domainDesc[parentId].domain.esramData.size; + scratchMin = domain->esramData.offset; + scratchMax = domain->esramData.offset + domain->esramData.size; + /* check if the scratch domain respects the parent domain (esram data only )*/ + if ( (parentMin > scratchMin) || (parentMax < scratchMax) ) { + return CM_INVALID_DOMAIN_DEFINITION; + } + + /* create the scratch domain */ + if ((error = cm_DM_CreateDomain(client, domain, handle)) != CM_OK) { + return error; + } + + /* check if this is the first scratch domain */ + if (domainDesc[parentId].scratch.parent.handle == 0) { + /* 1st scratch domain */ + t_cm_domain_segment tmp; + + /* reserve the zone for the scratch domain */ + tmp = domainDesc[parentId].domain.esramData; + domainDesc[parentId].domain.esramData = domain->esramData; + memhandle = cm_DM_Alloc(parentId, ESRAM_EXT16, domain->esramData.size / 2, CM_MM_ALIGN_NONE, FALSE); //note byte to 16bit-word conversion + domainDesc[parentId].domain.esramData = tmp; + if (memhandle == 0) { + cm_DM_DestroyDomain(*handle); + cm_DM_DomainError(parentId, client); + return CM_NO_MORE_MEMORY; + } + + domainDesc[parentId].type = DOMAIN_SCRATCH_PARENT; + domainDesc[parentId].refcount = 0; //reinit the refcount + domainDesc[parentId].scratch.parent.handle = memhandle; + + } else { + /* nth scratch domain */ + t_uint32 i; + t_uint32 oldMin = domainDesc[parentId].domain.esramData.offset + domainDesc[parentId].domain.esramData.offset; + t_uint32 oldMax = 0; + + /* compute the new scratch zone size */ + for(i = 0; i < MAX_USER_DOMAIN_NB; i++) { + if ((domainDesc[i].type == DOMAIN_SCRATCH_CHILD) && (domainDesc[i].scratch.child.parent_ref == parentId)) { + /* ok, here we have a scratch domain created from the same child domain */ + t_uint32 min = domainDesc[i].domain.esramData.offset; + t_uint32 max = domainDesc[i].domain.esramData.offset + domainDesc[i].domain.esramData.size; + + oldMin = (min < oldMin)?min:oldMin; + oldMax = (max > oldMax)?max:oldMax; + } + } + + /* resize the scratch zone */ + if ((oldMin > scratchMin) || (oldMax < scratchMax)) { + t_uint32 newMin = (oldMin > scratchMin)?scratchMin:oldMin; + t_uint32 newMax = (oldMax < scratchMax)?scratchMax:oldMax; + t_uint16 userData; + + /* save user data lost during realloc, user data do not change */ + cm_MM_GetMemoryHandleUserData(domainDesc[parentId].scratch.parent.handle, &userData, 0); + memhandle = cm_MM_Realloc(cm_DM_getAllocator(parentId, ESRAM_EXT16), newMax - newMin, newMin, + CM_MM_MPC_ALIGN_NONE, domainDesc[parentId].scratch.parent.handle); + if (memhandle == 0) { + /* failed to extend the zone */ + cm_DM_DestroyDomain(*handle); + cm_DM_DomainError(parentId, client); + return CM_NO_MORE_MEMORY; + } + + cm_MM_SetMemoryHandleUserData(memhandle, userData); + domainDesc[parentId].scratch.parent.handle = memhandle; + } + } + + /* create esram-data allocator in the scratch domain */ + alloc = cm_MM_CreateAllocator(domainDesc[*handle].domain.esramData.size, + domainDesc[*handle].domain.esramData.offset, + "scratch"); + + domainDesc[*handle].type = DOMAIN_SCRATCH_CHILD; + domainDesc[*handle].scratch.child.parent_ref = parentId; + domainDesc[*handle].scratch.child.alloc = alloc; + domainDesc[parentId].refcount++; + + return error; +} + +PUBLIC t_cm_error cm_DM_DestroyDomains(const t_nmf_client_id client) +{ + t_cm_domain_id handle; + t_cm_error error, status=CM_OK; + + for (handle=0; handle<MAX_USER_DOMAIN_NB; handle++) { + if ((domainDesc[handle].client == client) + && ((error=cm_DM_DestroyDomain(handle)) != CM_OK)) { + LOG_INTERNAL(0, "Error (%d) destroying remaining domainId %d for client %u\n", error, handle, client, 0, 0, 0); + status = error; + } + } + return status; +} + +PUBLIC t_cm_error cm_DM_DestroyDomain(t_cm_domain_id handle) +{ + t_cm_error error = CM_OK; + t_uint32 i; + + if ((error = cm_DM_CheckDomain(handle, DOMAIN_ANY)) != CM_OK) { + return error; + } + + //forbid destruction of cm domains + //if (handle == cm_DSP_GetState(domainDesc[handle].domain.coreId)->domainEE) + // return CM_INVALID_DOMAIN_HANDLE; + + /* loop all components and check if there are still components instantiated with this handle */ + //actually this check is redundant with the usage counters as component instantiations allocate memory + for (i=0; i<ComponentTable.idxMax; i++) + { + if (NULL != componentEntry(i) && componentEntry(i)->domainId == handle) { + return CM_ILLEGAL_DOMAIN_OPERATION; + } + } + + //perform check based on usage counters + if (domainDesc[handle].refcount != 0) { + return CM_ILLEGAL_DOMAIN_OPERATION; + } + + if (domainDesc[handle].type == DOMAIN_SCRATCH_PARENT) { + return CM_ILLEGAL_DOMAIN_OPERATION; //parent destroyed implicitly with the last scratch + } else if (domainDesc[handle].type == DOMAIN_SCRATCH_CHILD) { + t_cm_allocator_status status; + t_cm_domain_id parentId = domainDesc[handle].scratch.child.parent_ref; + + cm_MM_GetAllocatorStatus(domainDesc[handle].scratch.child.alloc, 0, 0xffff, &status); + if (status.global.accumulate_used_memory != 0) { + //something is still allocated + return CM_ILLEGAL_DOMAIN_OPERATION; + } + + domainDesc[parentId].refcount--; + cm_MM_DeleteAllocator(domainDesc[handle].scratch.child.alloc); //returns no error + + if (domainDesc[parentId].refcount == 0) { + /* last scratch domain */ + cm_DM_Free(domainDesc[parentId].scratch.parent.handle, FALSE); + domainDesc[parentId].scratch.parent.handle = 0; + domainDesc[parentId].type = DOMAIN_NORMAL; + } else { + /* other child scratch domains exist, check if the reserved zone needs resize, ie reduce */ + + t_uint32 i; + /* init oldMin and oldMax to values we are sure will get overwritten below */ + t_uint32 oldMin = 0xffffffff; + t_uint32 oldMax = 0x0; + t_uint32 scratchMin = domainDesc[handle].domain.esramData.offset; + t_uint32 scratchMax = domainDesc[handle].domain.esramData.offset + domainDesc[handle].domain.esramData.size; + t_memory_handle memhandle; + + /* compute the remaining reserved zone size */ + for(i = 0; i < MAX_USER_DOMAIN_NB; i++) { + if (i == handle) + continue; //do not consider the current domain to be destroyed later in this function + if ((domainDesc[i].type == DOMAIN_SCRATCH_CHILD) && (domainDesc[i].scratch.child.parent_ref == parentId)) { + /* ok, here we have a scratch domain created from the same child domain */ + t_uint32 min = domainDesc[i].domain.esramData.offset; + t_uint32 max = domainDesc[i].domain.esramData.offset + domainDesc[i].domain.esramData.size; + + oldMin = (min < oldMin)?min:oldMin; + oldMax = (max > oldMax)?max:oldMax; + } + } + + /* resize the scratch zone */ + if ((oldMin > scratchMin) || (oldMax < scratchMax)) { + t_uint16 userData; + + /* save user data lost during realloc, user data do not change */ + cm_MM_GetMemoryHandleUserData(domainDesc[parentId].scratch.parent.handle, &userData, 0); + memhandle = cm_MM_Realloc(cm_DM_getAllocator(parentId, ESRAM_EXT16), oldMax - oldMin, oldMin, + CM_MM_MPC_ALIGN_NONE, domainDesc[parentId].scratch.parent.handle); + CM_ASSERT(memhandle); //the realloc shouldn't fail.. + + cm_MM_SetMemoryHandleUserData(memhandle, userData); + domainDesc[parentId].scratch.parent.handle = memhandle; + } + } + } + + //reset the domain desc + INIT_DOMAIN_STRUCT(domainDesc[handle]); + + return CM_OK; +} + +/* + * - if the domainId is scratch parent, all allocations are done as in normal domains + * - if the domainId is scratch child + * if allocation type is esram, retrieve the allocator from the domainDesc + * else allocation is done as for normal domain + * - if the domainId is normal, allocator is retrieved from mpcDesc via cm_DSP_GetAllocator() + */ +static t_cm_allocator_desc *cm_DM_getAllocator(t_cm_domain_id domainId, t_dsp_memory_type_id memType) +{ + t_cm_allocator_desc *alloc = 0; + + if ((domainDesc[domainId].type == DOMAIN_SCRATCH_CHILD) + && ((memType == ESRAM_EXT16) || (memType == ESRAM_EXT24))) { + alloc = domainDesc[domainId].scratch.child.alloc; + } else { + alloc = cm_DSP_GetAllocator(domainDesc[domainId].domain.coreId, memType); + } + + return alloc; +} + +void START(void); +void END(const char*); + +//TODO, juraj, alloc would need to return finer errors then 0 +PUBLIC t_memory_handle cm_DM_Alloc(t_cm_domain_id domainId, t_dsp_memory_type_id memType, t_uint32 wordSize, t_cm_mpc_memory_alignment memAlignment, t_bool powerOn) +{ + t_nmf_core_id coreId = domainDesc[domainId].domain.coreId; + t_memory_handle handle; + t_cm_allocator_desc *alloc; + t_uint32 offset; + t_uint32 size; + + cm_DSP_GetInternalMemoriesInfo(domainId, memType, &offset, &size); + + if ((alloc = cm_DM_getAllocator(domainId, memType)) == 0) { + return 0; + } + + handle = cm_MM_Alloc(alloc, + cm_DSP_ConvertSize(memType, wordSize), + (t_cm_memory_alignment) memAlignment, + offset, size, domainId); + + if(handle != INVALID_MEMORY_HANDLE) + { + cm_MM_SetMemoryHandleUserData(handle, (coreId << SHIFT_BYTE1) | (memType << SHIFT_BYTE0)); + + if (powerOn) { + // [Pwr] The associated power domain can be enabled only after the Alloc request. + // Associated MPC memory chunk is not accessed (Remote allocator feature) + cm_PWR_EnableMemory( + coreId, + memType, + /* + * Compute physical address based on cm_DSP_GetHostSystemAddress but in optimized way + * -> See it for information + * -> Note TCM memory is not correctly compute, but it's not used + */ + cm_DSP_GetState(coreId)->allocator[memType]->baseAddress.physical + cm_MM_GetOffset(handle), + cm_MM_GetSize(handle)); + } + } + + return handle; +} + +PUBLIC void cm_DM_FreeWithInfo(t_memory_handle memHandle, t_nmf_core_id *coreId, t_dsp_memory_type_id *memType, t_bool powerOff) +{ + t_dsp_chunk_info chunk_info; + + cm_DSP_GetDspChunkInfo(memHandle, &chunk_info); + + if (powerOff) { + cm_PWR_DisableMemory( + chunk_info.coreId, + chunk_info.memType, + cm_DSP_GetPhysicalAdress(memHandle), + cm_MM_GetSize(memHandle)); + } + + cm_MM_Free(chunk_info.alloc, memHandle); + + *coreId = chunk_info.coreId; + *memType = chunk_info.memType; +} + +PUBLIC void cm_DM_Free(t_memory_handle memHandle, t_bool powerOff) +{ + t_nmf_core_id coreId; + t_dsp_memory_type_id memType; + + cm_DM_FreeWithInfo(memHandle, &coreId, &memType, powerOff); +} + +PUBLIC t_cm_error cm_DM_GetAllocatorStatus(t_cm_domain_id domainId, t_dsp_memory_type_id memType, t_cm_allocator_status *pStatus) +{ + t_cm_error error; + t_uint32 dOffset; + t_uint32 dSize; + + //TODO, scratch + error = cm_DM_CheckDomain(domainId, DOMAIN_ANY); + if (error != CM_OK) { + return error; + } + + cm_DSP_GetInternalMemoriesInfo(domainId, memType, &dOffset, &dSize); + + return cm_DSP_GetAllocatorStatus(domainDesc[domainId].domain.coreId, memType, + dOffset, dSize, pStatus); +} + +//WARNING: this function is only correct *before* migration! because +//the computation of absolute adresses of a domain is based on the allocator for the given +//segment (this is hidden in cm_DSP_GetDspBaseAddress and this info is not valid +//after migration (non-contiguous address-space from the ARM-side) +PUBLIC t_cm_error cm_DM_GetDomainAbsAdresses(t_cm_domain_id domainId, t_cm_domain_info *info) +{ + t_cm_error error; + t_nmf_core_id coreId = domainDesc[domainId].domain.coreId; + + cm_migration_check_state(coreId, STATE_NORMAL); + + error = cm_DM_CheckDomain(domainId, DOMAIN_NORMAL); + if (error != CM_OK) { + return error; + } + + cm_DSP_GetDspBaseAddress(coreId, SDRAM_CODE, &info->sdramCode); + cm_DSP_GetDspBaseAddress(coreId, ESRAM_CODE, &info->esramCode); + cm_DSP_GetDspBaseAddress(coreId, SDRAM_EXT24, &info->sdramData); + cm_DSP_GetDspBaseAddress(coreId, ESRAM_EXT24, &info->esramData); + + info->sdramCode.physical += domainDesc[domainId].domain.sdramCode.offset; + info->sdramCode.logical += domainDesc[domainId].domain.sdramCode.offset; + info->esramCode.physical += domainDesc[domainId].domain.esramCode.offset; + info->esramCode.logical += domainDesc[domainId].domain.esramCode.offset; + info->sdramData.physical += domainDesc[domainId].domain.sdramData.offset; + info->sdramData.logical += domainDesc[domainId].domain.sdramData.offset; + info->esramData.physical += domainDesc[domainId].domain.esramData.offset; + info->esramData.logical += domainDesc[domainId].domain.esramData.offset; + + return CM_OK; +} + +static void cm_DM_DomainError(const t_cm_domain_id parentId, const t_nmf_client_id client) +{ + int i; + LOG_INTERNAL(0, "NMF_DEBUG_SCRATCH failed to allocate domain (client %u): 0x%08x -> 0x%08x\n", + client, + domainDesc[parentId].domain.esramData.offset, + domainDesc[parentId].domain.esramData.offset + domainDesc[parentId].domain.esramData.size, + 0, 0, 0); + for(i = 0; i < MAX_USER_DOMAIN_NB; i++) { + if (domainDesc[i].type == DOMAIN_SCRATCH_CHILD) { + LOG_INTERNAL(0, "NMF_DEBUG_SCRATCH scratch domain %d allocated (client %u): 0x%08x -> 0x%08x\n", + i, domainDesc[i].client, + domainDesc[i].domain.esramData.offset, + domainDesc[i].domain.esramData.offset + domainDesc[i].domain.esramData.size, + 0, 0); + } + } + cm_MM_DumpMemory(cm_DM_getAllocator(parentId, ESRAM_EXT16), + domainDesc[parentId].domain.esramData.offset, + domainDesc[parentId].domain.esramData.offset + domainDesc[parentId].domain.esramData.size); +} + diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/domain_wrapper.c b/drivers/staging/nmf-cm/cm/engine/memory/src/domain_wrapper.c new file mode 100644 index 00000000000..ec305812f15 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/domain_wrapper.c @@ -0,0 +1,95 @@ +/* + * 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/domain_engine.h> +#include <cm/engine/api/migration_engine.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/memory/inc/migration.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_CreateMemoryDomain( + const t_nmf_client_id client, + const t_cm_domain_memory *domain, + t_cm_domain_id *handle + ) +{ + t_cm_error error; + + OSAL_LOCK_API(); + error = cm_DM_CreateDomain(client, domain, handle); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_CreateMemoryDomainScratch( + const t_nmf_client_id client, + const t_cm_domain_id parentId, + const t_cm_domain_memory *domain, + t_cm_domain_id *handle + ) +{ + t_cm_error error; + + OSAL_LOCK_API(); + error = cm_DM_CreateDomainScratch(client, parentId, domain, handle); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_DestroyMemoryDomain( + t_cm_domain_id handle) +{ + t_cm_error error; + + OSAL_LOCK_API(); + error = cm_DM_DestroyDomain(handle); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_FlushMemoryDomains( + t_nmf_client_id client) +{ + t_cm_error error; + + OSAL_LOCK_API(); + error = cm_DM_DestroyDomains(client); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetDomainCoreId(const t_cm_domain_id domainId, t_nmf_core_id *coreId) +{ + t_cm_error error; + OSAL_LOCK_API(); + //TODO, scratch + error = cm_DM_CheckDomain(domainId, DOMAIN_NORMAL); + if (error != CM_OK) { + OSAL_UNLOCK_API(); + return error; + } + + *coreId = cm_DM_GetDomainCoreId(domainId); + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_Migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst) +{ + t_cm_error error; + OSAL_LOCK_API(); + error = cm_migrate(srcShared, src, dst); + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_Unmigrate(void) +{ + t_cm_error error; + OSAL_LOCK_API(); + error = cm_unmigrate(); + OSAL_UNLOCK_API(); + return error; +} diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/memory_wrapper.c b/drivers/staging/nmf-cm/cm/engine/memory/src/memory_wrapper.c new file mode 100644 index 00000000000..15961aea516 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/memory_wrapper.c @@ -0,0 +1,243 @@ +/* + * 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/memory/inc/memory.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/component/inc/instance.h> +#include <cm/engine/configuration/inc/configuration.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/trace/inc/trace.h> + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_AllocMpcMemory( + t_cm_domain_id domainId, + t_nmf_client_id clientId, + t_cm_mpc_memory_type memType, + t_cm_size size, + t_cm_mpc_memory_alignment memAlignment, + t_cm_memory_handle *pHandle + ) +{ + t_dsp_memory_type_id dspMemType; + + switch(memType) + { + case CM_MM_MPC_TCM16_X: + dspMemType = INTERNAL_XRAM16; + break; + case CM_MM_MPC_TCM24_X: + dspMemType = INTERNAL_XRAM24; + break; + case CM_MM_MPC_TCM16_Y: + dspMemType = INTERNAL_YRAM16; + break; + case CM_MM_MPC_TCM24_Y: + dspMemType = INTERNAL_YRAM24; + break; +#ifndef __STN_8810 + case CM_MM_MPC_ESRAM16: + dspMemType = ESRAM_EXT16; + break; + case CM_MM_MPC_ESRAM24: + dspMemType = ESRAM_EXT24; + break; +#endif /* ndef __STN_8810 */ + case CM_MM_MPC_SDRAM16: + dspMemType = SDRAM_EXT16; + break; + case CM_MM_MPC_SDRAM24: + dspMemType = SDRAM_EXT24; + break; + default: + return CM_INVALID_PARAMETER; + } + + OSAL_LOCK_API(); + { + t_cm_error error; + error = cm_DM_CheckDomainWithClient(domainId, DOMAIN_ANY, clientId); + if (error != CM_OK) { + OSAL_UNLOCK_API(); + return error; + } + } + + switch(memAlignment) { + case CM_MM_MPC_ALIGN_NONE : + case CM_MM_MPC_ALIGN_HALFWORD : + case CM_MM_MPC_ALIGN_WORD : + case CM_MM_MPC_ALIGN_2WORDS : + case CM_MM_MPC_ALIGN_4WORDS : + case CM_MM_MPC_ALIGN_8WORDS : + case CM_MM_MPC_ALIGN_16WORDS : + case CM_MM_MPC_ALIGN_32WORDS : + case CM_MM_MPC_ALIGN_64WORDS : + case CM_MM_MPC_ALIGN_128WORDS : + case CM_MM_MPC_ALIGN_256WORDS : + case CM_MM_MPC_ALIGN_512WORDS : + case CM_MM_MPC_ALIGN_1024WORDS : + case CM_MM_MPC_ALIGN_65536BYTES : + //case CM_MM_MPC_ALIGN_16384WORDS : maps to the same value as above + break; + default: + OSAL_UNLOCK_API(); + return CM_INVALID_PARAMETER; + } + + /* in case we allocate in tcm x be sure ee is load before */ + if ( memType == CM_MM_MPC_TCM16_X || memType == CM_MM_MPC_TCM24_X || + memType == CM_MM_MPC_TCM16_Y || memType == CM_MM_MPC_TCM24_Y ) + { + t_cm_error error; + if ((error = cm_CFG_CheckMpcStatus(cm_DM_GetDomainCoreId(domainId))) != CM_OK) + { + OSAL_UNLOCK_API(); + return error; + } + } + + /* alloc memory */ + *pHandle = (t_cm_memory_handle)cm_DM_Alloc(domainId, dspMemType, size, memAlignment, TRUE); + if(*pHandle == (t_cm_memory_handle)INVALID_MEMORY_HANDLE) + { + OSAL_UNLOCK_API(); + return CM_NO_MORE_MEMORY; + } + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_FreeMpcMemory(t_cm_memory_handle handle) +{ + t_cm_error error; + t_memory_handle validHandle; + t_nmf_core_id coreId; + t_dsp_memory_type_id memType; + + OSAL_LOCK_API(); + + if((error = cm_MM_getValidMemoryHandle(handle, &validHandle)) != CM_OK) + { + OSAL_UNLOCK_API(); + return error; + } + + cm_DM_FreeWithInfo(validHandle, &coreId, &memType, TRUE); + + /* in case we allocate in tcm x be sure ee is load before */ + if ( memType == INTERNAL_XRAM16 || memType == INTERNAL_XRAM24 || + memType == INTERNAL_YRAM16 || memType == INTERNAL_YRAM24 ) + { + cm_CFG_ReleaseMpc(coreId); + } + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemorySystemAddress(t_cm_memory_handle handle, t_cm_system_address *pSystemAddress) +{ + t_cm_error error; + t_memory_handle validHandle; + + OSAL_LOCK_API(); + + if((error = cm_MM_getValidMemoryHandle(handle, &validHandle)) != CM_OK) + { + OSAL_UNLOCK_API(); + return error; + } + + cm_DSP_GetHostSystemAddress(validHandle, pSystemAddress); + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemoryMpcAddress(t_cm_memory_handle handle, t_uint32 *pDspAddress) +{ + t_cm_error error; + t_memory_handle validHandle; + + OSAL_LOCK_API(); + + if((error = cm_MM_getValidMemoryHandle(handle, &validHandle)) != CM_OK) + { + OSAL_UNLOCK_API(); + return error; + } + + cm_DSP_GetDspAddress(validHandle, pDspAddress); + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC IMPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemorySize( + t_cm_memory_handle handle, + t_uint32 *pSize) +{ + t_cm_error error; + t_memory_handle validHandle; + + OSAL_LOCK_API(); + + if((error = cm_MM_getValidMemoryHandle(handle, &validHandle)) != CM_OK) + { + OSAL_UNLOCK_API(); + return error; + } + + *pSize = validHandle->size; + + OSAL_UNLOCK_API(); + return CM_OK; +} + + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetMpcMemoryStatus(t_nmf_core_id coreId, t_cm_mpc_memory_type memType, t_cm_allocator_status *pStatus) +{ + t_dsp_memory_type_id dspMemType; + t_cm_error error; + + switch(memType) + { + case CM_MM_MPC_TCM16_X: + dspMemType = INTERNAL_XRAM16; + break; + case CM_MM_MPC_TCM24_X: + dspMemType = INTERNAL_XRAM24; + break; + case CM_MM_MPC_TCM16_Y: + dspMemType = INTERNAL_YRAM16; + break; + case CM_MM_MPC_TCM24_Y: + dspMemType = INTERNAL_YRAM24; + break; +#ifndef __STN_8810 + case CM_MM_MPC_ESRAM16: + dspMemType = ESRAM_EXT16; + break; + case CM_MM_MPC_ESRAM24: + dspMemType = ESRAM_EXT24; + break; +#endif /* ndef __STN_8810 */ + case CM_MM_MPC_SDRAM16: + dspMemType = SDRAM_EXT16; + break; + case CM_MM_MPC_SDRAM24: + dspMemType = SDRAM_EXT24; + break; + default: + return CM_INVALID_PARAMETER; + } + + OSAL_LOCK_API(); + error = cm_DSP_GetAllocatorStatus(coreId, dspMemType, 0, 0, pStatus); + OSAL_UNLOCK_API(); + + return error; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/migration.c b/drivers/staging/nmf-cm/cm/engine/memory/src/migration.c new file mode 100644 index 00000000000..35813a56bf2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/migration.c @@ -0,0 +1,391 @@ +/* + * 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 <inc/type.h> +#include <inc/nmf-limits.h> + +#include <cm/engine/communication/fifo/inc/nmf_fifo_arm.h> +#include <cm/engine/dsp/inc/dsp.h> +#include <cm/engine/memory/inc/domain.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/memory/inc/migration.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/mem.h> + +#if defined(__STN_8500) && (__STN_8500 > 10) + +typedef enum { + CM_MIGRATION_OK = 0, + CM_MIGRATION_INVALID_ARGUMENT = 1, + CM_MIGRATION_ERROR = 2, +} t_cm_migration_error; + +extern t_nmf_fifo_arm_desc* mpc2mpcComsFifoId[NB_CORE_IDS][NB_CORE_IDS]; + +/*! + * \brief Data structure representing a segment to migrate + * + * segment: + * - used to determine which mmdsp-hw base is to be updated, index in mpcDesc->segments[] structure + * * this is hard-coded in cm_migrate(), could be computed (would be nice) LIMITATION + * srcAdr.physical: + * - new base setting + * * computed from the src domain in cm_DM_GetAbsAdresses() which uses the start of the allocator for the memory + * this is a LIMITATION, as this information is valid only before migration + * srcAdr.logical: + * - cm_MemCopy() + * * computed as srcAdr.logical + * dstAdr.physical: see srcAdr.physical + * dstAdr.logical: see srcAdr.logical + * size: + * - cm_MemCopy() + * - setting the top when new base is set + */ +typedef struct { + t_dsp_segment_type segment; //!< the link to the segment type + t_cm_system_address srcAdr; //!< source address + t_cm_system_address dstAdr; //!< destination address + t_uint32 size; //!< size of the segment +} t_cm_migration_segment; + +/*! + * \brief Internal data structure 1/ during migration, and 2/ between migration and unmigration calls + * + * all needed information are computed before calling _cm_migration_move() + */ +typedef struct { + t_cm_migration_state state; //!< migration state + t_nmf_core_id coreId; //!< migration only on one mpc + t_cm_migration_segment segments[NB_MIGRATION_SEGMENT]; //!< segments to migrate (selected on migration_move) + t_memory_handle handles[NB_MIGRATION_SEGMENT]; //!< memory handles for destination chunks allocated prior migration +} t_cm_migration_internal_state; + +static t_cm_migration_internal_state migrationState = {STATE_NORMAL, }; + +static t_cm_error _cm_migration_initSegment( + t_dsp_segment_type dspSegment, + t_cm_system_address *srcAdr, + t_uint32 size, + t_cm_domain_id dst, + t_cm_migration_internal_state *info + ) +{ + t_cm_system_address dstAdr; + t_cm_migration_segment *segment = &info->segments[dspSegment]; + t_memory_handle handle; + + handle = cm_DM_Alloc(dst, ESRAM_EXT16, size >> 1, CM_MM_ALIGN_AHB_BURST, TRUE); //note: byte to half-word conversion + if (handle == 0) { + return CM_NO_MORE_MEMORY; + } + + info->handles[dspSegment] = handle; + + cm_DSP_GetHostSystemAddress(handle, &dstAdr); + + segment->segment = dspSegment; //this is redundant and could be avoided by recoding move(), but nice to have for debug + segment->size = size; + segment->srcAdr = *srcAdr; + segment->dstAdr = dstAdr; + + return CM_OK; +} + +static void _cm_migration_releaseSegment(t_cm_migration_internal_state *info, t_dsp_segment_type segId) +{ + cm_DM_Free(info->handles[segId], TRUE); +} + +static t_cm_migration_error _cm_migration_release(t_cm_migration_internal_state *info) +{ + t_uint32 i = 0; + for (i = 0; i < NB_MIGRATION_SEGMENT; i++) { + cm_DM_Free(info->handles[i], TRUE); + } + + return CM_MIGRATION_OK; +} + +#define SEGMENT_START(seg) \ + seg.offset + +#define SEGMENT_END(seg) \ + seg.offset + seg.size + +static t_cm_error _cm_migration_check( + const t_cm_domain_id srcShared, + const t_cm_domain_id src, + const t_cm_domain_id dst, + t_cm_migration_internal_state *info + ) +{ + t_cm_error error = CM_OK; + t_cm_domain_info domainInfoSrc; + t_cm_domain_info domainInfoShared; + t_cm_domain_desc *domainEE; + t_cm_domain_desc *domainShared; + t_nmf_core_id coreId = cm_DM_GetDomainCoreId(src); + + //coreIds in src, srcShared and dst match + if (!((domainDesc[src].domain.coreId == domainDesc[srcShared].domain.coreId) + && (domainDesc[src].domain.coreId == domainDesc[dst].domain.coreId))) { + return CM_INVALID_PARAMETER; + } + + //check srcShared starts at 0 + //FIXME, juraj, today EE code is in SDRAM, but this is flexible, so must find out where EE is instantiated + if (domainDesc[srcShared].domain.sdramCode.offset != 0x0) { + return CM_INVALID_PARAMETER; + } + + //check srcShared contains EE domain + domainEE = &domainDesc[cm_DSP_GetState(coreId)->domainEE]; + domainShared = &domainDesc[srcShared]; + if ((SEGMENT_START(domainEE->domain.esramCode) < SEGMENT_START(domainShared->domain.esramCode)) + ||(SEGMENT_END(domainEE->domain.esramCode) > SEGMENT_END(domainShared->domain.esramCode)) + ||(SEGMENT_START(domainEE->domain.esramData) < SEGMENT_START(domainShared->domain.esramData)) + ||(SEGMENT_END(domainEE->domain.esramData) > SEGMENT_END(domainShared->domain.esramData)) + ||(SEGMENT_START(domainEE->domain.sdramCode) < SEGMENT_START(domainShared->domain.sdramCode)) + ||(SEGMENT_END(domainEE->domain.sdramCode) > SEGMENT_END(domainShared->domain.sdramCode)) + ||(SEGMENT_START(domainEE->domain.sdramData) < SEGMENT_START(domainShared->domain.sdramData)) + ||(SEGMENT_END(domainEE->domain.sdramData) > SEGMENT_END(domainShared->domain.sdramData)) + ) { + return CM_INVALID_PARAMETER; + } + + info->coreId = coreId; + cm_DM_GetDomainAbsAdresses(srcShared, &domainInfoShared); + cm_DM_GetDomainAbsAdresses(src, &domainInfoSrc); + + if ((error = _cm_migration_initSegment(SDRAM_CODE_EE, &domainInfoShared.sdramCode, + domainDesc[srcShared].domain.sdramCode.size, dst, info)) != CM_OK) + goto _migration_error1; + if ((error = _cm_migration_initSegment(SDRAM_CODE_USER, &domainInfoSrc.sdramCode, + domainDesc[src].domain.sdramCode.size, dst, info)) != CM_OK) + goto _migration_error2; + if ((error = _cm_migration_initSegment(SDRAM_DATA_EE, &domainInfoShared.sdramData, + domainDesc[srcShared].domain.sdramData.size, dst, info)) != CM_OK) + goto _migration_error3; + if ((error = _cm_migration_initSegment(SDRAM_DATA_USER, &domainInfoSrc.sdramData, + domainDesc[src].domain.sdramData.size, dst, info)) != CM_OK) + goto _migration_error4; + return error; + +_migration_error4: _cm_migration_releaseSegment(info, SDRAM_DATA_EE); +_migration_error3: _cm_migration_releaseSegment(info, SDRAM_CODE_USER); +_migration_error2: _cm_migration_releaseSegment(info, SDRAM_CODE_EE); +_migration_error1: + OSAL_Log("Couldn't allocate memory for migration\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; +} + +typedef t_cm_error (*updateBase_t)(t_nmf_core_id, t_dsp_segment_type, t_cm_system_address, t_cm_system_address); + +static t_cm_migration_error _cm_migration_move( + t_nmf_core_id coreId, + t_cm_migration_segment *seg, + updateBase_t updateBase, + char* name + ) +{ + LOG_INTERNAL(1, "##### Migration %s: 0x%x -> 0x%x\n", name, seg->srcAdr.logical, seg->dstAdr.logical, 0, 0, 0); + cm_MemCopy((void*)seg->dstAdr.logical, (void*)seg->srcAdr.logical, seg->size); + updateBase(coreId, seg->segment, seg->srcAdr, seg->dstAdr); + cm_MemSet((void*)seg->srcAdr.logical, 0xdead, seg->size); //for debug, to be sure that we have actually moved the code and bases + + return CM_MIGRATION_OK; +} + +static t_cm_migration_error _cm_migration_update_internal( + t_cm_migration_internal_state *info, + t_cm_migration_state state + ) +{ + t_nmf_fifo_arm_desc *pArmFifo; + + migrationState.state = state; + + switch(state) { + case STATE_MIGRATED: + //move fifos + pArmFifo = mpc2mpcComsFifoId[ARM_CORE_ID][info->coreId]; + pArmFifo->fifoDesc = (t_nmf_fifo_desc*)cm_migration_translate(pArmFifo->dspAddressInfo.segmentType, (t_shared_addr)pArmFifo->fifoDescShadow); + pArmFifo = mpc2mpcComsFifoId[info->coreId][ARM_CORE_ID]; + pArmFifo->fifoDesc = (t_nmf_fifo_desc*)cm_migration_translate(pArmFifo->dspAddressInfo.segmentType, (t_shared_addr)pArmFifo->fifoDescShadow); + break; + + case STATE_NORMAL: + //move fifos + pArmFifo = mpc2mpcComsFifoId[ARM_CORE_ID][info->coreId]; + pArmFifo->fifoDesc = pArmFifo->fifoDescShadow; + pArmFifo = mpc2mpcComsFifoId[info->coreId][ARM_CORE_ID]; + pArmFifo->fifoDesc = pArmFifo->fifoDescShadow; + break; + + default: + OSAL_Log("unknown state", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + + return CM_MIGRATION_OK; +} + +PUBLIC t_cm_error cm_migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst) +{ + t_cm_migration_error mError; + t_cm_error error; + + if ((error = _cm_migration_check(srcShared, src, dst, &migrationState)) != CM_OK) { + return error; + } + + /* stop DSP execution */ + cm_DSP_Stop(migrationState.coreId); + + /* migrate EE and FX */ + mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_EE], cm_DSP_updateCodeBase, "code"); + if (mError) { + OSAL_Log("EE code migration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_EE], cm_DSP_updateDataBase, "data"); + if (mError) { + OSAL_Log("EE data migration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + /* migrate user domain */ + mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_USER], cm_DSP_updateCodeBase, "code"); + if (mError) { + OSAL_Log("User code migration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_USER], cm_DSP_updateDataBase, "data"); + if (mError) { + OSAL_Log("User data migration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + /* update CM internal structures */ + mError = _cm_migration_update_internal(&migrationState, STATE_MIGRATED); + if (mError) { + OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + + /* Be sure everything has been write before restarting mmdsp */ + OSAL_mb(); + + /* resume DSP execution */ + cm_DSP_Start(migrationState.coreId); + + return CM_OK; +} + +static void _cm_migration_swapSegments( + t_cm_migration_segment *segment + ) +{ + t_cm_system_address tmp; + tmp = segment->dstAdr; + segment->dstAdr = segment->srcAdr; + segment->srcAdr = tmp; +} + +PUBLIC t_cm_error cm_unmigrate(void) +{ + t_cm_migration_error merror; + + if (migrationState.state != STATE_MIGRATED) + return CM_INVALID_PARAMETER; //TODO, juraj, define a proper error for this migration case + + cm_DSP_Stop(migrationState.coreId); + + _cm_migration_swapSegments(&migrationState.segments[SDRAM_CODE_EE]); + _cm_migration_swapSegments(&migrationState.segments[SDRAM_DATA_EE]); + _cm_migration_swapSegments(&migrationState.segments[SDRAM_CODE_USER]); + _cm_migration_swapSegments(&migrationState.segments[SDRAM_DATA_USER]); + + merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_EE], cm_DSP_updateCodeBase, "code"); + if (merror) { + OSAL_Log("EE code unmigration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_EE], cm_DSP_updateDataBase, "data"); + if (merror) { + OSAL_Log("EE data unmigration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_USER], cm_DSP_updateCodeBase, "code"); + if (merror) { + OSAL_Log("User code unmigration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_USER], cm_DSP_updateDataBase, "data"); + if (merror) { + OSAL_Log("User data unmigration failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + + /* update CM internal structures */ + merror = _cm_migration_update_internal(&migrationState, STATE_NORMAL); + if (merror) { + OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + + /* Be sure everything has been write before restarting mmdsp */ + OSAL_mb(); + + cm_DSP_Start(migrationState.coreId); + + /* update CM internal structures */ + merror = _cm_migration_release(&migrationState); + if (merror) { + OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0); + CM_ASSERT(0); + } + + return CM_OK; +} + +// here we make the assumption that the offset doesn't depend from the dsp!! +PUBLIC t_uint32 cm_migration_translate(t_dsp_segment_type segmentType, t_uint32 addr) +{ + //TODO, juraj, save delta instead of recalculating it + t_sint32 offset; + if (migrationState.state == STATE_MIGRATED) { + offset = migrationState.segments[segmentType].dstAdr.logical - migrationState.segments[segmentType].srcAdr.logical; + } else { + offset = 0; + } + return addr + offset; +} + +PUBLIC void cm_migration_check_state(t_nmf_core_id coreId, t_cm_migration_state expected) +{ + CM_ASSERT(migrationState.state == expected); +} + +#else +PUBLIC t_cm_error cm_migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst) +{ + return CM_OK; +} + +PUBLIC t_cm_error cm_unmigrate(void) +{ + return CM_OK; +} + +PUBLIC t_uint32 cm_migration_translate(t_dsp_segment_type segmentType, t_uint32 addr) +{ + return addr; +} + +PUBLIC void cm_migration_check_state(t_nmf_core_id coreId, t_cm_migration_state expected) +{ + return; +} +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator.c b/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator.c new file mode 100644 index 00000000000..3df552aca4d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator.c @@ -0,0 +1,680 @@ +/* + * 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. + */ +/* +Â * 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 + */ +#include "../inc/remote_allocator.h" +#include "../inc/remote_allocator_utils.h" +#include "../inc/chunk_mgr.h" + +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/trace/inc/xtitrace.h> + +static t_cm_chunk* cm_MM_RA_getLastChunk(t_cm_allocator_desc* alloc); +static void cm_MM_RA_checkAllocator(t_cm_allocator_desc* alloc); +//static void cm_MM_RA_checkAlloc(t_cm_allocator_desc* alloc, t_uint32 size, t_uint32 align, t_uint32 min, t_uint32 max); + +int bin_index(unsigned int sz) { + /* + * 32 bins of size 2 + * 16 bins of size 16 + * 8 bins of size 128 + * 4 bins of size 1024 + * 2 bins of size 8192 + * 1 bin of size what's left + * + */ + return (((sz >> 6) == 0) ? (sz >> 1): // 0 -> 0 .. 31 + ((sz >> 6) <= 4) ? 28 + (sz >> 4): // 64 -> 32 .. 47 + ((sz >> 6) <= 20) ? 46 + (sz >> 7): // 320 -> 48 .. 55 + ((sz >> 6) <= 84) ? 55 + (sz >> 10): // 1344 -> 56 .. 59 + ((sz >> 6) <= 340) ? 59 + (sz >> 13): // 5440 -> 60 .. 61 + 62); // 21824.. +} + +static t_cm_allocator_desc* ListOfAllocators = NULL; + +PUBLIC t_cm_allocator_desc* cm_MM_CreateAllocator(t_cm_size size, t_uint32 offset, const char* name) +{ + t_cm_allocator_desc *alloc; + + CM_ASSERT(fillChunkPool() == CM_OK); + + /* Alloc structure */ + alloc = (t_cm_allocator_desc*)OSAL_Alloc_Zero(sizeof(t_cm_allocator_desc)); + CM_ASSERT(alloc != NULL); + + // Add allocator in list + alloc->next = ListOfAllocators; + ListOfAllocators = alloc; + + /* Create first chunk */ + alloc->chunks = allocChunk(); + + /* assign name */ + alloc->pAllocName = name; + + alloc->chunks->size = size; + alloc->chunks->offset = offset; + alloc->chunks->alloc = alloc; + alloc->free_mem_chunks[bin_index(alloc->chunks->size)] = alloc->chunks; + + alloc->size = size; + + //TODO, juraj, alloc impacts trace format + cm_TRC_traceMemAlloc(TRACE_ALLOCATOR_COMMAND_CREATE, 0, size, name); + + return alloc; +} + +PUBLIC t_cm_error cm_MM_DeleteAllocator(t_cm_allocator_desc *alloc) +{ + t_cm_chunk *chunk, *next_cm_chunk; + + cm_TRC_traceMemAlloc(TRACE_ALLOCATOR_COMMAND_DESTROY, 0, 0, alloc->pAllocName); + + /* Parse all chunks and free them */ + chunk = alloc->chunks; + while(chunk != 0) + { + next_cm_chunk = chunk->next; + unlinkChunk(alloc, chunk); + freeChunk(chunk); + + chunk = next_cm_chunk; + } + + // Remove allocator from the list + if(ListOfAllocators == alloc) + ListOfAllocators = alloc->next; + else { + t_cm_allocator_desc *prev = ListOfAllocators; + while(prev->next != alloc) + prev = prev->next; + prev->next = alloc->next; + } + + + /* Free allocator descriptor */ + OSAL_Free(alloc); + + return CM_OK; +} + +PUBLIC t_cm_error cm_MM_ResizeAllocator(t_cm_allocator_desc *alloc, t_cm_size size) +{ + t_cm_error error; + + /* sanity check */ + if (size == 0) + return CM_INVALID_PARAMETER; + + if((error = fillChunkPool()) != CM_OK) + return error; + + if (size > alloc->size) { + /* ok, increase allocator */ + t_uint32 deltaSize = size - alloc->size; + t_cm_chunk *last = cm_MM_RA_getLastChunk(alloc); + + if (last->status == MEM_FREE) { + /* last chunk is a free one, just increase size */ + unlinkFreeMem(alloc, last); + last->size += deltaSize; + alloc->size += deltaSize; + /* now list of free chunk is potentially no more ordered */ + updateFreeList(alloc, last); + } else { + /* last chunk is a used one, add new free chunk */ + last->size += deltaSize; + splitChunk(alloc, last, last->offset + deltaSize, FREE_CHUNK_AFTER); + alloc->size += deltaSize; + } + } else { + /* reduce allocator */ + t_uint32 deltaSize = alloc->size - size; + t_cm_chunk *last = cm_MM_RA_getLastChunk(alloc); + + /* check if resize is possible */ + if (last->status == MEM_USED) + return CM_NO_MORE_MEMORY; + if (last->size < deltaSize) + return CM_NO_MORE_MEMORY; + + /* ok, rezise can be performed */ + if (last->size == deltaSize) { + t_cm_chunk *prev = last->prev; + + /* remove last free chunk */ + mergeChunk(alloc, prev, last); + prev->size -= deltaSize; + } else { + unlinkFreeMem(alloc, last); + /* reduce size of last free chunk */ + last->size -= deltaSize; + /* now list of free chunk is potentially no more ordered */ + updateFreeList(alloc, last); + } + } + + alloc->size = size; + + if (cmIntensiveCheckState) { + cm_MM_RA_checkAllocator(alloc); + } + + return CM_OK; +} + +t_cm_error cm_MM_getValidMemoryHandle(t_cm_memory_handle handle, t_memory_handle* validHandle) +{ +#ifdef LINUX + /* On linux, there is already a check within the linux part + * => we don't need to check twice */ + *validHandle = (t_memory_handle)handle; + return CM_OK; +#else + t_cm_allocator_desc *alloc = ListOfAllocators; + + for(; alloc != NULL; alloc = alloc->next) + { + t_cm_chunk* chunk = alloc->chunks; + + /* Parse all chunks */ + for(; chunk != NULL; chunk = chunk->next) + { + if(chunk == (t_memory_handle)handle) + { + if(chunk->status == MEM_FREE) + return CM_MEMORY_HANDLE_FREED; + + *validHandle = (t_memory_handle)handle; + + return CM_OK; + } + } + } + + return CM_UNKNOWN_MEMORY_HANDLE; +#endif +} + +//TODO, juraj, add appartenance to allocHandle (of chunk) and degage setUserData +PUBLIC t_memory_handle cm_MM_Alloc( + t_cm_allocator_desc* alloc, + t_cm_size size, + t_cm_memory_alignment memAlignment, + t_uint32 seg_offset, + t_uint32 seg_size, + t_uint32 domainId) +{ + t_cm_chunk* chunk; + t_uint32 aligned_offset; + t_uint32 aligned_end; + t_uint32 seg_end = seg_offset + seg_size; + int i; + + /* Sanity check */ + if ( (size == 0) || (size > seg_size) ) + return INVALID_MEMORY_HANDLE; + + if(fillChunkPool() != CM_OK) + return INVALID_MEMORY_HANDLE; + + /* Get first chunk available for the specific size */ + // Search a list with a free chunk + for(i = bin_index(size); i < BINS; i++) + { + chunk = alloc->free_mem_chunks[i]; + while (chunk != 0) + { + /* Alignment of the lower boundary */ + aligned_offset = ALIGN_VALUE(MAX(chunk->offset, seg_offset), (memAlignment + 1)); + + aligned_end = aligned_offset + size; + + if ((aligned_end <= seg_end) + && aligned_end <= (chunk->offset + chunk->size) + && aligned_offset >= seg_offset + && aligned_offset >= chunk->offset) + goto found; + + chunk = chunk->next_free_mem; + } + } + + return INVALID_MEMORY_HANDLE; + +found: + + /* Remove chunk from free list */ + unlinkFreeMem(alloc, chunk); + + //create an empty chunk before the allocated one + if (chunk->offset < aligned_offset) { + chunk = splitChunk(alloc, chunk, aligned_offset, FREE_CHUNK_BEFORE); + } + //create an empty chunk after the allocated one + if (chunk->offset + chunk->size > aligned_end) { + splitChunk(alloc, chunk, aligned_end, FREE_CHUNK_AFTER); + } + + chunk->status = MEM_USED; + chunk->prev_free_mem = 0; + chunk->next_free_mem = 0; + chunk->domainId = domainId; + + //TODO, juraj, alloc impacts trace format + cm_TRC_traceMem(TRACE_ALLOC_COMMAND_ALLOC, 0, chunk->offset, chunk->size); + + if (cmIntensiveCheckState) { + cm_MM_RA_checkAllocator(alloc); + } + + chunk->alloc = alloc; + return (t_memory_handle) chunk; +} + +//caution - if successfull, the chunk offset will be aligned with seg_offset +//caution++ the offset of the allocated chunk changes implicitly +PUBLIC t_memory_handle cm_MM_Realloc( + t_cm_allocator_desc* alloc, + const t_cm_size size, + const t_uint32 offset, + const t_cm_memory_alignment memAlignment, + const t_memory_handle handle) +{ + t_cm_chunk *chunk = (t_cm_chunk*)handle; + + /* check reallocation is related to this chunk! */ + CM_ASSERT(chunk->offset <= (offset + size)); + CM_ASSERT(offset <= (chunk->offset + chunk->size)); + CM_ASSERT(size); + + /* check if extend low */ + if (offset < chunk->offset) { + /* note: it is enough to check only the previous chunk, + * because adjacent chunks of same status are merged + */ + if ((chunk->prev == 0) + ||(chunk->prev->status != MEM_FREE) + ||(chunk->prev->offset > offset)) { + return INVALID_MEMORY_HANDLE; + } + } + + /* check if extend high, note as above */ + if ( (offset + size) > (chunk->offset + chunk->size)) { + if ((chunk->next == 0) + ||(chunk->next->status != MEM_FREE) + ||( (chunk->next->offset + chunk->next->size) < (offset + size))) { + return INVALID_MEMORY_HANDLE; + } + } + + if(fillChunkPool() != CM_OK) + return INVALID_MEMORY_HANDLE; + + +#if 0 + /* extend low + * all conditions should have been checked + * this must not fail + */ + if (offset < chunk->offset) { + t_cm_chunk *tmp = splitChunk(alloc, chunk->prev, offset, FREE_CHUNK_BEFORE); //tmp = chunk->prev + CM_ASSERT(tmp); + tmp->status = MEM_USED; + tmp->prev->status = MEM_FREE; + mergeChunk(alloc, tmp, chunk); + if ((tmp->prev->prev != 0) + && (tmp->prev->prev->status == MEM_FREE)) { + mergeChunk(alloc, tmp->prev->prev, tmp->prev); + } + chunk = tmp; + } + + /* extend high */ + if ( (offset + size) > (chunk->offset + chunk->size)) { + t_cm_chunk *tmp = splitChunk(alloc, chunk->next, offset + size, FREE_CHUNK_AFTER); //tmp = chunk->next->next + CM_ASSERT(tmp); + tmp->status = MEM_USED; + mergeChunk(alloc, chunk, tmp); + if ((tmp->next->next != 0) + && (tmp->next->next->status == MEM_FREE)) { + mergeChunk(alloc, tmp->next, tmp->next->next); + } + } + + /* reduce top */ + if ((offset + size) < (chunk->offset + chunk->size)) { + t_cm_chunk *tmp = splitChunk(alloc, chunk, offset + size, FREE_CHUNK_AFTER); //tmp = chunk, chunk = result + CM_ASSERT(tmp); + tmp->status = MEM_USED; + tmp->next->status = MEM_FREE; + if ((tmp->next->next != 0) + && (tmp->next->next->status == MEM_FREE)) { + mergeChunk(alloc, tmp->next, tmp->next->next); + } + } + + /* reduce bottom */ + if (offset > chunk->offset) { + t_cm_chunk *tmp = splitChunk(alloc, chunk, offset, FREE_CHUNK_BEFORE); //tmp->next = chunk, tmp = result + CM_ASSERT(tmp); + tmp->status = MEM_USED; + tmp->prev->status = MEM_FREE; + if ((tmp->prev->prev != 0) + &&(tmp->prev->prev->status == MEM_FREE)) { + mergeChunk(alloc, tmp->prev->prev, tmp->prev); + } + chunk = tmp; + } +#else + /* extend low + * all conditions should have been checked + * this must not fail + */ + if (offset < chunk->offset) { + t_uint32 delta = chunk->prev->offset + chunk->prev->size - offset; + CM_ASSERT(chunk->prev->status == MEM_FREE); //TODO, juraj, already checked + unlinkFreeMem(alloc, chunk->prev); + chunk->prev->size -= delta; + chunk->offset -= delta; + chunk->size += delta; + updateFreeList(alloc, chunk->prev); + } + + /* extend high */ + if ( (offset + size) > (chunk->offset + chunk->size)) { + t_uint32 delta = size - chunk->size; + CM_ASSERT(chunk->next->status == MEM_FREE); //TODO, juraj, already checked + unlinkFreeMem(alloc, chunk->next); + chunk->size += delta; + chunk->next->offset += delta; + chunk->next->size -= delta; + updateFreeList(alloc, chunk->next); + } + + /* reduce top */ + if ((offset + size) < (chunk->offset + chunk->size)) { + if (chunk->next->status == MEM_FREE) { + t_uint32 delta = chunk->size - size; + unlinkFreeMem(alloc, chunk->next); + chunk->size -= delta; + chunk->next->offset -= delta; + chunk->next->size += delta; + updateFreeList(alloc, chunk->next); + } else { + t_cm_chunk *tmp = splitChunk(alloc, chunk, offset + size, FREE_CHUNK_AFTER); //tmp = chunk, chunk = result + tmp->status = MEM_USED; + tmp->next->status = MEM_FREE; + } + } + + /* reduce bottom */ + if (offset > chunk->offset) { + if (chunk->prev->status == MEM_FREE) { + t_uint32 delta = offset - chunk->offset; + unlinkFreeMem(alloc, chunk->prev); + chunk->prev->size += delta; + chunk->offset = offset; + chunk->size -= delta; + updateFreeList(alloc, chunk->prev); + } else { + t_cm_chunk *tmp = splitChunk(alloc, chunk, offset, FREE_CHUNK_BEFORE); //tmp->next = chunk, tmp = result + tmp->status = MEM_USED; + tmp->prev->status = MEM_FREE; + } + } +#endif + cm_MM_RA_checkAllocator(alloc); + + return (t_memory_handle)chunk; +} + +PUBLIC void cm_MM_Free(t_cm_allocator_desc* alloc, t_memory_handle memHandle) +{ + t_cm_chunk* chunk = (t_cm_chunk*)memHandle; + + //TODO, juraj, alloc impacts trace format + cm_TRC_traceMem(TRACE_ALLOC_COMMAND_FREE, 0, + chunk->offset, chunk->size); + + /* Update chunk status */ + chunk->status = MEM_FREE; + chunk->domainId = 0x0; + + /* Check if the previous chunk is free */ + if((chunk->prev != 0) && (chunk->prev->status == MEM_FREE)) { + chunk = chunk->prev; //chunk, ie. chunk->next, will be freed + mergeChunk(alloc, chunk, chunk->next); + } + + /* Check if the next chunk is free */ + if((chunk->next != 0) && (chunk->next->status == MEM_FREE)) { + mergeChunk(alloc, chunk, chunk->next); + } + + unlinkFreeMem(alloc, chunk); + updateFreeList(alloc, chunk); + + if (cmIntensiveCheckState) { + cm_MM_RA_checkAllocator(alloc); + } +} + +PUBLIC t_cm_error cm_MM_GetAllocatorStatus(t_cm_allocator_desc* alloc, t_uint32 offset, t_uint32 size, t_cm_allocator_status *pStatus) +{ + t_cm_chunk* chunk = alloc->chunks; + t_uint8 min_free_size_updated = FALSE; + + /* Init status */ + pStatus->global.used_block_number = 0; + pStatus->global.free_block_number = 0; + pStatus->global.maximum_free_size = 0; + pStatus->global.minimum_free_size = 0xFFFFFFFF; + pStatus->global.accumulate_free_memory = 0; + pStatus->global.accumulate_used_memory = 0; + pStatus->global.size = alloc->size; + pStatus->domain.maximum_free_size = 0; + pStatus->domain.minimum_free_size = 0xFFFFFFFF; + pStatus->domain.accumulate_free_memory = 0; + pStatus->domain.accumulate_used_memory = 0; + pStatus->domain.size= size; + + //TODO, juraj, get allocator status for a domain + /* Parse all chunks */ + while(chunk != 0) + { + + /* Chunk is free */ + if (chunk->status == MEM_FREE) { + pStatus->global.free_block_number++; + pStatus->global.accumulate_free_memory += chunk->size; + + /* Check max size */ + if (chunk->size > pStatus->global.maximum_free_size) + { + pStatus->global.maximum_free_size = chunk->size; + } + + /* Check min size */ + if (chunk->size < pStatus->global.minimum_free_size) + { + pStatus->global.minimum_free_size = chunk->size; + min_free_size_updated = TRUE; + } + } else {/* Chunk used */ + pStatus->global.used_block_number++; + pStatus->global.accumulate_used_memory += chunk->size; + } + + chunk = chunk->next; + } + + /* Put max free size to min free size */ + if (min_free_size_updated == FALSE) { + pStatus->global.minimum_free_size = pStatus->global.maximum_free_size; + } + + return CM_OK; +} + +PUBLIC t_uint32 cm_MM_GetOffset(t_memory_handle memHandle) +{ + /* Provide offset */ + return ((t_cm_chunk*)memHandle)->offset; +} + +PUBLIC t_uint32 cm_MM_GetSize(t_memory_handle memHandle) +{ + return ((t_cm_chunk*)memHandle)->size; +} + +PUBLIC t_uint32 cm_MM_GetAllocatorSize(t_cm_allocator_desc* alloc) +{ + return alloc->size; +} + +PUBLIC void cm_MM_SetMemoryHandleUserData(t_memory_handle memHandle, t_uint16 userData) +{ + ((t_cm_chunk*)memHandle)->userData = userData; +} + +PUBLIC void cm_MM_GetMemoryHandleUserData(t_memory_handle memHandle, t_uint16 *pUserData, t_cm_allocator_desc **alloc) +{ + *pUserData = ((t_cm_chunk*)memHandle)->userData; + if (alloc) + *alloc = ((t_cm_chunk*)memHandle)->alloc; +} + +/* + * check free list is ordered + * check all chunks are correctly linked + * check adjacent chunks are not FREE + */ +static void cm_MM_RA_checkAllocator(t_cm_allocator_desc* alloc) +{ + t_cm_chunk *chunk = alloc->chunks; + t_cm_chunk *first = chunk; + t_cm_chunk *last = chunk; + t_uint32 size = 0; + int i; + + while(chunk != 0) { + CM_ASSERT(chunk->alloc == alloc); + + if (chunk->next != 0) { + CM_ASSERT(!((chunk->status == MEM_FREE) && (chunk->next->status == MEM_FREE))); //two free adjacent blocks + CM_ASSERT(chunk->offset < chunk->next->offset); //offsets reverted + last = chunk->next; + } + size += chunk->size; + chunk = chunk->next; + } + + CM_ASSERT(size == alloc->size); + + for(i = 0; i < BINS; i++) + { + chunk = alloc->free_mem_chunks[i]; + while(chunk != 0) { + if (chunk->next_free_mem != 0) { + CM_ASSERT(chunk->size <= chunk->next_free_mem->size); //free list not ordered + } + CM_ASSERT(!(chunk->prev == 0 && (chunk != first))); //chunk not linked properly + CM_ASSERT(!(chunk->next == 0 && (chunk != last))); //chunk not linked property + chunk = chunk->next_free_mem; + } + } +} + +#if 0 +static void cm_MM_RA_checkAlloc(t_cm_allocator_desc* alloc, t_uint32 size, t_uint32 align, t_uint32 min, t_uint32 max) +{ + t_cm_chunk *chunk = alloc->chunks; + + while(chunk != 0) { + if (chunk->status == MEM_USED) { + chunk = chunk->next; + continue; + } + if (chunk->size < size) { + chunk = chunk->next; + continue; + } + + if (min < chunk->offset) { + t_uint32 aligned_offset = ALIGN_VALUE(chunk->offset, align + 1); + t_uint32 aligned_end = aligned_offset + size; + if ((aligned_offset + size <= chunk->offset + chunk->size) + && (chunk->offset + chunk->size <= aligned_end)){ + break; + } + } + + if (min >= chunk->offset) { + t_uint32 aligned_offset = ALIGN_VALUE(min, align + 1); + t_uint32 aligned_end = aligned_offset + size; + if ((aligned_offset + size <= chunk->offset + chunk->size) + && (chunk->offset + chunk->size <= aligned_end)) { + break; + } + } + + chunk = chunk->next; + } + + CM_ASSERT(chunk == 0); +} +#endif + +/***************************************************************************/ +/* + * cm_mm_ra_getLastChunk + * param handle : Handle of the allocator + * return : last + * + * Free all chunk in the allocator + * Free allocator descriptor + * + */ +/***************************************************************************/ +static t_cm_chunk* cm_MM_RA_getLastChunk(t_cm_allocator_desc* alloc) +{ + t_cm_chunk* pChunk = alloc->chunks; + + while(pChunk->next != 0) {pChunk = pChunk->next;} + + return pChunk; +} + +PUBLIC void cm_MM_DumpMemory(t_cm_allocator_desc* alloc, t_uint32 start, t_uint32 end) +{ + t_cm_chunk *chunk = alloc->chunks; + + LOG_INTERNAL(0, "ALLOCATOR Dumping allocator \"%s\" [0x%08x:0x%08x]\n", alloc->pAllocName, start, end, 0, 0, 0); + while(chunk != 0) { + if (((chunk->offset < start) && (chunk->offset + chunk->size > start)) + || ((chunk->offset < end) && (chunk->offset + chunk->size > end)) + || ((chunk->offset > start) && (chunk->offset + chunk->size < end)) + || ((chunk->offset < start) && (chunk->offset + chunk->size > end))) + { + LOG_INTERNAL(0, "ALLOCATOR chunk 0x%08x -> 0x%08x: status:%s, domainId: 0x%x\n", + chunk->offset, + chunk->offset + chunk->size, + chunk->status?"FREE":"USED", + chunk->domainId, 0, 0); + } + chunk = chunk->next; + } +} diff --git a/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator_utils.c b/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator_utils.c new file mode 100644 index 00000000000..5c19d3e9b5e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator_utils.c @@ -0,0 +1,270 @@ +/* + * 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/memory/inc/remote_allocator_utils.h> + +/***************************************************************************/ +/* + * linkChunk + * param prev : Pointer on previous chunk where the chunk will be added + * param add : Pointer on chunk to add + * + * Add a chunk in the memory list + * + */ +/***************************************************************************/ +PUBLIC void linkChunk(t_cm_chunk* prev, t_cm_chunk* add) +{ + /* Link previous */ + add->prev = prev; + add->next = prev->next; + + /* Link next */ + if (prev->next != 0) + { + prev->next->prev = add; + } + prev->next = add; +} + +/***************************************************************************/ +/* + * unlinkChunk + * param allocHandle : Allocator handle + * param current : Pointer on chunk to remove + * + * Remove a chunk in the memory list and update first pointer + * + */ +/***************************************************************************/ +PUBLIC void unlinkChunk(t_cm_allocator_desc* alloc ,t_cm_chunk* current) +{ + /* Unlink previous */ + if (current->prev !=0) + { + current->prev->next = current->next; + } + + /* Unlink next */ + if (current->next !=0) + { + current->next->prev= current->prev; + } + + /* Update first pointer */ + if (alloc ->chunks == current) + { + alloc ->chunks = current->next; + } +} + + +/***************************************************************************/ +/* + * unlinkFreeMem() unlinks chunk from free memory double-linked list + * makes the previous and next chunk in the list point to each other.. + * param allocHandle : Allocator handle + * param current : Pointer on chunk to remove + * + * Remove a chunk in the free memory list and update pointer + * + */ +/***************************************************************************/ +PUBLIC void unlinkFreeMem(t_cm_allocator_desc* alloc ,t_cm_chunk* current) +{ + int bin = bin_index(current->size); + + /* unlink previous */ + if (current->prev_free_mem != 0) + { + current->prev_free_mem->next_free_mem = current->next_free_mem; + } + + /* Unlink next */ + if (current->next_free_mem !=0 ) + { + current->next_free_mem->prev_free_mem = current->prev_free_mem; + } + + /* update first free pointer */ + if (alloc->free_mem_chunks[bin] == current) + { + alloc->free_mem_chunks[bin] = current->next_free_mem; + } + + current->prev_free_mem = 0; + current->next_free_mem = 0; +} + +/***************************************************************************/ +/* + * linkFreeMemBefore + * param add : Pointer on chunk to add + * param next : Pointer on next chunk where the chunk will be added before + * + * Add a chunk in the free memory list + * + */ +/***************************************************************************/ +PUBLIC void linkFreeMemBefore(t_cm_chunk* add, t_cm_chunk* next) +{ + /* Link next */ + add->prev_free_mem = next->prev_free_mem; + add->next_free_mem = next; + + /* Link previous */ + if (next->prev_free_mem != 0) + { + next->prev_free_mem->next_free_mem = add; + } + next->prev_free_mem = add; +} + +/***************************************************************************/ +/* + * linkFreeMemAfter + * param add : Pointer on chunk to add + * param prev : Pointer on previous chunk where the chunk will be added after + * + * Add a chunk in the free memory list + * + */ +/***************************************************************************/ +PUBLIC void linkFreeMemAfter(t_cm_chunk* prev,t_cm_chunk* add) +{ + /* Link previous */ + add->prev_free_mem = prev; + add->next_free_mem = prev->next_free_mem; + + /* Link next */ + if (prev->next_free_mem != 0) + { + prev->next_free_mem->prev_free_mem = add; + } + prev->next_free_mem = add; +} + + +/***************************************************************************/ +/* + * updateFreeList + * param allocHandle : Allocator handle + * param offset : Pointer on chunk + * + * Update free memory list, ordered by size + * + */ +/***************************************************************************/ +PUBLIC void updateFreeList(t_cm_allocator_desc* alloc , t_cm_chunk* chunk) +{ + t_cm_chunk* free_chunk; + int bin = bin_index(chunk->size); + + /* check case with no more free block */ + if (alloc->free_mem_chunks[bin] == 0) + { + alloc->free_mem_chunks[bin] = chunk; + return ; + } + + /* order list */ + free_chunk = alloc->free_mem_chunks[bin]; + while ((free_chunk->next_free_mem != 0) && (chunk->size > free_chunk->size)) + { + free_chunk = free_chunk->next_free_mem; + } + + /* Add after free chunk if smaller -> we are the last */ + if(free_chunk->size <= chunk->size) + { + linkFreeMemAfter(free_chunk,chunk); + } + else // This mean that we are smaller + { + linkFreeMemBefore(chunk,free_chunk); + + /* Update first free chunk */ + if (alloc->free_mem_chunks[bin] == free_chunk) + { + alloc->free_mem_chunks[bin] = chunk; + } + } +} + + +/***************************************************************************/ +/* + * mergeChunk + * param allocHandle : Allocator handle + * param merged_chunk : Pointer on merged chunk + * param destroy : Pointer on chunk to destroy + * + * Link and destroy merged chunks + * + */ +/***************************************************************************/ +PUBLIC void mergeChunk(t_cm_allocator_desc* alloc,t_cm_chunk *merged_chunk, t_cm_chunk *destroy) +{ + /* Assign offset to the merged */ + /* assume chunks ordered! + if (merged_chunk->offset > destroy->offset) { + merged_chunk->offset = destroy->offset; + } + */ + + /* Remove chunk */ + unlinkChunk(alloc, destroy); + unlinkFreeMem(alloc, destroy); + + if (merged_chunk->status == MEM_FREE) + unlinkFreeMem(alloc, merged_chunk); + + /* Update size */ + merged_chunk->size += destroy->size; + + if (merged_chunk->status == MEM_FREE) + updateFreeList(alloc, merged_chunk); + + freeChunk(destroy); +} + +/***************************************************************************/ +/* + * splitChunk + * param allocHandle : Allocator handle + * param chunk : Current chunk (modified in place) + * param offset : Offset address of the start memory + * return : New chunk handle or 0 if an error occurs + * + * Create new chunk before/after the current chunk with the size + */ +/***************************************************************************/ +PUBLIC t_cm_chunk* splitChunk(t_cm_allocator_desc* alloc ,t_cm_chunk *chunk, + t_uint32 offset, t_mem_split_position position) +{ + t_cm_chunk *free; + t_cm_chunk *returned; + + t_cm_chunk* new_chunk = allocChunk(); + + if (position == FREE_CHUNK_AFTER) { + returned = chunk; + free = new_chunk; + } else { //FREE_CHUNK_BEFORE + returned = new_chunk; + free = chunk; + } + + new_chunk->offset = offset; + new_chunk->size = chunk->offset + chunk->size - offset; + new_chunk->alloc = alloc; + chunk->size = offset - chunk->offset; + + linkChunk(chunk, new_chunk); + unlinkFreeMem(alloc, free); + updateFreeList(alloc, free); + + return returned; +} diff --git a/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h b/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h new file mode 100644 index 00000000000..8d95436e796 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h @@ -0,0 +1,471 @@ +/* + * 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. + */ +/*! + * \brief OS Adaptation Layer API + * + * \defgroup CM_ENGINE_OSAL_API CM Engine OSAL (Operating System Abstraction Layer) API + * \ingroup CM_ENGINE_MODULE + */ +#ifndef __INC_CM_OSAL_H +#define __INC_CM_OSAL_H + +#include <cm/inc/cm_type.h> +#include <cm/engine/communication/inc/communication_type.h> + +/*! + * \brief Identifier of a trace channel (id in [0..255]) + * \ingroup CM_ENGINE_OSAL_API + */ +typedef t_uint8 t_nmf_trace_channel; + +/*! + * \brief Identifier of lock create by OSAL + * \ingroup CM_ENGINE_OSAL_API + */ +typedef t_uint32 t_nmf_osal_sync_handle; + +/*! + * \brief Identifier of semaphore create by OSAL + * \ingroup CM_ENGINE_OSAL_API + */ +typedef t_uint32 t_nmf_osal_sem_handle; + +/*! + * \brief Identifier of semaphore wait error return by semaphore OSAL API + * \ingroup CM_ENGINE_OSAL_API + */ +typedef t_uint8 t_nmf_osal_sync_error; +#define SYNC_ERROR_TIMEOUT ((t_nmf_osal_sync_error)-1) +#define SYNC_OK ((t_nmf_osal_sync_error)0) +#define SEM_TIMEOUT_NORMAL 3000 +#define SEM_TIMEOUT_DEBUG 300000 + +/*! + * \brief Description of the Scheduling part of the OS Adaptation Layer + * + * <B>Goal:</B> Support of uplink communication path (from Media Processors to Host (ARM)) + * + * Post a function call outside of Host CPU Interrupt mode in order to minimize ISR execution time + * \param[in] upLayerTHIS : this one provided by user when calling CM_ENGINE_BindComponentToCMCore() (first field of the interface context) \n + * \param[in] methodIndex : index method to be called \n + * \param[in] anyPtr : internal NMF marshaled parameters block (to be passed as second parameter when calling the previous pSkeleton method) \n + * \param[in] ptrSize : size of anyPtr in bytes \n + * + * Called by: + * - CM_ProcessMpcEvent() call (shall be bound by OS integrator to HSEM IRQ) + * + * \ingroup CM_ENGINE_OSAL_API + */ + +PUBLIC void OSAL_PostDfc( + t_nmf_mpc2host_handle upLayerTHIS, + t_uint32 methodIndex, + t_event_params_handle anyPtr, + t_uint32 ptrSize); + + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to protect global variable against multiple call. Interrupt and scheduler function are use when + * we take hardware/local semaphore. Scheduler lock functions can have empty implementation but this may + * impact performance (dsp waiting semaphore because host thread was preempted whereas it has already take semaphore + * but not yet release it). + * + * \return handle of the Mutex created + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_nmf_osal_sync_handle OSAL_CreateLock(void); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to protect global variable against multiple call. Interrupt and scheduler function are use when + * we take hardware/local semaphore. Scheduler lock functions can have empty implementation but this may + * impact performance (dsp waiting semaphore because host thread was preempted whereas it has already take semaphore + * but not yet release it). + * + * \param[in] handle handle of the Mutex to be locked + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Lock( + t_nmf_osal_sync_handle handle); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to protect global variable against multiple call. Interrupt and scheduler function are use when + * we take hardware/local semaphore. Scheduler lock functions can have empty implementation but this may + * impact performance (dsp waiting semaphore because host thread was preempted whereas it has already take semaphore + * but not yet release it). + * + * \param[in] handle handle of the Mutex to be unlocked + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Unlock( + t_nmf_osal_sync_handle handle); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to protect global variable against multiple call. Interrupt and scheduler function are use when + * we take hardware/local semaphore. Scheduler lock functions can have empty implementation but this may + * impact performance (dsp waiting semaphore because host thread was preempted whereas it has already take semaphore + * but not yet release it). + * + * \param[in] handle handle of the Mutex to be destroyed + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_DestroyLock( + t_nmf_osal_sync_handle handle); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to allow to synchronize with code running on mpc side. + * + * \param[in] value : Initial value of semaphore. + * + * \return handle of the Semaphore created + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_nmf_osal_sem_handle OSAL_CreateSemaphore( + t_uint32 value); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to allow to synchronize with code running on mpc side. This function can be call under + * Irq context by CM. + * + * \param[in] handle handle of the Semaphore for which we increase value and so potentially wake up thread. + * + * \param[in] aCtx is a hint to indicate to os that we are in a none normal context (e.g under interruption). + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_SemaphorePost( + t_nmf_osal_sem_handle handle, + t_uint8 aCtx); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to allow to synchronize with code running on mpc side. + * + * \param[in] handle of the Semaphore for which we decrease value and so potentially block current thread. + * + * \param[in] timeOutInMs maximun time in ms after which the block thread is wake up. In this case function return SYNC_ERROR_TIMEOUT value. + * + * \return error number: SYNC_ERROR_TIMEOUT in case semaphore is not release withing timeOutInMs. + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_nmf_osal_sync_error OSAL_SemaphoreWaitTimed( + t_nmf_osal_sem_handle handle, + t_uint32 timeOutInMs); + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * <B>Goal:</B> Use by CM to allow to synchronize with code running on mpc side. + * + * \param[in] handle handle of the Semaphore to be destroyed + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_DestroySemaphore( + t_nmf_osal_sem_handle handle); + +/*! + * \brief Description of the System Memory Allocator part of the OS Adaptation Layer + * + * <B>Goal:</B> Allocate CM some cacheable and bufferable memory (SDRAM) for internal usage \n + * This memory will be accessed only by Host CPU (ARM) + * + * This function provide a simple, general-purpose memory allocation. The + * OSAL_Alloc macro returns a pointer to a block of at least size bytes + * suitably aligned for any use. If there is no available memory, this + * function returns a null pointer. + * + * \param[in] size size in bytes, of memory to be allocated + * \return pointer on the beginning of the allocated memory + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void* OSAL_Alloc( + t_cm_size size); + +/*! + * \brief Description of the System Memory Allocator part of the OS Adaptation Layer with memory set to zero + * + * Compare to \see OSAL_Alloc, same allocation is done but memory is set with zero before returning. + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void* OSAL_Alloc_Zero( + t_cm_size size); + +/*! + * \brief Description of the System Memory Allocator part of the OS Adaptation Layer + * + * <B>Goal:</B> Free CM some cacheable and bufferable memory (SDRAM) for internal usage \n + * This memory will be accessed only by Host CPU (ARM) + * + * \param[in] pHandle pointer on the begining of the memory previously allocated + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Free( + void *pHandle); + +/*! + * \brief Clean data cache in DDR in order to be accessible from peripheral. + * + * This method must be synchronized with MMDSP Code cache attribute. + * Strongly Ordered -> nothing + * Shared device -> dsb + L2 Write buffer drain + * Non cacheable, Bufferable -> dsb + L2 Write buffer drain + * WT or WB -> Flush cache range + dsb + L2 Write buffer drain + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_CleanDCache( + t_uint32 startAddr, //!< [in] Start data address of range to clean + t_uint32 Size //!< [in] Size of range to clean + ); + +/*! + * \brief Flush write buffer. + * + * This method must be synchronized with MMDSP Data cache attribute. + * Strongly Ordered -> nothing + * Shared device -> dsb + L2 Write buffer drain + * Non cacheable, Bufferable -> dsb + L2 Write buffer drain + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_mb(void); + +/*! + * \brief Description of the System Memory part of the OS Adaptation Layer + * + * <B>Goal:</B> Copy some cacheable and bufferable memory (SDRAM) provided by a client to\n + * internal memory. + * + * \param[in] dst : pointer on the begining of the internal memory previously allocated + * \param[in] src : pointer on the begining of the client's memory + * \param[in] size : The size of the data to copy + * + * Called by: + * - CM_ENGINE_PushComponent() + * + * \note This API is mainly provided for the OS were the client application does execute in the same + * address space as the CM. + * For example in Linux or Symbian, the client's address space is userland but the CM execute in + * kernel space. Thus, 'dst' is supposed to be a kernel address but src is supposed to be a user + * space address + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_cm_error OSAL_Copy( + void *dst, + const void *src, + t_cm_size size); + +/*! + * \brief Description of the internal log traces configuration of the Component Manager + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Log( + const char *format, + int param1, + int param2, + int param3, + int param4, + int param5, + int param6); + +/*! + * \brief Generate an OS-Panic. Called in from CM_ASSERT(). + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Panic(void); + +/*! + * \brief Description of the configuration of the trace features + * + * (trace output itself is provided by user through his custom implementation of the generic APIs) + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_Write64( + t_nmf_trace_channel channel, + t_uint8 isTimestamped, + t_uint64 value); + +/*! + * \brief Power enabling/disabling commands description. + * + * \ingroup CM_ENGINE_OSAL_API + */ +typedef enum +{ + CM_OSAL_POWER_SxA_CLOCK, //!< SxA Power & Clock, firstParam contains Core ID + CM_OSAL_POWER_SxA_AUTOIDLE, //!< SxA AutoIdle, firstParam contains Core ID + CM_OSAL_POWER_SxA_HARDWARE, //!< SxA Hardware Power, firstParam contains Core ID + CM_OSAL_POWER_HSEM, //!< HSEM Power + CM_OSAL_POWER_SDRAM, //!< SDRAM memory, firstParam contains physical resource address, secondParam contains size + CM_OSAL_POWER_ESRAM //!< ESRAM memory, firstParam contains physical resource address, secondParam contains size +} t_nmf_power_resource; + +/*! + * \brief Description of the Power Management part of the OS Adaptation Layer + * + * Use by CM engine to disable a logical power domain (see \ref t_nmf_power_resource) + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_DisablePwrRessource( + t_nmf_power_resource resource, //!< [in] Describe the domain which must be disabled + t_uint32 firstParam, //!< [in] Eventual first parameter to power to disable + t_uint32 secondParam //!< [in] Eventual second parameter to power to disable + ); + +/*! + * \brief Description of the Power Management part of the OS Adaptation Layer + * + * Use by CM engine to enable a logical power domain (see \ref t_nmf_power_resource) + * + * \return + * - \ref CM_OK + * - \ref CM_PWR_NOT_AVAILABLE A specified power domain is not managed (see returned value in aPowerMask) + * + * Called by: + * - any CM API call + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_cm_error OSAL_EnablePwrRessource( + t_nmf_power_resource resource, //!< [in] Describing the domains which must be enabled + t_uint32 firstParam, //!< [in] Eventual first parameter to power to disable + t_uint32 secondParam //!< [in] Eventual second parameter to power to disable + ); + + +/*! + * \brief return prcmu timer value. + * + * This is need for perfmeter api (see \ref t_nmf_power_resource) + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC t_uint64 OSAL_GetPrcmuTimer(void); + +/*! + * \brief Disable the service message handling (panic, etc) + * + * It must disable the handling of all service messages + * If a service message is currently handled, it must wait till the end + * of its managment before returning. + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_DisableServiceMessages(void); + +/*! + * \brief Enable the service message handling (panic, etc) + * + * It enables the handling of all service messages + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_EnableServiceMessages(void); + +extern /*const*/ t_nmf_osal_sync_handle lockHandleApi; +extern /*const*/ t_nmf_osal_sync_handle lockHandleCom; +extern /*const*/ t_nmf_osal_sem_handle semHandle; + +/*! + * \brief Take a lock before entering critical section. Can suspend current thread if lock already taken. \n + * Use this macro in api function. For com function use OSAL_LOCK_COM. + * + * \ingroup CM_ENGINE_OSAL_API + */ +#define OSAL_LOCK_API() OSAL_Lock(lockHandleApi) + +/*! + * \brief Release lock before leaving critical section. + * + * \ingroup CM_ENGINE_OSAL_API + */ +#define OSAL_UNLOCK_API() OSAL_Unlock((lockHandleApi)) + +/*! + * \brief Take a lock before entering critical section. Can suspend current thread if lock already taken. \n + * Use this macro in com function. For com function use OSAL_LOCK_API. + * + * \ingroup CM_ENGINE_OSAL_API + */ +#define OSAL_LOCK_COM() OSAL_Lock(lockHandleCom) + +/*! + * \brief Release lock before leaving critical section. + * + * \ingroup CM_ENGINE_OSAL_API + */ +#define OSAL_UNLOCK_COM() OSAL_Unlock((lockHandleCom)) + +/*! + * \brief Go to sleep untill post done on semaphore or timeout expire. In that case SYNC_ERROR_TIMEOUT is return. + * + * \ingroup CM_ENGINE_OSAL_API + */ +#define OSAL_SEMAPHORE_WAIT_TIMEOUT(semHandle) OSAL_SemaphoreWaitTimed(semHandle, (cm_PWR_GetMode() == NORMAL_PWR_MODE)?SEM_TIMEOUT_NORMAL:SEM_TIMEOUT_DEBUG) + + +/****************/ +/* Generic part */ +/****************/ +t_cm_error cm_OSAL_Init(void); +void cm_OSAL_Destroy(void); + +#endif /* __INC_CM_OSAL_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/src/os_adaptation_layer.c b/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/src/os_adaptation_layer.c new file mode 100644 index 00000000000..9beb60dea18 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/os_adaptation_layer/src/os_adaptation_layer.c @@ -0,0 +1,39 @@ +/* + * 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/os_adaptation_layer/inc/os_adaptation_layer.h> + +t_nmf_osal_sync_handle lockHandleApi; +t_nmf_osal_sync_handle lockHandleCom; +t_nmf_osal_sem_handle semHandle; + +/****************/ +/* Generic part */ +/****************/ +PUBLIC t_cm_error cm_OSAL_Init(void) +{ + + /* create locks */ + lockHandleApi = OSAL_CreateLock(); + if (lockHandleApi == 0) {return CM_INVALID_PARAMETER;} + lockHandleCom = OSAL_CreateLock(); + if (lockHandleCom == 0) {return CM_INVALID_PARAMETER;} + + /* create semaphore */ + semHandle = OSAL_CreateSemaphore(0); + if (semHandle == 0) {return CM_INVALID_PARAMETER;} + + return CM_OK; +} + +PUBLIC void cm_OSAL_Destroy(void) +{ + /* destroy locks */ + OSAL_DestroyLock(lockHandleApi); + OSAL_DestroyLock(lockHandleCom); + + /* destroy semaphore */ + OSAL_DestroySemaphore(semHandle); +} diff --git a/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/mpcload.h b/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/mpcload.h new file mode 100644 index 00000000000..0831f1940ca --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/mpcload.h @@ -0,0 +1,21 @@ +/* + * 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. + */ +/*! + * \internal + */ +#ifndef MPCLOAD_H_ +#define MPCLOAD_H_ + +#include <cm/engine/component/inc/instance.h> + +/******************************************************************************/ +/************************ FUNCTIONS PROTOTYPES ********************************/ +/******************************************************************************/ + +PUBLIC t_cm_error cm_PFM_allocatePerfmeterDataMemory(t_nmf_core_id coreId, t_cm_domain_id domainId); +PUBLIC void cm_PFM_deallocatePerfmeterDataMemory(t_nmf_core_id coreId); + +#endif /* MPCLOAD_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/perfmeter_type.h b/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/perfmeter_type.h new file mode 100644 index 00000000000..78de395acc2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/perfmeter/inc/perfmeter_type.h @@ -0,0 +1,34 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Public Component Manager Performance Meter API type. + * + * This file contains the Component Manager API type for performance meter. + * + * \defgroup PERFMETER CM Monitoring API + * \ingroup CM_USER_API + */ +#ifndef CM_COMMON_PERFMETER_TYPE_H_ +#define CM_COMMON_PERFMETER_TYPE_H_ + +#include <cm/inc/cm_type.h> +/*! + * \brief Description of mpc load structure. + * + * This contain mpc load value. + * + * \ingroup PERFMETER + */ +typedef struct { + t_uint64 totalCounter; + t_uint64 loadCounter; +} t_cm_mpc_load_counter; + + +#endif /* CM_COMMON_PERFMETER_TYPE_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/perfmeter/src/mpcload.c b/drivers/staging/nmf-cm/cm/engine/perfmeter/src/mpcload.c new file mode 100644 index 00000000000..b157103934d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/perfmeter/src/mpcload.c @@ -0,0 +1,116 @@ +/* + * 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/perfmeter/inc/mpcload.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> + +#include <cm/engine/api/perfmeter_engine.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +#define PERFMETER_MAX_RETRIES 32 +#define PERFMETER_DATA_WORD_NB 7 + +/* private type */ +typedef struct { + t_memory_handle perfmeterDataHandle; + t_cm_logical_address perfmeterDataAddr; +} t_mpcLoad; + +/* private globals */ +t_mpcLoad mpcLoad_i[NB_CORE_IDS]; + +/* engine api */ +PUBLIC EXPORT_SHARED t_cm_error CM_GetMpcLoadCounter( + t_nmf_core_id coreId, + t_cm_mpc_load_counter *pMpcLoadCounter +) +{ + t_uint24 data[PERFMETER_DATA_WORD_NB]; + t_uint32 i; + t_uint64 prcmuBeforeAttributes; + t_uint32 retryCounter = 0; + volatile t_uint32 *pData; + + pMpcLoadCounter->totalCounter = 0; + pMpcLoadCounter->loadCounter = 0; + /* check core id is an mpc */ + if (coreId < FIRST_MPC_ID || coreId > LAST_CORE_ID) {return CM_INVALID_PARAMETER;} + + /* check core has been booted */ + pData = (t_uint32 *) mpcLoad_i[coreId].perfmeterDataAddr; + if (pData == NULL) {return CM_OK;} + + do { + prcmuBeforeAttributes = OSAL_GetPrcmuTimer(); + /* get attributes */ + do + { + for(i = 0;i < PERFMETER_DATA_WORD_NB;i++) + data[i] = pData[i]; + } + while(((data[0] & 0xff0000) != (data[1] & 0xff0000) || (data[0] & 0xff0000) != (data[2] & 0xff0000) || + (data[0] & 0xff0000) != (data[3] & 0xff0000) || (data[0] & 0xff0000) != (data[4] & 0xff0000) || + (data[0] & 0xff0000) != (data[5] & 0xff0000) || (data[0] & 0xff0000) != (data[6] & 0xff0000) || + (data[0] & 0xff0000) != (data[6] & 0xff0000)) + && retryCounter-- < PERFMETER_MAX_RETRIES); // check data coherence + if (retryCounter >= PERFMETER_MAX_RETRIES) + return CM_MPC_NOT_RESPONDING; + + /* read forever counter for totalCounter */ + pMpcLoadCounter->totalCounter = OSAL_GetPrcmuTimer(); + } while(pMpcLoadCounter->totalCounter - prcmuBeforeAttributes >= 32); //we loop until it seems we have not be preempt too long (< 1ms) + + /* we got coherent data, use them */ + pMpcLoadCounter->loadCounter = ((data[0] & (t_uint64)0xffff) << 32) + ((data[1] & (t_uint64)0xffff) << 16) + ((data[2] & (t_uint64)0xffff) << 0); + //fix load counter if needed + if ((data[6] & 0xffff) == 1) { + t_uint64 lastEvent; + + lastEvent = ((data[3] & (t_uint64)0xffff) << 32) + ((data[4] & (t_uint64)0xffff) << 16) + ((data[5] & (t_uint64)0xffff) << 0); + pMpcLoadCounter->loadCounter += pMpcLoadCounter->totalCounter - lastEvent; + } + + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_getMpcLoadCounter( + t_nmf_core_id coreId, + t_cm_mpc_load_counter *pMpcLoadCounter +) +{ + t_cm_error error; + + OSAL_LOCK_API(); + error = CM_GetMpcLoadCounter(coreId, pMpcLoadCounter); + OSAL_UNLOCK_API(); + return error; +} + +/* internal api */ +PUBLIC t_cm_error cm_PFM_allocatePerfmeterDataMemory(t_nmf_core_id coreId, t_cm_domain_id domainId) +{ + t_cm_error error = CM_OK; + t_mpcLoad *pMpcLoad = (t_mpcLoad *) &mpcLoad_i[coreId]; + + pMpcLoad->perfmeterDataHandle = cm_DM_Alloc(domainId, SDRAM_EXT24, PERFMETER_DATA_WORD_NB, CM_MM_ALIGN_WORD, TRUE); + if (pMpcLoad->perfmeterDataHandle == INVALID_MEMORY_HANDLE) + error = CM_NO_MORE_MEMORY; + else { + t_uint32 mmdspAddr; + + pMpcLoad->perfmeterDataAddr = cm_DSP_GetHostLogicalAddress(pMpcLoad->perfmeterDataHandle); + cm_DSP_GetDspAddress(pMpcLoad->perfmeterDataHandle, &mmdspAddr); + cm_writeAttribute(cm_EEM_getExecutiveEngine(coreId)->instance, "rtos/perfmeter/perfmeterDataAddr", mmdspAddr); + } + + return error; +} + +PUBLIC void cm_PFM_deallocatePerfmeterDataMemory(t_nmf_core_id coreId) +{ + mpcLoad_i[coreId].perfmeterDataAddr = 0; + cm_DM_Free(mpcLoad_i[coreId].perfmeterDataHandle, TRUE); +} diff --git a/drivers/staging/nmf-cm/cm/engine/power_mgt/inc/power.h b/drivers/staging/nmf-cm/cm/engine/power_mgt/inc/power.h new file mode 100644 index 00000000000..1ca1b314833 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/power_mgt/inc/power.h @@ -0,0 +1,59 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Enable a CM power domain by CoreID. + * + * \ingroup COMPONENT_INTERNAL + */ +#ifndef __INC_NMF_POWER +#define __INC_NMF_POWER + +#include <cm/inc/cm_type.h> +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/dsp/inc/dsp.h> + +typedef enum +{ + NORMAL_PWR_MODE = 0x1, //!< Normal mode + DISABLE_PWR_MODE = 0x2 //!< Disable mode - CM Power management is disabled. CM Power domain are always enabled and the EEs are loaded by default +} t_nmf_power_mode; + +PUBLIC t_cm_error cm_PWR_Init(void); +void cm_PWR_SetMode(t_nmf_power_mode aMode); +t_nmf_power_mode cm_PWR_GetMode(void); +t_uint32 cm_PWR_GetMPCMemoryCount(t_nmf_core_id coreId); + +typedef enum +{ + MPC_PWR_CLOCK, + MPC_PWR_AUTOIDLE, + MPC_PWR_HWIP +} t_mpc_power_request; + +PUBLIC t_cm_error cm_PWR_EnableMPC( + t_mpc_power_request request, + t_nmf_core_id coreId); +PUBLIC void cm_PWR_DisableMPC( + t_mpc_power_request request, + t_nmf_core_id coreId); + +PUBLIC t_cm_error cm_PWR_EnableHSEM(void); +PUBLIC void cm_PWR_DisableHSEM(void); + +PUBLIC t_cm_error cm_PWR_EnableMemory( + t_nmf_core_id coreId, + t_dsp_memory_type_id dspMemType, + t_cm_physical_address address, + t_cm_size size); +PUBLIC void cm_PWR_DisableMemory( + t_nmf_core_id coreId, + t_dsp_memory_type_id dspMemType, + t_cm_physical_address address, + t_cm_size size); + + +#endif /* __INC_NMF_POWER */ diff --git a/drivers/staging/nmf-cm/cm/engine/power_mgt/src/cmpower.c b/drivers/staging/nmf-cm/cm/engine/power_mgt/src/cmpower.c new file mode 100644 index 00000000000..5b206bfb82d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/power_mgt/src/cmpower.c @@ -0,0 +1,226 @@ +/* + * 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/power.h" + +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/convert.h> +#include <cm/engine/dsp/inc/dsp.h> + +// ------------------------------------------------------------------------------- +// Compilation flags +// ------------------------------------------------------------------------------- +#define __PWR_DEBUG_TRACE_LEVEL 2 // Debug trave level for CM power module + +// ------------------------------------------------------------------------------- +// Internal counter to store the TCM allocated chunk (by MPC) +// ------------------------------------------------------------------------------- +static t_uint32 _pwrMPCHWIPCountT[NB_CORE_IDS]; + +// ------------------------------------------------------------------------------- +// Internal counter to store the TCM allocated chunk (by MPC) +// ------------------------------------------------------------------------------- +static t_uint32 _pwrMPCMemoryCountT[NB_CORE_IDS]; + + +// ------------------------------------------------------------------------------- +// Internal data to store the global Power Manager mode (see cm_PWR_Init fct) +// ------------------------------------------------------------------------------- +static t_nmf_power_mode _pwrMode = NORMAL_PWR_MODE; + +// ------------------------------------------------------------------------------- +// cm_PWR_Init +// ------------------------------------------------------------------------------- +PUBLIC t_cm_error cm_PWR_Init(void) +{ + int i; + + for (i=0; i<NB_CORE_IDS;i++) + { + _pwrMPCHWIPCountT[i] = 0; + _pwrMPCMemoryCountT[i] = 0; + } + + return CM_OK; +} + +// ------------------------------------------------------------------------------- +// cm_PWR_SetMode +// ------------------------------------------------------------------------------- +void cm_PWR_SetMode(t_nmf_power_mode aMode) +{ + _pwrMode = aMode; +} + +t_nmf_power_mode cm_PWR_GetMode() +{ + return _pwrMode; +} + +t_uint32 cm_PWR_GetMPCMemoryCount(t_nmf_core_id coreId) +{ + return _pwrMPCMemoryCountT[coreId]; +} + + +PUBLIC t_cm_error cm_PWR_EnableMPC( + t_mpc_power_request request, + t_nmf_core_id coreId) +{ + t_cm_error error; + + switch(request) + { + case MPC_PWR_CLOCK: + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] MPC %s enable clock\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + if((error = OSAL_EnablePwrRessource(CM_OSAL_POWER_SxA_CLOCK, coreId, 0)) != CM_OK) + { + ERROR("[Pwr] MPC %s clock can't be enabled\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + return error; + } + break; + case MPC_PWR_AUTOIDLE: + if((error = OSAL_EnablePwrRessource(CM_OSAL_POWER_SxA_AUTOIDLE, coreId, 0)) != CM_OK) + { + ERROR("[Pwr] MPC %s clock can't be auto-idle\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + return error; + } + break; + case MPC_PWR_HWIP: + if(_pwrMPCHWIPCountT[coreId]++ == 0) + { + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] MPC %s HW IP enable clock\n",cm_getDspName(coreId), 0, 0, 0, 0, 0); + if((error = OSAL_EnablePwrRessource(CM_OSAL_POWER_SxA_HARDWARE, coreId, 0)) != CM_OK) + { + ERROR("[Pwr] MPC %s HW IP clock can't be enabled\n", cm_getDspName(coreId), 0, 0, 0, 0, 0); + return error; + } + } + break; + } + + return CM_OK; +} + +PUBLIC void cm_PWR_DisableMPC( + t_mpc_power_request request, + t_nmf_core_id coreId) +{ + switch(request) + { + case MPC_PWR_CLOCK: + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] MPC %s disable clock\n",cm_getDspName(coreId), 0, 0, 0, 0, 0); + OSAL_DisablePwrRessource(CM_OSAL_POWER_SxA_CLOCK, coreId, 0); + break; + case MPC_PWR_AUTOIDLE: + OSAL_DisablePwrRessource(CM_OSAL_POWER_SxA_AUTOIDLE, coreId, 0); + break; + case MPC_PWR_HWIP: + if(--_pwrMPCHWIPCountT[coreId] == 0) + { + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] MPC %s HW IP disable clock\n",cm_getDspName(coreId), 0, 0, 0, 0, 0); + OSAL_DisablePwrRessource(CM_OSAL_POWER_SxA_HARDWARE, coreId, 0); + } + break; + } +} + +PUBLIC t_cm_error cm_PWR_EnableHSEM(void) +{ + t_cm_error error; + + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] HSEM enable clock\n",0 , 0, 0, 0, 0, 0); + if((error = OSAL_EnablePwrRessource(CM_OSAL_POWER_HSEM, 0, 0)) != CM_OK) + { + ERROR("[Pwr] HSEM clock can't be enabled\n", 0, 0, 0, 0, 0, 0); + return error; + } + + return CM_OK; +} + +PUBLIC void cm_PWR_DisableHSEM(void) +{ + LOG_INTERNAL(__PWR_DEBUG_TRACE_LEVEL, "[Pwr] HSEM disable clock\n",0 , 0, 0, 0, 0, 0); + OSAL_DisablePwrRessource(CM_OSAL_POWER_HSEM, 0, 0); +} + +PUBLIC t_cm_error cm_PWR_EnableMemory( + t_nmf_core_id coreId, + t_dsp_memory_type_id dspMemType, + t_cm_physical_address address, + t_cm_size size) +{ + switch(dspMemType) + { + case INTERNAL_XRAM24: + case INTERNAL_XRAM16: + case INTERNAL_YRAM24: + case INTERNAL_YRAM16: + _pwrMPCMemoryCountT[coreId]++; + break; + case SDRAM_EXT24: + case SDRAM_EXT16: + case SDRAM_CODE: + case LOCKED_CODE: + return OSAL_EnablePwrRessource( + CM_OSAL_POWER_SDRAM, + address, + size); + case ESRAM_EXT24: + case ESRAM_EXT16: + case ESRAM_CODE: + return OSAL_EnablePwrRessource( + CM_OSAL_POWER_ESRAM, + address, + size); + default: + CM_ASSERT(0); + } + + return CM_OK; +} + +PUBLIC void cm_PWR_DisableMemory( + t_nmf_core_id coreId, + t_dsp_memory_type_id dspMemType, + t_cm_physical_address address, + t_cm_size size) +{ + switch(dspMemType) + { + case INTERNAL_XRAM24: + case INTERNAL_XRAM16: + case INTERNAL_YRAM24: + case INTERNAL_YRAM16: + _pwrMPCMemoryCountT[coreId]--; + break; + case SDRAM_EXT24: + case SDRAM_EXT16: + case SDRAM_CODE: + case LOCKED_CODE: + OSAL_DisablePwrRessource( + CM_OSAL_POWER_SDRAM, + address, + size); + break; + case ESRAM_EXT24: + case ESRAM_EXT16: + case ESRAM_CODE: + OSAL_DisablePwrRessource( + CM_OSAL_POWER_ESRAM, + address, + size); + break; + default: + CM_ASSERT(0); + } +} + + + + + diff --git a/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_mgt.h b/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_mgt.h new file mode 100644 index 00000000000..d2c7185b24f --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_mgt.h @@ -0,0 +1,55 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Component repository internal methods. + * + * \defgroup REPOSITORY_INTERNAL Component repository. + */ +#ifndef __INC_CM_REP_MGT_H +#define __INC_CM_REP_MGT_H + +#include <cm/inc/cm_type.h> +#include <inc/nmf-limits.h> + +/*! + * \brief Identification of a component entry. + * \ingroup REPOSITORY_INTERNAL + */ +typedef struct t_rep_component { + t_dup_char name; + struct t_rep_component *prev; + struct t_rep_component *next; + t_elfdescription *elfhandle; //!< Must be last as data will be stored here +} t_rep_component; + +/*! + * \brief Search a component entry by name. + * + * \param[in] name The name of the component to look for. + * \param[out] component The corresponding component entry in the repository + * + * \retval t_cm_error + * + * \ingroup REPOSITORY_INTERNAL + */ +PUBLIC t_cm_error cm_REP_lookupComponent(const char *name, t_rep_component **component); + +/*! + * \brief Helper method that return the dataFile found in parameter or in the cache + */ +t_elfdescription* cm_REP_getComponentFile(t_dup_char templateName, t_elfdescription* elfhandle); + +/*! + * \brief Destroy the full repository (remove and free all components) + * + * \retval none + * + * \ingroup REPOSITORY_INTERNAL + */ +PUBLIC void cm_REP_Destroy(void); + +#endif /* __INC_CM_REP_MGT_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_type.h b/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_type.h new file mode 100644 index 00000000000..7c41fe1bedb --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/repository_mgt/inc/repository_type.h @@ -0,0 +1,28 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Components Component Manager API type. + * + * \defgroup COMPONENT CM Components API + * \ingroup CM_USER_API + */ + +#ifndef REPOSITORY_TYPE_H_ +#define REPOSITORY_TYPE_H_ + +typedef enum +{ + GET_EE_NAME, + BIND_ASYNC, + BIND_TRACE, + BIND_FROMUSER, + BIND_TOUSER +} t_action_to_do; + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/repository_mgt/src/repository_mgt.c b/drivers/staging/nmf-cm/cm/engine/repository_mgt/src/repository_mgt.c new file mode 100644 index 00000000000..c972783db4b --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/repository_mgt/src/repository_mgt.c @@ -0,0 +1,311 @@ +/* + * 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/utils/inc/string.h> + +#include <cm/engine/component/inc/component_type.h> +#include <cm/engine/component/inc/bind.h> +#include <cm/engine/configuration/inc/configuration.h> +#include <cm/engine/component/inc/introspection.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/repository_mgt/inc/repository_mgt.h> +#include <cm/engine/api/repository_mgt_engine.h> +#include <cm/engine/trace/inc/trace.h> + + +#define NHASH 157 //Use a prime number! +#define MULT 17 + +static t_rep_component *componentCaches[NHASH]; + +static unsigned int repcomponentHash(const char *str) +{ + unsigned int h = 0; + for(; *str; str++) + h = MULT * h + *str; + return h % NHASH; +} + +static void repcomponentAdd(t_rep_component *component) +{ + unsigned int h = repcomponentHash(component->name); + + if(componentCaches[h] != NULL) + componentCaches[h]->prev = component; + component->next = componentCaches[h]; + component->prev = NULL; + componentCaches[h] = component; +} + +static void repcomponentRemove(t_rep_component *component) +{ + unsigned int h = repcomponentHash(component->name); + + if(component->prev != NULL) + component->prev->next = component->next; + if(component->next != NULL) + component->next->prev = component->prev; + if(component == componentCaches[h]) + componentCaches[h] = component->next; +} + + +PUBLIC t_cm_error cm_REP_lookupComponent(const char *name, t_rep_component **component) +{ + t_rep_component *tmp; + + for(tmp = componentCaches[repcomponentHash(name)]; tmp != NULL; tmp = tmp->next) + { + if(cm_StringCompare(name, tmp->name, MAX_TEMPLATE_NAME_LENGTH) == 0) + { + if(component != NULL) + *component = tmp; + return CM_OK; + } + } + + return CM_COMPONENT_NOT_FOUND; +} + +t_elfdescription* cm_REP_getComponentFile(t_dup_char templateName, t_elfdescription* elfhandle) +{ + if(elfhandle == NULL) + { + t_rep_component *pRepComponent; + + for(pRepComponent = componentCaches[repcomponentHash(templateName)]; pRepComponent != NULL; pRepComponent = pRepComponent->next) + { + if(pRepComponent->name == templateName) + return pRepComponent->elfhandle; + } + + return NULL; + } + + return elfhandle; +} + + +PUBLIC void cm_REP_Destroy(void) +{ + t_rep_component *component, *next; + int i; + + for(i = 0; i < NHASH; i++) + { + for (component = componentCaches[i]; component != NULL; component = next) + { + next = component->next; + cm_ELF_CloseFile(FALSE, component->elfhandle); + cm_StringRelease(component->name); + OSAL_Free(component); + } + componentCaches[i] = NULL; + } +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_GetRequiredComponentFiles( + // IN + t_action_to_do action, + const t_cm_instance_handle client, + const char *requiredItfClientName, + const t_cm_instance_handle server, + const char *providedItfServerName, + // OUT component to be pushed + char fileList[][MAX_INTERFACE_TYPE_NAME_LENGTH], + t_uint32 listSize, + // OUT interface information + char type[MAX_INTERFACE_TYPE_NAME_LENGTH], + t_uint32 *methodNumber) +{ + t_cm_error error; + t_component_instance* compClient, *compServer; + int n; + + OSAL_LOCK_API(); + + // No component required + for(n = 0; n < listSize; n++) + fileList[n][0] = 0; + + compClient = cm_lookupComponent(client); + compServer = cm_lookupComponent(server); + switch(action) + { + case GET_EE_NAME: + /* Get Executive Engine names */ + error = cm_CFG_GetRequiredExecutiveEngineComponentNames(fileList, listSize); + break; + + case BIND_FROMUSER:{ + t_interface_provide_description itfProvide; + + // Check server validity + if((error = cm_checkValidServer(compServer, providedItfServerName, + &itfProvide)) == CM_OK) + { + cm_StringCopy(type, itfProvide.server->template->provides[itfProvide.provideIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + + cm_StringCopy(fileList[0], "_sk.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[0], itfProvide.server->template->provides[itfProvide.provideIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + } + } break; + + case BIND_TOUSER: { + /* Get Components names for a BindComponentToCMCore */ + t_interface_require_description itfRequire; + t_bool bindable; + + // Check client validity + if((error = cm_checkValidClient(compClient, requiredItfClientName, + &itfRequire, &bindable)) == CM_OK) + { + cm_StringCopy(type, itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + *methodNumber = itfRequire.client->template->requires[itfRequire.requireIndex].interface->methodNumber; + + cm_StringCopy(fileList[0], "_st.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[0], itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + } + }; break; + + case BIND_ASYNC: { + /* Get Components names for an asynchronous binding */ + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_bool bindable; + + // Check invalid binding + if((error = cm_checkValidBinding(compClient, requiredItfClientName, + compServer, providedItfServerName, + &itfRequire, &itfProvide, &bindable)) == CM_OK) + { + if(compClient->template->dspId != compServer->template->dspId) + { + cm_StringCopy(fileList[0], "_sk.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[0], itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + + cm_StringCopy(fileList[1], "_st.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[1], itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + } + else + { + cm_StringCopy(fileList[0], "_ev.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[0], itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + } + } + }; break; + + case BIND_TRACE: { + /* Get Components names for an asynchronous binding */ + t_interface_require_description itfRequire; + t_interface_provide_description itfProvide; + t_bool bindable; + + // Check invalid binding + if((error = cm_checkValidBinding(compClient, requiredItfClientName, + compServer, providedItfServerName, + &itfRequire, &itfProvide, &bindable)) == CM_OK) + { + cm_StringCopy(fileList[0], "_tr.", MAX_INTERFACE_TYPE_NAME_LENGTH); + cm_StringConcatenate(fileList[0], itfRequire.client->template->requires[itfRequire.requireIndex].interface->type, MAX_INTERFACE_TYPE_NAME_LENGTH); + } + }; break; + + default: + error = CM_OK; + break; + } + + if(error == CM_OK) + { + for(n = 0; n < listSize; n++) + { + t_rep_component *comp; + + // If already loaded, don't ask to load it and put the name to NULL + if (fileList[n][0] != 0 && + cm_REP_lookupComponent(fileList[n], &comp) == CM_OK) + fileList[n][0] = 0; + } + } + + + OSAL_UNLOCK_API(); + return error; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_PushComponent(const char *name, const void *data, t_cm_size size) +{ + t_rep_component *comp; + t_cm_error error; + + OSAL_LOCK_API(); + + if (cm_REP_lookupComponent(name, &comp) == CM_OK) { + /* Component is already there: silently ignore it */ + OSAL_UNLOCK_API(); + return CM_OK; + } + + comp = OSAL_Alloc(sizeof(*comp)); + if (comp == NULL) { + OSAL_UNLOCK_API(); + return CM_NO_MORE_MEMORY; + } + + comp->name = cm_StringDuplicate(name); + if(comp->name == NULL) + { + OSAL_Free(comp); + OSAL_UNLOCK_API(); + return CM_NO_MORE_MEMORY; + } + + if((error = cm_ELF_CheckFile( + data, + FALSE, + &comp->elfhandle)) != CM_OK) { + cm_StringRelease(comp->name); + OSAL_Free(comp); + OSAL_UNLOCK_API(); + return error; + } +/* + if (OSAL_Copy(comp->data, data, size)) { + OSAL_Free(comp); + OSAL_UNLOCK_API(); + return CM_UNKNOWN_MEMORY_HANDLE; + }*/ + + repcomponentAdd(comp); + + OSAL_UNLOCK_API(); + return CM_OK; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ENGINE_ReleaseComponent (const char *name) +{ + t_rep_component *component; + t_cm_error err; + + OSAL_LOCK_API(); + err = cm_REP_lookupComponent(name , &component); + + if (CM_OK == err) + { + repcomponentRemove(component); + + cm_ELF_CloseFile(FALSE, component->elfhandle); + cm_StringRelease(component->name); + OSAL_Free(component); + } + + OSAL_UNLOCK_API(); + + return err; +} diff --git a/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h b/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h new file mode 100644 index 00000000000..bd914195b6d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h @@ -0,0 +1,32 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_HW_SEMA_H_ +#define __INC_HW_SEMA_H_ + +#include <cm/inc/cm_type.h> +#include <cm/engine/semaphores/inc/semaphores.h> +#include <share/semaphores/inc/hwsem_hwp.h> + + +/******************************************************************************/ +/************************ FUNCTIONS PROTOTYPES ********************************/ +/******************************************************************************/ + +PUBLIC t_cm_error cm_HSEM_Init(const t_cm_system_address *pSystemAddr); +PUBLIC t_cm_error cm_HSEM_EnableSemIrq(t_semaphore_id semId, t_nmf_core_id toCoreId); +PUBLIC void cm_HSEM_Take(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_HSEM_Give(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_HSEM_GiveWithInterruptGeneration(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC void cm_HSEM_GenerateIrq(t_nmf_core_id coreId, t_semaphore_id semId); +PUBLIC t_nmf_core_id cm_HSEM_GetCoreIdFromIrqSrc(void); + +PUBLIC t_cm_error cm_HSEM_PowerOn(t_nmf_core_id coreId); +PUBLIC void cm_HSEM_PowerOff(t_nmf_core_id coreId); + +#endif /* __INC_HW_SEMA_H_ */ diff --git a/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/src/hw_semaphores.c b/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/src/hw_semaphores.c new file mode 100644 index 00000000000..932058cd4f2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/semaphores/hw_semaphores/src/hw_semaphores.c @@ -0,0 +1,171 @@ +/* + * 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. + */ +/******************************************************************* Includes + ****************************************************************************/ + +#include "../inc/hw_semaphores.h" +#include <share/semaphores/inc/hwsem_hwp.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/power_mgt/inc/power.h> +static t_hw_semaphore_regs *pHwSemRegs = (t_hw_semaphore_regs *)0; + +static t_uint32 semaphoreUseCounter = 0; +static t_uint32 imsc[HSEM_MAX_INTR]; +PRIVATE void restoreMask(void); + +/****************************************************************************/ +/* NAME: t_cm_error cm_HSEM_Init(const t_cm_system_address *pSystemAddr) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Initialize the HW Semaphores module */ +/* */ +/* PARAMETERS: */ +/* (in) pSystemAddr: system base address of the HW semaphores IP */ +/* */ +/* RETURN: CM_OK always */ +/* */ +/****************************************************************************/ +PUBLIC t_cm_error cm_HSEM_Init(const t_cm_system_address *pSystemAddr) +{ + t_uint8 i; + + pHwSemRegs = (t_hw_semaphore_regs *)pSystemAddr->logical; + + for (i=HSEM_FIRST_INTR; i < HSEM_MAX_INTR; i++) + { + imsc[i] = 0; // Mask all interrupt + } + + return CM_OK; +} + +static void cm_HSEM_ReInit(void) +{ + t_uint8 i; + + pHwSemRegs->icrall = MASK_ALL16; + + for (i=HSEM_FIRST_INTR; i < HSEM_MAX_INTR; i++) + { + pHwSemRegs->it[i].imsc = imsc[i]; + pHwSemRegs->it[i].icr = MASK_ALL16; + } + + for (i=0; i < NUM_HW_SEMAPHORES; i++) + { + pHwSemRegs->sem[i] = 0; + } +} + +/****************************************************************************/ +/* NAME: t_cm_error cm_HSEM_EnableSemIrq( */ +/* t_semaphore_id semId, */ +/* t_nmf_core_id toCoreId */ +/* ) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Enable Irq for a given coreId (communication receiver) */ +/* */ +/* PARAMETERS: */ +/* (in) semId: identifier of the semaphore */ +/* (in) toCoreId: identifier of coreId destination of the coms */ +/* */ +/* RETURN: CM_OK always */ +/* */ +/****************************************************************************/ +PUBLIC t_cm_error cm_HSEM_EnableSemIrq(t_semaphore_id semId, t_nmf_core_id toCoreId) +{ + static t_uint32 CoreIdToIntr[NB_CORE_IDS] = {0, 2, 3}; + int i = CoreIdToIntr[toCoreId]; + + imsc[i] |= (1UL << semId); + + // Allow cm_HSEM_EnableSemIrq to be called before real start in order to save power + if(semaphoreUseCounter > 0) + { + pHwSemRegs->it[i].imsc = imsc[i]; + } + + return CM_OK; +} + +/****************************************************************************/ +/* NAME: void cm_HSEM_GenerateIrq(t_semaphore_id semId) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Generate an irq toward correct core according to semId */ +/* */ +/* PARAMETERS: */ +/* (in) semId: identifier of the semaphore to handle */ +/* */ +/* RETURN: none */ +/* */ +/****************************************************************************/ +PUBLIC void cm_HSEM_GenerateIrq(t_nmf_core_id coreId, t_semaphore_id semId) +{ + // TODO Move restore in OS BSP or in PRCMU in order to to it only when wake-up, for now do it always !!!!!!!!!!!! + restoreMask(); + + pHwSemRegs->sem[semId] = CORE_ID_2_HW_CORE_ID(ARM_CORE_ID); + pHwSemRegs->sem[semId] = (HSEM_INTRA_MASK|HSEM_INTRB_MASK|HSEM_INTRC_MASK|HSEM_INTRD_MASK); +} + +/****************************************************************************/ +/* NAME: t_nmf_core_id cm_HSEM_GetCoreIdFromIrqSrc(void) */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: Check Masked Interrupt Status to know which semaphore(s) */ +/* have pending interrupt and return the identifier of the given dsp */ +/* */ +/* PARAMETERS: none */ +/* */ +/* RETURN: none */ +/* */ +/****************************************************************************/ +PUBLIC t_nmf_core_id cm_HSEM_GetCoreIdFromIrqSrc(void) +{ + t_uword misValue = pHwSemRegs->it[ARM_CORE_ID].mis; + t_uint32 mask = 1 << FIRST_NEIGHBOR_SEMID(ARM_CORE_ID) /* == 0 here */; + t_nmf_core_id coreId = FIRST_MPC_ID; + + while ((misValue & mask) == 0) + { + mask <<= 1; + + coreId++; + if(coreId > LAST_MPC_ID) + return coreId; + } + + /* Acknowledge Hsem interrupt */ + pHwSemRegs->it[ARM_CORE_ID].icr = mask; + + return coreId; +} + +PUBLIC t_cm_error cm_HSEM_PowerOn(t_nmf_core_id coreId) +{ + if(semaphoreUseCounter++ == 0) + { + cm_PWR_EnableHSEM(); + + cm_HSEM_ReInit(); // HSEM is called one time only when the HSEM is switched ON + } + + return CM_OK; +} + +PUBLIC void cm_HSEM_PowerOff(t_nmf_core_id coreId) +{ + if(--semaphoreUseCounter == 0) + { + cm_PWR_DisableHSEM(); + } +} + +PRIVATE void restoreMask() +{ + t_uint8 i; + + for (i=HSEM_FIRST_INTR; i < HSEM_MAX_INTR; i++) + pHwSemRegs->it[i].imsc = imsc[i]; +} diff --git a/drivers/staging/nmf-cm/cm/engine/semaphores/inc/semaphores.h b/drivers/staging/nmf-cm/cm/engine/semaphores/inc/semaphores.h new file mode 100644 index 00000000000..7636d8e7c9d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/semaphores/inc/semaphores.h @@ -0,0 +1,25 @@ +/* + * 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. + */ +/** + * \internal + */ +#ifndef __INC_NMF_SEMAPHORE_H +#define __INC_NMF_SEMAPHORE_H + +#include <cm/engine/api/control/configuration_engine.h> +#include <share/semaphores/inc/semaphores.h> +#include <cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h> + +PUBLIC t_cm_error cm_SEM_Init(const t_cm_system_address *pSystemAddr); +PUBLIC t_cm_error cm_SEM_InitMpc(t_nmf_core_id coreId, t_nmf_semaphore_type_id semTypeId); +PUBLIC t_semaphore_id cm_SEM_Alloc(t_nmf_core_id fromCoreId, t_nmf_core_id toCoreId); + +/* Semaphores management virtualized functions */ +extern void (*cm_SEM_GenerateIrq[NB_CORE_IDS])(t_nmf_core_id coreId, t_semaphore_id semId); +extern t_cm_error (*cm_SEM_PowerOn[NB_CORE_IDS])(t_nmf_core_id coreId); +extern void (*cm_SEM_PowerOff[NB_CORE_IDS])(t_nmf_core_id coreId); + +#endif /* __INC_NMF_SEMAPHORE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/semaphores/src/semaphores.c b/drivers/staging/nmf-cm/cm/engine/semaphores/src/semaphores.c new file mode 100644 index 00000000000..daf95355a56 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/semaphores/src/semaphores.c @@ -0,0 +1,94 @@ +/* + * 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/semaphores/inc/semaphores.h> +#include <cm/engine/semaphores/hw_semaphores/inc/hw_semaphores.h> +#include <cm/engine/dsp/inc/semaphores_dsp.h> +#include <cm/engine/trace/inc/trace.h> +#include <share/inc/nmf.h> + +void (*cm_SEM_GenerateIrq[NB_CORE_IDS])(t_nmf_core_id coreId, t_semaphore_id semId); +t_cm_error (*cm_SEM_PowerOn[NB_CORE_IDS])(t_nmf_core_id coreId); +void (*cm_SEM_PowerOff[NB_CORE_IDS])(t_nmf_core_id coreId); + +#define SEM_TYPE_ID_DEFAULT_VALUE ((t_nmf_semaphore_type_id)MASK_ALL32) +static t_nmf_semaphore_type_id semaphoreTypePerCoreId[NB_CORE_IDS]; + +static t_cm_error cm_LSEM_PowerOn(t_nmf_core_id coreId) +{ + return CM_OK; +} + +static void cm_LSEM_PowerOff(t_nmf_core_id coreId) +{ +} + +PUBLIC t_cm_error cm_SEM_Init(const t_cm_system_address *pSystemAddr) +{ + t_nmf_core_id coreId; + + for (coreId = ARM_CORE_ID; coreId < NB_CORE_IDS; coreId++) + { + semaphoreTypePerCoreId[coreId] = SEM_TYPE_ID_DEFAULT_VALUE; + + /* By default, we suppose that we use a full feature NMF ;) */ + cm_SEM_GenerateIrq[coreId] = NULL; + cm_SEM_PowerOn[coreId] = NULL; + cm_SEM_PowerOff[coreId] = NULL; + } + + cm_HSEM_Init(pSystemAddr); + /* if needed local semaphore init will be done coreId per coreId */ + + return CM_OK; +} + +PUBLIC t_cm_error cm_SEM_InitMpc(t_nmf_core_id coreId, t_nmf_semaphore_type_id semTypeId) +{ + if (semaphoreTypePerCoreId[coreId] != SEM_TYPE_ID_DEFAULT_VALUE) + return CM_MPC_ALREADY_INITIALIZED; + + if(semTypeId == SYSTEM_SEMAPHORES) + { + cm_SEM_GenerateIrq[coreId] = cm_HSEM_GenerateIrq; + cm_SEM_PowerOn[coreId] = cm_HSEM_PowerOn; + cm_SEM_PowerOff[coreId] = cm_HSEM_PowerOff; + } + else if (semTypeId == LOCAL_SEMAPHORES) + { + cm_SEM_GenerateIrq[coreId] = cm_DSP_SEM_GenerateIrq; + cm_SEM_PowerOn[coreId] = cm_LSEM_PowerOn; + cm_SEM_PowerOff[coreId] = cm_LSEM_PowerOff; + } + + semaphoreTypePerCoreId[coreId] = semTypeId; + + return CM_OK; +} + +PUBLIC t_semaphore_id cm_SEM_Alloc(t_nmf_core_id fromCoreId, t_nmf_core_id toCoreId) +{ + t_semaphore_id semId; + t_nmf_core_id corex; + + semId = FIRST_NEIGHBOR_SEMID(toCoreId); + for (corex = FIRST_CORE_ID; corex < fromCoreId; corex++) + { + if (corex == toCoreId) + continue; + semId++; + } + + if ( + (toCoreId == ARM_CORE_ID && semaphoreTypePerCoreId[fromCoreId] == SYSTEM_SEMAPHORES) || + (semaphoreTypePerCoreId[toCoreId] == SYSTEM_SEMAPHORES) + ) + { + cm_HSEM_EnableSemIrq(semId, toCoreId); + } + + return semId; +} diff --git a/drivers/staging/nmf-cm/cm/engine/trace/inc/trace.h b/drivers/staging/nmf-cm/cm/engine/trace/inc/trace.h new file mode 100644 index 00000000000..111eaf1324e --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/trace/inc/trace.h @@ -0,0 +1,48 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Trace facilities management API + * + * \defgroup Trace Facilities + */ +#ifndef __INC_CM_TRACE_H +#define __INC_CM_TRACE_H + +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/configuration/inc/configuration_status.h> + +/*********************/ +/* Log related stuff */ +/*********************/ +#define ERROR(format, param1, param2, param3, param4, param5, param6) \ +do { \ + if (cm_debug_level != -1) \ + OSAL_Log("Error: " format, (int)(param1), (int)(param2), (int)(param3), (int)(param4), (int)(param5), (int)(param6)); \ + while(cm_error_break);\ +} while(0) + +#define WARNING(format, param1, param2, param3, param4, param5, param6) \ +do { \ + if (cm_debug_level != -1) \ + OSAL_Log("Warning: " format, (int)(param1), (int)(param2), (int)(param3), (int)(param4), (int)(param5), (int)(param6)); \ +} while(0) + +#define LOG_INTERNAL(level, format, param1, param2, param3, param4, param5, param6) \ +do { \ + if (level <= cm_debug_level) \ + OSAL_Log((const char *)format, (int)(param1), (int)(param2), (int)(param3), (int)(param4), (int)(param5), (int)(param6)); \ +} while(0) + +/*************************/ +/* Panic related stuff */ +/*************************/ +#define CM_ASSERT(cond) \ +do { \ + if(!(cond)) { OSAL_Log("CM_ASSERT at %s:%d\n", (int)__FILE__, (int)__LINE__, 0, 0, 0, 0); OSAL_Panic(); while(1); } \ +} while (0) + +#endif /* __INC_CM_TRACE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/trace/inc/xtitrace.h b/drivers/staging/nmf-cm/cm/engine/trace/inc/xtitrace.h new file mode 100644 index 00000000000..6ab960b69b2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/trace/inc/xtitrace.h @@ -0,0 +1,42 @@ +/* + * 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. + */ +#ifndef __INC_CM_XTITRACE_H +#define __INC_CM_XTITRACE_H + +#include <cm/engine/component/inc/instance.h> + +#include <inc/nmf-tracedescription.h> + +extern t_bool cm_trace_enabled; + +/*************************/ +/* Trace related stuff */ +/*************************/ +void cm_TRC_Dump(void); + +void cm_TRC_traceReset(void); + +void cm_TRC_traceLoadMap( + t_nmfTraceComponentCommandDescription cmd, + const t_component_instance* component); + +#define ARM_TRACE_COMPONENT ((const t_component_instance*)0xFFFFFFFF) + +void cm_TRC_traceBinding( + t_nmfTraceBindCommandDescription command, + const t_component_instance* clientComponent, const t_component_instance* serverComponent, + const char *requiredItfName, const char *providedItfName); + +void cm_TRC_traceCommunication( + t_nmfTraceCommunicationCommandDescription command, + t_nmf_core_id coreId, + t_nmf_core_id remoteCoreId); + +void cm_TRC_traceMemAlloc(t_nmfTraceAllocatorCommandDescription command, t_uint8 allocId, t_uint32 memorySize, const char *allocname); + +void cm_TRC_traceMem(t_nmfTraceAllocCommandDescription command, t_uint8 allocId, t_uint32 startAddress, t_uint32 memorySize); + +#endif /* __INC_CM_TRACE_H */ diff --git a/drivers/staging/nmf-cm/cm/engine/trace/src/panic.c b/drivers/staging/nmf-cm/cm/engine/trace/src/panic.c new file mode 100644 index 00000000000..832b9f28756 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/trace/src/panic.c @@ -0,0 +1,222 @@ +/* + * 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/component/inc/bind.h> +#include <cm/engine/executive_engine_mgt/inc/executive_engine_mgt.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/api/control/irq_engine.h> + +#include <cm/engine/utils/inc/convert.h> +#include <share/communication/inc/nmf_service.h> + + +/* + * Panic + */ +const struct { + char* name; + unsigned int info1:1; + unsigned int PC:1; + unsigned int SP:1; + unsigned int interface:1; +} reason_descrs[] = { + {"NONE_PANIC", 0, 0, 0, 0}, + {"INTERNAL_PANIC", 1, 0, 0, 0}, + {"Reserved Panic", 0, 0, 0, 0}, + {"USER_STACK_OVERFLOW", 0, 1, 1, 0}, + {"SYSTEM_STACK_OVERFLOW", 0, 1, 1, 0}, + {"UNALIGNED_LONG_ACCESS", 0, 1, 0, 0}, + {"EVENT_FIFO_OVERFLOW", 0, 0, 0, 1}, + {"PARAM_FIFO_OVERFLOW", 0, 0, 0, 1}, + {"INTERFACE_NOT_BINDED", 0, 0, 0, 0}, + {"USER_PANIC", 1, 0, 0, 0} +}; + +static t_component_instance* getCorrespondingInstance( + t_panic_reason panicReason, + t_uint32 panicThis, + t_dup_char *itfName, + t_cm_instance_handle *instHandle) { + t_component_instance *instance; + t_uint32 k; + + for (k=0; k<ComponentTable.idxMax; k++) { + if ((instance = componentEntry(k)) == NULL) + continue; + if(panicReason == PARAM_FIFO_OVERFLOW || + panicReason == EVENT_FIFO_OVERFLOW) { + // Panic has been generated by binding component, search the client who has call it + // and return the client handle (not the BC one). + int i; + + if(instance->thisAddress == panicThis && panicThis == 0) { + *itfName = "Internal NMF service"; + *instHandle = ENTRY2HANDLE(instance, k); + return instance; + } + + for(i = 0; i < instance->template->requireNumber; i++) { + int nb = instance->template->requires[i].collectionSize, j; + for(j = 0; j < nb; j++) { + if(instance->interfaceReferences[i][j].instance != NULL && + instance->interfaceReferences[i][j].instance != (t_component_instance *)NMF_HOST_COMPONENT && + instance->interfaceReferences[i][j].instance != (t_component_instance *)NMF_VOID_COMPONENT && + instance->interfaceReferences[i][j].instance->thisAddress == panicThis) + { + *itfName = instance->template->requires[i].name; + *instHandle = ENTRY2HANDLE(instance, k); + return instance; + } + } + } + } else { + // The component which has generated the panic is the good one. + + if(instance->thisAddress == panicThis) { + *itfName = "?"; + *instHandle = ENTRY2HANDLE(instance, k); + return instance; + } + } + } + + *itfName = "?"; + *instHandle = 0; + return 0; +} + +PUBLIC EXPORT_SHARED t_cm_error CM_ReadMPCString( + t_nmf_core_id coreId, + t_uint32 dspAddress, + char * buffer, + t_uint32 bufferSize) { + + while(--bufferSize > 0) + { + char ch = cm_DSP_ReadXRamWord(coreId, dspAddress++); + if(ch == 0) + break; + + *buffer++ = ch; + }; + + *buffer = 0; + + // Reset panicReason + cm_writeAttribute(cm_EEM_getExecutiveEngine(coreId)->instance, + "rtos/commonpart/serviceReason", MPC_SERVICE_NONE); + + return CM_OK; +} + +/****************/ +/* Generic part */ +/****************/ +PUBLIC EXPORT_SHARED t_cm_error CM_getServiceDescription( + t_nmf_core_id coreId, + t_cm_service_type *srcType, + t_cm_service_description *srcDescr) +{ + t_uint32 serviceReason; + t_component_instance *ee; + + // Acknowledge interrupt (do it before resetting panicReason) + cm_DSP_AcknowledgeDspIrq(coreId, DSP2ARM_IRQ_1); + + ee = cm_EEM_getExecutiveEngine(coreId)->instance; + + // Read panicReason + serviceReason = cm_readAttributeNoError(ee, "rtos/commonpart/serviceReason"); + if(serviceReason == MPC_SERVICE_PRINT) + { + *srcType = CM_MPC_SERVICE_PRINT; + + srcDescr->u.print.dspAddress = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo0"); + srcDescr->u.print.value1 = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo1"); + srcDescr->u.print.value2 = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo2"); + } + else if(serviceReason != MPC_SERVICE_NONE) + { + t_uint32 panicThis; + t_dup_char itfName; + t_component_instance *instance; + + *srcType = CM_MPC_SERVICE_PANIC; + srcDescr->u.panic.panicReason = (t_panic_reason)serviceReason; + srcDescr->u.panic.panicSource = MPC_EE; + srcDescr->u.panic.info.mpc.coreid = coreId; + + // Read panicThis + panicThis = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo0"); + + instance = getCorrespondingInstance(srcDescr->u.panic.panicReason, panicThis, &itfName, &srcDescr->u.panic.info.mpc.faultingComponent); + + LOG_INTERNAL(0, "Error: Panic(%s, %s), This=%x", cm_getDspName(coreId), + reason_descrs[srcDescr->u.panic.panicReason].name, (void*)panicThis, 0, 0, 0); + + if(reason_descrs[srcDescr->u.panic.panicReason].interface != 0) + { + LOG_INTERNAL(0, ", interface=%s", itfName, 0, 0, 0, 0, 0); + } + + if(reason_descrs[srcDescr->u.panic.panicReason].info1 != 0) + { + // Info 1 + srcDescr->u.panic.info.mpc.panicInfo1 = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo1"); + + LOG_INTERNAL(0, ", Info=%x", srcDescr->u.panic.info.mpc.panicInfo1, 0, 0, 0, 0, 0); + } + + if(reason_descrs[srcDescr->u.panic.panicReason].PC != 0) + { + t_uint32 DspAddress = 0xFFFFFFFF; + t_uint32 DspSize = 0x0; + + // PC need to be read in rtos/commonpart/serviceInfo1 + srcDescr->u.panic.info.mpc.panicInfo1 = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo1"); + + if(instance != 0) + { + cm_DSP_GetDspAddress(instance->memories[instance->template->codeMemory->id], &DspAddress); + cm_DSP_GetDspMemoryHandleSize(instance->memories[instance->template->codeMemory->id], &DspSize); + } + + if(DspAddress <= srcDescr->u.panic.info.mpc.panicInfo1 && + srcDescr->u.panic.info.mpc.panicInfo1 < (DspAddress + DspSize)) + LOG_INTERNAL(0, ", PC:off=%x <abs=%x>", + srcDescr->u.panic.info.mpc.panicInfo1 - DspAddress, + srcDescr->u.panic.info.mpc.panicInfo1, 0, 0, 0, 0); + else + LOG_INTERNAL(0, ", PC:<abs=%x>", srcDescr->u.panic.info.mpc.panicInfo1, 0, 0, 0, 0, 0); + } + + if(reason_descrs[srcDescr->u.panic.panicReason].SP != 0) + { + srcDescr->u.panic.info.mpc.panicInfo2 = cm_readAttributeNoError(ee, "rtos/commonpart/serviceInfo2"); + + LOG_INTERNAL(0, ", SP=%x", srcDescr->u.panic.info.mpc.panicInfo2, 0, 0, 0, 0, 0); + } + + LOG_INTERNAL(0, "\n", 0, 0, 0, 0, 0, 0); + + if(instance != 0) + { + LOG_INTERNAL(0, "Error: Component=%s<%s>\n", + instance->pathname, instance->template->name, 0, 0, 0, 0); + } + + // We don't set rtos/commonpart/serviceReason = MPC_SERVICE_NONE, since we don't want the + // MMDSP to continue execution, and we put in in Panic state + cm_DSP_SetStatePanic(coreId); + } + else + { + *srcType = CM_MPC_SERVICE_NONE; + } + + return CM_OK; +} diff --git a/drivers/staging/nmf-cm/cm/engine/trace/src/trace.c b/drivers/staging/nmf-cm/cm/engine/trace/src/trace.c new file mode 100644 index 00000000000..ac948c767b4 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/trace/src/trace.c @@ -0,0 +1,220 @@ +/* + * 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/trace.h" +#include "../inc/xtitrace.h" +#include <inc/nmf-tracedescription.h> +#include <inc/nmf-limits.h> +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +t_bool cm_trace_enabled = FALSE; + +/* + * STM message dump + */ +#define HEADER(t, s) ((t) | (s << 16)) + +static void writeN(struct t_nmfTraceChannelHeader* header) +{ + t_uint64* data = (t_uint64*)header; + t_uint64 *end = (t_uint64*)(((unsigned int)data) + header->traceSize - sizeof(t_uint64)); + + while(data < end) + { + OSAL_Write64(CM_CHANNEL, 0, *data++); + } + + OSAL_Write64(CM_CHANNEL, 1, *data); +} + +void cm_TRC_Dump(void) +{ + t_uint32 i; + + cm_TRC_traceReset(); + + for (i=0; i<ComponentTable.idxMax; i++) + { + if (componentEntry(i) != NULL) + cm_TRC_traceLoadMap(TRACE_COMPONENT_COMMAND_ADD, componentEntry(i)); + } +} + +void cm_TRC_traceReset(void) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceReset trace; + + trace.header.v = HEADER(TRACE_TYPE_RESET, sizeof(trace)); + + trace.minorVersion = TRACE_MINOR_VERSION; + trace.majorVersion = TRACE_MAJOR_VERSION; + + writeN((struct t_nmfTraceChannelHeader*)&trace); + } +} + +void cm_TRC_traceLoadMap( + t_nmfTraceComponentCommandDescription command, + const t_component_instance* component) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceComponent trace; + + /* + * Generate instantiate trace + */ + trace.header.v = HEADER(TRACE_TYPE_COMPONENT, sizeof(trace)); + + trace.command = (t_uint16)command; + trace.domainId = (t_uint16)component->template->dspId + 1; + trace.componentContext = (t_uint32)component->thisAddress; + trace.componentUserContext = (t_uint32)component; + cm_StringCopy((char*)trace.componentLocalName, component->pathname, MAX_COMPONENT_NAME_LENGTH); + cm_StringCopy((char*)trace.componentTemplateName, component->template->name, MAX_TEMPLATE_NAME_LENGTH); + + writeN((struct t_nmfTraceChannelHeader*)&trace); + + if(command == TRACE_COMPONENT_COMMAND_ADD) + { + struct t_nmfTraceMethod tracemethod; + int i, j, k; + + /* + * Generate method trace + */ + tracemethod.header.v = HEADER(TRACE_TYPE_METHOD, sizeof(tracemethod)); + + tracemethod.domainId = (t_uint16)component->template->dspId + 1; + tracemethod.componentContext = (t_uint32)component->thisAddress; + + for(i = 0; i < component->template->provideNumber; i++) + { + t_interface_provide* provide = &component->template->provides[i]; + + for(j = 0; j < provide->collectionSize; j++) + { + for(k = 0; k < provide->interface->methodNumber; k++) + { + tracemethod.methodId = provide->indexes[j][k].methodAddresses; + + cm_StringCopy((char*)tracemethod.methodName, provide->interface->methodNames[k], MAX_INTERFACE_METHOD_NAME_LENGTH); + + writeN((struct t_nmfTraceChannelHeader*)&tracemethod); + } + } + } + } + } +} + +void cm_TRC_traceBinding( + t_nmfTraceBindCommandDescription command, + const t_component_instance* clientComponent, const t_component_instance* serverComponent, + const char *requiredItfName, const char *providedItfName) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceBind trace; + + trace.header.v = HEADER(TRACE_TYPE_BIND, sizeof(trace)); + + trace.command = (t_uint16)command; + + if(clientComponent == ARM_TRACE_COMPONENT) // ARM + { + trace.clientDomainId = 0x1; + trace.clientComponentContext = 0x0; + } + else + { + trace.clientDomainId = (t_uint16)clientComponent->template->dspId + 1; + trace.clientComponentContext = (t_uint32)clientComponent->thisAddress; + } + if(requiredItfName != NULL) + cm_StringCopy((char*)trace.requiredItfName, requiredItfName, MAX_INTERFACE_NAME_LENGTH); + else + trace.requiredItfName[0] = 0; + + if(serverComponent == NULL) + { // Unbind or VOID + trace.serverDomainId = 0; + trace.serverComponentContext = 0x0; + } + else if(serverComponent == ARM_TRACE_COMPONENT) + { // ARM + trace.serverDomainId = 0x1; + trace.serverComponentContext = 0x0; + } + else + { + trace.serverDomainId = (t_uint16)serverComponent->template->dspId + 1; + trace.serverComponentContext = (t_uint32)serverComponent->thisAddress; + } + if(providedItfName != NULL) + cm_StringCopy((char*)trace.providedItfName, providedItfName, MAX_INTERFACE_NAME_LENGTH); + else + trace.providedItfName[0] = 0; + + writeN((struct t_nmfTraceChannelHeader*)&trace); + } +} + +void cm_TRC_traceCommunication( + t_nmfTraceCommunicationCommandDescription command, + t_nmf_core_id coreId, + t_nmf_core_id remoteCoreId) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceCommunication trace; + + trace.header.v = HEADER(TRACE_TYPE_COMMUNICATION, sizeof(trace)); + + trace.command = (t_uint16)command; + trace.domainId = (t_uint16)coreId + 1; + trace.remoteDomainId = (t_uint16)remoteCoreId + 1; + + writeN((struct t_nmfTraceChannelHeader*)&trace); + } +} + +void cm_TRC_traceMemAlloc(t_nmfTraceAllocatorCommandDescription command, t_uint8 allocId, t_uint32 memorySize, const char *allocname) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceAllocator trace; + + trace.header.v = HEADER(TRACE_TYPE_ALLOCATOR, sizeof(trace)); + + trace.command = (t_uint16)command; + trace.allocId = (t_uint16)allocId; + trace.size = memorySize; + cm_StringCopy((char*)trace.name, allocname, sizeof(trace.name)); + + writeN((struct t_nmfTraceChannelHeader*)&trace); + } +} + +void cm_TRC_traceMem(t_nmfTraceAllocCommandDescription command, t_uint8 allocId, t_uint32 startAddress, t_uint32 memorySize) +{ + if(cm_trace_enabled) + { + struct t_nmfTraceAlloc trace; + + trace.header.v = HEADER(TRACE_TYPE_ALLOC, sizeof(trace)); + + trace.command = (t_uint16)command; + trace.allocId = (t_uint16)allocId; + trace.offset = startAddress; + trace.size = memorySize; + + writeN((struct t_nmfTraceChannelHeader*)&trace); + } +} + diff --git a/drivers/staging/nmf-cm/cm/engine/utils/inc/convert.h b/drivers/staging/nmf-cm/cm/engine/utils/inc/convert.h new file mode 100644 index 00000000000..d6912e58687 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/inc/convert.h @@ -0,0 +1,21 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Conversion utility methods. + */ +#ifndef H_CM_CONVERTS_MEM +#define H_CM_CONVERTS_MEM + +#include <share/inc/nmf.h> + +/* + * Utils convert methods + */ +const char* cm_getDspName(t_nmf_core_id dsp); + + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/utils/inc/mem.h b/drivers/staging/nmf-cm/cm/engine/utils/inc/mem.h new file mode 100644 index 00000000000..c950a94023d --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/inc/mem.h @@ -0,0 +1,19 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Memory manipulation. + */ +#ifndef H_CM_UTILS_MEM +#define H_CM_UTILS_MEM + +/* + * Utils libc methods + */ +void cm_MemCopy(void* dest, const void *src, int count); +void cm_MemSet(void *str, int c, int count); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/utils/inc/string.h b/drivers/staging/nmf-cm/cm/engine/utils/inc/string.h new file mode 100644 index 00000000000..d2b7c0b0823 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/inc/string.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +/*! + * \internal + * \brief String manipulation. + */ +#ifndef H_CM_UTILS_STRING +#define H_CM_UTILS_STRING + +#include <cm/engine/memory/inc/memory.h> + +#define MAX_INTERNAL_STRING_LENGTH 2048 + +typedef const char *t_dup_char; + +t_dup_char cm_StringGet(const char* str); +t_dup_char cm_StringReference(t_dup_char str); +t_dup_char cm_StringDuplicate(const char* orig); +void cm_StringRelease(t_dup_char orig); + +/* + * Utils libc methods + */ +void cm_StringCopy(char* dest, const char* src, int count); +int cm_StringCompare(const char* str1, const char* str2, int count); +int cm_StringLength(const char * str, int count); +void cm_StringConcatenate(char* dest, const char* src, int count); +char* cm_StringSearch(const char* str, int c); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/utils/inc/swap.h b/drivers/staging/nmf-cm/cm/engine/utils/inc/swap.h new file mode 100644 index 00000000000..e4f5acb3010 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/inc/swap.h @@ -0,0 +1,23 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Swap integer manipulation. + */ +#ifndef H_CM_UTILS_SWAP +#define H_CM_UTILS_SWAP + +#include <cm/inc/cm_type.h> + +/* + * Swap methods + */ +t_uint16 swap16(t_uint16 x); +t_uint32 swap32(t_uint32 x); +t_uint64 swap64(t_uint64 x); +t_uint32 noswap32(t_uint32 x); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/utils/inc/table.h b/drivers/staging/nmf-cm/cm/engine/utils/inc/table.h new file mode 100644 index 00000000000..9d9828a81f6 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/inc/table.h @@ -0,0 +1,59 @@ +/* + * 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. + */ +/*! + * \internal + * \brief Dynamic table manipulation. + */ +#ifndef H_CM_UTILS_TABLE +#define H_CM_UTILS_TABLE + +#include <cm/inc/cm_type.h> + +/* + This implement a (generic) dynamic table (the size is dynamic) + to register some pointers of a given kind of elements + + It also allows to compute/convert each kernel pointer registered in the + table to a user handler, that can be checked. + + The "user" handler is composed by the index in this table + (the low INDEX_SHIFT bits) and the low bits of the "local" pointer + shifted by INDEX_SHIFT are stored in the high bits: + + handle bits: 31 ................................ 12 11 ...... 0 + | lower bits of of the local pointer | index | + + This allows a straight translation from a user handle to a local pointer + + a strong check to validate the value of a user handle. + The reverse translation from pointer to a user handle is + slower as it requires an explicit search in the list. + */ + + +/* INDEX_SHIFT determines the index size and thus the max index */ +#define INDEX_SHIFT 12 +#define INDEX_MAX (1UL << INDEX_SHIFT) +#define INDEX_MASK (INDEX_MAX-1) +#define ENTRY2HANDLE(pointer, index) (((unsigned int)pointer << INDEX_SHIFT) | index) +#define TABLE_DEF_SIZE 0x1000 + +typedef struct { + t_uint32 idxNb; /**< number of entries used */ + t_uint32 idxCur; /**< current index: point to next supposed + free entry: used to look for the next + free entry */ + t_uint32 idxMax; /**< index max currently allowed */ + void **entries; /**< table itself */ +} t_nmf_table; + +t_cm_error cm_initTable(t_nmf_table* table); +void cm_destroyTable(t_nmf_table* table); +t_uint32 cm_addEntry(t_nmf_table *table, void *entry); +void cm_delEntry(t_nmf_table *table, t_uint32 idx); +void *cm_lookupEntry(const t_nmf_table *table, const t_uint32 hdl); +t_uint32 cm_lookupHandle(const t_nmf_table *table, const void *entry); + +#endif diff --git a/drivers/staging/nmf-cm/cm/engine/utils/src/convert.c b/drivers/staging/nmf-cm/cm/engine/utils/src/convert.c new file mode 100644 index 00000000000..ad6e097bfe6 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/src/convert.c @@ -0,0 +1,20 @@ +/* + * 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/utils/inc/convert.h> + +const char* dspNames[NB_CORE_IDS] = { + "ARM", + "SVA", + "SIA" +}; + + +const char* cm_getDspName(t_nmf_core_id dsp) { + return dspNames[dsp]; +} diff --git a/drivers/staging/nmf-cm/cm/engine/utils/src/mem.c b/drivers/staging/nmf-cm/cm/engine/utils/src/mem.c new file mode 100644 index 00000000000..130a044bbf8 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/src/mem.c @@ -0,0 +1,27 @@ +/* + * 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/utils/inc/mem.h> + + +/* + * Methods + */ +void cm_MemCopy(void* dest, const void *src, int count) { + char *tmp = (char *) dest, *s = (char *) src; + + while (count--) + *tmp++ = *s++; +} + +void cm_MemSet(void *str, int c, int count) { + char *tmp = (char *)str; + + while (count--) + *tmp++ = c; +} diff --git a/drivers/staging/nmf-cm/cm/engine/utils/src/string.c b/drivers/staging/nmf-cm/cm/engine/utils/src/string.c new file mode 100644 index 00000000000..0ed6fb3a214 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/src/string.c @@ -0,0 +1,229 @@ +/* + * 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. + */ +/* + * + * Shared string manipulation. + * TODO This is a list today, must be a hash later !!!!! + */ +#include <cm/engine/utils/inc/string.h> +#include <cm/engine/trace/inc/trace.h> + +#include <cm/engine/memory/inc/memory.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +#define NHASH 257 //Use a prime number! +#define MULT 17 + +/* + * Data + */ +struct t_linkedstring +{ + struct t_linkedstring *next; + int referencer; + char string[1]; +}; + +static struct t_linkedstring *list[NHASH]; + +#define myoffsetof(st, m) \ + ((int) ( (char *)&((st *)(0))->m - (char *)0 )) + +unsigned int hash(const char *str) +{ + unsigned int h = 0; + for(; *str; str++) + h = MULT * h + *str; + return h % NHASH; +} +/* + * Methods + */ +PRIVATE struct t_linkedstring *lookupString( + const char* str, + struct t_linkedstring *first) +{ + while(first != 0) + { + if(cm_StringCompare(str, first->string, MAX_INTERNAL_STRING_LENGTH) == 0) + break; + first = first->next; + } + + return first; +} + +t_dup_char cm_StringGet(const char* str) +{ + struct t_linkedstring *entry; + + entry = lookupString(str, list[hash(str)]); + CM_ASSERT(entry != 0); + + return (t_dup_char)entry->string; +} + +t_dup_char cm_StringReference(t_dup_char str) +{ + struct t_linkedstring* entry = (struct t_linkedstring*)((t_uint32)str - myoffsetof(struct t_linkedstring, string)); + + // One more referencer + entry->referencer++; + + return (t_dup_char)entry->string; +} + +t_dup_char cm_StringDuplicate(const char* str) +{ + struct t_linkedstring *entry; + unsigned int h; + + h = hash(str); + entry = lookupString(str, list[h]); + if(entry != 0) + { + // One more referencer + entry->referencer++; + } + else + { + // Allocate new entry + entry = (struct t_linkedstring *)OSAL_Alloc(sizeof(struct t_linkedstring)-1 + cm_StringLength(str, MAX_INTERNAL_STRING_LENGTH)+1); + if(entry == NULL) + return NULL; + + entry->referencer = 1; + cm_StringCopy(entry->string, str, MAX_INTERNAL_STRING_LENGTH); + + // Link it in list + entry->next = list[h]; + list[h] = entry; + } + + return (t_dup_char)entry->string; +} + +void cm_StringRelease(t_dup_char str) +{ + if(str != NULL) + { + struct t_linkedstring* entry = (struct t_linkedstring*)((t_uint32)str - myoffsetof(struct t_linkedstring, string)); + + // One less referencer + entry->referencer--; + + if(entry->referencer == 0) + { + int h = hash(entry->string); + + if(list[h] == entry) // This first first one + { + list[h] = entry->next; + } + else + { + struct t_linkedstring *tmp = list[h]; + + // Here we assume that entry is in the list + while(/*tmp != NULL && */tmp->next != entry) + tmp = tmp->next; + + tmp->next = entry->next; + } + OSAL_Free(entry); + } + } +} + +#if 0 +void checkString() +{ + struct t_linkedstring *tmp = list; + + while(tmp != 0) + { + printf(" stay %s %d\n", tmp->string, tmp->referencer); + tmp = tmp->next; + } +} +#endif + +/* + * LibC method + */ +void cm_StringCopy(char* dest, const char *src, int count) +{ + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */ + ; +} +#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) + +int cm_StringCompare(const char* str1, const char* str2, int count) +{ + /* If s1 and s2 are word-aligned, compare them a word at a time. */ + if ((((int)str1 & 3) | ((int)str2 & 3)) == 0) + { + unsigned int *a1 = (unsigned int*)str1; + unsigned int *a2 = (unsigned int*)str2; + + while (count >= sizeof (unsigned int) && *a1 == *a2) + { + count -= sizeof (unsigned int); + + /* If we've run out of bytes or hit a null, return zero since we already know *a1 == *a2. */ + if (count == 0 || DETECTNULL (*a1)) + return 0; + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of s1, so search bytewise */ + str1 = (char*)a1; + str2 = (char*)a2; + } + + while (count-- > 0 && *str1 == *str2) + { + /* If we've run out of bytes or hit a null, return zero + since we already know *s1 == *s2. */ + if (count == 0 || *str1 == '\0') + return 0; + str1++; + str2++; + } + + return (*(unsigned char *) str1) - (*(unsigned char *) str2); +} + +int cm_StringLength(const char * str, int count) +{ + const char *sc; + + for (sc = str; count-- && *sc != '\0'; ++sc) + /* nothing */ + ; + return sc - str; +} + +void cm_StringConcatenate(char* dest, const char* src, int count) +{ + while ((*dest) != '\0') + { + dest++; + count--; + } + cm_StringCopy(dest, src, count); +} + +char* cm_StringSearch(const char* str, int c) +{ + for(; *str != (char) c; ++str) + if (*str == '\0') + return 0; + return (char *) str; +} diff --git a/drivers/staging/nmf-cm/cm/engine/utils/src/swap.c b/drivers/staging/nmf-cm/cm/engine/utils/src/swap.c new file mode 100644 index 00000000000..e3e2d536144 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/src/swap.c @@ -0,0 +1,156 @@ +/* + * 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/utils/inc/swap.h> + + +/* + * Methods + */ +t_uint16 swap16(t_uint16 x) +{ + return ((x >> 8) | + ((x << 8) & 0xff00U)); +} + +#ifdef LINUX + +#if defined(__STN_8815) /* __STN_8815 -> ARMv5*/ +t_uint32 swap32(t_uint32 x) +{ + asm volatile ( + "EOR r1, r0, r0, ROR #16 \n\t" + "BIC r1, r1, #0xFF0000 \n\t" + "MOV r0, r0, ROR #8 \n\t" + "EOR r0, r0, r1, LSR #8" + : : : "r3" ); + + return x; +} + +t_uint64 swap64(t_uint64 x) +{ + asm volatile ( + "MOV r2, r1 \n\t" + " \n\t" + "EOR r3, r0, r0, ROR #16 \n\t" + "BIC r3, r3, #0xFF0000 \n\t" + "MOV r0, r0, ROR #8 \n\t" + "EOR r1, r0, r3, LSR #8 \n\t" + " \n\t" + "EOR r3, r2, r2, ROR #16 \n\t" + "BIC r3, r3, #0xFF0000 \n\t" + "MOV r2, r2, ROR #8 \n\t" + "EOR r0, r2, r3, LSR #8" + : : : "r3", "r2" ); + + return x; +} +#else /* -> ARMv6 or later */ + +t_uint32 swap32(t_uint32 x) +{ + asm volatile ( + "REV %0, %0" + : "+r"(x) : ); + + return x; +} + +t_uint64 swap64(t_uint64 x) +{ + asm volatile ( + "REV r2, %Q0 \n\t" + "REV %Q0, %R0 \n\t" + "MOV %R0, r2" + : "+&r" (x) : : "r2" ); + + return x; +} + +#endif + +#else /* Symbian, Think -> We assume ARMCC */ + +#if defined(__thumb__) + +t_uint32 swap32(t_uint32 x) +{ + return ((x >> 24) | + ((x >> 8) & 0xff00U) | + ((x << 8) & 0xff0000U) | + ((x << 24) & 0xff000000U)); +} + +t_uint64 swap64(t_uint64 x) +{ + return ((x >> 56) | + ((x >> 40) & 0xff00UL) | + ((x >> 24) & 0xff0000UL) | + ((x >> 8) & 0xff000000UL) | + ((x << 8) & 0xff00000000ULL) | + ((x << 24) & 0xff0000000000ULL) | + ((x << 40) & 0xff000000000000ULL) | + ((x << 56))); +} + +#elif (__TARGET_ARCH_ARM < 6) + +__asm t_uint32 swap32(t_uint32 x) +{ + EOR r1, r0, r0, ROR #16 + BIC r1, r1, #0xFF0000 + MOV r0, r0, ROR #8 + EOR r0, r0, r1, LSR #8 + + BX lr +} + +__asm t_uint64 swap64(t_uint64 x) +{ + MOV r2, r1 + + EOR r3, r0, r0, ROR #16 // Swap low (r0) and store it in high (r1) + BIC r3, r3, #0xFF0000 + MOV r0, r0, ROR #8 + EOR r1, r0, r3, LSR #8 + + EOR r3, r2, r2, ROR #16 // Swap high (r2 = ex r1) and store it in low (r0) + BIC r3, r3, #0xFF0000 + MOV r2, r2, ROR #8 + EOR r0, r2, r3, LSR #8 + + BX lr +} + +#else /* -> ARMv6 or later */ + +__asm t_uint32 swap32(t_uint32 x) +{ + REV r0, r0 + + BX lr +} + +__asm t_uint64 swap64(t_uint64 x) +{ + REV r2, r0 + REV r0, r1 + MOV r1, r2 + + BX lr +} + +#endif + +#endif + +t_uint32 noswap32(t_uint32 x) { + return x; +} + diff --git a/drivers/staging/nmf-cm/cm/engine/utils/src/table.c b/drivers/staging/nmf-cm/cm/engine/utils/src/table.c new file mode 100644 index 00000000000..708396a01b2 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/engine/utils/src/table.c @@ -0,0 +1,155 @@ +/* + * 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/os_adaptation_layer/inc/os_adaptation_layer.h> +#include <cm/engine/trace/inc/trace.h> +#include <cm/engine/utils/inc/mem.h> +#include <cm/engine/utils/inc/table.h> + +/* + * Methods + */ +t_cm_error cm_initTable(t_nmf_table* table) +{ + table->idxMax = TABLE_DEF_SIZE / sizeof(table->entries); + + table->entries = OSAL_Alloc_Zero(table->idxMax*sizeof(table->entries)); + + if (table->entries == NULL) { + table->idxMax = 0; + return CM_NO_MORE_MEMORY; + } + + return CM_OK; +} + +void cm_destroyTable(t_nmf_table* table) +{ + if (table->idxNb) { + ERROR("Attempt to free non-empty table !!!\n", 0, 0, 0, 0, 0, 0); + return; + } + OSAL_Free(table->entries); + table->idxMax = 0; +} + +static t_cm_error cm_increaseTable(t_nmf_table* table) +{ + t_uint32 new_max; + void *mem; + + if (table->idxMax == INDEX_MASK) { + ERROR("CM_NO_MORE_MEMORY: Maximum table entries reached\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + new_max = table->idxMax + + TABLE_DEF_SIZE / sizeof(table->entries); + + if (new_max > INDEX_MAX) + new_max = INDEX_MAX; + + mem = OSAL_Alloc(new_max * sizeof(table->entries)); + + if (mem == NULL) { + ERROR("CM_NO_MORE_MEMORY: Unable to allocate memory for a table\n", 0, 0, 0, 0, 0, 0); + return CM_NO_MORE_MEMORY; + } + + cm_MemCopy(mem, table->entries, + table->idxMax*sizeof(table->entries)); + cm_MemSet((void *)((t_uint32) mem + table->idxMax*sizeof(*table->entries)), 0, + (new_max-table->idxMax) * sizeof(*table->entries)); + + OSAL_Free(table->entries); + table->entries = mem; + table->idxMax = new_max; + + return CM_OK; +} + +/** cm_addEntry - Add an local pointer to an element 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_uint32 cm_addEntry(t_nmf_table *table, void *entry) +{ + unsigned int i; + t_uint32 hdl = 0; + + if (table->idxNb == table->idxMax) + cm_increaseTable(table); + + for (i = table->idxCur; + table->entries[i] != 0 && i != (table->idxCur-1); + i = (i+1)%table->idxMax); + + if (table->entries[i] == 0) { + table->entries[i] = entry; + table->idxCur = (i+1) % table->idxMax; + table->idxNb++; + hdl = ENTRY2HANDLE(entry, i); + } else + ERROR("No free entry found in table\n", 0, 0, 0, 0, 0, 0); + + return hdl; +} + +/** cm_delEntry - remove the given element from the list + * + * 1. Check if the handle is valid + * 2. Search the entry and free it + */ +void cm_delEntry(t_nmf_table *table, t_uint32 idx) +{ + table->entries[idx] = NULL; + table->idxNb--; +} + +/** cm_lookupEntry - search the entry corresponding to + * the user handle. + * + * 1. Check if the handle is valid + * 2. Return a pointer to the element + */ +void *cm_lookupEntry(const t_nmf_table *table, const t_uint32 hdl) +{ + unsigned int idx = hdl & INDEX_MASK; + + if ((idx >= table->idxMax) + || (((unsigned int)table->entries[idx] << INDEX_SHIFT) != (hdl & ~INDEX_MASK))) + return NULL; + else + return table->entries[idx]; +} + +/** cm_lookupHandle - search the handle corresponding + * to the given element + * + * 1. Check if the handler is valid or is a special handler + * 2. Loop in the table to retrieve the entry matching and return its value + */ +t_uint32 cm_lookupHandle(const t_nmf_table *table, const void *entry) +{ + t_uint32 i; + + /* NULL is an invalid value that must be handle separatly + as it'll match all used/free entries value */ + if (entry == NULL) + return 0; + + for (i=0; i < table->idxMax; i++) { + if (table->entries[i] == entry) + return ENTRY2HANDLE(table->entries[i], i); + } + + return 0; +} diff --git a/drivers/staging/nmf-cm/cm/inc/cm.h b/drivers/staging/nmf-cm/cm/inc/cm.h new file mode 100644 index 00000000000..37ccb36a5ee --- /dev/null +++ b/drivers/staging/nmf-cm/cm/inc/cm.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_CM_H +#define __INC_CM_H + +#include <cm/inc/cm_def.h> + +/********************************************************************************/ +/* Component Manager API prototypes */ +/********************************************************************************/ + +/* + * User level wrapper + */ +#include <cm/proxy/api/cm_proxy.h> + +#endif /* __INC_CM_H */ diff --git a/drivers/staging/nmf-cm/cm/inc/cm_def.h b/drivers/staging/nmf-cm/cm/inc/cm_def.h new file mode 100644 index 00000000000..dc7a1fdad66 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/inc/cm_def.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +/*! + * \brief Component Manager API. + * + * This file contains the Component Manager API for manipulating components. + * + */ + +#ifndef __INC_CM_DEF_H +#define __INC_CM_DEF_H + +#include <cm/inc/cm_type.h> +#include <inc/nmf-def.h> + +/*! + * \brief Get the version of the NMF CM engine at runtime + * + * This method should be used to query the version number of the + * NMF Component Manager engine at runtime. This is useful when using + * to check if version of the engine linked with application correspond + * to engine used for development. + * + * Such code can be used to check compatibility: \code + t_uint32 nmfversion; + + // Print NMF version + CM_GetVersion(&nmfversion); + LOG("NMF Version %d-%d-%d\n", + VERSION_MAJOR(nmfversion), + VERSION_MINOR(nmfversion), + VERSION_PATCH(nmfversion)); + if(NMF_VERSION != nmfversion) { + LOG("Error: Incompatible API version %d != %d\n", NMF_VERSION, nmfversion); + EXIT(); + } + * \endcode + * + * \param[out] version Internal hardcoded version (use \ref VERSION_MAJOR, \ref VERSION_MINOR, \ref VERSION_PATCH macros to decode it). + * + * \ingroup CM + */ +PUBLIC IMPORT_SHARED void CM_GetVersion(t_uint32 *version); + +#endif /* __INC_CM_H */ diff --git a/drivers/staging/nmf-cm/cm/inc/cm_macros.h b/drivers/staging/nmf-cm/cm/inc/cm_macros.h new file mode 100644 index 00000000000..2279c204a20 --- /dev/null +++ b/drivers/staging/nmf-cm/cm/inc/cm_macros.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +/*! + * \brief Component Manager Macros. + * + * \defgroup CM_MACROS NMF Macros (ANSI C99) + * The Component Manager Macros are provided to ease FromHost interface call and ToHost callback definition. + * \attention <b>These macros are only ANSI C99 compliant</b> (ARM RVCT 2.x/3.x, GNU gcc 4.x, ...) + * \ingroup CM_USER_API + */ + +#ifndef __INC_CM_MACROS_H +#define __INC_CM_MACROS_H + +/* + * The next macros are supported only with C Ansi 99, so.... + */ + +/* + * The Symbian environment dependency, computation which uses an old gnu cpp, + * does not accept "..." parameters. + * However the actual compiler (armcc) does. + * So remove the macro definitions when computing dependencies. + */ +#if ( defined(__CC_ARM) && !defined(__STRICT_ANSI__) ) || !defined(__SYMBIAN32__) + +/* + * Only for skilled eyes ;) + * The following macros are used to implement NMFCALL[VOID] and NMFMETH[VOID] macros in an elegant way + */ +#define WITH_PARAM(...) __VA_ARGS__) +#define WITH_NOPARAM(...) ) + +/*! + * \brief Macro to ease Host to Dsp interface calling + * + * \attention <b>This macro is only ANSI C99 compliant</b> + * + * The <i>NMFCALL</i> macro can be used to call one method of any previously FromHost bounded interface.\n + * From Host side, today, we have no way to mask the multi-instance handling, so + * this macro is provided to ease FromHost interface calling and to avoid any mistake into the THIS parameter passing. + * + * So, any fromHost interface method call like: \code + * itf.method(itf.THIS, param1, param2, ...); + * \endcode + * can be replaced by: \code + * NMFCALL(itf, method)(param1, param2, ...); + * \endcode + * + * \warning Don't forget to use NMFCALLVOID macro when declaring a FromHost interface method having none application parameter, + * else it will lead to erroneous C code expansion + * \see NMFCALLVOID + * \hideinitializer + * \ingroup CM_MACROS + */ +#define NMFCALL(itfHandle, itfMethodName) \ + (itfHandle).itfMethodName((itfHandle).THIS, WITH_PARAM + +/*! + * \brief Macro to ease Host to Dsp interface calling (method without any user parameter) + * + * \attention <b>This macro is only ANSI C99 compliant</b> + * + * The <i>NMFCALLVOID</i> macro can be used to call one method (those without any user parameter) of any previously FromHost bounded interface.\n + * From Host side, today, we have no way to mask the multi-instance handling, so + * this macro is provided to ease FromHost interface calling and to avoid any mistake into the THIS parameter passing. + * + * So, any FromHost interface method call without any application parameter like:\code + * itf.method(itf.THIS); + * \endcode + * can be replaced by: \code + * NMFCALLVOID(itf, method)(); + * \endcode + * \see NMFCALL + * \hideinitializer + * \ingroup CM_MACROS + */ +#define NMFCALLVOID(itfHandle, itfMethodName) \ + (itfHandle).itfMethodName((itfHandle).THIS WITH_NOPARAM + +/*! + * \brief Macro to ease Dsp to Host interface method declaration + * + * \attention <b>This macro definition is only ANSI C99 compliant</b> + * + * The <i>NMFMETH</i> macro can be used to ease the ToHost interface method declaration.\n + * From Host side, today, we have no way to mask the multi-intance handling, so the user shall handle it by hand + * by passing the "component" context as first parameter of each ToHost interface method through the void *THIS parameter. + * This macro could avoid any mistake into the THIS parameter declaration when never used by the user code. + * + * So, any ToHost interface method declaration like:\code + * void mynotify(void *THIS, mytype1 myparam1, mytype2 myparam2, ...) { + * <body of the interface routine> + * } + * \endcode + * can be replaced by: \code + * void NMFMETH(mynotify)(mytype1 myparam1, mytype2 myparam2, ...) { + * <body of the interface routine> + * } + * \endcode + * + * \warning Don't forget to use NMFMETHVOID macro when declaring a ToHost interface method having none application parameter, + * else it will lead to erroneous C code expansion + * + * \see NMFMETHVOID + * \hideinitializer + * \ingroup CM_MACROS + */ +#define NMFMETH(itfMethodName) \ + itfMethodName(void *THIS, WITH_PARAM + +/*! + * \brief Macro to ease Dsp to Host interface method declaration (method without any user parameter) + * + * \attention <b>This macro is only ANSI C99 compliant</b> + * + * The <i>NMFMETHVOID</i> macro can be used to ease the ToHost interface method (those without any user parameter) declaration.\n + * From Host side, today, we have no way to mask the multi-intance handling, so the user shall handle it by hand + * by passing the "component" context as first parameter of each ToHost interface method through the void *THIS parameter. + * This macro could avoid any mistake into the THIS parameter declaration when never used by the user code. + * + * So, any ToHost interface method declaration having none application parameter like:\code + * void mynotify(void *THIS) { + * <body of the interface routine> + * } + * \endcode + * can be replaced by: \code + * void NMFMETHVOID(mynotify)(void) { + * <body of the interface routine> + * } + * \endcode + * + * \see NMFMETH + * \hideinitializer + * \ingroup CM_MACROS + */ +#define NMFMETHVOID(itfMethodName) \ + itfMethodName(void *THIS WITH_NOPARAM + +#endif /* not Symbian environment or compiling with ARMCC and not in strict ANSI */ + +#endif /* __INC_CM_MACROS_H */ + diff --git a/drivers/staging/nmf-cm/cm/inc/cm_type.h b/drivers/staging/nmf-cm/cm/inc/cm_type.h new file mode 100644 index 00000000000..b2f97090a3a --- /dev/null +++ b/drivers/staging/nmf-cm/cm/inc/cm_type.h @@ -0,0 +1,147 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Component Manager types. + * + * This file contains the Component Manager types. + * + * \defgroup CM CM Type Definitions + * \ingroup CM_USER_API + */ +#ifndef _CM_TYPE_H_ +#define _CM_TYPE_H_ + +#include <share/inc/nmf.h> +#include <share/inc/macros.h> + +#include <nmf/inc/channel_type.h> + +/*! + * @defgroup t_cm_error t_cm_error + * \brief Description of the various errors returned by CM API routines + * @{ + * \ingroup CM + */ +typedef t_nmf_error t_cm_error; //!< Error type returned by CM API routines + +/*********************************************************************************/ +/* WARNING: UPDATE CM_StringError() func each time an error is added/removed !!! */ +/* CM_StringError() is defined twice in: */ +/* nmf_core/host/cm/proxy/common/wrapper/src/wrapper.c */ +/* tests/src/common/nte/src/nte.c */ +/*********************************************************************************/ +#define CM_LAST_ERROR_ID ((t_cm_error)-128) +#define CM_INTEGRATION_ERROR NMF_INTEGRATION_ERROR0 //!< \ref NMF_INTEGRATION_ERROR0 + + /* Communication */ +#define CM_FLUSH_MESSAGE NMF_FLUSH_MESSAGE //!< Message send after call to CM_FlushChannel() +#define CM_BUFFER_OVERFLOW ((t_cm_error)-105) //!< Buffer overflow (interface binding message bigger than buffer) +#define CM_USER_NOT_REGISTERED ((t_cm_error)-104) //!< User not registered +#define CM_NO_MESSAGE NMF_NO_MESSAGE //!< \ref NMF_NO_MESSAGE +#define CM_PARAM_FIFO_OVERFLOW ((t_cm_error)-102) //!< Param fifo overflow +#define CM_INTERNAL_FIFO_OVERFLOW ((t_cm_error)-101) //!< Internal services fifo overflow (not returned to user) +#define CM_MPC_NOT_RESPONDING ((t_cm_error)-100) //!< MPC not responding (either crash, interrupt handler too long, internal NMF fifo coms overflow, ...). + + /* ELF & File system */ +#define CM_FS_ERROR ((t_cm_error)-96) //!< FileSystem error +#define CM_NO_SUCH_FILE ((t_cm_error)-95) //!< No such file or directory +#define CM_INVALID_ELF_FILE ((t_cm_error)-94) //!< File isn't a valid MMDSP ELF file +#define CM_NO_SUCH_BASE ((t_cm_error)-93) //!< The memory base doesn't exist + + /* Introspection */ +#define CM_NO_SUCH_ATTRIBUTE NMF_NO_SUCH_ATTRIBUTE //!< \ref NMF_NO_SUCH_ATTRIBUTE +#define CM_NO_SUCH_PROPERTY NMF_NO_SUCH_PROPERTY //!< \ref NMF_NO_SUCH_PROPERTY + + /* Component Life Cycle */ +#define CM_COMPONENT_NOT_STOPPED NMF_COMPONENT_NOT_STOPPED //!< \ref NMF_COMPONENT_NOT_STOPPED +#define CM_COMPONENT_NOT_UNBINDED ((t_cm_error)-79) //!< Component must be fully unbinded before perform operation +#define CM_COMPONENT_NOT_STARTED ((t_cm_error)-78) //!< Component must be started to perform operation +#define CM_COMPONENT_WAIT_RUNNABLE ((t_cm_error)-76) //!< Component need acknowlegdment of life cycle start function before perform operation +#define CM_REQUIRE_INTERFACE_UNBINDED ((t_cm_error)-75) //!< Required component interfaces must be binded before perform operation +#define CM_INVALID_COMPONENT_HANDLE ((t_cm_error)-74) //!< Try to access a component already destroyed + + /* Binder */ +#define CM_NO_SUCH_PROVIDED_INTERFACE NMF_NO_SUCH_PROVIDED_INTERFACE //!< \ref NMF_NO_SUCH_PROVIDED_INTERFACE +#define CM_NO_SUCH_REQUIRED_INTERFACE NMF_NO_SUCH_REQUIRED_INTERFACE //!< \ref NMF_NO_SUCH_REQUIRED_INTERFACE +#define CM_ILLEGAL_BINDING ((t_cm_error)-62) //!< Client and server interface type mismatch +#define CM_ILLEGAL_UNBINDING ((t_cm_error)-61) //!< Try to unbind component with bad binding Factories +#define CM_INTERFACE_ALREADY_BINDED NMF_INTERFACE_ALREADY_BINDED//!< \ref NMF_INTERFACE_ALREADY_BINDED +#define CM_INTERFACE_NOT_BINDED NMF_INTERFACE_NOT_BINDED //!< \ref NMF_INTERFACE_NOT_BINDED + + /* Loader */ +#define CM_BINDING_COMPONENT_NOT_FOUND ((t_cm_error)-48) //!< Binding Component template name don't exist on components repository (should be generated thanks nkitf tool) +#define CM_COMPONENT_NOT_FOUND ((t_cm_error)-47) //!< Component template name doesn't exist on components repository +#define CM_NO_SUCH_SYMBOL ((t_cm_error)-46) //!< Symbol name doesn't exported by the underlying component +#define CM_COMPONENT_EXIST ((t_cm_error)-45) //!< Component name already exists in the component cache + + /* Fifo management related ones */ +#define CM_FIFO_FULL ((t_cm_error)-40) //!< Fifo is full +#define CM_FIFO_EMPTY ((t_cm_error)-39) //!< Fifo is empty +#define CM_UNKNOWN_FIFO_ID ((t_cm_error)-38) //!< Fifo handle doesn't exist + + /* Memory management related ones */ +#define CM_DOMAIN_VIOLATION ((t_cm_error)-33) //!< Domain violation +#define CM_CREATE_ALLOC_ERROR ((t_cm_error)-32) //!< Error during allocator creation +#define CM_UNKNOWN_MEMORY_HANDLE ((t_cm_error)-31) //!< Handle doesn't exists +#define CM_NO_MORE_MEMORY NMF_NO_MORE_MEMORY //!< \ref NMF_NO_MORE_MEMORY +#define CM_BAD_MEMORY_ALIGNMENT ((t_cm_error)-29) //!< Memory alignment wanted is not correct +#define CM_MEMORY_HANDLE_FREED ((t_cm_error)-28) //!< Handle was alread freed +#define CM_INVALID_DOMAIN_DEFINITION ((t_cm_error)-27) //!< Domain to be created is not correctly defined +#define CM_INTERNAL_DOMAIN_OVERFLOW ((t_cm_error)-26) //!< Internal domain descriptor overflow (too many domains) //TODO, juraj, remove this error +#define CM_INVALID_DOMAIN_HANDLE ((t_cm_error)-25) //!< Invalid domain handle +#define CM_ILLEGAL_DOMAIN_OPERATION ((t_cm_error)-21) //!< Operation on a domain is illegal (like destroy of a domain with referenced components) + + /* Media Processor related ones */ +#define CM_MPC_INVALID_CONFIGURATION ((t_cm_error)-24) //!< Media Processor Core invalid configuration +#define CM_MPC_NOT_INITIALIZED ((t_cm_error)-23) //!< Media Processor Core not yet initialized +#define CM_MPC_ALREADY_INITIALIZED ((t_cm_error)-22) //!< Media Processor Core already initialized +//ERROR 21 is defined above, with the domains + + /* Power Mgt related ones */ +#define CM_PWR_NOT_AVAILABLE ((t_cm_error)-16) //!< No modification of the state of the power input + + /* Common errors */ +#define CM_OUT_OF_LIMITS ((t_cm_error)-3) //!< User reach an internal nmf limits of limits.h file +#define CM_INVALID_PARAMETER NMF_INVALID_PARAMETER //!< \ref NMF_INVALID_PARAMETER +#define CM_NOT_YET_IMPLEMENTED ((t_cm_error)-1) //!< CM API not yet implemented +#define CM_OK NMF_OK //!< \ref NMF_OK + +/** @} */ + +/*! + * \brief Definition of a physical memory address + * \ingroup MEMORY + */ +typedef t_uint32 t_cm_physical_address; + +/*! + * \brief Definition of a logical memory address + * \ingroup MEMORY + */ +typedef t_uint32 t_cm_logical_address; + +/*! + * \brief Definition of a system address into a system with MMU + * \ingroup MEMORY + */ +typedef struct { + t_cm_physical_address physical; //!< Physical memory address + t_cm_logical_address logical; //!< Logical memory address +} t_cm_system_address; +#define INVALID_SYSTEM_ADDRESS {(t_cm_physical_address)MASK_ALL32, (t_cm_logical_address)MASK_ALL32} + + +/*! + * \brief Define a type used to manipulate size of various buffers + * \ingroup MEMORY + */ +typedef t_uint32 t_cm_size; + +#endif /* _CM_TYPE_H_ */ + diff --git a/drivers/staging/nmf-cm/cm_dma.c b/drivers/staging/nmf-cm/cm_dma.c new file mode 100644 index 00000000000..1db5a3cf951 --- /dev/null +++ b/drivers/staging/nmf-cm/cm_dma.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <asm/io.h> + + #include "cm_dma.h" + + #define CMDMA_LIDX (2) + #define CMDMA_BASE (0x801C0000) + #define CMDMA_REG_LCLA (0x024) + +void __iomem *virtbase = NULL; + +static int cmdma_write_cyclic_list_mem2per( + unsigned int from_addr, + unsigned int to_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS); + +static int cmdma_write_cyclic_list_per2mem( + unsigned int from_addr, + unsigned int to_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS); + +int cmdma_setup_relink_area( unsigned int mem_addr, + unsigned int per_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS, + enum cmdma_type type) +{ + switch (type) { + + case CMDMA_MEM_2_PER: + return cmdma_write_cyclic_list_mem2per( + mem_addr, + per_addr, + segments, + segmentsize, + LOS); + + case CMDMA_PER_2_MEM: + return cmdma_write_cyclic_list_per2mem( + per_addr, + mem_addr, + segments, + segmentsize, + LOS); + + default : + return -EINVAL; + } + } + + static unsigned int cmdma_getlcla( void) { + + if(!virtbase) + virtbase = ioremap(CMDMA_BASE, CMDMA_REG_LCLA + sizeof(int) ); + + return readl(virtbase + CMDMA_REG_LCLA); + } + + static void cmdma_write_relink_params_mem2per ( + int * relink, + unsigned int LOS, + unsigned int nb_element, + unsigned int src_addr, + unsigned int dst_addr, + unsigned int burst_size) { + + relink[0] = (((long)(nb_element & 0xFFFF)) << 16) | + (src_addr & 0xFFFF); + + relink[1] = (((src_addr >> 16) & 0xFFFFUL) << 16) | + (0x1200UL | (LOS << 1) | (burst_size<<10)); + + relink[2] = ((nb_element & 0xFFFF) << 16) | + (dst_addr & 0xFFFF); + + relink[3] = (((dst_addr >> 16) & 0xFFFFUL) << 16 ) | + 0x8201UL | ((LOS+1) << 1) | (burst_size<<10); +} + +static void cmdma_write_relink_params_per2mem ( + int * relink, + unsigned int LOS, + unsigned int nb_element, + unsigned int src_addr, + unsigned int dst_addr, + unsigned int burst_size) { + + relink[0] = (((long)(nb_element & 0xFFFF)) << 16) | + (src_addr & 0xFFFF); + + relink[1] = (((src_addr >> 16) & 0xFFFFUL) << 16) | + (0x8201UL | (LOS << 1) | (burst_size<<10)); + + relink[2] = ((nb_element & 0xFFFF) << 16) | + (dst_addr & 0xFFFF); + + relink[3] = (((dst_addr >> 16) & 0xFFFFUL) << 16 ) | + 0x1200UL | ((LOS+1) << 1) | (burst_size<<10); +} + +static int cmdma_write_cyclic_list_mem2per( + unsigned int from_addr, + unsigned int to_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS) { + + unsigned int i,j; + int *relink; + + j = LOS; + + for ( i = 0; i < segments; i++) { + relink = phys_to_virt (cmdma_getlcla() + 1024 * CMDMA_LIDX + 8 * j); + + if (i == (segments-1)) + j = LOS; + else + j += 2; + + cmdma_write_relink_params_mem2per ( + relink, + j, + segmentsize / 4, + from_addr, + to_addr, + 0x2); + + from_addr += segmentsize; + } + + return 0; +} + +static int cmdma_write_cyclic_list_per2mem( + unsigned int from_addr, + unsigned int to_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS) { + + unsigned int i,j; + int *relink; + j = LOS; + + for ( i = 0; i < segments; i++) { + relink = phys_to_virt (cmdma_getlcla() + 1024 * CMDMA_LIDX + 8 * j); + + if (i == (segments-1)) + j = LOS; + else + j += 2; + + cmdma_write_relink_params_per2mem ( + relink, + j, + segmentsize / 4, + from_addr, + to_addr, + 0x2); + + to_addr += segmentsize; + } + + return 0; +} diff --git a/drivers/staging/nmf-cm/cm_dma.h b/drivers/staging/nmf-cm/cm_dma.h new file mode 100644 index 00000000000..6ee4caafeae --- /dev/null +++ b/drivers/staging/nmf-cm/cm_dma.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * License terms: GNU General Public License (GPL), version 2, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +#ifndef __CMDMA_H +#define __CMDMA_H + +enum cmdma_type { + CMDMA_MEM_2_PER, + CMDMA_PER_2_MEM +}; + +int cmdma_setup_relink_area( + unsigned int mem_addr, + unsigned int per_addr, + unsigned int segments, + unsigned int segmentsize, + unsigned int LOS, + enum cmdma_type type); + +#endif diff --git a/drivers/staging/nmf-cm/cm_service.c b/drivers/staging/nmf-cm/cm_service.c new file mode 100644 index 00000000000..1b5ee111e09 --- /dev/null +++ b/drivers/staging/nmf-cm/cm_service.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/** \file cm_service.c + * + * Nomadik Multiprocessing Framework Linux Driver + * + */ + +#include <linux/module.h> +#include <linux/plist.h> +#include <linux/slab.h> +#include <linux/spinlock_types.h> + +#include <cm/engine/api/control/irq_engine.h> + +#include "osal-kernel.h" +#include "cmld.h" +#include "cm_service.h" + +/* Panic managment */ +static void service_tasklet_func(unsigned long); +unsigned long service_tasklet_data = 0; +DECLARE_TASKLET(cmld_service_tasklet, service_tasklet_func, 0); + +void dispatch_service_msg(struct osal_msg *msg) +{ + struct list_head *head, *next; + + /* Note: no lock needed to protect the channel_list to protect against list + changes, as the current tasklet is disabled each time we modify the list */ + list_for_each_safe(head, next, &channel_list) { + struct cm_channel_priv *channelPriv = list_entry(head, struct cm_channel_priv, entry); + struct osal_msg *new_msg; + size_t msg_size; + + if (channelPriv->state == CHANNEL_CLOSED) + continue; + msg_size = sizeof(new_msg->hdr) + sizeof(new_msg->d.srv); + new_msg = kmalloc(msg_size, GFP_ATOMIC); + if (new_msg == NULL) { + pr_err("[CM] %s: can't allocate memory, service" + " message not dispatched !!\n", __func__); + continue; + } + memcpy(new_msg, msg, msg_size); + plist_node_init(&new_msg->msg_entry, 0); + spin_lock_bh(&channelPriv->bh_lock); + plist_add(&new_msg->msg_entry, &channelPriv->messageQueue); + spin_unlock_bh(&channelPriv->bh_lock); + wake_up_interruptible(&channelPriv->waitq); + } +} + +static void service_tasklet_func(unsigned long unused) +{ + t_cm_service_type type; + t_cm_service_description desc; + int i=0; + + do { + if (test_and_clear_bit(i, &service_tasklet_data)) { + CM_getServiceDescription(osalEnv.mpc[i].coreId, &type, &desc); + + switch (type) { + case CM_MPC_SERVICE_PANIC: { + struct osal_msg msg; + + msg.msg_type = MSG_SERVICE; + msg.d.srv.srvType = NMF_SERVICE_PANIC; + msg.d.srv.srvData.panic = desc.u.panic; + + dispatch_service_msg(&msg); + break; + } + case CM_MPC_SERVICE_PRINT: { + char msg[256]; + if (CM_ReadMPCString(osalEnv.mpc[i].coreId, + desc.u.print.dspAddress, msg, + sizeof(msg)) == CM_OK) + printk(msg, desc.u.print.value1, desc.u.print.value2); + break; + } + default: + pr_err("[CM] %s: MPC Service Type %d not supported\n", __func__, type); + } + enable_irq(osalEnv.mpc[i].interrupt1); + } + i = (i+1) % NB_MPC; + } while (service_tasklet_data != 0); +} diff --git a/drivers/staging/nmf-cm/cm_service.h b/drivers/staging/nmf-cm/cm_service.h new file mode 100644 index 00000000000..39582eae573 --- /dev/null +++ b/drivers/staging/nmf-cm/cm_service.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/** \file cm_service.c + * + * Nomadik Multiprocessing Framework Linux Driver + * + */ + +#ifndef CM_SERVICE_H +#define CM_SERVICE_H + +#include <linux/interrupt.h> + +extern unsigned long service_tasklet_data; +extern struct tasklet_struct cmld_service_tasklet; +void dispatch_service_msg(struct osal_msg *msg); + +#endif diff --git a/drivers/staging/nmf-cm/cm_syscall.c b/drivers/staging/nmf-cm/cm_syscall.c new file mode 100644 index 00000000000..d1ad3a1f935 --- /dev/null +++ b/drivers/staging/nmf-cm/cm_syscall.c @@ -0,0 +1,1390 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <cm/engine/api/cm_engine.h> +#include "cmioctl.h" +#include "osal-kernel.h" +#include "cmld.h" +#include <cm/engine/memory/inc/remote_allocator.h> +#include <linux/kernel.h> + +/** Dequeue and free per-process messages for specific binding + * + * \note + * This is only safe if the per process mutex is held when called. + */ +static inline void freeMessages(struct cm_channel_priv* cPriv, t_skelwrapper* binding) +{ + struct osal_msg *this, *next; + + spin_lock_bh(&cPriv->bh_lock); + + /* free any pending messages */ + plist_for_each_entry_safe(this, next, &cPriv->messageQueue, msg_entry) { + if (this->msg_type == MSG_INTERFACE + && this->d.itf.skelwrap == binding) { + plist_del(&this->msg_entry, &cPriv->messageQueue); + kfree(this); + } + } + spin_unlock_bh(&cPriv->bh_lock); +} + +static t_cm_error copy_string_from_user(char *dst, const char __user *src, int len) +{ + int ret; + + ret = strncpy_from_user(dst, src, len); + if (ret < 0) /* -EFAULT */ + return CM_INVALID_PARAMETER; + + if (ret >= len) + return CM_OUT_OF_LIMITS; + + return 0; +} + +inline int cmld_InstantiateComponent(struct cm_process_priv* procPriv, + CM_InstantiateComponent_t __user *param) +{ + CM_InstantiateComponent_t data; + char templateName[MAX_TEMPLATE_NAME_LENGTH]; + char localName[MAX_COMPONENT_NAME_LENGTH]; + char *dataFile = NULL; + + /* Copy all user data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if (data.in.dataFile != NULL) { + dataFile = OSAL_Alloc(data.in.dataFileSize); + if (dataFile == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFile, data.in.dataFile, data.in.dataFileSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + if ((data.out.error = copy_string_from_user(templateName, + data.in.templateName, + sizeof(templateName)))) + goto out; + + if ((data.in.localName != NULL) && + (data.out.error = copy_string_from_user(localName, + data.in.localName, + sizeof(localName)))) + goto out; + + /* Do appropriate CM Engine call */ + data.out.error = CM_ENGINE_InstantiateComponent(templateName, + data.in.domainId, + procPriv->pid, + data.in.priority, + data.in.localName ? localName : NULL, + dataFile, + &data.out.component); + +out: + if (dataFile) + OSAL_Free(dataFile); + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_BindComponentFromCMCore(struct cm_process_priv* procPriv, + CM_BindComponentFromCMCore_t __user *param) +{ + CM_BindComponentFromCMCore_t data; + char providedItfServerName[MAX_INTERFACE_NAME_LENGTH]; + char *dataFileSkeleton = NULL; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(providedItfServerName, + data.in.providedItfServerName, + sizeof(providedItfServerName)))) + goto out; + + if (data.in.dataFileSkeleton != NULL) { + dataFileSkeleton = OSAL_Alloc(data.in.dataFileSkeletonSize); + if (dataFileSkeleton == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFileSkeleton, data.in.dataFileSkeleton, + data.in.dataFileSkeletonSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + data.out.error = CM_ENGINE_BindComponentFromCMCore(data.in.server, + providedItfServerName, + data.in.fifosize, + data.in.eventMemType, + &data.out.host2mpcId, + procPriv->pid, + dataFileSkeleton); +out: + if (dataFileSkeleton) + OSAL_Free(dataFileSkeleton); + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + + return 0; +} + +inline int cmld_UnbindComponentFromCMCore(CM_UnbindComponentFromCMCore_t __user *param) +{ + CM_UnbindComponentFromCMCore_t data; + + /* Copy all user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_UnbindComponentFromCMCore(data.in.host2mpcId); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_BindComponentToCMCore(struct cm_channel_priv* channelPriv, + CM_BindComponentToCMCore_t __user *param) +{ + CM_BindComponentToCMCore_t data; + t_skelwrapper *skelwrapper; + struct cm_process_priv *procPriv = channelPriv->proc; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + char *dataFileStub = NULL; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + /* Do appropriate CM Engine call */ + skelwrapper = (t_skelwrapper *)OSAL_Alloc(sizeof(*skelwrapper)); + if (skelwrapper == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + + if (data.in.dataFileStub != NULL) { + dataFileStub = OSAL_Alloc(data.in.dataFileStubSize); + if (dataFileStub == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFileStub, data.in.dataFileStub, data.in.dataFileStubSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + if ((data.out.error = CM_ENGINE_BindComponentToCMCore( + data.in.client, + requiredItfClientName, + data.in.fifosize, + (t_nmf_mpc2host_handle)skelwrapper, + dataFileStub, + &data.out.mpc2hostId, + procPriv->pid)) != CM_OK) { + OSAL_Free(skelwrapper); + goto out; + } + + skelwrapper->upperLayerThis = data.in.upLayerThis; + skelwrapper->mpc2hostId = data.out.mpc2hostId; + skelwrapper->channelPriv = channelPriv; + mutex_lock(&channelPriv->skelListLock); + list_add(&skelwrapper->entry, &channelPriv->skelList); + mutex_unlock(&channelPriv->skelListLock); +out: + if (dataFileStub != NULL) + OSAL_Free(dataFileStub); + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_UnbindComponentToCMCore(struct cm_process_priv* procPriv, + CM_UnbindComponentToCMCore_t __user *param) +{ + CM_UnbindComponentToCMCore_t data; + t_skelwrapper *skelwrapper; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + data.out.error = CM_ENGINE_UnbindComponentToCMCore( + data.in.client, requiredItfClientName, + (t_nmf_mpc2host_handle*)&skelwrapper, + procPriv->pid); + + if (data.out.error != CM_OK && data.out.error != CM_MPC_NOT_RESPONDING) + goto out; + + data.out.upLayerThis = skelwrapper->upperLayerThis; + + mutex_lock(&skelwrapper->channelPriv->msgQueueLock); + freeMessages(skelwrapper->channelPriv, skelwrapper); + mutex_lock(&skelwrapper->channelPriv->skelListLock); + list_del(&skelwrapper->entry); + mutex_unlock(&skelwrapper->channelPriv->skelListLock); + mutex_unlock(&skelwrapper->channelPriv->msgQueueLock); + OSAL_Free(skelwrapper); +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_BindComponentAsynchronous(struct cm_process_priv* procPriv, + CM_BindComponentAsynchronous_t __user *param) +{ + CM_BindComponentAsynchronous_t data; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + char providedItfServerName[MAX_INTERFACE_NAME_LENGTH]; + char *dataFileSkeletonOrEvent = NULL; + char *dataFileStub = NULL; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + if ((data.out.error = copy_string_from_user(providedItfServerName, + data.in.providedItfServerName, + sizeof(providedItfServerName)))) + goto out; + + if (data.in.dataFileSkeletonOrEvent != NULL) { + dataFileSkeletonOrEvent = + OSAL_Alloc(data.in.dataFileSkeletonOrEventSize); + if (dataFileSkeletonOrEvent == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFileSkeletonOrEvent, data.in.dataFileSkeletonOrEvent, data.in.dataFileSkeletonOrEventSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + if (data.in.dataFileStub != NULL) { + dataFileStub = OSAL_Alloc(data.in.dataFileStubSize); + if (dataFileStub == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFileStub, data.in.dataFileStub, data.in.dataFileStubSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + /* Do appropriate CM Engine call */ + data.out.error = CM_ENGINE_BindComponentAsynchronous(data.in.client, + requiredItfClientName, + data.in.server, + providedItfServerName, + data.in.fifosize, + data.in.eventMemType, + procPriv->pid, + dataFileSkeletonOrEvent, + dataFileStub); + +out: + if (dataFileSkeletonOrEvent != NULL) + OSAL_Free(dataFileSkeletonOrEvent); + if (dataFileStub != NULL) + OSAL_Free(dataFileStub); + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_UnbindComponentAsynchronous(struct cm_process_priv* procPriv, + CM_UnbindComponentAsynchronous_t __user *param) +{ + CM_UnbindComponentAsynchronous_t data; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + + /* Copy all user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + /* Do appropriate CM Engine call */ + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_UnbindComponentAsynchronous(data.in.client, + requiredItfClientName, + procPriv->pid); +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_BindComponent(struct cm_process_priv* procPriv, + CM_BindComponent_t __user *param) +{ + CM_BindComponent_t data; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + char providedItfServerName[MAX_INTERFACE_NAME_LENGTH]; + char *dataFileTrace = NULL; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + if ((data.out.error = copy_string_from_user(providedItfServerName, + data.in.providedItfServerName, + sizeof(providedItfServerName)))) + goto out; + + if (data.in.dataFileTrace != NULL) { + dataFileTrace = OSAL_Alloc(data.in.dataFileTraceSize); + if (dataFileTrace == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFileTrace, data.in.dataFileTrace, + data.in.dataFileTraceSize)) { + data.out.error = CM_INVALID_PARAMETER; + goto out; + } + } + + /* Do appropriate CM Engine call */ + data.out.error = CM_ENGINE_BindComponent(data.in.client, + requiredItfClientName, + data.in.server, + providedItfServerName, + data.in.traced, + procPriv->pid, + dataFileTrace); +out: + if (dataFileTrace != NULL) + OSAL_Free(dataFileTrace); + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_UnbindComponent(struct cm_process_priv* procPriv, + CM_UnbindComponent_t __user *param) +{ + CM_UnbindComponent_t data; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + /* Do appropriate CM Engine call */ + data.out.error = CM_ENGINE_UnbindComponent(data.in.client, + requiredItfClientName, + procPriv->pid); + +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_BindComponentToVoid(struct cm_process_priv* procPriv, + CM_BindComponentToVoid_t __user *param) +{ + CM_BindComponentToVoid_t data; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + data.out.error = CM_ENGINE_BindComponentToVoid(data.in.client, + requiredItfClientName, + procPriv->pid); + +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_DestroyComponent(struct cm_process_priv* procPriv, + CM_DestroyComponent_t __user *param) +{ + CM_DestroyComponent_t data; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_DestroyComponent(data.in.component, + procPriv->pid); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_CreateMemoryDomain(struct cm_process_priv *procPriv, + CM_CreateMemoryDomain_t __user *param) +{ + CM_CreateMemoryDomain_t data; + t_cm_domain_memory domain; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if (copy_from_user(&domain, data.in.domain, sizeof(domain))) + return -EFAULT; + + if (data.in.client == NMF_CURRENT_CLIENT) + data.out.error = CM_ENGINE_CreateMemoryDomain(procPriv->pid, + &domain, + &data.out.handle); + else + data.out.error = CM_ENGINE_CreateMemoryDomain(data.in.client, + &domain, + &data.out.handle); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_CreateMemoryDomainScratch(struct cm_process_priv *procPriv, + CM_CreateMemoryDomainScratch_t __user *param) +{ + CM_CreateMemoryDomainScratch_t data; + t_cm_domain_memory domain; + + /* Copy all user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if (copy_from_user(&domain, data.in.domain, sizeof(domain))) + return -EFAULT; + + data.out.error = CM_ENGINE_CreateMemoryDomainScratch(procPriv->pid, + data.in.parentId, + &domain, + &data.out.handle); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_DestroyMemoryDomain(CM_DestroyMemoryDomain_t __user *param) +{ + CM_DestroyMemoryDomain_t data; + + /* Copy all user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_DestroyMemoryDomain(data.in.domainId); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetDomainCoreId(CM_GetDomainCoreId_t __user *param) +{ + CM_GetDomainCoreId_t data; + + /* Copy all user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_GetDomainCoreId(data.in.domainId, + &data.out.coreId); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_AllocMpcMemory(struct cm_process_priv *procPriv, + CM_AllocMpcMemory_t __user *param) +{ + t_cm_error err; + CM_AllocMpcMemory_t data; + t_cm_memory_handle handle = 0; + struct memAreaDesc_t* memAreaDesc; + t_cm_system_address systemAddress; + t_uint32 mpcAddress; + + /* Copy all user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* Disregard alignment information and force 4kB memory alignment, + in any case (see devnotes.txt) */ + /* PP: Disable this 'force' for now, because of the low amount of + available MPC Memory */ + //data.in.memAlignment = CM_MM_MPC_ALIGN_1024WORDS; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_AllocMpcMemory(data.in.domainId, + procPriv->pid, + data.in.memType, + data.in.size, + data.in.memAlignment, + &handle); + + data.out.pHandle = handle; + + if (data.out.error != CM_OK) + goto out; + + /* Get memory area decriptors in advance + so to fill in list elements right now */ + err = CM_ENGINE_GetMpcMemorySystemAddress(handle, &systemAddress); + if (err != CM_OK) { + pr_err("%s: failed CM_ENGINE_GetMpcMemorySystemAddress (%i)\n", __func__, err); + /* If we can't manage internally this allocated memory latter, it's + better to report the error now. + Free the handle to not let the driver in an inconsistent state */ + CM_ENGINE_FreeMpcMemory(handle); + return -EFAULT; + } + + /* Get MPC address in advance so to fill in list elements right now */ + err = CM_ENGINE_GetMpcMemoryMpcAddress(handle, &mpcAddress); + if (err != CM_OK) { + pr_err("%s: failed CM_ENGINE_GetMpcMemoryMpcAddress (%i)\n", __func__, err); + /* see comments above */ + CM_ENGINE_FreeMpcMemory(handle); + return -EFAULT; + } + + /* Allocate and fill a new memory area descriptor. Add it to the list */ + memAreaDesc = OSAL_Alloc(sizeof(struct memAreaDesc_t)); + if (memAreaDesc == NULL) { + pr_err("%s: failed allocating memAreaDesc\n", __func__); + /* see comments above */ + CM_ENGINE_FreeMpcMemory(handle); + return -ENOMEM; + } + + memAreaDesc->procPriv = procPriv; + memAreaDesc->handle = handle; + memAreaDesc->tid = 0; + memAreaDesc->physAddr = systemAddress.physical; + memAreaDesc->kernelLogicalAddr = systemAddress.logical; + memAreaDesc->userLogicalAddr = 0; + memAreaDesc->mpcPhysAddr = mpcAddress; + memAreaDesc->size = data.in.size * ((data.in.memType % 2) ? 4 : 2); // betzw: set size in bytes for host (ugly version) + atomic_set(&memAreaDesc->count, 0); + + if (lock_process(procPriv)) { + /* may be rather call lock_process_uninterruptible() */ + CM_ENGINE_FreeMpcMemory(handle); + OSAL_Free(memAreaDesc); + return -ERESTARTSYS; + } + list_add(&memAreaDesc->list, &procPriv->memAreaDescList); + unlock_process(procPriv); +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_FreeMpcMemory(struct cm_process_priv *procPriv, + CM_FreeMpcMemory_t __user *param) +{ + CM_FreeMpcMemory_t data; + struct list_head *cursor, *next; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* check that it is actually owned by the process */ + data.out.error = CM_UNKNOWN_MEMORY_HANDLE; + + if (lock_process(procPriv)) + return -ERESTARTSYS; + list_for_each_safe(cursor, next, &procPriv->memAreaDescList){ + struct memAreaDesc_t* curr; + curr = list_entry(cursor, struct memAreaDesc_t, list); + if (curr->handle == data.in.handle){ + if (atomic_read(&curr->count) != 0) { + pr_err("%s: Memory area (phyAddr: %x, size: %d) " + "still in use (count=%d)!\n", __func__, + curr->physAddr, curr->size, + atomic_read(&curr->count)); + data.out.error = CM_INVALID_PARAMETER; + } else { + data.out.error = + CM_ENGINE_FreeMpcMemory(data.in.handle); + if (data.out.error == CM_OK) { + list_del(cursor); + OSAL_Free(curr); + } + } + break; + } + } + unlock_process(procPriv); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetMpcMemoryStatus(CM_GetMpcMemoryStatus_t __user *param) +{ + CM_GetMpcMemoryStatus_t data; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_GetMpcMemoryStatus(data.in.coreId, + data.in.memType, + &data.out.pStatus); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_StartComponent(struct cm_process_priv *procPriv, + CM_StartComponent_t __user *param) +{ + CM_StartComponent_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_StartComponent(data.in.client, + procPriv->pid); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_StopComponent(struct cm_process_priv *procPriv, + CM_StopComponent_t __user *param) +{ + CM_StopComponent_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_StopComponent(data.in.client, + procPriv->pid); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetMpcLoadCounter(CM_GetMpcLoadCounter_t __user *param) +{ + CM_GetMpcLoadCounter_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_getMpcLoadCounter(data.in.coreId, + &data.out.pMpcLoadCounter); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentDescription(struct cm_process_priv *procPriv, + CM_GetComponentDescription_t __user *param) +{ + CM_GetComponentDescription_t data; + char templateName[MAX_TEMPLATE_NAME_LENGTH]; + char localName[MAX_COMPONENT_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentDescription(data.in.component, + templateName, + data.in.templateNameLength, + &data.out.coreId, + localName, + data.in.localNameLength, + &data.out.priority); + + /* Copy results back to userspace */ + if (data.out.error == CM_OK) { + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.templateName, templateName, data.in.templateNameLength)) + return -EFAULT; + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.localName, localName, data.in.localNameLength)) + return -EFAULT; + } + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentListHeader(struct cm_process_priv *procPriv, + CM_GetComponentListHeader_t __user *param) +{ + CM_GetComponentListHeader_t data; + + data.out.error = CM_ENGINE_GetComponentListHeader(procPriv->pid, + &data.out.headerComponent); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentListNext(struct cm_process_priv *procPriv, + CM_GetComponentListNext_t __user *param) +{ + CM_GetComponentListNext_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentListNext(procPriv->pid, + data.in.prevComponent, + &data.out.nextComponent); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentRequiredInterfaceNumber(struct cm_process_priv *procPriv, + CM_GetComponentRequiredInterfaceNumber_t __user *param) +{ + CM_GetComponentRequiredInterfaceNumber_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentRequiredInterfaceNumber(data.in.component, + &data.out.numberRequiredInterfaces); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentRequiredInterface(struct cm_process_priv *procPriv, + CM_GetComponentRequiredInterface_t __user *param) +{ + CM_GetComponentRequiredInterface_t data; + char itfName[MAX_INTERFACE_NAME_LENGTH]; + char itfType[MAX_INTERFACE_TYPE_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentRequiredInterface(data.in.component, + data.in.index, + itfName, + data.in.itfNameLength, + itfType, + data.in.itfTypeLength, + &data.out.requireState, + &data.out.collectionSize); + + /* Copy results back to userspace */ + if (data.out.error == CM_OK) { + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.itfName, itfName, data.in.itfNameLength)) + return -EFAULT; + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.itfType, itfType, data.in.itfTypeLength)) + return -EFAULT; + } + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentRequiredInterfaceBinding(struct cm_process_priv *procPriv, + CM_GetComponentRequiredInterfaceBinding_t __user *param) +{ + CM_GetComponentRequiredInterfaceBinding_t data; + char itfName[MAX_INTERFACE_NAME_LENGTH]; + char serverItfName[MAX_INTERFACE_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + if ((data.out.error = copy_string_from_user(itfName, + data.in.itfName, + sizeof(itfName)))) + goto out; + + data.out.error = CM_ENGINE_GetComponentRequiredInterfaceBinding(data.in.component, + itfName, + &data.out.server, + serverItfName, + data.in.serverItfNameLength); + + /* Copy results back to userspace */ + if (data.out.error != CM_OK) + goto out; + + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.serverItfName, serverItfName, data.in.serverItfNameLength)) + return -EFAULT; +out: + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentProvidedInterfaceNumber(struct cm_process_priv *procPriv, + CM_GetComponentProvidedInterfaceNumber_t __user *param) +{ + CM_GetComponentProvidedInterfaceNumber_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentProvidedInterfaceNumber(data.in.component, + &data.out.numberProvidedInterfaces); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentProvidedInterface(struct cm_process_priv *procPriv, + CM_GetComponentProvidedInterface_t __user *param) +{ + CM_GetComponentProvidedInterface_t data; + char itfName[MAX_INTERFACE_NAME_LENGTH]; + char itfType[MAX_INTERFACE_TYPE_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentProvidedInterface(data.in.component, + data.in.index, + itfName, + data.in.itfNameLength, + itfType, + data.in.itfTypeLength, + &data.out.collectionSize); + + /* Copy results back to userspace */ + if (data.out.error == CM_OK) { + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.itfName, itfName, data.in.itfNameLength)) + return -EFAULT; + /* coverity[tainted_data : FALSE] */ + if (copy_to_user(data.in.itfType, itfType, data.in.itfTypeLength)) + return -EFAULT; + } + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentPropertyNumber(struct cm_process_priv *procPriv, + CM_GetComponentPropertyNumber_t __user *param) +{ + CM_GetComponentPropertyNumber_t data; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentPropertyNumber(data.in.component, + &data.out.numberProperties); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentPropertyName(struct cm_process_priv *procPriv, + CM_GetComponentPropertyName_t __user *param) +{ + CM_GetComponentPropertyName_t data; + char propertyName[MAX_PROPERTY_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_GetComponentPropertyName(data.in.component, + data.in.index, + propertyName, + data.in.propertyNameLength); + + /* Copy results back to userspace */ + /* coverity[tainted_data : FALSE] */ + if ((data.out.error == CM_OK) && + copy_to_user(data.in.propertyName, propertyName, data.in.propertyNameLength)) + return -EFAULT; + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetComponentPropertyValue(struct cm_process_priv *procPriv, + CM_GetComponentPropertyValue_t __user *param) +{ + CM_GetComponentPropertyValue_t data; + char propertyName[MAX_PROPERTY_NAME_LENGTH]; + char propertyValue[MAX_PROPERTY_VALUE_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(propertyName, + data.in.propertyName, + sizeof(propertyName)))) + goto out; + + data.out.error = CM_ENGINE_GetComponentPropertyValue(data.in.component, + propertyName, + propertyValue, + data.in.propertyValueLength); + /* Copy results back to userspace */ + /* coverity[tainted_data : FALSE] */ + if ((data.out.error == CM_OK) && + copy_to_user(data.in.propertyValue, propertyValue, data.in.propertyValueLength)) + return -EFAULT; +out: + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_ReadComponentAttribute(struct cm_process_priv *procPriv, + CM_ReadComponentAttribute_t __user *param) +{ + CM_ReadComponentAttribute_t data; + char attrName[MAX_ATTRIBUTE_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(attrName, + data.in.attrName, + sizeof(attrName)))) + goto out; + + data.out.error = CM_ENGINE_ReadComponentAttribute(data.in.component, + attrName, + &data.out.value); +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetExecutiveEngineHandle(struct cm_process_priv *procPriv, + CM_GetExecutiveEngineHandle_t __user *param) +{ + CM_GetExecutiveEngineHandle_t data; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_GetExecutiveEngineHandle(data.in.domainId, + &data.out.executiveEngineHandle); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_SetMode(CM_SetMode_t __user *param) +{ + CM_SetMode_t data; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_SetMode(data.in.aCmdID, data.in.aParam); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_GetRequiredComponentFiles(struct cm_process_priv *procPriv, + CM_GetRequiredComponentFiles_t __user *param) +{ + CM_GetRequiredComponentFiles_t data; + char components[4][MAX_INTERFACE_TYPE_NAME_LENGTH]; + char requiredItfClientName[MAX_INTERFACE_NAME_LENGTH]; + char providedItfServerName[MAX_INTERFACE_NAME_LENGTH]; + char type[MAX_INTERFACE_TYPE_NAME_LENGTH]; + unsigned int i; + int err; + + /* Copy user input data in kernel space */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if (data.in.requiredItfClientName && + (data.out.error = copy_string_from_user(requiredItfClientName, + data.in.requiredItfClientName, + sizeof(requiredItfClientName)))) + goto out; + + if (data.in.providedItfServerName && + (data.out.error = copy_string_from_user(providedItfServerName, + data.in.providedItfServerName, + sizeof(providedItfServerName)))) + goto out; + + data.out.error = CM_ENGINE_GetRequiredComponentFiles(data.in.action, + data.in.client, + requiredItfClientName, + data.in.server, + providedItfServerName, + components, + data.in.listSize, + data.in.type ? type : NULL, + &data.out.methodNumber); + + if (data.out.error) + goto out; + + if (data.in.fileList) { + /* Copy results back to userspace */ + for (i=0; i<data.in.listSize; i++) { + err = copy_to_user(&((char*)data.in.fileList)[i*MAX_INTERFACE_TYPE_NAME_LENGTH], components[i], MAX_INTERFACE_TYPE_NAME_LENGTH); + if (err) + return -EFAULT; + } + } + if (data.in.type + && copy_to_user(data.in.type, type, MAX_INTERFACE_TYPE_NAME_LENGTH)) + return -EFAULT; +out: + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_Migrate(CM_Migrate_t __user *param) +{ + CM_Migrate_t data; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + data.out.error = CM_ENGINE_Migrate(data.in.srcShared, data.in.src, data.in.dst); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_Unmigrate(CM_Unmigrate_t __user *param) +{ + CM_Unmigrate_t data; + + data.out.error = CM_ENGINE_Unmigrate(); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +int cmld_SetupRelinkArea(CM_SetupRelinkArea_t __user *param) +{ + CM_SetupRelinkArea_t data; + t_cm_system_address systemAddress; + t_uint32 size; + + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + + data.out.error = CM_ENGINE_GetMpcMemorySystemAddress( + data.in.mem_handle, &systemAddress); + + if (data.out.error != CM_OK) + return 0; + + data.out.error = CM_ENGINE_GetMpcMemorySize(data.in.mem_handle, &size); + if (data.out.error != CM_OK) + return 0; + + if (size < data.in.segments * data.in.segmentsize) + { + return -EINVAL; + } + + data.out.error = cmdma_setup_relink_area( + systemAddress.physical, + data.in.peripheral_addr, + data.in.segments, + data.in.segmentsize, + data.in.LOS, + data.in.type); + + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + + return 0; +} + + +inline int cmld_PushComponent(CM_PushComponent_t __user *param) +{ + CM_PushComponent_t data; + char name[MAX_INTERFACE_TYPE_NAME_LENGTH]; + void *dataFile = NULL; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(name, + data.in.name, + sizeof(name)))) + goto out; + + if (data.in.data != NULL) { + dataFile = OSAL_Alloc(data.in.size); + if (dataFile == NULL) { + data.out.error = CM_NO_MORE_MEMORY; + goto out; + } + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(dataFile, data.in.data, data.in.size)) + data.out.error = CM_INVALID_PARAMETER; + else + data.out.error = CM_ENGINE_PushComponent(name, dataFile, + data.in.size); + OSAL_Free(dataFile); + } + +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_ReleaseComponent(CM_ReleaseComponent_t __user *param) +{ + CM_ReleaseComponent_t data; + char name[MAX_INTERFACE_TYPE_NAME_LENGTH]; + + /* Copy user input data in kernel space */ + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if ((data.out.error = copy_string_from_user(name, + data.in.name, + sizeof(name)))) + goto out; + + /* coverity[tainted_data : FALSE] */ + data.out.error = CM_ENGINE_ReleaseComponent(name); + +out: + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +inline int cmld_PrivGetMPCMemoryDesc(struct cm_process_priv *procPriv, CM_PrivGetMPCMemoryDesc_t __user *param) +{ + CM_PrivGetMPCMemoryDesc_t data; + struct list_head* cursor; + + if (copy_from_user(&data.in, ¶m->in, sizeof(data.in))) + return -EFAULT; + + if (lock_process(procPriv)) + return -ERESTARTSYS; + /* Scan the memory descriptors list looking for the requested handle */ + data.out.error = CM_UNKNOWN_MEMORY_HANDLE; + list_for_each(cursor, &procPriv->memAreaDescList) { + struct memAreaDesc_t* curr; + curr = list_entry(cursor, struct memAreaDesc_t, list); + if (curr->handle == data.in.handle) { + data.out.size = curr->size; + data.out.physAddr = curr->physAddr; + data.out.kernelLogicalAddr = curr->kernelLogicalAddr; + data.out.userLogicalAddr = curr->userLogicalAddr; + data.out.mpcPhysAddr = curr->mpcPhysAddr; + data.out.error = CM_OK; + break; + } + } + unlock_process(procPriv); + + /* Copy results back to userspace */ + if (copy_to_user(¶m->out, &data.out, sizeof(data.out))) + return -EFAULT; + return 0; +} + +int cmld_PrivReserveMemory(struct cm_process_priv *procPriv, unsigned int physAddr) +{ + struct list_head* cursor; + struct memAreaDesc_t* curr; + int err = -ENXIO; + + if (lock_process(procPriv)) + return -ERESTARTSYS; + list_for_each(cursor, &procPriv->memAreaDescList) { + curr = list_entry(cursor, struct memAreaDesc_t, list); + if (curr->physAddr == physAddr) { + /* Mark this memory area reserved for a mapping for this thread ID */ + /* It must not be already reserved but this should not happen */ + if (curr->tid) { + pr_err("%s: thread %d can't reseveved memory %x already " + "reserved for %d\n", + __func__, current->pid, physAddr, curr->tid); + err = -EBUSY; + } else { + curr->tid = current->pid; + err = 0; + } + break; + } + } + unlock_process(procPriv); + return err; +} diff --git a/drivers/staging/nmf-cm/cmioctl.h b/drivers/staging/nmf-cm/cmioctl.h new file mode 100644 index 00000000000..7ca46fc25e8 --- /dev/null +++ b/drivers/staging/nmf-cm/cmioctl.h @@ -0,0 +1,588 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +#ifndef __CMIOCTL_H +#define __CMIOCTL_H + +#include <cm/engine/component/inc/component_type.h> +#include <cm/engine/communication/inc/communication_type.h> +#include <cm/engine/configuration/inc/configuration_type.h> +#include <cm/engine/memory/inc/domain_type.h> +#include <cm/engine/memory/inc/memory_type.h> +#include <cm/engine/perfmeter/inc/perfmeter_type.h> +#include <cm/engine/repository_mgt/inc/repository_type.h> +#include "cm_dma.h" + +#define CMLD_DEV_NAME \ + { "cm_control", \ + "cm_channel" \ + } + +/* + * The following structures are used to exchange CM_SYSCALL parameters with + * the driver. There is one structure per ioctl command, ie per CM_SYSCAL. + * Each of them contains: + * - One set of fields placed in a struture 'in' which are all input + * parameters of the syscall (parameters that kernel side must retrieve + * from user space) + * - One set of fields placed in a struture 'out' which contains all output + * parameters of the syscall plus the error code. + * + * NOTE: all pointers to (user) buffer are always placed in struct 'in', including + * buffers used as output parameters; because the pointer itself is considered as + * an input parameter, as it is directly accessed from kernel space. + */ +typedef struct{ + struct { + const char * templateName; + t_cm_domain_id domainId; + t_nmf_ee_priority priority; + const char * localName; + const char *dataFile; + t_uint32 dataFileSize; + } in; + struct { + t_cm_instance_handle component; /** < Output parameter */ + t_cm_error error; + } out; +} CM_InstantiateComponent_t; + +typedef struct { + struct { + t_cm_bf_host2mpc_handle host2mpcId; + t_event_params_handle h; + t_uint32 size; + t_uint32 methodIndex; + } in; + struct { + t_cm_error error; + } out; +} CM_PushEventWithSize_t; + +typedef struct { + struct { + t_cm_instance_handle server; + const char * providedItfServerName; + t_uint32 fifosize; + t_cm_mpc_memory_type eventMemType; + const char *dataFileSkeleton; + t_uint32 dataFileSkeletonSize; + } in; + struct { + t_cm_bf_host2mpc_handle host2mpcId; /** < Output parameter */ + t_cm_error error; + } out; +} CM_BindComponentFromCMCore_t; + +typedef struct { + struct { + t_cm_bf_host2mpc_handle host2mpcId; + } in; + struct { + t_cm_error error; + } out; +} CM_UnbindComponentFromCMCore_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char *requiredItfClientName; + t_uint32 fifosize; + t_nmf_mpc2host_handle upLayerThis; + const char *dataFileStub; + t_uint32 dataFileStubSize; + } in; + struct { + t_cm_bf_mpc2host_handle mpc2hostId; /** < Output parameter */ + t_cm_error error; + } out; +} CM_BindComponentToCMCore_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char *requiredItfClientName; + } in; + struct { + t_nmf_mpc2host_handle upLayerThis; /** < Output parameter */ + t_cm_error error; + } out; +} CM_UnbindComponentToCMCore_t; + +typedef struct { + struct { + t_cm_instance_handle component; + } in; + struct { + t_cm_error error; /** < Output parameter */ + } out; /** < Output parameter */ +} CM_DestroyComponent_t; + +typedef struct { + struct { + const t_cm_domain_memory *domain; + t_nmf_client_id client; + } in; + struct { + t_cm_domain_id handle; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_CreateMemoryDomain_t; + +typedef struct { + struct { + t_cm_domain_id parentId; + const t_cm_domain_memory *domain; + } in; + struct { + t_cm_domain_id handle; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_CreateMemoryDomainScratch_t; + +typedef struct { + struct { + t_cm_domain_id domainId; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_DestroyMemoryDomain_t; + +typedef struct { + struct { + t_cm_domain_id domainId; /** < In parameter */ + } in; + struct { + t_nmf_core_id coreId; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_GetDomainCoreId_t; + +typedef struct { + struct { + t_cm_domain_id domainId; + t_cm_mpc_memory_type memType; + t_cm_size size; + t_cm_memory_alignment memAlignment; + } in; + struct { + t_cm_memory_handle pHandle; /** < Output parameter */ + t_cm_error error; + } out; /** < Output parameter */ +} CM_AllocMpcMemory_t; + +typedef struct{ + struct { + t_cm_memory_handle handle; + } in; + struct { + t_cm_error error; + } out; /** < Output parameter */ +} CM_FreeMpcMemory_t; + +typedef struct { + struct { + t_cm_memory_handle handle; + } in; + struct { + t_uint32 size; /** < Out parameter */ + t_uint32 physAddr; /** < Out parameter */ + t_uint32 kernelLogicalAddr; /** < Out parameter */ + t_uint32 userLogicalAddr; /** < Out parameter */ + t_uint32 mpcPhysAddr; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Output parameter */ +} CM_PrivGetMPCMemoryDesc_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char *requiredItfClientName; + t_cm_instance_handle server; + const char *providedItfServerName; + t_uint32 fifosize; + t_cm_mpc_memory_type eventMemType; + const char *dataFileSkeletonOrEvent; + t_uint32 dataFileSkeletonOrEventSize; + const char *dataFileStub; + t_uint32 dataFileStubSize; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_BindComponentAsynchronous_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char* requiredItfClientName; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_UnbindComponentAsynchronous_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char *requiredItfClientName; + t_cm_instance_handle server; + const char *providedItfServerName; + t_bool traced; + const char *dataFileTrace; + t_uint32 dataFileTraceSize; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_BindComponent_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char* requiredItfClientName; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_UnbindComponent_t; + +typedef struct { + struct { + t_cm_instance_handle client; + const char* requiredItfClientName; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_BindComponentToVoid_t; + +typedef struct { + struct { + t_cm_instance_handle client; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_StartComponent_t; + +typedef struct { + struct { + t_cm_instance_handle client; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_StopComponent_t; + +typedef struct { + struct { + t_nmf_core_id coreId; + } in; + struct { + t_cm_mpc_load_counter pMpcLoadCounter; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetMpcLoadCounter_t; + +typedef struct { + struct { + t_nmf_core_id coreId; + t_cm_mpc_memory_type memType; + } in; + struct { + t_cm_allocator_status pStatus; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_GetMpcMemoryStatus_t; + +typedef struct { + struct { + t_cm_instance_handle component; + t_uint32 templateNameLength; + t_uint32 localNameLength; + char *templateName; /** < Out parameter */ + char *localName; /** < Out parameter */ + } in; + struct { + t_nmf_core_id coreId; /** < Out parameter */ + t_nmf_ee_priority priority; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_GetComponentDescription_t; + +typedef struct { + struct { + t_cm_instance_handle headerComponent; /** < Output parameter */ + t_cm_error error; /** < Out parameter */ + } out; /** < Out parameter */ +} CM_GetComponentListHeader_t; + +typedef struct { + struct { + t_cm_instance_handle prevComponent; + } in; + struct { + t_cm_instance_handle nextComponent; /** < Output parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentListNext_t; + +typedef struct { + struct { + t_cm_instance_handle component; + } in; + struct { + t_uint8 numberRequiredInterfaces; /** < Output parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentRequiredInterfaceNumber_t; + +typedef struct { + struct { + t_cm_instance_handle component; + t_uint8 index; + t_uint32 itfNameLength; + t_uint32 itfTypeLength; + char *itfName; /** < Out parameter */ + char *itfType; /** < Out parameter */ + } in; + struct { + t_cm_require_state requireState; /** < Out parameter */ + t_sint16 collectionSize; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentRequiredInterface_t; + +typedef struct { + struct { + t_cm_instance_handle component; + const char *itfName; + t_uint32 serverItfNameLength; + char *serverItfName; /** < Out parameter */ + } in; + struct { + t_cm_instance_handle server; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentRequiredInterfaceBinding_t; + +typedef struct { + struct { + t_cm_instance_handle component; + } in; + struct { + t_uint8 numberProvidedInterfaces; /** < Output parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentProvidedInterfaceNumber_t; + +typedef struct { + struct { + t_cm_instance_handle component; + t_uint8 index; + t_uint32 itfNameLength; + t_uint32 itfTypeLength; + char *itfName; /** < Out parameter */ + char *itfType; /** < Out parameter */ + } in; + struct { + t_sint16 collectionSize; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentProvidedInterface_t; + +typedef struct { + struct { + t_cm_instance_handle component; + } in; + struct { + t_uint8 numberProperties; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentPropertyNumber_t; + +typedef struct { + struct { + t_cm_instance_handle component; + const char *attrName; + t_uint8 index; + t_uint32 propertyNameLength; + char *propertyName; /** < Out parameter */ + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentPropertyName_t; + +typedef struct { + struct { + t_cm_instance_handle component; + const char *propertyName; + t_uint32 propertyValueLength; + char *propertyValue; /** < Out parameter */ + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetComponentPropertyValue_t; + +typedef struct { + struct { + t_cm_instance_handle component; + const char *attrName; + } in; + struct { + t_uint32 value; /** < Out parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_ReadComponentAttribute_t; + +typedef struct { + struct { + t_cm_domain_id domainId; + } in; + struct { + t_cm_instance_handle executiveEngineHandle; + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetExecutiveEngineHandle_t; + +typedef struct { + struct { + t_cm_cmd_id aCmdID; + t_sint32 aParam; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_SetMode_t; + +typedef struct { + struct { + t_action_to_do action; + t_cm_instance_handle client; + const char *requiredItfClientName; + t_cm_instance_handle server; + const char *providedItfServerName; + char **fileList; + unsigned int listSize; + char *type; + } in; + struct { + t_uint32 methodNumber; /** < Output parameter */ + t_cm_error error; /** < Out parameter */ + } out; +} CM_GetRequiredComponentFiles_t; + +typedef struct { + struct { + const char *name; + const void *data; + t_cm_size size; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_PushComponent_t; + +typedef struct { + struct { + const char *name; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_ReleaseComponent_t; + +typedef struct { + struct { + t_cm_domain_id srcShared; + t_cm_domain_id src; + t_cm_domain_id dst; + } in; + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_Migrate_t; + +typedef struct { + struct { + t_cm_error error; /** < Out parameter */ + } out; +} CM_Unmigrate_t; + +typedef struct{ + struct { + t_cm_memory_handle mem_handle; + unsigned int peripheral_addr; + unsigned int segments; + unsigned int segmentsize; + unsigned int LOS; + enum cmdma_type type; + } in; + struct { + t_cm_error error; + } out; +} CM_SetupRelinkArea_t; + +#define CM_PUSHEVENTWITHSIZE _IOWR('c', 0, CM_PushEventWithSize_t) +#define CM_GETVERSION _IOR('c', 1, t_uint32) +#define CM_INSTANTIATECOMPONENT _IOWR('c', 2, CM_InstantiateComponent_t) +#define CM_BINDCOMPONENTFROMCMCORE _IOWR('c', 3, CM_BindComponentFromCMCore_t) +#define CM_UNBINDCOMPONENTFROMCMCORE _IOWR('c', 4, CM_UnbindComponentFromCMCore_t) +#define CM_BINDCOMPONENTTOCMCORE _IOWR('c', 5, CM_BindComponentToCMCore_t) +#define CM_UNBINDCOMPONENTTOCMCORE _IOWR('c', 6, CM_UnbindComponentToCMCore_t) +#define CM_DESTROYCOMPONENT _IOWR('c', 7, CM_DestroyComponent_t) +#define CM_CREATEMEMORYDOMAIN _IOWR('c', 8, CM_CreateMemoryDomain_t) +#define CM_CREATEMEMORYDOMAINSCRATCH _IOWR('c', 9, CM_CreateMemoryDomainScratch_t) +#define CM_DESTROYMEMORYDOMAIN _IOWR('c', 10, CM_DestroyMemoryDomain_t) +#define CM_GETDOMAINCOREID _IOWR('c', 11, CM_GetDomainCoreId_t) +#define CM_ALLOCMPCMEMORY _IOWR('c', 12, CM_AllocMpcMemory_t) +#define CM_FREEMPCMEMORY _IOWR('c', 13, CM_FreeMpcMemory_t) +#define CM_BINDCOMPONENTASYNCHRONOUS _IOWR('c', 14, CM_BindComponentAsynchronous_t) +#define CM_UNBINDCOMPONENTASYNCHRONOUS _IOWR('c', 15, CM_UnbindComponentAsynchronous_t) +#define CM_BINDCOMPONENT _IOWR('c', 16, CM_BindComponent_t) +#define CM_UNBINDCOMPONENT _IOWR('c', 17, CM_UnbindComponent_t) +#define CM_BINDCOMPONENTTOVOID _IOWR('c', 18, CM_BindComponentToVoid_t) +#define CM_STARTCOMPONENT _IOWR('c', 19, CM_StartComponent_t) +#define CM_STOPCOMPONENT _IOWR('c', 20, CM_StopComponent_t) +#define CM_GETMPCLOADCOUNTER _IOWR('c', 21, CM_GetMpcLoadCounter_t) +#define CM_GETMPCMEMORYSTATUS _IOWR('c', 22, CM_GetMpcMemoryStatus_t) +#define CM_GETCOMPONENTDESCRIPTION _IOWR('c', 23, CM_GetComponentDescription_t) +#define CM_GETCOMPONENTLISTHEADER _IOWR('c', 24, CM_GetComponentListHeader_t) +#define CM_GETCOMPONENTLISTNEXT _IOWR('c', 25, CM_GetComponentListNext_t) +#define CM_GETCOMPONENTREQUIREDINTERFACENUMBER _IOWR('c', 26, CM_GetComponentRequiredInterfaceNumber_t) +#define CM_GETCOMPONENTREQUIREDINTERFACE _IOWR('c', 27, CM_GetComponentRequiredInterface_t) +#define CM_GETCOMPONENTREQUIREDINTERFACEBINDING _IOWR('c', 28, CM_GetComponentRequiredInterfaceBinding_t) +#define CM_GETCOMPONENTPROVIDEDINTERFACENUMBER _IOWR('c', 29, CM_GetComponentProvidedInterfaceNumber_t) +#define CM_GETCOMPONENTPROVIDEDINTERFACE _IOWR('c', 30, CM_GetComponentProvidedInterface_t) +#define CM_GETCOMPONENTPROPERTYNUMBER _IOWR('c', 31, CM_GetComponentPropertyNumber_t) +#define CM_GETCOMPONENTPROPERTYNAME _IOWR('c', 32, CM_GetComponentPropertyName_t) +#define CM_GETCOMPONENTPROPERTYVALUE _IOWR('c', 33, CM_GetComponentPropertyValue_t) +#define CM_READCOMPONENTATTRIBUTE _IOWR('c', 34, CM_ReadComponentAttribute_t) +#define CM_GETEXECUTIVEENGINEHANDLE _IOWR('c', 35, CM_GetExecutiveEngineHandle_t) +#define CM_SETMODE _IOWR('c', 36, CM_SetMode_t) +#define CM_GETREQUIREDCOMPONENTFILES _IOWR('c', 37, CM_GetRequiredComponentFiles_t) +#define CM_PUSHCOMPONENT _IOWR('c', 38, CM_PushComponent_t) +#define CM_FLUSHCHANNEL _IO('c', 39) +#define CM_MIGRATE _IOWR('c', 40, CM_Migrate_t) +#define CM_UNMIGRATE _IOR('c', 41, CM_Unmigrate_t) +#define CM_RELEASECOMPONENT _IOWR('c', 42, CM_ReleaseComponent_t) +#define CM_SETUPRELINKAREA _IOWR('c', 43, CM_SetupRelinkArea_t) + +#define CM_PRIVGETMPCMEMORYDESC _IOWR('c', 100, CM_PrivGetMPCMemoryDesc_t) +#define CM_PRIVRESERVEMEMORY _IOW('c', 101, unsigned int) +#define CM_PRIV_GETBOARDVERSION _IOR('c', 102, unsigned int) + +enum board_version { + U8500_V1, + U8500_V2 +}; +#endif diff --git a/drivers/staging/nmf-cm/cmld.c b/drivers/staging/nmf-cm/cmld.c new file mode 100644 index 00000000000..04433f10f0c --- /dev/null +++ b/drivers/staging/nmf-cm/cmld.c @@ -0,0 +1,1317 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/** \file cmld.c + * + * Nomadik Multiprocessing Framework Linux Driver + * + */ + +#include <linux/cdev.h> +#include <linux/fs.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +#include <cm/inc/cm_def.h> +#include <cm/engine/api/cm_engine.h> +#include <cm/engine/api/control/irq_engine.h> + +#include "cmioctl.h" +#include "osal-kernel.h" +#include "cmld.h" +#include "cm_service.h" + +#define CMDRIVER_PATCH_VERSION 106 +#define O_FLUSH 0x1000000 + +static int cmld_major; +static struct cdev cmld_cdev; +static struct class cmld_class = { + .name = "cm", + .owner = THIS_MODULE, +}; +const char *cmld_devname[] = CMLD_DEV_NAME; +static struct device *cmld_dev[ARRAY_SIZE(cmld_devname)]; + +/* List of per process structure (struct cm_process_priv list) */ +LIST_HEAD(process_list); +static DEFINE_MUTEX(process_lock); /* lock used to protect previous list */ +/* List of per channel structure (struct cm_channel_priv list). + A channel == One file descriptor */ +LIST_HEAD(channel_list); +static DEFINE_MUTEX(channel_lock); /* lock used to protect previous list */ + +/* Variables used to manage temporary allocation of ESRAM + reserved for DMA and B2R2 + MCDE */ +/* As of now, the reservation is done in RME */ +static int cfgESRAM_ReserveMCDE = 0; +static int cfgESRAM_ReserveDMA = 0; +static int cfgESRAMDmaSize = 4; /* in Kb */ +static int cfgESRAMMcdeSize = 128; /* in Kb */ +module_param(cfgESRAM_ReserveMCDE, bool, S_IRUGO); +module_param(cfgESRAM_ReserveDMA, bool, S_IRUGO); +module_param(cfgESRAMDmaSize, uint, S_IRUGO); +module_param(cfgESRAMMcdeSize, uint, S_IRUGO); +static t_cm_domain_id dmaDomainId, mcdeDomainId; +static t_cm_memory_handle dmaMemoryHdl, mcdeMemoryHdl; + +static inline struct cm_process_priv *getProcessPriv(void) +{ + struct list_head* head; + struct cm_process_priv *entry; + + mutex_lock(&process_lock); + + /* Look for an entry for the calling process */ + list_for_each(head, &process_list) { + entry = list_entry(head, struct cm_process_priv, entry); + if (entry->pid == current->tgid) { + kref_get(&entry->ref); + goto out; + } + } + mutex_unlock(&process_lock); + + /* Allocate, init and register a new one otherwise */ + entry = OSAL_Alloc(sizeof(*entry)); + if (entry == NULL) + return ERR_PTR(-ENOMEM); + + /* init host2mpcLock */ + mutex_init(&entry->host2mpcLock); + + INIT_LIST_HEAD(&entry->memAreaDescList); + kref_init(&entry->ref); + mutex_init(&entry->mutex); + + entry->pid = current->tgid; + mutex_lock(&process_lock); + list_add(&entry->entry, &process_list); +out: + mutex_unlock(&process_lock); + return entry; +} + +/* Free all messages */ +static inline void freeMessages(struct cm_channel_priv* channelPriv) +{ + struct osal_msg *this, *next; + int warn = 0; + + spin_lock_bh(&channelPriv->bh_lock); + plist_for_each_entry_safe(this, next, &channelPriv->messageQueue, msg_entry) { + plist_del(&this->msg_entry, &channelPriv->messageQueue); + kfree(this); + warn = 1; + } + spin_unlock_bh(&channelPriv->bh_lock); + if (warn) { + pr_err("[CM - PID=%d]: Some remaining" + " message(s) freed\n", current->tgid); + warn = 0; + } +} + +/* Free all pending memory areas and relative descriptors */ +static inline void freeMemHandles(struct cm_process_priv* processPriv) +{ + struct list_head* head, *next; + int warn = 0; + + list_for_each_safe(head, next, &processPriv->memAreaDescList) { + struct memAreaDesc_t* curr; + int err; + curr = list_entry(head, struct memAreaDesc_t, list); + err=CM_ENGINE_FreeMpcMemory(curr->handle); + if (err) + pr_err("[CM - PID=%d]: Error (%d) freeing remaining memory area " + "handle\n", current->tgid, err); + list_del(head); + OSAL_Free(curr); + warn = 1; + } + if (warn) { + pr_err("[CM - PID=%d]: Some remaining memory area " + "handle(s) freed\n", current->tgid); + warn = 0; + } +} + +/* Free any skeleton, called when freeing the process entry */ +static inline void freeSkelList(struct list_head* skelList) +{ + struct list_head* head, *next; + int warn = 0; + + /* No lock held, we know that we are the only and the last user + of the list */ + list_for_each_safe(head, next, skelList) { + t_skelwrapper* curr; + curr = list_entry(head, t_skelwrapper, entry); + list_del(head); + OSAL_Free(curr); + warn = 1; + } + if (warn) + pr_err("[CM - PID=%d]: Some remaining skeleton " + "wrapper(s) freed\n", current->tgid); +} + +/* Free any remaining channels belonging to this process */ +/* Called _only_ when freeing the process entry, once the network constructed by + this process has been destroyed. + See cmld_release() to see why there can be some remaining non-freed channels */ +static inline void freeChannels(struct cm_process_priv* processPriv) +{ + struct list_head* head, *next; + int warn = 0; + + list_for_each_safe(head, next, &channel_list) { + struct cm_channel_priv *channelPriv; + channelPriv = list_entry(head, struct cm_channel_priv, entry); + /* Only channels belonging to this process are concerned */ + if (channelPriv->proc == processPriv) { + tasklet_disable(&cmld_service_tasklet); + mutex_lock(&channel_lock); + list_del(&channelPriv->entry); + mutex_unlock(&channel_lock); + tasklet_enable(&cmld_service_tasklet); + + /* Free all remaining messages if any + (normally none, but double check) */ + freeMessages(channelPriv); + + /* Free any pending skeleton wrapper */ + /* Here it's safe, we know that all bindings have been undone */ + freeSkelList(&channelPriv->skelList); + + /* Free the per-channel descriptor */ + OSAL_Free(channelPriv); + } + warn = 1; + } + if (warn) + pr_err("[CM - PID=%d]: Some remaining channel entries " + "freed\n", current->tgid); +} + +/* Free the process priv structure and all related stuff */ +/* Called only when the last ref to this structure is released */ +static void freeProcessPriv(struct kref *ref) +{ + struct cm_process_priv *entry = container_of(ref, struct cm_process_priv, ref); + t_nmf_error err; + + mutex_lock(&process_lock); + list_del(&entry->entry); + mutex_unlock(&process_lock); + + /* Destroy all remaining components */ + err=CM_ENGINE_FlushComponents(entry->pid); + if (err != NMF_OK) + pr_err("[CM - PID=%d]: Error while flushing some remaining" + " components: error=%d\n", current->tgid, err); + + freeChannels(entry); + + /* Free any pending memory areas and relative descriptors */ + freeMemHandles(entry); + + /* Destroy all remaining domains */ + err=CM_ENGINE_FlushMemoryDomains(entry->pid); + if (err != NMF_OK) + pr_err("[CM - PID=%d]: Error while flushing some remaining" + " domains: error=%d\n", current->tgid, err); + + /* Free the per-process descriptor */ + OSAL_Free(entry); +} + +/** Driver's open method + * Allocates per-process resources: private data, wait queue, + * memory area descriptors linked list, message queue. + * + * \return POSIX error code + */ +static int cmld_open(struct inode *inode, struct file *file) +{ + struct cm_process_priv *procPriv = getProcessPriv(); + + if (IS_ERR(procPriv)) + return PTR_ERR(procPriv); + + if (iminor(inode) == 0) + file->private_data = procPriv; + else { + struct cm_channel_priv *channelPriv = (struct cm_channel_priv*)OSAL_Alloc(sizeof(*channelPriv)); + if (channelPriv == NULL) { + kref_put(&procPriv->ref, freeProcessPriv); + return -ENOMEM; + } + + channelPriv->proc = procPriv; + channelPriv->state = CHANNEL_OPEN; + + /* Initialize wait_queue, lists and mutexes */ + init_waitqueue_head(&channelPriv->waitq); + plist_head_init(&channelPriv->messageQueue, &channelPriv->bh_lock); + INIT_LIST_HEAD(&channelPriv->skelList); + spin_lock_init(&channelPriv->bh_lock); + mutex_init(&channelPriv->msgQueueLock); + mutex_init(&channelPriv->skelListLock); + + tasklet_disable(&cmld_service_tasklet); + mutex_lock(&channel_lock); + list_add(&channelPriv->entry, &channel_list); + mutex_unlock(&channel_lock); + tasklet_enable(&cmld_service_tasklet); + + file->private_data = channelPriv; // store channel private struct in file descriptor + } + return 0; +} + +/** Driver's release method. + * Frees any per-process pending resource: components, bindings, memory areas. + * + * \return POSIX error code + */ +static int cmld_release(struct inode *inode, struct file *file) +{ + struct cm_process_priv* procPriv; + + BUG_ON(file->private_data == NULL); + + /* The driver must guarantee that all related resources are released. + Thus all these checks below are necessary to release all remaining + resources still linked to this 'client', in case of abnormal process + exit. + => These are error cases ! + In the usual case, nothing should be done except the free of + the cmPriv itself + */ + + if (iminor(inode) != 0) { + struct cm_channel_priv* channelPriv; + channelPriv = file->private_data; + procPriv = channelPriv->proc; + + /* We don't need to synchronize here by using the skelListLock: + the list is only accessed during ioctl() and we can't be here + if an ioctl() is on-going */ + if (list_empty(&channelPriv->skelList)) { + /* There is no pending MPC->HOST binding + => we can quietly delete the channel */ + tasklet_disable(&cmld_service_tasklet); + mutex_lock(&channel_lock); + list_del(&channelPriv->entry); + mutex_unlock(&channel_lock); + tasklet_enable(&cmld_service_tasklet); + + /* Free all remaining messages if any */ + freeMessages(channelPriv); + + /* Free the per-channel descriptor */ + OSAL_Free(channelPriv); + } else { + /* Uh: there are still some MPC->HOST binding but we don't have the + required info to unbind them. + => we must keep all skel structures because possibly used in OSAL_PostDfc + (incoming callback msg) */ + /* We flag the channel as closed to discard any new msg that will never be read anyway */ + channelPriv->state = CHANNEL_CLOSED; + + /* Already Free all remaining messages if any, + they will never be read anyway */ + freeMessages(channelPriv); + } + } else + procPriv = file->private_data; + + kref_put(&procPriv->ref, freeProcessPriv); + file->private_data = NULL; + + return 0; +} + +/** Reads Component Manager messages destinated to this process. + * The message is composed by three fields: + * 1) mpc2host handle (distinguishes interfaces) + * 2) methodIndex (distinguishes interface's methods) + * 3) Variable length parameters (method's parameters values) + * + * \note cfr GetEvent() + * \return POSIX error code + */ +static ssize_t cmld_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + int err = 0; + struct cm_channel_priv* channelPriv = (struct cm_channel_priv*)(file->private_data); + int msgSize = 0; + struct plist_head* messageQueue; + struct osal_msg* msg; + t_os_message *os_msg = (t_os_message *)buf; + int block = !(file->f_flags & O_NONBLOCK); + + if (iminor(file->f_dentry->d_inode) == 0) + return -ENOSYS; + + BUG_ON(channelPriv == NULL); + messageQueue = &channelPriv->messageQueue; + + if (mutex_lock_killable(&channelPriv->msgQueueLock)) + return -ERESTARTSYS; +wait: + while (plist_head_empty(messageQueue)) { + mutex_unlock(&channelPriv->msgQueueLock); + if (block == 0) + return -EAGAIN; + /* Wait until there is a message to ferry up */ + if (wait_event_interruptible(channelPriv->waitq, ((!plist_head_empty(messageQueue)) || (file->f_flags & O_FLUSH)))) + return -ERESTARTSYS; + if (file->f_flags & O_FLUSH) { + file->f_flags &= ~O_FLUSH; + return 0; + } + if (mutex_lock_killable(&channelPriv->msgQueueLock)) + return -ERESTARTSYS; + } + + /* Pick up the first message from the queue, making sure that the + * hwsem tasklet does not wreak havoc the queue in the meantime + */ + spin_lock_bh(&channelPriv->bh_lock); + msg = plist_first_entry(messageQueue, struct osal_msg, msg_entry); + plist_del(&msg->msg_entry, messageQueue); + spin_unlock_bh(&channelPriv->bh_lock); + + switch (msg->msg_type) { + case MSG_INTERFACE: { + + /* Check if enough space is available */ + msgSize = sizeof(msg->msg_type) + msg->d.itf.ptrSize + sizeof(os_msg->data.itf) - sizeof(os_msg->data.itf.params) ; + if (msgSize > count) { + mutex_unlock(&channelPriv->msgQueueLock); + pr_err("CM: message size bigger than buffer size silently ignored!\n"); + err = -EMSGSIZE; + goto out; + } + + /* Copy to user message type */ + err = put_user(msg->msg_type, &os_msg->type); + if (err) goto ack_evt; + + /* Copy to user the t_nmf_mpc2host_handle */ + err = put_user(msg->d.itf.skelwrap->upperLayerThis, &os_msg->data.itf.THIS); + if (err) goto ack_evt; + + /* The methodIndex */ + err = put_user(msg->d.itf.methodIdx, &os_msg->data.itf.methodIndex); + if (err) goto ack_evt; + + /* And the parameters */ + err = copy_to_user(os_msg->data.itf.params, msg->d.itf.anyPtr, msg->d.itf.ptrSize); + + ack_evt: + /* This call is void */ + /* Note: that we cannot release the lock before having called this function + as acknowledgements MUST be executed in the same order as their + respective messages have arrived! */ + CM_ENGINE_AcknowledgeEvent(msg->d.itf.skelwrap->mpc2hostId); + + mutex_unlock(&channelPriv->msgQueueLock); + break; + } + case MSG_SERVICE: { + mutex_unlock(&channelPriv->msgQueueLock); + msgSize = sizeof(msg->msg_type) + sizeof(msg->d.srv.srvType) + + sizeof(msg->d.srv.srvData); + if (count < msgSize) { + pr_err("CM: service message size bigger than buffer size - silently ignored!\n"); + err = -EMSGSIZE; + } + + /* Copy to user message type */ + err = put_user(msg->msg_type, &os_msg->type); + if (err) goto out; + err = copy_to_user(&os_msg->data.srv, &msg->d.srv, + sizeof(msg->d.srv.srvType) + sizeof(msg->d.srv.srvData)); + break; + } + default: + mutex_unlock(&channelPriv->msgQueueLock); + pr_err("CM: invalid message type %d discarded\n", msg->msg_type); + goto wait; + } +out: + /* Destroy the message */ + kfree(msg); + + return err ? err : msgSize; +} + +/** Part of driver's release method. (ie userspace close()) + * It wakes up all waiter. + * + * \return POSIX error code + */ +static int cmld_flush(struct file *file, fl_owner_t id) +{ + if (iminor(file->f_dentry->d_inode) != 0) { + struct cm_channel_priv* channelPriv = (struct cm_channel_priv*)(file->private_data); + //channelPriv->closed = CHANNEL_CLOSED; + file->f_flags |= O_FLUSH; + wake_up_all(&channelPriv->waitq); + } + return 0; +} + +static long cmld_channel_ctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cm_channel_priv *channelPriv = file->private_data; + + switch(cmd) { + /* + * All channel CM SYSCALL + */ + case CM_BINDCOMPONENTTOCMCORE: + return cmld_BindComponentToCMCore(channelPriv, (CM_BindComponentToCMCore_t *)arg); + case CM_FLUSHCHANNEL: + return cmld_flush(file, 0); + default: + pr_err("CM(%s): unsupported command %i\n", __func__, cmd); + return -EINVAL; + } + return 0; +} + +static long cmld_control_ctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cm_process_priv* procPriv = file->private_data; + switch(cmd) { + /* + * All wrapped CM SYSCALL + */ + case CM_INSTANTIATECOMPONENT: + return cmld_InstantiateComponent(procPriv, + (CM_InstantiateComponent_t *)arg); + + case CM_BINDCOMPONENTFROMCMCORE: + return cmld_BindComponentFromCMCore(procPriv, + (CM_BindComponentFromCMCore_t *)arg); + + case CM_UNBINDCOMPONENTFROMCMCORE: + return cmld_UnbindComponentFromCMCore((CM_UnbindComponentFromCMCore_t *)arg); + + case CM_UNBINDCOMPONENTTOCMCORE: + return cmld_UnbindComponentToCMCore(procPriv, (CM_UnbindComponentToCMCore_t *)arg); + + case CM_BINDCOMPONENTASYNCHRONOUS: + return cmld_BindComponentAsynchronous(procPriv, (CM_BindComponentAsynchronous_t *)arg); + + case CM_UNBINDCOMPONENTASYNCHRONOUS: + return cmld_UnbindComponentAsynchronous(procPriv, (CM_UnbindComponentAsynchronous_t *)arg); + + case CM_BINDCOMPONENT: + return cmld_BindComponent(procPriv, (CM_BindComponent_t *)arg); + + case CM_UNBINDCOMPONENT: + return cmld_UnbindComponent(procPriv, (CM_UnbindComponent_t *)arg); + + case CM_BINDCOMPONENTTOVOID: + return cmld_BindComponentToVoid(procPriv, (CM_BindComponentToVoid_t *)arg); + + case CM_DESTROYCOMPONENT: + return cmld_DestroyComponent(procPriv, (CM_DestroyComponent_t *)arg); + + case CM_CREATEMEMORYDOMAIN: + return cmld_CreateMemoryDomain(procPriv, (CM_CreateMemoryDomain_t *)arg); + + case CM_CREATEMEMORYDOMAINSCRATCH: + return cmld_CreateMemoryDomainScratch(procPriv, (CM_CreateMemoryDomainScratch_t *)arg); + + case CM_DESTROYMEMORYDOMAIN: + return cmld_DestroyMemoryDomain((CM_DestroyMemoryDomain_t *)arg); + + case CM_GETDOMAINCOREID: + return cmld_GetDomainCoreId((CM_GetDomainCoreId_t *)arg); + + case CM_ALLOCMPCMEMORY: + return cmld_AllocMpcMemory(procPriv, (CM_AllocMpcMemory_t *)arg); + + case CM_FREEMPCMEMORY: + return cmld_FreeMpcMemory(procPriv, (CM_FreeMpcMemory_t *)arg); + + case CM_GETMPCMEMORYSTATUS: + return cmld_GetMpcMemoryStatus((CM_GetMpcMemoryStatus_t *)arg); + + case CM_STARTCOMPONENT: + return cmld_StartComponent(procPriv, (CM_StartComponent_t *)arg); + + case CM_STOPCOMPONENT: + return cmld_StopComponent(procPriv, (CM_StopComponent_t *)arg); + + case CM_GETMPCLOADCOUNTER: + return cmld_GetMpcLoadCounter((CM_GetMpcLoadCounter_t *)arg); + + case CM_GETCOMPONENTDESCRIPTION: + return cmld_GetComponentDescription(procPriv, (CM_GetComponentDescription_t *)arg); + + case CM_GETCOMPONENTLISTHEADER: + return cmld_GetComponentListHeader(procPriv, (CM_GetComponentListHeader_t *)arg); + + case CM_GETCOMPONENTLISTNEXT: + return cmld_GetComponentListNext(procPriv, (CM_GetComponentListNext_t *)arg); + + case CM_GETCOMPONENTREQUIREDINTERFACENUMBER: + return cmld_GetComponentRequiredInterfaceNumber(procPriv, + (CM_GetComponentRequiredInterfaceNumber_t *)arg); + + case CM_GETCOMPONENTREQUIREDINTERFACE: + return cmld_GetComponentRequiredInterface(procPriv, + (CM_GetComponentRequiredInterface_t *)arg); + + case CM_GETCOMPONENTREQUIREDINTERFACEBINDING: + return cmld_GetComponentRequiredInterfaceBinding(procPriv, + (CM_GetComponentRequiredInterfaceBinding_t *)arg); + + case CM_GETCOMPONENTPROVIDEDINTERFACENUMBER: + return cmld_GetComponentProvidedInterfaceNumber(procPriv, + (CM_GetComponentProvidedInterfaceNumber_t *)arg); + + case CM_GETCOMPONENTPROVIDEDINTERFACE: + return cmld_GetComponentProvidedInterface(procPriv, + (CM_GetComponentProvidedInterface_t *)arg); + + case CM_GETCOMPONENTPROPERTYNUMBER: + return cmld_GetComponentPropertyNumber(procPriv, + (CM_GetComponentPropertyNumber_t *)arg); + + case CM_GETCOMPONENTPROPERTYNAME: + return cmld_GetComponentPropertyName(procPriv, + (CM_GetComponentPropertyName_t *)arg); + + case CM_GETCOMPONENTPROPERTYVALUE: + return cmld_GetComponentPropertyValue(procPriv, + (CM_GetComponentPropertyValue_t *)arg); + + case CM_READCOMPONENTATTRIBUTE: + return cmld_ReadComponentAttribute(procPriv, + (CM_ReadComponentAttribute_t *)arg); + + case CM_GETEXECUTIVEENGINEHANDLE: + return cmld_GetExecutiveEngineHandle(procPriv, + (CM_GetExecutiveEngineHandle_t *)arg); + + case CM_SETMODE: + return cmld_SetMode((CM_SetMode_t *)arg); + + case CM_GETREQUIREDCOMPONENTFILES: + return cmld_GetRequiredComponentFiles(procPriv, + (CM_GetRequiredComponentFiles_t *)arg); + + case CM_MIGRATE: + return cmld_Migrate((CM_Migrate_t *)arg); + + case CM_UNMIGRATE: + return cmld_Unmigrate((CM_Unmigrate_t *)arg); + + case CM_SETUPRELINKAREA: + return cmld_SetupRelinkArea((CM_SetupRelinkArea_t *)arg); + + case CM_PUSHCOMPONENT: + return cmld_PushComponent((CM_PushComponent_t *)arg); + + case CM_RELEASECOMPONENT: + return cmld_ReleaseComponent((CM_ReleaseComponent_t *)arg); + + /* + * NMF CALLS (Host->MPC bindings) + */ + case CM_PUSHEVENTWITHSIZE: { + CM_PushEventWithSize_t data; + t_event_params_handle event; + + /* coverity[tainted_data_argument : FALSE] */ + if (copy_from_user(&data.in, (CM_PushEventWithSize_t*)arg, sizeof(data.in))) + return -EFAULT; + + /* Take the lock to synchronize CM_ENGINE_AllocEvent() + * and CM_ENGINE_PushEvent() + */ + if (mutex_lock_killable(&procPriv->host2mpcLock)) + return -ERESTARTSYS; + + event = CM_ENGINE_AllocEvent(data.in.host2mpcId); + if (event == NULL) { + mutex_unlock(&procPriv->host2mpcLock); + return put_user(CM_PARAM_FIFO_OVERFLOW, + &((CM_PushEventWithSize_t*)arg)->out.error); + } + if (data.in.size != 0) + /* coverity[tainted_data : FALSE] */ + if (copy_from_user(event, data.in.h, data.in.size)) { + mutex_unlock(&procPriv->host2mpcLock); + return -EFAULT; // TODO: what about the already allocated and acknowledged event!?! + } + + data.out.error = CM_ENGINE_PushEvent(data.in.host2mpcId, event, data.in.methodIndex); + mutex_unlock(&procPriv->host2mpcLock); + + /* copy error value back */ + return put_user(data.out.error, &((CM_PushEventWithSize_t*)arg)->out.error); + } + + /* + * All private (internal) commands + */ + case CM_PRIVGETMPCMEMORYDESC: + return cmld_PrivGetMPCMemoryDesc(procPriv, (CM_PrivGetMPCMemoryDesc_t *)arg); + + case CM_PRIVRESERVEMEMORY: + return cmld_PrivReserveMemory(procPriv, arg); + + case CM_GETVERSION: { + t_uint32 nmfversion = NMF_VERSION; + return copy_to_user((void*)arg, &nmfversion, sizeof(nmfversion)); + } + case CM_PRIV_GETBOARDVERSION: + if (cpu_is_u8500v20_or_later()) { + enum board_version v = U8500_V2; + return copy_to_user((void*)arg, &v, sizeof(v)); + } else + return -EINVAL; + + default: { + pr_err("CM(%s): unsupported command %i\n", __func__, cmd); + return -EINVAL; + } + } + + return 0; +} + +/** Driver's ioctl method + * Implements user/kernel crossing for SYSCALL API. + * + * \return POSIX error code + */ +static long cmld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + BUG_ON(filp->private_data == NULL); + + if (iminor(filp->f_dentry->d_inode) == 0) { + return cmld_control_ctl(filp, cmd, arg); + } else { + return cmld_channel_ctl(filp, cmd, arg); + } +} + +/** VMA open callback function + */ +static void cmld_vma_open(struct vm_area_struct* vma) { + struct memAreaDesc_t* curr = (struct memAreaDesc_t*)vma->vm_private_data; + + atomic_inc(&curr->count); +} + +/** VMA close callback function + */ +static void cmld_vma_close(struct vm_area_struct* vma) { + struct memAreaDesc_t* curr = (struct memAreaDesc_t*)vma->vm_private_data; + + atomic_dec(&curr->count); +} + +static struct vm_operations_struct cmld_remap_vm_ops = { + .open = cmld_vma_open, + .close = cmld_vma_close, +}; + +/** mmap implementation. + * Remaps just once. + * + * \return POSIX error code + */ +static int cmld_mmap(struct file* file, struct vm_area_struct* vma) +{ + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + struct list_head* listHead; + struct list_head* cursor; + struct cm_process_priv* procPriv = file->private_data; + struct memAreaDesc_t* curr = NULL; + unsigned int vma_size = vma->vm_end-vma->vm_start; + + BUG_ON(procPriv == NULL); + + listHead = &procPriv->memAreaDescList; + + if (lock_process(procPriv)) return -ERESTARTSYS; + /* Make sure the memory area has not already been remapped */ + list_for_each(cursor, listHead) { + curr = list_entry(cursor, struct memAreaDesc_t, list); + /* For now, the user space aligns any requested physaddr to a page-size limit + This is not safe and must be fixed. But this is the only way to + minimize the allocated TCM memory, needed because of low amount of + TCM memory + Another way is to add some more check before doing this mmap() + to allow this mmap, for example. + NOTE: this memory must be first reserved via the CM_PRIVRESERVEMEMORY ioctl() + */ + if ((curr->physAddr&PAGE_MASK) == offset && + curr->tid == current->pid) { + if (curr->userLogicalAddr) { + unlock_process(procPriv); + return -EINVAL; // already mapped! + } + /* reset the thread id value, to not confuse any further mmap() */ + curr->tid = 0; + break; + } + } + + if (cursor == listHead) { + unlock_process(procPriv); + return -EINVAL; // no matching memory area descriptor found! + } + + /* Very, very important to have consistent buffer transition */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTEXPAND | VM_DONTCOPY; + + if (remap_pfn_range(vma, vma->vm_start, offset>>PAGE_SHIFT, + vma_size, vma->vm_page_prot)) { + unlock_process(procPriv); + return -EAGAIN; + } + + /* Offset represents the physical address. + * Update the list entry filling in the logical address assigned to the user + */ + /* + * NOTE: here the useLogicalAddr is page-aligned, but not necessaly the + * phycical address. We mmap() more than originaly requested by the + * user, see in CM User Proxy (file cmsyscallwrapper.c) + */ + curr->userLogicalAddr = vma->vm_start; + + /* increment reference counter */ + atomic_inc(&curr->count); + + unlock_process(procPriv); + + /* set private data structure and callbacks */ + vma->vm_private_data = (void *)curr; + vma->vm_ops = &cmld_remap_vm_ops; + + return 0; +} + +/** MPC Events tasklet + * The parameter is used to know from which interrupts we're comming + * and which core to pass to CM_ProcessMpcEvent(): + * 0 means HSEM => ARM_CORE_ID + * otherwise, it gives the index+1 of MPC within osalEnv.mpc table + */ +static void mpc_events_tasklet_handler(unsigned long core) +{ + /* This serves internal events directly. No propagation to user space. + * Calls OSAL_PostDfc implementation for user interface events */ + if (core == 0) { + CM_ProcessMpcEvent(ARM_CORE_ID); + enable_irq(IRQ_DB8500_HSEM); + } else { + --core; + CM_ProcessMpcEvent(osalEnv.mpc[core].coreId); + enable_irq(osalEnv.mpc[core].interrupt0); + } +} + +/** Hardware semaphore and MPC interrupt handler + * 'data' param is the one given when registering the IRQ hanlder, + * contains the source core (ARM or MPC), and follows the same logic + * as for mpc_events_tasklet_handler() + * This handler is used for all IRQ handling some com (ie HSEM or + * all MPC IRQ line0) + */ +static irqreturn_t mpc_events_irq_handler(int irq, void *data) +{ + unsigned core = (unsigned)data; + + if (core != 0) + --core; + disable_irq_nosync(irq); + tasklet_schedule(&osalEnv.mpc[core].tasklet); + + return IRQ_HANDLED; +} + +/** MPC panic handler + * 'idx' contains the index of the core within the osalEnv.mpc table. + * This handler is used for all MPC IRQ line1 + */ +static irqreturn_t panic_handler(int irq, void *idx) +{ + set_bit((int)idx, &service_tasklet_data); + disable_irq_nosync(irq); + tasklet_schedule(&cmld_service_tasklet); + return IRQ_HANDLED; +} + +/** Driver's operations + */ +static struct file_operations cmld_fops = { + .owner = THIS_MODULE, + .read = cmld_read, + .unlocked_ioctl = cmld_ioctl, + .mmap = cmld_mmap, + .open = cmld_open, + .flush = cmld_flush, + .release = cmld_release, +}; + +/** + * Configure a MPC, called for each MPC to configure + * + * \param i index of the MPC to configure (refer to the index + * of the MPC within the osalEnvironment.mpc table) + * \param dataAllocId allocId of the data segment, passed through each call of + * this function, and initialized at the first call in case + * shared data segment + */ +static int configureMpc(unsigned i, t_cfg_allocator_id *dataAllocId) +{ + int err; + t_cm_system_address mpcSystemAddress; + t_nmf_memory_segment codeSegment, dataSegment; + t_cfg_allocator_id codeAllocId; + t_cm_domain_id eeDomainId; + t_cm_domain_memory eeDomain = INIT_DOMAIN; + char regulator_name[14]; + + getMpcSystemAddress(i, &mpcSystemAddress); + getMpcSdramSegments(i, &codeSegment, &dataSegment); + + /* Create code segment */ + err = CM_ENGINE_AddMpcSdramSegment(&codeSegment, &codeAllocId, "Code"); + if (err != CM_OK) { + pr_err("CM_ENGINE_AddMpcSdramSegment() error code: %d\n", err); + return -EAGAIN; + } + + /* Create data segment + * NOTE: in case of shared data segment, all MPC point to the same data segment + * (see in remapRegions()) and we need to create the segment only at first call. + * => we reuse the same allocId for the following MPCs + */ + if ((osalEnv.mpc[i].sdramDataL != osalEnv.mpc[0].sdramDataL) + || *dataAllocId == -1) { + err = CM_ENGINE_AddMpcSdramSegment(&dataSegment, dataAllocId, "Data"); + if (err != CM_OK) { + pr_err("CM_ENGINE_AddMpcSdramSegment() error code: %d\n", err); + return -EAGAIN; + } + } + + /* create default domain for the given coreId + * this serves for instanciating EE and the LoadMap, only sdram segment is present + * this domain will probably overlap with other user domains + */ + eeDomain.coreId = osalEnv.mpc[i].coreId; + eeDomain.sdramCode.offset = 0x0; + eeDomain.sdramData.offset = 0x0; + eeDomain.sdramCode.size = 0x8000; + eeDomain.sdramData.size = 0x40000; + eeDomain.esramCode.size = 0x4000; + eeDomain.esramData.size = 0x40000; + err = CM_ENGINE_CreateMemoryDomain(NMF_CORE_CLIENT, &eeDomain, &eeDomainId); + if (err != CM_OK) { + pr_err("Create EE domain on %s failed with error code: %d\n", osalEnv.mpc[i].name, err); + return -EAGAIN; + } + + err = CM_ENGINE_ConfigureMediaProcessorCore( + osalEnv.mpc[i].coreId, + osalEnv.mpc[i].eeId, + (cfgSemaphoreTypeHSEM ? SYSTEM_SEMAPHORES : LOCAL_SEMAPHORES), + osalEnv.mpc[i].nbYramBanks, + &mpcSystemAddress, + eeDomainId, + codeAllocId, + *dataAllocId); + + if (err != CM_OK) { + pr_err("CM_ConfigureMediaProcessorCore failed with error code: %d\n", err); + return -EAGAIN; + } + + // Communication channel + if (! cfgSemaphoreTypeHSEM) { + tasklet_init(&osalEnv.mpc[i].tasklet, mpc_events_tasklet_handler, i+1); + err = request_irq(osalEnv.mpc[i].interrupt0, mpc_events_irq_handler, IRQF_DISABLED, osalEnv.mpc[i].name, (void*)(i+1)); + if (err != 0) { + pr_err("CM: request_irq failed to register irq0 %i for %s (%i)\n", osalEnv.mpc[i].interrupt0, osalEnv.mpc[i].name, err); + return err; + } + } + + // Panic channel + err = request_irq(osalEnv.mpc[i].interrupt1, panic_handler, IRQF_DISABLED, osalEnv.mpc[i].name, (void*)i); + if (err != 0) { + pr_err("CM: request_irq failed to register irq1 %i for %s (%i)\n", osalEnv.mpc[i].interrupt1, osalEnv.mpc[i].name, err); + free_irq(osalEnv.mpc[i].interrupt0, (void*)(i+1)); + return err; + } + + // Retrieve the regulators used for this MPCs + sprintf(regulator_name, "%s-mmdsp", osalEnv.mpc[i].name); + osalEnv.mpc[i].mmdsp_regulator = regulator_get(cmld_dev[0], regulator_name); + if (IS_ERR(osalEnv.mpc[i].mmdsp_regulator)) { + long err = PTR_ERR(osalEnv.mpc[i].mmdsp_regulator); + pr_err("CM: Error while retrieving the regulator %s: %ld\n", regulator_name, err); + osalEnv.mpc[i].mmdsp_regulator = NULL; + return err; + } + sprintf(regulator_name, "%s-pipe", osalEnv.mpc[i].name); + osalEnv.mpc[i].pipe_regulator = regulator_get(cmld_dev[0], regulator_name); + if (IS_ERR(osalEnv.mpc[i].pipe_regulator)) { + long err = PTR_ERR(osalEnv.mpc[i].pipe_regulator); + pr_err("CM: Error while retrieving the regulator %s: %ld\n", regulator_name, err); + osalEnv.mpc[i].pipe_regulator = NULL; + return err; + } +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&osalEnv.mpc[i].wakelock, WAKE_LOCK_SUSPEND, osalEnv.mpc[i].name); +#endif + return 0; +} + +/* Free all used MPC irqs and clocks. + * max_mpc allows it to be called from init_module and free + * only the already configured irqs. + */ +static void free_mpc_irqs(int max_mpc) +{ + int i; + for (i=0; i<max_mpc; i++) { + if (! cfgSemaphoreTypeHSEM) + free_irq(osalEnv.mpc[i].interrupt0, (void*)(i+1)); + free_irq(osalEnv.mpc[i].interrupt1, (void*)i); + if (osalEnv.mpc[i].mmdsp_regulator) + regulator_put(osalEnv.mpc[i].mmdsp_regulator); + if (osalEnv.mpc[i].pipe_regulator) + regulator_put(osalEnv.mpc[i].pipe_regulator); +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&osalEnv.mpc[i].wakelock); +#endif + } +} + +/** Module entry point + * Allocate memory chunks. Register hardware semaphore, SIA and SVA interrupts. + * Initialize Component Manager. Register hotplug for components download. + * + * \return POSIX error code + */ +static int __init cmld_init_module(void) +{ + int err; + unsigned i=0; + dev_t dev; + t_cfg_allocator_id dataAllocId = -1; + void *htim_base=NULL; + + /* Component manager initialization descriptors */ + t_nmf_hw_mapping_desc nmfHwMappingDesc; + t_nmf_config_desc nmfConfigDesc = { cfgCommunicationLocationInSDRAM ? COMS_IN_SDRAM : COMS_IN_ESRAM }; + + /* OSAL_*Resources() assumes the following, so check that it is correct */ + if (SVA != COREIDX((int)SVA_CORE_ID)) { + pr_err("SVA and (SVA_CORE_ID-1) differs : code must be fixed !\n"); + return -EIO; + } + if (SIA != COREIDX((int)SIA_CORE_ID)) { + pr_err("SIA and (SIA_CORE_ID-1) differs : code must be fixed !\n"); + return -EIO; + } + +#ifdef CM_DEBUG_ALLOC + init_debug_alloc(); +#endif + + err = -EIO; + prcmu_base = __io_address(U8500_PRCMU_BASE); + if (cpu_is_u8500v20_or_later()) { + /* power on a clock/timer 90KHz used on SVA */ + htim_base = ioremap_nocache(U8500_CR_BASE /*0xA03C8000*/, SZ_4K); + prcmu_tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); + } else { + pr_err("CM: Unsupported chip version\n"); + goto out; + } + + /* Activate SVA 90 KHz timer */ + if (htim_base == NULL) + goto out; + iowrite32((1<<26), htim_base); + iounmap(htim_base); + + /*i = ioread32(PRCM_SVAMMDSPCLK_MGT) & 0xFF; + if (i != 0x22) + pr_alert("CM: Looks like SVA is not clocked at 200MHz (PRCM_SVAMMDSPCLK_MGT=%x)\n", i); + i = ioread32(PRCM_SIAMMDSPCLK_MGT) & 0xFF; + if (i != 0x22) + pr_alert("CM: Looks like SIA is not clocked at 200MHz (PRCM_SIAMMDSPCLK_MGT=%x)\n", i); + + i = 0;*/ + err = init_config(); + if (err) + goto out; + + /* Remap all needed regions and store in osalEnv base addresses */ + err = remapRegions(); + if (err != 0) + goto out; + + /* Initialize linux devices */ + err = class_register(&cmld_class); + if (err) { + pr_err("CM: class_register failed (%d)\n", err); + goto out; + } + + /* Register char device */ + err = alloc_chrdev_region(&dev, 0, ARRAY_SIZE(cmld_devname), "cm"); + if (err) { + pr_err("CM: alloc_chrdev_region failed (%d)\n", err); + goto out_destroy_class; + } + cmld_major = MAJOR(dev); + + cdev_init(&cmld_cdev, &cmld_fops); + cmld_cdev.owner = THIS_MODULE; + err = cdev_add (&cmld_cdev, dev, ARRAY_SIZE(cmld_devname)); + if (err) { + pr_err("CM: cdev_add failed (%d)\n", err); + goto out_destroy_chrdev; + } + + for (i=0; i<ARRAY_SIZE(cmld_devname); i++) { + cmld_dev[i] = device_create(&cmld_class, NULL, MKDEV(cmld_major, i), NULL, + "%s", cmld_devname[i]); + if (IS_ERR(cmld_dev[i])) { + err = PTR_ERR(cmld_dev[i]); + pr_err("CM: device_create failed (%d)\n", err); + goto out_destroy_device; + } + } + + osalEnv.esram_regulator[ESRAM_12] = regulator_get(cmld_dev[0], "esram12"); + if (IS_ERR(osalEnv.esram_regulator[ESRAM_12])) { + err = PTR_ERR(osalEnv.esram_regulator[ESRAM_12]); + pr_err("CM: Error while retrieving the regulator for esram12: %d\n", err); + osalEnv.esram_regulator[ESRAM_12] = NULL; + goto out_destroy_device; + } + osalEnv.esram_regulator[ESRAM_34] = regulator_get(cmld_dev[0], "esram34"); + if (IS_ERR(osalEnv.esram_regulator[ESRAM_34])) { + err = PTR_ERR(osalEnv.esram_regulator[ESRAM_34]); + pr_err("CM: Error while retrieving the regulator for esram34: %d\n", err); + osalEnv.esram_regulator[ESRAM_34] = NULL; + goto out_destroy_device; + } + + /* Fill in the descriptors needed by CM_ENGINE_Init() */ + getNmfHwMappingDesc(&nmfHwMappingDesc); + + /* Initialize Component Manager */ + err = CM_ENGINE_Init(&nmfHwMappingDesc, &nmfConfigDesc); + if (err != CM_OK) { + pr_err("CM: CM_Init failed with error code: %d\n", err); + err = -EAGAIN; + goto out_destroy_device; + } else { + pr_info("Initialize NMF %d.%d.%d Component Manager......\n", + VERSION_MAJOR(NMF_VERSION), + VERSION_MINOR(NMF_VERSION), + VERSION_PATCH(NMF_VERSION)); + pr_info("[ CM Linux Driver %d.%d.%d ]\n", + VERSION_MAJOR(NMF_VERSION), + VERSION_MINOR(NMF_VERSION), + CMDRIVER_PATCH_VERSION); + } + + /* Reserve DMA and MCDE ESRAM if needed */ + if (cfgESRAM_ReserveDMA) { + t_cm_domain_memory domain = INIT_DOMAIN; + + // Reserve memory used by DMA + domain.coreId = ARM_CORE_ID; + domain.esramData.offset = 0x0; + domain.esramData.size = cfgESRAMDmaSize * ONE_KB; + err = CM_ENGINE_CreateMemoryDomain(NMF_CORE_CLIENT, + &domain, &dmaDomainId); + if (err != CM_OK) { + pr_err("CM: Create DMA/ESRAM domain failed with error code: %d\n", err); + err = -EAGAIN; + goto out_all; + } + + err = CM_ENGINE_AllocMpcMemory(dmaDomainId, + NMF_CORE_CLIENT, + CM_MM_MPC_ESRAM16, + cfgESRAMDmaSize * ONE_KB / 2, + CM_MM_MPC_ALIGN_NONE, + &dmaMemoryHdl); + if (err != CM_OK) { + pr_err("CM: Alloc DMA in ESRAM domain failed with error code: %d\n", err); + err = -EAGAIN; + goto out_all; + } + } + + if (cfgESRAM_ReserveMCDE) { + t_cm_domain_memory domain = INIT_DOMAIN; + + // Reserve memory used by MCDE + domain.coreId = ARM_CORE_ID; + domain.esramData.offset = (cfgESRAMSize - cfgESRAMMcdeSize) * ONE_KB; + domain.esramData.size = cfgESRAMMcdeSize * ONE_KB; + err = CM_ENGINE_CreateMemoryDomain(NMF_CORE_CLIENT, + &domain, &mcdeDomainId); + if (err != CM_OK) { + pr_err("CM: Create MCDE/ESRAM domain failed with error code: %d\n", err); + err = -EAGAIN; + goto out_all; + } + + err = CM_ENGINE_AllocMpcMemory(mcdeDomainId, + NMF_CORE_CLIENT, + CM_MM_MPC_ESRAM16, + cfgESRAMMcdeSize * ONE_KB / 2, + CM_MM_MPC_ALIGN_NONE, + &mcdeMemoryHdl); + if (err != CM_OK) { + pr_err("CM: Alloc MCDE in ESRAM domain failed with error code: %d\n", err); + err = -EAGAIN; + goto out_all; + } + } + + /* Configure MPC Cores */ + for (i=0; i<NB_MPC; i++) { + err = configureMpc(i, &dataAllocId); + if (err) + goto out_all; + } + /* End of Component Manager initialization phase */ + + + if (cfgSemaphoreTypeHSEM) { + /* We use tasklet of mpc[0]. See comments above osalEnvironnent struct */ + tasklet_init(&osalEnv.mpc[0].tasklet, mpc_events_tasklet_handler, 0); + err = request_irq(IRQ_DB8500_HSEM, mpc_events_irq_handler, IRQF_DISABLED, + "hwsem", 0); + if (err) { + pr_err("CM: request_irq failed to register hwsem irq %i (%i)\n", + IRQ_DB8500_HSEM, err); + goto out_all; + } + } + + return 0; + +out_all: + if (err) { + if (cfgESRAM_ReserveMCDE) { + if (mcdeMemoryHdl) + CM_ENGINE_FreeMpcMemory(mcdeMemoryHdl); + CM_ENGINE_DestroyMemoryDomain(mcdeDomainId); + } + if (cfgESRAM_ReserveDMA) { + if (dmaMemoryHdl) + CM_ENGINE_FreeMpcMemory(dmaMemoryHdl); + CM_ENGINE_DestroyMemoryDomain(dmaDomainId); + } + } + free_mpc_irqs(i); + CM_ENGINE_Destroy(); + i=ARRAY_SIZE(cmld_devname); +out_destroy_device: + if (osalEnv.esram_regulator[ESRAM_12]) + regulator_put(osalEnv.esram_regulator[ESRAM_12]); + if (osalEnv.esram_regulator[ESRAM_34]) + regulator_put(osalEnv.esram_regulator[ESRAM_34]); + while (i--) + device_destroy(&cmld_class, MKDEV(cmld_major, i)); + cdev_del(&cmld_cdev); +out_destroy_chrdev: + unregister_chrdev_region(dev, ARRAY_SIZE(cmld_devname)); +out_destroy_class: + class_unregister(&cmld_class); +out: + unmapRegions(); +#ifdef CM_DEBUG_ALLOC + cleanup_debug_alloc(); +#endif + return err; +} + +/** Module exit point + * Unregister the driver. This will lead to a 'remove' call. + */ +static void __exit cmld_cleanup_module(void) +{ + unsigned i; + + if (!list_empty(&channel_list)) + pr_err("CM Driver ending with non empty channel list\n"); + if (!list_empty(&process_list)) + pr_err("CM Driver ending with non empty process list\n"); + + if (cfgESRAM_ReserveMCDE) { + if (mcdeMemoryHdl) + CM_ENGINE_FreeMpcMemory(mcdeMemoryHdl); + CM_ENGINE_DestroyMemoryDomain(mcdeDomainId); + } + if (cfgESRAM_ReserveDMA) { + if (dmaMemoryHdl) + CM_ENGINE_FreeMpcMemory(dmaMemoryHdl); + CM_ENGINE_DestroyMemoryDomain(dmaDomainId); + } + if (cfgSemaphoreTypeHSEM) + free_irq(IRQ_DB8500_HSEM, NULL); + free_mpc_irqs(NB_MPC); + tasklet_kill(&cmld_service_tasklet); + + if (osalEnv.esram_regulator[ESRAM_12]) + regulator_put(osalEnv.esram_regulator[ESRAM_12]); + if (osalEnv.esram_regulator[ESRAM_34]) + regulator_put(osalEnv.esram_regulator[ESRAM_34]); + for (i=0; i<ARRAY_SIZE(cmld_devname); i++) + device_destroy(&cmld_class, MKDEV(cmld_major, i)); + cdev_del(&cmld_cdev); + unregister_chrdev_region(MKDEV(cmld_major, 0), ARRAY_SIZE(cmld_devname)); + class_unregister(&cmld_class); + + CM_ENGINE_Destroy(); + + unmapRegions(); +#ifdef CM_DEBUG_ALLOC + cleanup_debug_alloc(); +#endif +} +module_init(cmld_init_module); +module_exit(cmld_cleanup_module); + +MODULE_AUTHOR("David Siorpaes"); +MODULE_AUTHOR("Wolfgang Betz"); +MODULE_AUTHOR("Pierre Peiffer"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Nomadik Multiprocessing Framework Component Manager Linux driver"); diff --git a/drivers/staging/nmf-cm/cmld.h b/drivers/staging/nmf-cm/cmld.h new file mode 100644 index 00000000000..234e30db503 --- /dev/null +++ b/drivers/staging/nmf-cm/cmld.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef CMLD_H +#define CMLD_H + +#include <linux/kref.h> +#include <linux/mutex.h> +#include <linux/version.h> +#include <linux/wait.h> +#include <inc/nmf-limits.h> +#include "cmioctl.h" + +/** Channel state used within the per-channel private structure 'cm_channel_priv' + */ +enum channel_state { + CHANNEL_CLOSED = 0, /**< Channel already closed */ + CHANNEL_OPEN, /**< Channel still open */ +}; + +/** Component Manager per-process private structure + * It is created the first time a process opens /dev/cm0 or /dev/cm1 + */ +struct cm_process_priv +{ + struct kref ref; /**< ref count */ + struct list_head entry; /**< This entry */ + pid_t pid; /**< pid of process owner */ + struct mutex mutex; /**< per process mutex: protect memAreaDescList */ + struct list_head memAreaDescList; /**< memAreaDesc_t list */ + struct mutex host2mpcLock; /**< used to synchronize each AllocEvent + PushEvent */ +}; + +/** Component Manager per-channel private structure + * It is created when a user opens /dev/cm1 + */ +struct cm_channel_priv +{ + enum channel_state state; /**< Channel state */ + struct list_head entry; /**< This entry */ + struct cm_process_priv *proc; /**< Pointer to the owner process structure */ + struct list_head skelList; /**< t_skelwrapper list */ + struct mutex skelListLock; /**< skelList mutex */ + struct plist_head messageQueue; /**< queueelem_t list */ + struct mutex msgQueueLock; /**< lock used to synchronize MPC to HOST bindings + in case of multiple read (see cmld_read comments) */ + spinlock_t bh_lock; /**< lock used to synchronize add/removal of element in/from + the message queue in both user context and tasklet */ + wait_queue_head_t waitq; /**< wait queue used to block read() call */ +}; + +/** Memory area descriptor. + */ +struct memAreaDesc_t { + struct list_head list; /**< Doubly linked list descriptor */ + atomic_t count; /**< Reference counter */ + pid_t tid; /**< tid of the process this area is reserved for */ + t_cm_memory_handle handle; /**< Component Manager handle */ + unsigned int size; /**< Size */ + unsigned int physAddr; /**< Physical address */ + unsigned int kernelLogicalAddr; /**< Logical address as seen by kernel */ + unsigned int userLogicalAddr; /**< Logical address as seen by user */ + unsigned int mpcPhysAddr; /**< Physicaladdress as seen by MPC */ + struct cm_process_priv* procPriv; /**< link to per process private structure */ +}; + +extern struct list_head channel_list; /**< List of all allocated channel structures */ +extern struct list_head process_list; /**< List of all allocated process private structure */ + +/** Lock/unlock per process mutex + * + * \note Must be taken before tasklet_disable (if necessary)! + */ +#define lock_process_uninterruptible(proc) (mutex_lock(&proc->mutex)) +#define lock_process(proc) (mutex_lock_killable(&proc->mutex)) +#define unlock_process(proc) (mutex_unlock(&proc->mutex)) + + + +int cmld_InstantiateComponent(struct cm_process_priv *, CM_InstantiateComponent_t __user *); +int cmld_BindComponentFromCMCore(struct cm_process_priv *, + CM_BindComponentFromCMCore_t __user *); +int cmld_UnbindComponentFromCMCore(CM_UnbindComponentFromCMCore_t __user *); +int cmld_BindComponentToCMCore(struct cm_channel_priv *, CM_BindComponentToCMCore_t __user *); +int cmld_UnbindComponentToCMCore(struct cm_process_priv*, CM_UnbindComponentToCMCore_t __user *); +int cmld_BindComponentAsynchronous(struct cm_process_priv*, CM_BindComponentAsynchronous_t __user *); +int cmld_UnbindComponentAsynchronous(struct cm_process_priv*, CM_UnbindComponentAsynchronous_t __user *); +int cmld_BindComponent(struct cm_process_priv*, CM_BindComponent_t __user *); +int cmld_UnbindComponent(struct cm_process_priv*, CM_UnbindComponent_t __user *); +int cmld_BindComponentToVoid(struct cm_process_priv*, CM_BindComponentToVoid_t __user *); +int cmld_DestroyComponent(struct cm_process_priv*, CM_DestroyComponent_t __user *); +int cmld_CreateMemoryDomain(struct cm_process_priv*, CM_CreateMemoryDomain_t __user *); +int cmld_CreateMemoryDomainScratch(struct cm_process_priv*, CM_CreateMemoryDomainScratch_t __user *); +int cmld_DestroyMemoryDomain(CM_DestroyMemoryDomain_t __user *); +int cmld_GetDomainCoreId(CM_GetDomainCoreId_t __user *); +int cmld_AllocMpcMemory(struct cm_process_priv *, CM_AllocMpcMemory_t __user *); +int cmld_FreeMpcMemory(struct cm_process_priv *, CM_FreeMpcMemory_t __user *); +int cmld_GetMpcMemoryStatus(CM_GetMpcMemoryStatus_t __user *); +int cmld_StartComponent(struct cm_process_priv *, CM_StartComponent_t __user *); +int cmld_StopComponent(struct cm_process_priv *, CM_StopComponent_t __user *); +int cmld_GetMpcLoadCounter(CM_GetMpcLoadCounter_t __user *); +int cmld_GetComponentDescription(struct cm_process_priv *, CM_GetComponentDescription_t __user *); +int cmld_GetComponentListHeader(struct cm_process_priv *, CM_GetComponentListHeader_t __user *); +int cmld_GetComponentListNext(struct cm_process_priv *, CM_GetComponentListNext_t __user *); +int cmld_GetComponentRequiredInterfaceNumber(struct cm_process_priv *, + CM_GetComponentRequiredInterfaceNumber_t __user *); +int cmld_GetComponentRequiredInterface(struct cm_process_priv *, + CM_GetComponentRequiredInterface_t __user *); +int cmld_GetComponentRequiredInterfaceBinding(struct cm_process_priv *, + CM_GetComponentRequiredInterfaceBinding_t __user *); +int cmld_GetComponentProvidedInterfaceNumber(struct cm_process_priv *, + CM_GetComponentProvidedInterfaceNumber_t __user *); +int cmld_GetComponentProvidedInterface(struct cm_process_priv *, + CM_GetComponentProvidedInterface_t __user *); +int cmld_GetComponentPropertyNumber(struct cm_process_priv *, + CM_GetComponentPropertyNumber_t __user *); +int cmld_GetComponentPropertyName(struct cm_process_priv *, CM_GetComponentPropertyName_t __user *); +int cmld_GetComponentPropertyValue(struct cm_process_priv *, CM_GetComponentPropertyValue_t __user *); +int cmld_ReadComponentAttribute(struct cm_process_priv *, CM_ReadComponentAttribute_t __user *); +int cmld_GetExecutiveEngineHandle(struct cm_process_priv *, CM_GetExecutiveEngineHandle_t __user *); +int cmld_SetMode(CM_SetMode_t __user *); +int cmld_GetRequiredComponentFiles(struct cm_process_priv *cmPriv, + CM_GetRequiredComponentFiles_t __user *); +int cmld_Migrate(CM_Migrate_t __user *); +int cmld_Unmigrate(CM_Unmigrate_t __user *); +int cmld_SetupRelinkArea(CM_SetupRelinkArea_t __user *); +int cmld_PushComponent(CM_PushComponent_t __user *); +int cmld_ReleaseComponent(CM_ReleaseComponent_t __user *); +int cmld_PrivGetMPCMemoryDesc(struct cm_process_priv *, CM_PrivGetMPCMemoryDesc_t __user *); +int cmld_PrivReserveMemory(struct cm_process_priv *, unsigned int); +#endif diff --git a/drivers/staging/nmf-cm/configuration.c b/drivers/staging/nmf-cm/configuration.c new file mode 100644 index 00000000000..175b6152b40 --- /dev/null +++ b/drivers/staging/nmf-cm/configuration.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/** \file configuration.c + * + * Nomadik Multiprocessing Framework Linux Driver + * + */ + +#include <cm/engine/api/configuration_engine.h> +#include <cm/engine/configuration/inc/configuration_status.h> + +#include "osal-kernel.h" + +/* Per-driver environment */ +struct OsalEnvironment osalEnv = +{ + .mpc = { + { + .coreId = SVA_CORE_ID, + .name = "sva", + .baseP = (void*)SVA_BASE_ADDR, + .interrupt0 = IRQ_DB8500_SVA, + .interrupt1 = IRQ_DB8500_SVA2, + .mmdsp_regulator = NULL, + .pipe_regulator = NULL, + .monitor_tsk = NULL, + .hwmemCode = NULL, + .hwmemData = NULL, + }, + { + .coreId = SIA_CORE_ID, + .name = "sia", + .baseP = (void*)SIA_BASE_ADDR, + .interrupt0 = IRQ_DB8500_SIA, + .interrupt1 = IRQ_DB8500_SIA2, + .mmdsp_regulator = NULL, + .pipe_regulator = NULL, + .monitor_tsk = NULL, + .hwmemCode = NULL, + .hwmemData = NULL, + } + }, + .esram_regulator = { NULL, NULL}, + .dsp_sleep = { + .sia_auto_pm_enable = PRCMU_AUTO_PM_OFF, + .sia_power_on = 0, + .sia_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF, + .sva_auto_pm_enable = PRCMU_AUTO_PM_OFF, + .sva_power_on = 0, + .sva_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF, + }, + .dsp_idle = { + .sia_auto_pm_enable = PRCMU_AUTO_PM_OFF, + .sia_power_on = 0, + .sia_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF, + .sva_auto_pm_enable = PRCMU_AUTO_PM_OFF, + .sva_power_on = 0, + .sva_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF, + }, +}; + +module_param_call(cm_debug_level, param_set_int, param_get_int, + &cm_debug_level, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(cm_debug_level, "Debug level of NMF Core"); + +module_param_call(cm_error_break, param_set_bool, param_get_bool, + &cm_error_break, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(cm_error_break, "Stop on error (in an infinite loop, for debugging purpose)"); + +module_param_call(cmIntensiveCheckState, param_set_bool, param_get_bool, + &cmIntensiveCheckState, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(cmIntensiveCheckState, "Add additional intensive checks"); + +DECLARE_MPC_PARAM(SVA, SDRAM_DATA_SIZE, "", 1); + +DECLARE_MPC_PARAM(SIA, 0, "\n\t\t\t(0 means shared with SVA)", 2); + +int cfgCommunicationLocationInSDRAM = 1; +module_param(cfgCommunicationLocationInSDRAM, bool, S_IRUGO); +MODULE_PARM_DESC(cfgCommunicationLocationInSDRAM, "Location of communications (SDRAM or ESRAM)"); + +int cfgSemaphoreTypeHSEM = 1; +module_param(cfgSemaphoreTypeHSEM, bool, S_IRUGO); +MODULE_PARM_DESC(cfgSemaphoreTypeHSEM, "Semaphore used (HSEM or LSEM)"); + +int cfgESRAMSize = ESRAM_SIZE; +module_param(cfgESRAMSize, uint, S_IRUGO); +MODULE_PARM_DESC(cfgESRAMSize, "Size of ESRAM used in the CM (in Kb)"); + +int init_config(void) +{ + if (cfgMpcSDRAMCodeSize_SVA == 0 || cfgMpcSDRAMCodeSize_SIA == 0) { + pr_err("SDRAM code size must be greater than 0\n"); + return -EINVAL; + } + + if (cfgMpcSDRAMDataSize_SVA == 0) { + pr_err("SDRAM data size for SVA must be greater than 0\n"); + return -EINVAL; + } + osalEnv.mpc[SVA].nbYramBanks = cfgMpcYBanks_SVA; + osalEnv.mpc[SVA].eeId = cfgSchedulerTypeHybrid_SVA ? HYBRID_EXECUTIVE_ENGINE : SYNCHRONOUS_EXECUTIVE_ENGINE; + osalEnv.mpc[SVA].sdramCodeSize = cfgMpcSDRAMCodeSize_SVA * ONE_KB; + osalEnv.mpc[SVA].sdramDataSize = cfgMpcSDRAMDataSize_SVA * ONE_KB; + osalEnv.mpc[SIA].nbYramBanks = cfgMpcYBanks_SIA; + osalEnv.mpc[SIA].eeId = cfgSchedulerTypeHybrid_SIA ? HYBRID_EXECUTIVE_ENGINE : SYNCHRONOUS_EXECUTIVE_ENGINE; + osalEnv.mpc[SIA].sdramCodeSize = cfgMpcSDRAMCodeSize_SIA * ONE_KB; + osalEnv.mpc[SIA].sdramDataSize = cfgMpcSDRAMDataSize_SIA * ONE_KB; + + return 0; +} diff --git a/drivers/staging/nmf-cm/configuration.h b/drivers/staging/nmf-cm/configuration.h new file mode 100644 index 00000000000..a3bc1ca9063 --- /dev/null +++ b/drivers/staging/nmf-cm/configuration.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +/** Peripherals description. + * Some of these values are taken from kernel header description (which should be the + * right place of these definition); the missing ones are defined here. + */ + +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include <generated/autoconf.h> +#else +#include <linux/autoconf.h> +#endif + +/** Nomadik embedded Static RAM base address*/ +#define ESRAM_BASE (U8500_ESRAM_BASE + 0x10000) // V1/V2 config: 0-64k: secure; +#define HWSEM_BASE U8500_HSEM_BASE + +/** SxA base address */ +#define SVA_BASE_ADDR U8500_SVA_BASE +#define SIA_BASE_ADDR U8500_SIA_BASE + +/** Nomadik embedded ram size for CM (in Kb) */ +#define ESRAM_SIZE 576 +enum { + ESRAM_12, + ESRAM_34, + NB_ESRAM, +}; + +/** MPCs */ +enum { + SVA, + SIA, + NB_MPC, +}; +#define COREIDX(id) (id-1) + +/** Base address of shared SDRAM: use upper SDRAM. We reserve a rather */ +#define SDRAM_CODE_SIZE_SVA (2*ONE_KB) +#define SDRAM_CODE_SIZE_SIA (2*ONE_KB) +#define SDRAM_DATA_SIZE (8*ONE_KB) + +extern int cfgCommunicationLocationInSDRAM; +extern int cfgSemaphoreTypeHSEM; +extern int cfgESRAMSize; + +int init_config(void); + +#define DECLARE_MPC_PARAM(mpc, sdramDataSize, extension, ybank) \ + static unsigned int cfgMpcYBanks_##mpc = ybank; \ + module_param(cfgMpcYBanks_##mpc, uint, S_IRUGO); \ + MODULE_PARM_DESC(cfgMpcYBanks_##mpc, "Nb of Y-Ram banks used on " #mpc); \ + \ + static int cfgSchedulerTypeHybrid_##mpc = 1; \ + module_param(cfgSchedulerTypeHybrid_##mpc, bool, S_IRUGO); \ + MODULE_PARM_DESC(cfgSchedulerTypeHybrid_##mpc, "Scheduler used on " #mpc " (Hybrid or Synchronous)"); \ + \ + static unsigned int cfgMpcSDRAMCodeSize_##mpc = SDRAM_CODE_SIZE_##mpc; \ + module_param(cfgMpcSDRAMCodeSize_##mpc, uint, S_IRUGO); \ + MODULE_PARM_DESC(cfgMpcSDRAMCodeSize_##mpc, "Size of code segment on " #mpc " (in Kb)"); \ + \ + static unsigned int cfgMpcSDRAMDataSize_##mpc = sdramDataSize; \ + module_param(cfgMpcSDRAMDataSize_##mpc, uint, S_IRUGO); \ + MODULE_PARM_DESC(cfgMpcSDRAMDataSize_##mpc, "Size of data segment on " #mpc " (in Kb)" extension) + +#endif diff --git a/drivers/staging/nmf-cm/ee/api/ee.h b/drivers/staging/nmf-cm/ee/api/ee.h new file mode 100644 index 00000000000..bde3cee9425 --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/ee.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +/*! + * \defgroup HOSTEE_MODULE Host Execution Engine + */ + +/*! + * \defgroup HOSTEE Host Execution Engine API + * \ingroup HOSTEE_MODULE + */ + +#ifndef HOST_EE_H +#define HOST_EE_H + + +#include <inc/typedef.h> + +#include <nmf/inc/channel_type.h> +#include <nmf/inc/service_type.h> + +#include <ee/api/ee_type.h> + +/*! + * \brief Get the version of the NMF Host EE at runtime + * + * This method should be used to query the version number of the + * NMF Component Manager engine at runtime. This is useful when using + * to check if version of the engine linked with application correspond + * to engine used for development. + * + * Such code can be used to check compatibility: \code + t_uint32 nmfversion; + + // Print NMF version + EE_GetVersion(&nmfversion); + LOG("NMF Version %d-%d-%d\n", + VERSION_MAJOR(nmfversion), + VERSION_MINOR(nmfversion), + VERSION_PATCH(nmfversion)); + if(NMF_VERSION != nmfversion) { + LOG("Error: Incompatible API version %d != %d\n", NMF_VERSION, nmfversion); + EXIT(); + } + * \endcode + * + * \param[out] version Internal hardcoded version (use \ref VERSION_MAJOR, \ref VERSION_MINOR, \ref VERSION_PATCH macros to decode it). + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED void EE_GetVersion(t_uint32 *version); + +/*! + * \brief Set the mode of the Host EE. + * + * According the (\ref t_ee_cmd_id) value, this routine allows to modify dynamically the behavior of the Host EE. + * + * \param[in] aCmdID Command ID. + * \param[in] aParam Parameter of command ID if required. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_SetMode(t_ee_cmd_id aCmdID, t_sint32 aParam); + +/*! + * \brief Create a channel for communication between host ee and user. + * + * The purpose of the function is to: + * - create a channel or get a channel, regarding the flag parameter + * + * \param[in] flags Whether the caller want to create a new channel (CHANNEL_PRIVATE) + * or use the shared one (CHANNEL_PRIVATE) (it will be created + * if it does not yet exist) + * \param[out] channel Channel number. + * + * \exception NMF_NO_MORE_MEMORY Not enough memory to create the callback Channel. + * \exception NMF_INVALID_PARAMETER The specified flags is invalid. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_CreateChannel(t_nmf_channel_flag flags, t_nmf_channel *channel); + +/*! + * \brief Flush a channel to allow user to safely close it. + * + * The purpose of the function is to allow safe call of EE_CloseChannel() later on. Calling + * EE_FlushChannel() will allow a blocking call to EE_GetMessage() to exit with an error + * NMF_FLUSH_MESSAGE. After EE_GetMessage() has exit with such a value user must no more + * call EE_GetMessage() and can safely call EE_CloseChannel() that will destroy channel. + * In case of the share channel EE_FlushChannel() will return false for isFlushMessageGenerated if + * it's internal reference counter is not zero, in that case no NMF_FLUSH_MESSAGE error is return + * by EE_GetMessage() and user can immediatly call EE_CloseChannel(). + * In case user know that no usage of channel is done when he want to destroy channel, call to this api + * is optionnal and user can safely call EE_CloseChannel(). + * + * \param[in] channel Channel number + * \param[out] isFlushMessageGenerated Allow user to know if it must wait for NMF_FLUSH_MESSAGE return + * of EE_GetMessage() before calling EE_CloseChannel() + * + * \exception NMF_INVALID_PARAMETER The specified flags is invalid. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_FlushChannel(t_nmf_channel channel, t_bool *isFlushMessageGenerated); + +/*! + * \brief Unregister channel + * + * The purpose of the function is to: + * - destroy a channel from the user to the Host ee. + * + * The user must call EE_UserDone() as many time as EE_UserInit(). + * At the last EE_UserDone() call, the channel is closed and definitely destroyed + * All service callback must be unregistered first. + * + * \param[in] channel Channel number: + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_CloseChannel(t_nmf_channel channel); + +/*! + * \brief Register a service callback to this channel. + * + * \param[in] channel The channel on which the callback must be registered. + * \param[in] handler The given callback. + * \param[in] contextHandler The context associated with this callback. + * + * \exception NMF_NO_MORE_MEMORY Not enough memory to associate service with the Channel. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_RegisterService(t_nmf_channel channel, t_nmf_serviceCallback handler, void *contextHandler); + +/*! + * \brief Unregister a service callback from this channel. + * + * \param[in] channel The channel on which the callback must be registered. + * \param[in] handler The given callback. + * \param[in] contextHandler The context associated with this callback. + * + * \exception NMF_INVALID_PARAMETER The channel or the callback doesn't exist. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_UnregisterService(t_nmf_channel channel, t_nmf_serviceCallback handler, void *contextHandler); + +/*! + * \brief Unregister a notify callback for this channel. + * + * This method will register a callback that will be call each time a message has + * been push in queue of the channel. + * To unregister your callback just register a null notify. + * + * \param[in] channel The channel on which the callback must be registered. + * \param[in] notify The given callback. + * \param[in] contextHandler The context associated with this callback. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_RegisterNotify(t_nmf_channel channel, t_nmf_notify notify, void *contextHandler); + +/*! + * \brief Get received message from specified callback channel. + * + * This method can be used to retrieve callback message from Host ee. Returned message could then + * be dispatch through EE_ExecuteMessage. + * + * \param[in] channel The channel from which the message must be retrieved + * \param[out] clientContext client context. + * \param[out] message Reference on buffer to be unmarshalled. The buffer is allocated internally. + * \param[in] blockable Indicate if the call could blocked or not. + * + * \exception NMF_NO_MESSAGE No waited message. + * \exception NMF_INVALID_PARAMETER At least one input parameters is invalid + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED t_nmf_error EE_GetMessage(t_nmf_channel channel, void **clientContext, char **message, t_bool blockable); + +/*! + * \brief Execute a message. User callback will be execute. + * + * This method allow the message retrieved through EE_GetMessage to the right user callback. + * + * \param[in] itfref Interface reference. + * \param[in] message Reference on buffer to be unmarshalled. + * + * \ingroup HOSTEE + */ +PUBLIC IMPORT_SHARED void EE_ExecuteMessage(void *itfref, char *message); + +#endif diff --git a/drivers/staging/nmf-cm/ee/api/ee_type.h b/drivers/staging/nmf-cm/ee/api/ee_type.h new file mode 100644 index 00000000000..368cd6d29ba --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/ee_type.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef HOST_EE_TYPE_H +#define HOST_EE_TYPE_H + +/*! + * \brief Notify callback method type. + * + * \ingroup HOSTEE + */ +typedef void (*t_nmf_notify)(void *contextHandler); + +/*! + * \brief Definition of the command ID type + */ +typedef t_uint32 t_ee_cmd_id; + +/*! + * \brief Definition of the command ID + */ +typedef enum { + EE_CMD_TRACE_ON, //!< Enable tracing and force network resetting and dumping + EE_CMD_TRACE_OFF //!< Disable tracing +} t_ee_cmd_idDescription; + + +#endif diff --git a/drivers/staging/nmf-cm/ee/api/list.idt b/drivers/staging/nmf-cm/ee/api/list.idt new file mode 100644 index 00000000000..a53a39734d8 --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/list.idt @@ -0,0 +1,18 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef LIST_IDT +#define LIST_IDT + +/* linking elem */ +struct _t_list_link { + struct _t_list_link *pNext; +}; +typedef struct _t_list_link t_list_link; + +#endif + diff --git a/drivers/staging/nmf-cm/ee/api/outnotify.h b/drivers/staging/nmf-cm/ee/api/outnotify.h new file mode 100644 index 00000000000..c88185fac16 --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/outnotify.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef OUT_IDT +#define OUT_IDT + +typedef void (*t_nmf_notify)(void *contextHandler); + +#endif + diff --git a/drivers/staging/nmf-cm/ee/api/panic.idt b/drivers/staging/nmf-cm/ee/api/panic.idt new file mode 100644 index 00000000000..612dfcc8b4b --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/panic.idt @@ -0,0 +1,73 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \defgroup NMF_EE_TYPE Execution Engine Common Type Definitions + * \ingroup COMMON + */ + +#ifndef __INC_PANIC_IDT +#define __INC_PANIC_IDT + +/*! + * \brief Panic reason type + * + * For values, see \ref t_panic_reasonDescription. + * + * \ingroup NMF_EE_TYPE + */ +typedef t_uint8 t_panic_reason; + +/*! + * \brief The different panic reasons + * + * \verbatim + * Reason | Information | Behavior + * ------------------------------------------------------------------- + * INTERNAL_PANIC | Not interpreted | Fatal panic, stop MPC + * USER_STACK_OVERFLOW | Faulting address & SPu | Fatal panic, stop MPC + * SYSTEM_STACK_OVERFLOW | Faulting address & SPu | Fatal panic, stop MPC + * UNALIGNED_LONG_ACCESS | Indicative Faulting address & SPu | Fatal panic, stop MPC + * EVENT_FIFO_OVERFLOW | 0 | Abort current task, stop MPC + * PARAM_FIFO_OVERFLOW | 0 | idem + * INTERFACE_NOT_BINDED | 0 | idem + * USER_PANIC | Not interpreted | idem + * UNBIND_INTERRUPT | Interrupt number | Do nothing, just return from interrupt. + * EVENT_FIFO_IN_USE | Destroy event Fifo while event already schedule (only for HostEE) + * \endverbatim + * + * \ingroup NMF_EE_TYPE + */ +typedef enum { + INTERNAL_PANIC = 1, + RESERVED_PANIC = 2, + USER_STACK_OVERFLOW = 3, + SYSTEM_STACK_OVERFLOW = 4, + UNALIGNED_LONG_ACCESS = 5, + EVENT_FIFO_OVERFLOW = 6, + PARAM_FIFO_OVERFLOW = 7, + INTERFACE_NOT_BINDED = 8, + USER_PANIC = 9, + UNBIND_INTERRUPT = 10, + EVENT_FIFO_IN_USE = 11 +} t_panic_reasonDescription; + +/*! + * \brief Define the source of the panic + * + * It indicates the source core of the panic message.\n + * It gives the member to use within \ref t_nmf_panic_data (which is a member of the t_nmf_service_data service data structure). + + * \ingroup NMF_EE_TYPE + */ +typedef enum { + HOST_EE, //!< If the source is the Executive Engine running on the ARM Core + MPC_EE //!< If the source is the Executive Engine running on one of the MPC Core +} t_panic_source; + +#endif diff --git a/drivers/staging/nmf-cm/ee/api/priority.idt b/drivers/staging/nmf-cm/ee/api/priority.idt new file mode 100644 index 00000000000..a276ba57727 --- /dev/null +++ b/drivers/staging/nmf-cm/ee/api/priority.idt @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef PRIORITY_IDT +#define PRIORITY_IDT + +/** + * 0 : background + * 1 : normal + * 2 : urgent + * 3 : + * 4 : CScall + * 5 : CScall + * 6 : IO (not linked with priority ordering) + */ +#define MAX_SCHEDULER_PRIORITY_NUMBER 7 +#define MAX_SCHEDULER_SUBPRIORITY_NUMBER 4 + +#endif + diff --git a/drivers/staging/nmf-cm/inc/nmf-def.h b/drivers/staging/nmf-cm/inc/nmf-def.h new file mode 100644 index 00000000000..345c8256212 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/nmf-def.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + /*! + * \brief NMF Version. + * + * This file contains the NMF Version. + * + * \defgroup NMF_VERSION NMF Version + * \ingroup COMMON + */ + +#ifndef __INC_NMF_DEF_H +#define __INC_NMF_DEF_H + +/*! + * \brief Current NMF version number + * + * \ingroup NMF_VERSION + */ +#define NMF_VERSION ((2 << 16) | (10 << 8) | (106)) + +/*! + * \brief Get NMF major version corresponding to NMF version number + * \ingroup NMF_VERSION + */ +#define VERSION_MAJOR(version) (((version) >> 16) & 0xFF) +/*! + * \brief Get NMF minor version corresponding to NMF version number + * \ingroup NMF_VERSION + */ +#define VERSION_MINOR(version) (((version) >> 8) & 0xFF) +/*! + * \brief Get NMF patch version corresponding to NMF version number + * \ingroup NMF_VERSION + */ +#define VERSION_PATCH(version) (((version) >> 0) & 0xFF) + +#endif /* __INC_NMF_DEF_H */ diff --git a/drivers/staging/nmf-cm/inc/nmf-limits.h b/drivers/staging/nmf-cm/inc/nmf-limits.h new file mode 100644 index 00000000000..a942e542233 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/nmf-limits.h @@ -0,0 +1,107 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Common Nomadik Multiprocessing Framework limits definition + * + * This file contains the limit definitions used into NMF. + * + * \warning Don't modify it since it is also hardcoded in tools + * + * \defgroup NMF_LIMITS NMF limits definition + * \ingroup COMMON + */ +#ifndef __INC_NMF_LIMITS_H +#define __INC_NMF_LIMITS_H + +/*! + * \brief Maximum interface name length + * + * Define the maximum interface name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_INTERFACE_NAME_LENGTH 32 + +/*! + * \brief Maximum interface method name length + * + * Define the maximum interface method name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_INTERFACE_METHOD_NAME_LENGTH 64 + +/*! + * \brief Maximum interface type name length + * + * Define the maximum interface type name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_INTERFACE_TYPE_NAME_LENGTH 128 + + +/*! + * \brief Maximum template name length + * + * Define the maximum template name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_TEMPLATE_NAME_LENGTH 128 + +/*! + * \brief Maximum component local name length + * + * Define the maximum component local name length inside a composite component allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_COMPONENT_NAME_LENGTH 32 + +/*! + * \brief Maximum property name length + * + * Define the maximum property name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_PROPERTY_NAME_LENGTH 32 + +/*! + * \brief Maximum property value length + * + * Define the maximum property value length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_PROPERTY_VALUE_LENGTH 128 + +/*! + * \brief Maximum attribute name length + * + * Define the maximum attribute name length allowed by NMF. + * + * \ingroup NMF_LIMITS + */ +#define MAX_ATTRIBUTE_NAME_LENGTH 32 + +/*! + * \brief Maximum fifo size allowed for binding component + * + * Define the maximum fifo size allowed for binding component allowed by NMF when calling + * CM_BindComponentFromHost and CM_BindComponentAsynchronous. + * + * \ingroup NMF_LIMITS + */ +#define MAX_COMMUNICATION_FIFO_SIZE 256 + +#define MAX_COMPONENT_FILE_PATH_LENGTH 1024 + +#endif /* __INC_NMF_LIMITS_H */ diff --git a/drivers/staging/nmf-cm/inc/nmf-tracedescription.h b/drivers/staging/nmf-cm/inc/nmf-tracedescription.h new file mode 100644 index 00000000000..9611803b978 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/nmf-tracedescription.h @@ -0,0 +1,324 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief NMF xti/stm trace format description + * + * \defgroup NMF_TRACE_FORMAT NMF xti/stm trace format description + * + * The NMF trace is output by either xti ip on 8815 or stm ip on 8820 and 8500. + * Each type of trace is output on a dedicated channel. Following is a description + * of each of this traces. + * + * Traces have generally a timestamp added by hardware but is not described here. + * \ingroup NMF_ABI + */ +#ifndef TRACE_FORMAT_H_ +#define TRACE_FORMAT_H_ + +#include <inc/nmf-limits.h> + +/*! + * \brief XTI/STM Channel where trace are dumped + * + * \note This type is only for defining constants, please not reference it. + * + * \note Ever if this format is able to be generated on same channel, Host EE & CM channel are separated + * in order to avoir concurrency and access STM IP without require mutual exclusion. + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + MPC_EE_CHANNEL = 100, //!< MPC EE channel (MPC activity) in 32bits bundle + CM_CHANNEL = 101, //!< CM channel (MPC deployment) in 64bits bundle + HOST_EE_CHANNEL = 151 //!< Host EE channel (deployment & activity) in 64bits bundle +} t_nmfTraceChannelDescription; + +/*! + * \brief Message trace type + * + * \note This type is only for defining constants, please not reference it. + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_TYPE_RESET = 1, //!< Reset trace type + TRACE_TYPE_COMPONENT = 2, //!< Component instantiate trace type + TRACE_TYPE_BIND = 3, //!< Component bind trace type + TRACE_TYPE_METHOD = 4, //!< Component method trace type + TRACE_TYPE_ACTIVITY = 5, //!< Activity trace type + TRACE_TYPE_PANIC = 6, //!< Panic trace type + TRACE_TYPE_COMMUNICATION = 7, //!< Communication trace type + TRACE_TYPE_ALLOCATOR = 8, //!< Allocator trace type + TRACE_TYPE_ALLOC = 9, //!< Alloc trace type + TRACE_TYPE_USER = 10 //!< User trace type +} t_nmfTraceTypeDescription; + +#define TRACE_MAJOR_VERSION 1 //!< Current major trace version number \ingroup NMF_TRACE_FORMAT +#define TRACE_MINOR_VERSION 2 //!< Current minor trace version number \ingroup NMF_TRACE_FORMAT + +/*! + * \brief Trace header description. + * + * \note XTI will add 64bits time-stamp in first field of this structure, but not generated by us ! + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceChannelHeader { + // t_uint64 timeStamp; + t_uint8 traceType; //!< Trace type + t_uint8 reserved; + t_uint16 traceSize; //!< Trace size (depending on trace type description) +}; + +/*! + * \brief Trace header union + * + * The purpose of this is to optimize header setting in one instruction. + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef union { + struct t_nmfTraceChannelHeader s; + t_uint32 v; +} t_nmfTraceChannelHeaderUnion; + + +/*! + * \brief Trace reset description + * + * Inform tools to reset their internal state because network will be dumped new time. + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceReset { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 minorVersion; //!< NMF trace format minor version + t_uint16 majorVersion; //!< NMF trace format major version +}; + +/** + * \brief Component instantiation trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_COMPONENT_COMMAND_ADD = 0x1, + TRACE_COMPONENT_COMMAND_REMOVE = 0x2 +} t_nmfTraceComponentCommandDescription; + + +/*! + * \brief Component instantiation trace description + * + * Component instantiation trace is generated each time an instance of a component is added or removed. + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceComponent { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceComponentCommandDescription + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA, in SMPEE: 0x1 + t_uint32 componentContext; //!< Component context belonging domain (DSP this or ARM class this) + t_uint32 componentUserContext; //!< User friendly component Id belonging the channel (CM handle or ARM class this) + t_uint8 componentLocalName[MAX_COMPONENT_NAME_LENGTH]; //!< local name of component as given by user (null terminated) + t_uint8 componentTemplateName[MAX_TEMPLATE_NAME_LENGTH];//!< template name of component (null terminated) +}; + +/** + * \brief Component binding trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_BIND_COMMAND_BIND_SYNCHRONOUS = 0x1, + TRACE_BIND_COMMAND_UNBIND_SYNCHRONOUS = 0x2, + TRACE_BIND_COMMAND_BIND_ASYNCHRONOUS = 0x3, + TRACE_BIND_COMMAND_UNBIND_ASYNCHRONOUS = 0x4 +} t_nmfTraceBindCommandDescription; + +/** + * \brief Component binding trace description + * + * \note clientComponentContext & serverComponentContext take value 0xffffffff when client or server are Component Manager. + * \note serverComponentContext take value 0x00000000 when binding to void. + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceBind { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceBindCommandDescription + t_uint16 reserved; + t_uint16 clientDomainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA, in SMPEE: 0x1 + t_uint16 serverDomainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA, in SMPEE: 0x1 + t_uint32 clientComponentContext; //!< Component context belonging domain (DSP this or ARM class this) + t_uint32 serverComponentContext; //!< Component context belonging domain (DSP this or ARM class this) + t_uint8 requiredItfName[MAX_INTERFACE_NAME_LENGTH]; //!< Required interface name + t_uint8 providedItfName[MAX_INTERFACE_NAME_LENGTH]; //!< Provided interface name +}; + +/*! + * \brief Component interface method name trace description + * + * For each methods of each interfaces provided by a component, one such trace is dumped. + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceMethod { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA, in SMPEE: 0x1 + t_uint16 reserved; + t_uint32 methodId; //!< Unique Method Id belonging the component + t_uint32 componentContext; //!< Component context belonging domain (DSP this or ARM class this) + t_uint8 methodName[MAX_INTERFACE_METHOD_NAME_LENGTH]; //!< Symbolic method name +}; + +/** + * \brief Activity trace trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_ACTIVITY_START = 0x1, //!< Start method + TRACE_ACTIVITY_END = 0x2, //!< End method + TRACE_ACTIVITY_POST = 0x3, //!< Post method + TRACE_ACTIVITY_CALL = 0x4, //!< Synchronous call method + TRACE_ACTIVITY_RETURN = 0x5 //!< Synchronous return method +} t_nmfTraceActivityCommandDescription; + +/*! + * \brief Execution Engine scheduling activity trace description + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceActivity { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceActivityCommandDescription + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA + t_uint32 componentContext; //!< Unique component Id (Component Handle for CM, Component this for EE) + t_uint32 methodId; //!< Unique Method Id belonging the component +}; + +/** + * \brief Component instantiation trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_COMMUNICATION_COMMAND_SEND = 0x1, + TRACE_COMMUNICATION_COMMAND_RECEIVE = 0x2 +} t_nmfTraceCommunicationCommandDescription; + +/** + * \brief Inter-processor communication signaling trace description + * + * Use when trigging interrupt through core. + * + * \note Not used on SMP EE + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceCommunication { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceCommunicationCommandDescription + t_uint16 reserved_0; + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA + t_uint16 remoteDomainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA +}; + +/** + * \brief Component instantiation trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_ALLOCATOR_COMMAND_CREATE = 0x1, + TRACE_ALLOCATOR_COMMAND_DESTROY = 0x2 +} t_nmfTraceAllocatorCommandDescription; + +/*! + * \brief Panic trace description + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceAllocator { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceAllocatorCommandDescription + t_uint16 allocId; //!< Memory allocator ID + t_uint32 size; //!< Memory allocator size + t_uint8 name[32]; //!< Memory allocator name +}; + +/** + * \brief Component instantiation trace command description + * + * \ingroup NMF_TRACE_FORMAT + */ +typedef enum { + TRACE_ALLOC_COMMAND_ALLOC = 0x1, + TRACE_ALLOC_COMMAND_FREE = 0x2 +} t_nmfTraceAllocCommandDescription; + +/*! + * \brief Panic trace description + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceAlloc { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 command; //!< See \ref t_nmfTraceAllocatorCommandDescription + t_uint16 allocId; //!< Memory allocator ID + t_uint32 offset; //!< Memory chunk offet + t_uint32 size; //!< Memory chunk size +}; + +/*! + * \brief Panic trace description + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTracePanic { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint16 reason; //!< See \ref t_panic_reason for description + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA + t_uint32 componentContext; //!< Unique component Id (Component Handle for CM, Component this for EE) + t_uint32 information1; //!< Reason dependent information 1st + t_uint32 information2; //!< Reason dependent information 2nd +}; + +/*! + * \brief User trace description + * + * \ingroup NMF_TRACE_FORMAT + */ +struct t_nmfTraceUser { + t_nmfTraceChannelHeaderUnion header; //!< Trace header + + t_uint32 key; //!< User key + t_uint16 domainId; //!< In CM: 0x01:Arm | 0x02:SAA | 0x03:SVA | 0x04:SIA + t_uint16 reserved; + t_uint32 componentContext; //!< Unique component Id (Component Handle for CM, Component this for EE) + t_uint32 callerAddress; //!< Unique code address belonging the component +}; + +/* +struct t_nmfTracePower{ + struct t_nmfTraceChannelHeader header; +}; +*/ + +#endif /* TRACE_FORMAT_H_ */ diff --git a/drivers/staging/nmf-cm/inc/nmf_type.idt b/drivers/staging/nmf-cm/inc/nmf_type.idt new file mode 100644 index 00000000000..e8cc4e09946 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/nmf_type.idt @@ -0,0 +1,64 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +#ifndef NMF_TYPE_H_ +#define NMF_TYPE_H_ + +/*! + * \defgroup NMF_COMMON_TYPE NMF Common Type + * \ingroup COMMON + */ + +/*! + * \brief Error type returned by NMF API routines + * + * Possible value describe by \ref t_nmf_errorDescription + * + * \ingroup NMF_COMMON_TYPE + */ +typedef t_sint8 t_nmf_error; + +/*! + * \brief Error type values + * + * \ingroup NMF_COMMON_TYPE + */ +typedef enum { + NMF_OK = 0, //!< No error + NMF_INVALID_PARAMETER = -2, //!< Invalid parameter + NMF_NO_MORE_MEMORY = -30, //!< Out of memory + NMF_INTERFACE_NOT_BINDED = -59, //!< Try to unbind not binded interface + NMF_INTERFACE_ALREADY_BINDED = -60, //!< Try to bind already binded interface + NMF_NO_SUCH_REQUIRED_INTERFACE = -63, //!< Interface name not required by a component + NMF_NO_SUCH_PROVIDED_INTERFACE = -64, //!< Interface name not provided by a component + NMF_COMPONENT_NOT_STOPPED = -80, //!< Component must be stopped to perform operation + NMF_INVALID_COMPONENT_STATE_TRANSITION = -81, //!< Invalid component state transition caused by user action + NMF_NO_SUCH_PROPERTY = -87, //!< Property name doesn't exported by the underlying component + NMF_NO_SUCH_ATTRIBUTE = -88, //!< Attribute name not shared (exported) by a component + NMF_NO_MESSAGE = -103, //!< No message available + NMF_FLUSH_MESSAGE = -106, //!< Message send after call to EE_FlushChannel() + NMF_INTEGRATION_ERROR0 = -112, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR1 = -113, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR2 = -114, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR3 = -115, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR4 = -116, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR5 = -117, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR6 = -118, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR7 = -119, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR8 = -120, //!< OS dependent integration Error [-112 -> -121] + NMF_INTEGRATION_ERROR9 = -121 //!< OS dependent integration Error [-112 -> -121] +} t_nmf_errorDescription; + +/*! + * \brief Define t_nmf_channel type that identify a communication channel between nmf and user. + * + * \ingroup NMF_COMMON_TYPE + */ +typedef t_uint32 t_nmf_channel; + +#endif /* NMF_TYPE_H_ */ diff --git a/drivers/staging/nmf-cm/inc/type.h b/drivers/staging/nmf-cm/inc/type.h new file mode 100644 index 00000000000..d6eafe9aea5 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/type.h @@ -0,0 +1,36 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/* inc/type.h - Programming Model. + * + * Copyright (c) 2006, 2007, 2008 STMicroelectronics. + * + * Reproduction and Communication of this document is strictly prohibited + * unless specifically authorized in writing by STMicroelectronics. + * + * Written by NMF team. + */ +#ifndef _NMF_TYPE_H_ +#define _NMF_TYPE_H_ + +#include <inc/typedef.h> + +PUBLIC IMPORT_SHARED void NMF_LOG(const char* fmt, ...); +PUBLIC IMPORT_SHARED void NMF_PANIC(const char* fmt, ...); + +#define NMF_ASSERT(cond) do { if(!(cond)) NMF_PANIC("NMF_ASSERT at %s:%d\n", (int)__FILE__, (int)__LINE__); } while(0) + +#ifndef EXPORT_NMF_COMPONENT + #define EXPORT_NMF_COMPONENT EXPORT_SHARED +#endif + +#ifndef IMPORT_NMF_COMPONENT + #define IMPORT_NMF_COMPONENT IMPORT_SHARED +#endif + +#endif /* _NMF_TYPE_H_ */ diff --git a/drivers/staging/nmf-cm/inc/typedef.h b/drivers/staging/nmf-cm/inc/typedef.h new file mode 100644 index 00000000000..97af9dec2c2 --- /dev/null +++ b/drivers/staging/nmf-cm/inc/typedef.h @@ -0,0 +1,193 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \defgroup COMMON Common types and definitions + * + * \defgroup NMF_COMMON NMF common definition + * \ingroup COMMON + * + * \defgroup NMF_ABI NMF ABI specification + * \warning This page is not for multimedia developers ! + */ +/*! + * \brief Primitive Type Definition + * + * \defgroup NMF_PRIMITIVE_TYPE Primitive type definition + * \ingroup COMMON + */ + +#ifndef NMF_TYPEDEF_H_ +#define NMF_TYPEDEF_H_ + +#undef PRIVATE +#define PRIVATE static //!< Private macro declaration \ingroup NMF_PRIMITIVE_TYPE + +#undef PUBLIC +#ifdef __cplusplus +#define PUBLIC extern "C" //!< Public macro declaration \ingroup NMF_PRIMITIVE_TYPE +#else +#define PUBLIC extern //!< Public macro declaration \ingroup NMF_PRIMITIVE_TYPE +#endif + +#if defined(__SYMBIAN32__) +/*! + * \brief Declared IMPORT_SHARED to allow dll/shared library creation + * + * \note Value depend on OS. + * + * \ingroup NMF_PRIMITIVE_TYPE + */ + #ifndef IMPORT_SHARED + #define IMPORT_SHARED IMPORT_C + #endif +/*! + * \brief Declared EXPORT_SHARED to allow dll/shared library creation + * + * \note Value depend on OS. + * + * \ingroup NMF_PRIMITIVE_TYPE + */ + #ifndef EXPORT_SHARED + #define EXPORT_SHARED EXPORT_C + #endif +#elif defined(LINUX) + #ifndef IMPORT_SHARED + #define IMPORT_SHARED + #endif + #ifndef EXPORT_SHARED + #define EXPORT_SHARED __attribute__ ((visibility ("default"))) + #endif +#else + #ifndef IMPORT_SHARED + #define IMPORT_SHARED + #endif + + #ifndef EXPORT_SHARED + #define EXPORT_SHARED + #endif +#endif + +/* + * Definition of type that are used by interface. + */ + +typedef unsigned int t_uword; +typedef signed int t_sword; + +#ifdef __flexcc2__ + +typedef unsigned char t_bool; + +#ifdef __mode16__ + +typedef signed char t_sint8; +typedef signed int t_sint16; +typedef signed long t_sint24; +typedef signed long t_sint32; +typedef signed long long t_sint40; +// bigger type are not handle on this mode + +typedef unsigned char t_uint8; +typedef unsigned int t_uint16; +typedef unsigned long t_uint24; +typedef unsigned long t_uint32; +typedef unsigned long long t_uint40; +// bigger type are not handle on this mode + +// shared addr type definition +//typedef __SHARED16 t_uint16 * t_shared_addr; +typedef void * t_shared_field; + +#else /* __mode16__ -> __mode24__ */ + +typedef signed char t_sint8; +typedef signed short t_sint16; +typedef signed int t_sint24; +typedef signed long t_sint32; +typedef signed long t_sint40; +typedef signed long t_sint48; +typedef signed long long t_sint56; + +typedef unsigned char t_uint8; +typedef unsigned short t_uint16; +typedef unsigned int t_uint24; +typedef unsigned long t_uint32; +typedef unsigned long t_uint40; +typedef unsigned long t_uint48; +typedef unsigned long long t_uint56; + +// shared addr type definition +//typedef __SHARED16 t_uint16 * t_shared_addr; +typedef t_uint24 t_shared_field; + +#endif /* MMDSP mode24 */ + +// shared register (ARM world) type definition +#if 0 +typedef struct { + t_uint16 lsb; + t_uint16 msb; +} t_shared_reg; +#endif +typedef t_uint32 t_shared_reg; + +typedef t_uint32 t_physical_address; + +#include <stwdsp.h> + +#else /* __flexcc2__ -> RISC 32 Bits */ + +#ifndef _HCL_DEFS_H +typedef unsigned char t_bool; //!< Boolean primitive type \ingroup NMF_PRIMITIVE_TYPE + +typedef unsigned char t_uint8; //!< Unsigned 8 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef signed char t_sint8; //!< Signed 8 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef unsigned short t_uint16; //!< Unsigned 16 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef signed short t_sint16; //!< Signed 16 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef unsigned long t_uint32; //!< Unsigned 32 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef signed long t_sint32; //!< Signed 32 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef unsigned long long t_uint64; //!< Unsigned 64 bits primitive type \ingroup NMF_PRIMITIVE_TYPE +typedef signed long long t_sint64; //!< Signed 64 bits primitive type \ingroup NMF_PRIMITIVE_TYPE + +typedef t_uint32 t_physical_address; +#endif /* _HCL_DEFS_H */ + +typedef unsigned long t_uint24; +typedef signed long t_sint24; +typedef unsigned long long t_uint48; +typedef signed long long t_sint48; + +// shared addr type definition +typedef t_uint32 t_shared_addr; + +// shared register (ARM world) type definition +typedef t_uint32 t_shared_reg; +typedef t_uint32 t_shared_field; + +#endif /* RISC 32 Bits */ + +/* + * Define boolean type + */ +#undef FALSE +#define FALSE 0 //!< Boolean FALSE value +#undef TRUE +#define TRUE 1 //!< Boolean TRUE value + +#ifndef NULL + #if defined __flexcc2__ || defined __SYMBIAN32__ + #define NULL (0x0) //!< Null type \ingroup NMF_PRIMITIVE_TYPE + #else + #define NULL ((void*)0x0) //!< Null type \ingroup NMF_PRIMITIVE_TYPE + #endif +#endif + +typedef t_uint32 t_nmf_component_handle; + +#endif /* NMF_TYPEDEF_H_ */ diff --git a/drivers/staging/nmf-cm/nmf/inc/channel_type.h b/drivers/staging/nmf-cm/nmf/inc/channel_type.h new file mode 100644 index 00000000000..7d439ebf0cf --- /dev/null +++ b/drivers/staging/nmf-cm/nmf/inc/channel_type.h @@ -0,0 +1,41 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Common Nomadik Multiprocessing Framework type definition + * + * This file contains the shared between cm and ee type definitions used into NMF for callback. + */ +/*! + * \defgroup _t_nmf_channel_flag t_nmf_channel_flag + * \ingroup NMF_COMMON + */ + +#ifndef __INC_CHANNEL_TYPE_H +#define __INC_CHANNEL_TYPE_H + +#include <inc/typedef.h> +#include <inc/nmf_type.idt> + +/*! + * \brief Define t_nmf_channel_flag type that allow to control if/how a new communication channel is created. + * \ingroup _t_nmf_channel_flag + */ +typedef t_uint32 t_nmf_channel_flag; + +#define NMF_CHANNEL_SHARED ((t_nmf_channel_flag)0) //!< \ingroup _t_nmf_channel_flag +#define NMF_CHANNEL_PRIVATE ((t_nmf_channel_flag)1) //!< \ingroup _t_nmf_channel_flag + +/*! + * \brief Define t_nmf_virtualInterruptHandler function type to allow to dispatch virtual interrupt + * \ingroup VIRTUAL_INTERRUPT + */ +typedef void (*t_nmf_virtualInterruptHandler)(void *interruptContext); + +#endif + diff --git a/drivers/staging/nmf-cm/nmf/inc/component_type.h b/drivers/staging/nmf-cm/nmf/inc/component_type.h new file mode 100644 index 00000000000..08b63b21225 --- /dev/null +++ b/drivers/staging/nmf-cm/nmf/inc/component_type.h @@ -0,0 +1,27 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Common Nomadik Multiprocessing Framework type definition + * + * This file contains the shared between cm and ee type definitions used into NMF for callback. + */ +#ifndef __INC_COMPONENT_TYPE_H +#define __INC_COMPONENT_TYPE_H + +#include <inc/typedef.h> + +/*! + * \brief Identifier of a component instance handle + * + * \ingroup NMF_COMMON + */ +typedef t_nmf_component_handle t_cm_instance_handle; + +#endif + diff --git a/drivers/staging/nmf-cm/nmf/inc/service_type.h b/drivers/staging/nmf-cm/nmf/inc/service_type.h new file mode 100644 index 00000000000..3e5473338ee --- /dev/null +++ b/drivers/staging/nmf-cm/nmf/inc/service_type.h @@ -0,0 +1,94 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Service type and data used through service callback. + * \defgroup NMF_SERVICE NMF Service Callback types and data definition + * \ingroup NMF_COMMON + */ +#ifndef SERVICE_TYPE_H +#define SERVICE_TYPE_H + +#include <ee/api/panic.idt> +#include <nmf/inc/component_type.h> +#include <share/inc/nmf.h> + +/*! + * \brief Define t_nmf_service_type type + * + * It gives the type of service message passed to service callback. + * \ingroup NMF_SERVICE + */ +typedef t_uint32 t_nmf_service_type; +#define NMF_SERVICE_PANIC ((t_nmf_service_type)0) //!< \ingroup NMF_SERVICE +#define NMF_SERVICE_SHUTDOWN ((t_nmf_service_type)1) //!< \ingroup NMF_SERVICE + +/* + * The following structured define each data structure used for each service type + * and given to each serviceCallback + */ + +/*! + * \brief Define t_nmf_panic_data type + * + * This is the data structure passed to the service callback (inside \ref t_nmf_service_data) + * when t_nmf_service_type == NMF_SERVICE_PANIC + * \ingroup NMF_SERVICE + */ +typedef struct { + t_panic_reason panicReason; //!< The reason of the panic + t_panic_source panicSource; //!< THe source of the panic (One of the MPC or the ARM-EE) + /*! + * union of structures containing specific info, depending on the panicSource + */ + union { + struct { + t_nmf_core_id coreid; //!< The coreId of the MPC on which the panic occured + t_cm_instance_handle faultingComponent; //!< The faulting component handle + t_uint32 panicInfo1; //!< First info (depend on \ref panicReason) + t_uint32 panicInfo2; //!< Second info (depend on \ref panicReason) + } mpc; //!< member to use if panicSource == MPC_EE + struct { + void * faultingComponent; //!< The faulting component handle + t_uint32 panicInfo1; //!< First info (depend on \ref panicReason) + t_uint32 panicInfo2; //!< Second info (depend on \ref panicReason) + } host; //!< member to use if panicSource == HOST_EE + } info; //!< union of structures containing specific info, depending on the panicSource +} t_nmf_panic_data; + +/*! + * \brief Define t_nmf_shutdown_data type + * + * This is the data structure passed to the service callback (inside \ref t_nmf_service_data) + * when t_nmf_service_type == NMF_SERVICE_SHUTDOWN + * \ingroup NMF_SERVICE + */ +typedef struct { + t_nmf_core_id coreid; //!< The coreId of the MPC on which has been shutdown +} t_nmf_shutdown_data; + +/*! + * \brief Define t_nmf_service_data type + * + * It gives the data passed to the service callbacks for each service type + * This is an union whose member to use is defined by the given \ref t_nmf_service_type + * + * \ingroup NMF_SERVICE + */ +typedef union { + t_nmf_panic_data panic; //!< if service_type == NMF_SERVICE_PANIC + t_nmf_shutdown_data shutdown; //!< if service_type == NMF_SERVICE_SHUTDOWN +} t_nmf_service_data; + +/*! + * \brief Define t_nmf_serviceCallback function type to allow to dispatch service message to user. + * \ingroup NMF_SERVICE + */ +typedef void (*t_nmf_serviceCallback)(void *contextHandler, t_nmf_service_type serviceType, t_nmf_service_data *serviceData); + +#endif //SERVICE_TYPE_H diff --git a/drivers/staging/nmf-cm/osal-kernel.c b/drivers/staging/nmf-cm/osal-kernel.c new file mode 100644 index 00000000000..8f547ba0ad9 --- /dev/null +++ b/drivers/staging/nmf-cm/osal-kernel.c @@ -0,0 +1,1162 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/** \file osal-kernel.c + * + * Implements NMF OSAL for Linux kernel-space environment + */ + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kthread.h> +#include <linux/mm.h> +#include <linux/semaphore.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> +#include <mach/prcmu.h> + +#include <trace/stm.h> + +#include <cm/engine/configuration/inc/configuration_status.h> + +#include "cmioctl.h" +#include "osal-kernel.h" +#include "cm_service.h" +#include "cmld.h" + +__iomem void *prcmu_base = NULL; +__iomem void *prcmu_tcdm_base = NULL; + +/* DSP Load Monitoring */ +#define FULL_OPP 100 +#define HALF_OPP 50 +static unsigned long running_dsp = 0; +static unsigned int dspLoadMonitorPeriod = 1000; +module_param(dspLoadMonitorPeriod, uint, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(dspLoadMonitorPeriod, "Period of the DSP-Load monitoring in ms"); +static unsigned int dspLoadHighThreshold = 85; +module_param(dspLoadHighThreshold, uint, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(dspLoadHighThreshold, "Threshold above which 100 APE OPP is requested"); +static unsigned int dspLoadLowThreshold = 35; +module_param(dspLoadLowThreshold, uint, S_IWUSR|S_IRUGO); +MODULE_PARM_DESC(dspLoadLowThreshold, "Threshold below which 100 APE OPP request is removed"); + +/** \defgroup ENVIRONMENT_INITIALIZATION Environment initialization + * Includes functions that initialize the Linux OSAL itself plus functions that + * are responsible to factor configuration objects needed to initialize Component Manager library + */ + +/** \defgroup OSAL_IMPLEMENTATION OSAL implementation + * Linux-specific implementation of the Component Manager OSAL interface. + */ + + +/** \ingroup ENVIRONMENT_INITIALIZATION + * Remaps IO, SDRAM and ESRAM regions + * + * \osalEnvironment NMF-Osal descriptor + * \return POSIX error code + */ +int remapRegions(void) +{ + unsigned i; + + /* Remap DSP base areas */ + for (i=0; i<NB_MPC; i++) { + osalEnv.mpc[i].baseL = ioremap_nocache((int)osalEnv.mpc[i].baseP, (1*ONE_MB)); + if(osalEnv.mpc[i].baseL == NULL){ + pr_err("%s: could not remap base address for %s\n", __func__, osalEnv.mpc[i].name); + return -ENOMEM; + } + } + + /* Remap hardware semaphores */ + osalEnv.hwsem_base = ioremap_nocache(HWSEM_BASE, (4*ONE_KB)); + if(osalEnv.hwsem_base == NULL){ + pr_err("%s: could not remap HWSEM Base\n", __func__); + return -ENOMEM; + } + + /* Remap _all_ ESRAM banks */ + osalEnv.esram_base = ioremap_nocache(ESRAM_BASE, cfgESRAMSize*ONE_KB); + if(osalEnv.esram_base == NULL){ + pr_err("%s: could not remap ESRAM Base\n", __func__); + return -ENOMEM; + } + memset(osalEnv.esram_base, 0x0, cfgESRAMSize*ONE_KB); + + + /* Allocate code and data sections for MPC (SVA, SIA) */ + for (i=0; i<NB_MPC; i++) { + /* Allocate MPC SDRAM code area */ + struct hwmem_mem_chunk mem_chunk; + size_t mem_chunk_length; + osalEnv.mpc[i].hwmemCode = hwmem_alloc(osalEnv.mpc[i].sdramCodeSize, + //HWMEM_ALLOC_HINT_CACHE_WB, + HWMEM_ALLOC_HINT_WRITE_COMBINE | HWMEM_ALLOC_HINT_UNCACHED, + HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE, + HWMEM_MEM_CONTIGUOUS_SYS); + if (IS_ERR(osalEnv.mpc[i].hwmemCode)) { + int err = PTR_ERR(osalEnv.mpc[i].hwmemCode); + osalEnv.mpc[i].hwmemCode = NULL; + pr_err("%s: could not allocate SDRAM Code for %s\n", + __func__, osalEnv.mpc[i].name); + return err; + } + osalEnv.mpc[i].sdramCodeL = hwmem_kmap(osalEnv.mpc[i].hwmemCode); + if (IS_ERR(osalEnv.mpc[i].sdramCodeL)) { + int err = PTR_ERR(osalEnv.mpc[i].sdramCodeL); + osalEnv.mpc[i].sdramCodeL = NULL; + pr_err("%s: could not map SDRAM Code for %s\n", __func__, osalEnv.mpc[i].name); + return err; + } + mem_chunk_length = 1; + (void)hwmem_pin(osalEnv.mpc[i].hwmemCode, &mem_chunk, &mem_chunk_length); + osalEnv.mpc[i].sdramCodeP = mem_chunk.paddr; + /* Allocate MPC SDRAM data area by taking care wether the data are shared or not */ + if (osalEnv.mpc[i].sdramDataSize == 0) { + /* size of 0 means shared data segment, reuse the same param as for first MPC */ + osalEnv.mpc[i].sdramDataP = osalEnv.mpc[0].sdramDataP; + osalEnv.mpc[i].sdramDataL = osalEnv.mpc[0].sdramDataL; + osalEnv.mpc[i].sdramDataSize = osalEnv.mpc[0].sdramDataSize; + } else { + /* If we do not share the data segment or if this is the first MPC */ + osalEnv.mpc[i].hwmemData = hwmem_alloc(osalEnv.mpc[i].sdramDataSize, + HWMEM_ALLOC_HINT_WRITE_COMBINE | HWMEM_ALLOC_HINT_UNCACHED, + HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE, + HWMEM_MEM_CONTIGUOUS_SYS); + if (IS_ERR(osalEnv.mpc[i].hwmemData)) { + int err = PTR_ERR(osalEnv.mpc[i].hwmemData); + osalEnv.mpc[i].hwmemData = NULL; + pr_err("%s: could not allocate SDRAM Data for %s\n", + __func__, osalEnv.mpc[i].name); + return err; + } + mem_chunk_length = 1; + (void)hwmem_pin(osalEnv.mpc[i].hwmemData, + &mem_chunk, &mem_chunk_length); + osalEnv.mpc[i].sdramDataP = mem_chunk.paddr; + osalEnv.mpc[i].sdramDataL = hwmem_kmap(osalEnv.mpc[i].hwmemData); + if (IS_ERR(osalEnv.mpc[i].sdramDataL)) { + int err = PTR_ERR(osalEnv.mpc[i].sdramDataL); + osalEnv.mpc[i].sdramDataL = NULL; + pr_err("%s: could not map SDRAM Data for %s\n", + __func__, osalEnv.mpc[i].name); + return err; + } + } + } + + return 0; +} + +/** \ingroup ENVIRONMENT_INITIALIZATION + * Unmaps IO, SDRAM and ESRAM regions + * + * \return POSIX error code + */ +void unmapRegions(void) +{ + unsigned i; + + /* Release SVA, SIA, Hardware sempahores and embedded SRAM mappings */ + for (i=0; i<NB_MPC; i++) { + if(osalEnv.mpc[i].baseL != NULL) + iounmap(osalEnv.mpc[i].baseL); + } + + if(osalEnv.hwsem_base != NULL) + iounmap(osalEnv.hwsem_base); + + if(osalEnv.esram_base != NULL) + iounmap(osalEnv.esram_base); + + /* + * Free SVA and SIA code and data sections or release their mappings + * according on how memory allocations has been achieved + */ + for (i=0; i<NB_MPC; i++) { + if (osalEnv.mpc[i].sdramCodeL != NULL) { + hwmem_unpin(osalEnv.mpc[i].hwmemCode); + hwmem_kunmap(osalEnv.mpc[i].hwmemCode); + if (osalEnv.mpc[i].hwmemCode != NULL) + hwmem_release(osalEnv.mpc[i].hwmemCode); + } + + /* If data segment is shared, we must free only the first data segment */ + if (((i == 0) || (osalEnv.mpc[i].sdramDataL != osalEnv.mpc[0].sdramDataL)) + && (osalEnv.mpc[i].sdramDataL != NULL)) { + hwmem_unpin(osalEnv.mpc[i].hwmemData); + hwmem_kunmap(osalEnv.mpc[i].hwmemData); + if (osalEnv.mpc[i].hwmemData != NULL) + hwmem_release(osalEnv.mpc[i].hwmemData); + } + } +} + + +/** \ingroup ENVIRONMENT_INITIALIZATION + * Fills a t_nmf_hw_mapping_desc object + * + * \param nmfHwMappingDesc Pointer to a t_nmf_hw_mapping_desc object + * \return POSIX error code + */ +int getNmfHwMappingDesc(t_nmf_hw_mapping_desc* nmfHwMappingDesc) +{ + + if (nmfHwMappingDesc == NULL) + return -ENXIO; + + nmfHwMappingDesc->esramDesc.systemAddr.physical = ESRAM_BASE; + nmfHwMappingDesc->esramDesc.systemAddr.logical = (t_cm_logical_address)osalEnv.esram_base; + nmfHwMappingDesc->esramDesc.size = cfgESRAMSize*ONE_KB; + + nmfHwMappingDesc->hwSemaphoresMappingBaseAddr.physical = HWSEM_BASE; + nmfHwMappingDesc->hwSemaphoresMappingBaseAddr.logical = (t_cm_logical_address)osalEnv.hwsem_base; + + return 0; +} + +/** \ingroup ENVIRONMENT_INITIALIZATION + * Fills a t_cm_system_address object + * + * \param mpcSystemAddress Pointer to a t_cm_system_address object + * \return POSIX error code + */ +void getMpcSystemAddress(unsigned i, t_cm_system_address* mpcSystemAddress) +{ + mpcSystemAddress->physical = (t_cm_physical_address)osalEnv.mpc[i].baseP; + mpcSystemAddress->logical = (t_cm_logical_address)osalEnv.mpc[i].baseL; +} + + +/** \ingroup ENVIRONMENT_INITIALIZATION + * Fills t_nmf_memory_segment objects for MPC code and data segments + * + * \param i Index of the MPC to initialize + * \param codeSegment Pointer to a t_nmf_memory_segment (code segment) + * \param dataSegment Pointer to a t_nmf_memory_segment (data segment) + * \return Always 0 + */ +void getMpcSdramSegments(unsigned i, t_nmf_memory_segment* codeSegment, t_nmf_memory_segment* dataSegment) +{ + codeSegment->systemAddr.logical = (t_cm_logical_address)osalEnv.mpc[i].sdramCodeL; + codeSegment->systemAddr.physical = osalEnv.mpc[i].sdramCodeP; + codeSegment->size = osalEnv.mpc[i].sdramCodeSize; + + dataSegment->systemAddr.logical = (t_cm_logical_address)osalEnv.mpc[i].sdramDataL; + dataSegment->systemAddr.physical = osalEnv.mpc[i].sdramDataP; + dataSegment->size = osalEnv.mpc[i].sdramDataSize; +} + +#ifdef CM_DEBUG_ALLOC +#include <linux/kallsyms.h> +struct cm_alloc cm_alloc; + +/** + * These routines initializes the structures used to trace all alloc/free. + * These are used in debug mode to track all memory leak about the allocations + * done through the OSAL. + */ +void init_debug_alloc(void) +{ + INIT_LIST_HEAD(&cm_alloc.chain); + spin_lock_init(&cm_alloc.lock); +} + +void cleanup_debug_alloc(void) +{ + struct cm_alloc_elem *entry, *next; + char buffer[128]; + + list_for_each_entry_safe(entry, next, &cm_alloc.chain, elem) { + sprint_symbol(buffer, (int)entry->caller); + pr_err("/!\\ ALLOC(size=%d) not freed from: 0x%p (%s)\n", + entry->size, entry->caller, buffer); + list_del(&entry->elem); + if ((void*)entry >= (void*)VMALLOC_START + && (void*)entry < (void*)VMALLOC_END) + vfree(entry); + else + kfree(entry); + } +} + +void dump_debug_alloc(void) +{ + struct cm_alloc_elem *entry, *next; + char buffer[128]; + + pr_err("Current allocated memory:\n"); + list_for_each_entry_safe(entry, next, &cm_alloc.chain, elem) { + sprint_symbol(buffer, (int)entry->caller); + pr_err("=> Alloc of size=%d from: 0x%p (%s)\n", + entry->size, entry->caller, buffer); + } +} +#endif + + +/** \ingroup OSAL_IMPLEMENTATION + * Called by CM_ProcessMpcEvent in interrupt/tasklet context. Schedules the DFC. + * Enqueues the new event in the process' message queue. + * + * \note This is _not_ called in response to internal events such as in + * response to a CM_InstantiateComponent. It is called when user-defined + * functions need to be called in skeletons. This behavior is different + * from 0.8.1 version. + */ +void OSAL_PostDfc(t_nmf_mpc2host_handle upLayerTHIS, t_uint32 methodIndex, t_event_params_handle ptr, t_uint32 size) +{ + /* skelwrapper has been created in CM_SYSCALL_BindComponentToCMCore and conveys per-process private data */ + t_skelwrapper* skelwrapper = (t_skelwrapper*)upLayerTHIS; + struct osal_msg* message; + + /* If the clannel has been closed, no more reader exists + => discard the message */ + if (skelwrapper->channelPriv->state == CHANNEL_CLOSED) { + pr_warning("%s: message discarded (channel closed)\n", + __func__ ); + return; + } + + /* Create a new message */ + message = kmalloc(sizeof(*message), GFP_ATOMIC); + if (!message) { + pr_err("%s: message discarded (alloc failed)\n", __func__ ); + return; + } + + /* Stuff it */ + plist_node_init(&message->msg_entry, 0); + message->msg_type = MSG_INTERFACE; + message->d.itf.skelwrap = skelwrapper; + message->d.itf.methodIdx = methodIndex; + message->d.itf.anyPtr = ptr; + message->d.itf.ptrSize = size; + + /* Enqueue it */ + /* Should be protected with the cmPriv->msgQueueLock held + But we know by design that we are safe here. (Alone here in + tasklet (soft-interrupt) context. + When accessed in process context, soft-irq are disable) + */ + spin_lock_bh(&skelwrapper->channelPriv->bh_lock); + plist_add(&message->msg_entry, &skelwrapper->channelPriv->messageQueue); + spin_unlock_bh(&skelwrapper->channelPriv->bh_lock); + + /* Wake up process' wait queue */ + wake_up_interruptible(&skelwrapper->channelPriv->waitq); +} + + +#define MAX_LOCKS 8 // max number of locks/semaphores creatable +static unsigned long semused = 0; // bit field for used semaphores +static unsigned long lockused = 0; // bit field for used mutexes +static struct mutex cmld_locks[MAX_LOCKS]; + +/** \ingroup OSAL_IMPLEMENTATION + */ +t_nmf_osal_sync_handle OSAL_CreateLock(void) +{ + int i; + + for (i=0; i<MAX_LOCKS; i++) + if (!test_and_set_bit(i, &lockused)) { + struct mutex* mutex = &cmld_locks[i]; + mutex_init(mutex); + return (t_nmf_osal_sync_handle)mutex; + } + + return (t_nmf_osal_sync_handle)NULL; +} + + +/** \ingroup OSAL_IMPLEMENTATION + */ +void OSAL_Lock(t_nmf_osal_sync_handle handle) +{ + // unfortunately there is no return value to this function + // so we cannot use 'down_interruptible()' + mutex_lock((struct mutex*)handle); +} + + +/** \ingroup OSAL_IMPLEMENTATION + */ +void OSAL_Unlock(t_nmf_osal_sync_handle handle) +{ + mutex_unlock((struct mutex*)handle); +} + + +/** \ingroup OSAL_IMPLEMENTATION + */ +void OSAL_DestroyLock(t_nmf_osal_sync_handle handle) +{ + int i; + + // clear the bit in the bits field about used locks + i = ((struct mutex*)handle - cmld_locks); + + clear_bit(i, &lockused); +} + +static struct semaphore cmld_semaphores[MAX_LOCKS]; +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * Goal: Use by CM to allow to synchronize with code running on mpc side. + * + * \param[in] value : Initial value of semaphore. + * + * \return handle of the Semaphore created + * + * Called by: + * - any CM API call + * + * \ingroup OSAL + */ +t_nmf_osal_sem_handle OSAL_CreateSemaphore(t_uint32 value) +{ + int i; + + for (i=0; i<MAX_LOCKS; i++) + if (!test_and_set_bit(i, &semused)) { + struct semaphore* sem = &cmld_semaphores[i]; + sema_init(sem, value); + return (t_nmf_osal_sem_handle)sem; + } + + return (t_nmf_osal_sem_handle)NULL; +} + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * Goal: Use by CM to allow to synchronize with code running on mpc side. This function can be called under + * Irq context by CM. + * + * param[in] : handle of the Semaphore for which we increase value and so potentially wake up thread. + * + * param[in] : aCtx is a hint to indicate to os that we are in a none normal context (e.g under interruption). + * + * Called by: + * - any CM API call + * + * \ingroup OSAL + */ +void OSAL_SemaphorePost(t_nmf_osal_sem_handle handle, t_uint8 aCtx) +{ + up((struct semaphore*)handle); +} + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * Goal: Use by CM to allow to synchronize with code running on mpc side. + * + * param[in] : handle of the Semaphore for which we decrease value and so potentially block current thread. + * + * param[in] : maximun time in ms after which the block thread is wake up. In this case function return SYNC_ERROR_TIMEOUT value. + * + * \return error number: SYNC_ERROR_TIMEOUT in case semaphore is not release withing timeOutInMs. + * + * Called by: + * - any CM API call + * + * \ingroup OSAL + */ +t_nmf_osal_sync_error OSAL_SemaphoreWaitTimed(t_nmf_osal_sem_handle handle, + t_uint32 timeOutInMs) +{ + if (down_timeout((struct semaphore*)handle, msecs_to_jiffies(timeOutInMs))) + return SYNC_ERROR_TIMEOUT; + else + return SYNC_OK; +} + +/*! + * \brief Description of the Synchronization part of the OS Adaptation Layer + * + * Goal: Use by CM to allow to synchronize with code running on mpc side. + * + * param[in] : handle of the Semaphore to be destroyed + * + * Called by: + * - any CM API call + * + * \ingroup OSAL + */ +void OSAL_DestroySemaphore(t_nmf_osal_sem_handle handle) +{ + int i; + + // clear the bit in the bits field about used locks + i = ((struct semaphore*)handle - cmld_semaphores); + + clear_bit(i, &semused); +} + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL alloc implementation + * + * In both OSAL_Alloc() and OSAL_Alloc_Zero() function, the strategy is to use + * kmalloc() as it is the more efficient and most common way to allocate memory. + * For big allocation, kmalloc may fail because memory is very fragmented + * (kmalloc() allocates contiguous memory). In that case, we fall to vmalloc() + * instead. + * In OSAL_Free(), we rely on the virtual address to know which of kfree() or + * vfree() to use (vmalloc() use its own range of virtual addresses) + */ +void* OSAL_Alloc(t_cm_size size) +{ +#ifdef CM_DEBUG_ALLOC + struct cm_alloc_elem *entry; + + if (size == 0) + return NULL; + + entry = kmalloc(size + sizeof(*entry), GFP_KERNEL); + + if (entry == NULL) { + entry = vmalloc(size + sizeof(*entry)); + + if (entry == NULL) { + pr_alert("%s: kmalloc(%d) and vmalloc(%d) failed\n", + __func__, (int)size, (int)size); + dump_debug_alloc(); + return NULL; + } + } + /* return address of the caller */ + entry->caller = __builtin_return_address(0); + entry->size = size; + + spin_lock(&cm_alloc.lock); + list_add_tail(&entry->elem, &cm_alloc.chain); + spin_unlock(&cm_alloc.lock); + + return entry->addr; +#else + void* mem; + + if (size == 0) + return NULL; + mem = kmalloc(size, GFP_KERNEL); + if (mem == NULL) { + mem = vmalloc(size); + if (mem == NULL) + pr_alert("CM (%s): No more memory (requested " + "size=%d) !!!\n", __func__, (int)size); + } + return mem; +#endif +} + + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL alloc implementation + */ +void* OSAL_Alloc_Zero(t_cm_size size) +{ +#ifdef CM_DEBUG_ALLOC + struct cm_alloc_elem *entry; + + if (size == 0) + return NULL; + + entry = kzalloc(size + sizeof(*entry), GFP_KERNEL); + if (entry == NULL) { + entry = vmalloc(size + sizeof(*entry)); + if (entry == NULL) { + pr_alert("%s: kmalloc(%d) and vmalloc(%d) failed\n", + __func__, (int)size, (int)size); + dump_debug_alloc(); + return NULL; + } else { + memset(entry, 0, size + sizeof(*entry)); + } + } + + /* return address of the caller */ + entry->caller = __builtin_return_address(0); + entry->size = size; + + spin_lock(&cm_alloc.lock); + list_add_tail(&entry->elem, &cm_alloc.chain); + spin_unlock(&cm_alloc.lock); + + return entry->addr; +#else + void* mem; + + if (size == 0) + return NULL; + mem = kzalloc(size, GFP_KERNEL); + if (mem == NULL) { + mem = vmalloc(size); + if (mem == NULL) + pr_alert("CM (%s): No more memory (requested " + "size=%d) !!!\n", __func__, (int)size); + else + memset(mem, 0, size); + } + + return mem; +#endif +} + + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL free implementation + */ +void OSAL_Free(void* mem) +{ +#ifdef CM_DEBUG_ALLOC + struct cm_alloc_elem *entry = container_of(mem, struct cm_alloc_elem, addr); + unsigned int i; + char pattern[4] = { 0xEF, 0xBE, 0xAD, 0xDE }; + + if (mem == NULL) + return; + + /* fill with a pattern to detect bad re-use of this area */ + for (i=0; i<entry->size; i++) + entry->addr[i] = pattern[i%4]; + + spin_lock(&cm_alloc.lock); + list_del(&entry->elem); + spin_unlock(&cm_alloc.lock); + + if ((void*)entry >= (void*)VMALLOC_START + && (void*)entry < (void*)VMALLOC_END) + vfree(entry); + else + kfree(entry); +#else + if (mem >= (void*)VMALLOC_START && mem < (void*)VMALLOC_END) + vfree(mem); + else + kfree(mem); +#endif +} + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL Copy implementation + * This copy some data from userspace (address to kernel space. + * This implementation differs on Symbian. + */ +t_cm_error OSAL_Copy(void *dst, const void *src, t_cm_size size) +{ + if (copy_from_user(dst, src, size)) + return CM_UNKNOWN_MEMORY_HANDLE; + return CM_OK; +} + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL write64 function implementation + */ +void OSAL_Write64(t_nmf_trace_channel channel, t_uint8 isTimestamped, t_uint64 value) +{ +#ifdef CONFIG_STM_TRACE + if (isTimestamped) + stm_tracet_64(channel, value); + else + stm_trace_64(channel, value); +#endif +} + + +/** \ingroup OSAL_IMPLEMENTATION + * OSAL log function implementation + */ +void OSAL_Log(const char *format, int param1, int param2, int param3, int param4, int param5, int param6) +{ + printk(format, param1, param2, param3, param4, param5, param6); +} + +/** + * compute the dsp load + * + * return -1 if in case of failure, a value between 0 and 100 otherwise + */ +static s8 computeDspLoad(t_cm_mpc_load_counter *oldCounter, t_cm_mpc_load_counter *counter) +{ + u32 t, l; + + if ((oldCounter->totalCounter == 0) && (oldCounter->loadCounter == 0)) + return -1; // Failure or not started ? + if ((counter->totalCounter == 0) && (counter->loadCounter == 0)) + return -1; // Failure or already stopped ? + + if (counter->totalCounter < oldCounter->totalCounter) + t = (u32)((((u64)-1) - oldCounter->totalCounter) + + counter->totalCounter + 1); + else + t = (u32)(counter->totalCounter - oldCounter->totalCounter); + + if (counter->loadCounter < oldCounter->loadCounter) + l = (u32)((((u64)-1) - oldCounter->loadCounter) + + counter->loadCounter + 1); + else + l = (u32)(counter->loadCounter - oldCounter->loadCounter); + + if (t == 0) // not significant + return -1; + + if (l > t) // not significant + return -1; + + return (l*100) / t; +} + +static void wakeup_process(unsigned long data) +{ + wake_up_process((struct task_struct *)data); +} + +/** + * Thread function entry for monitorin the CPU load + */ +static int dspload_monitor(void *idx) +{ + int i = (int)idx; + unsigned char current_opp_request = HALF_OPP; + struct mpcConfig *mpc = &osalEnv.mpc[i]; + struct timer_list timer; + + timer.function = wakeup_process; + timer.data = (unsigned long)current; + init_timer_deferrable(&timer); + + if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char*)mpc->name, + current_opp_request)) + pr_err("CM Driver: Add QoS failed\n"); + + /* init counter */ + if (CM_GetMpcLoadCounter(mpc->coreId, + &mpc->oldLoadCounter) != CM_OK) + pr_err("CM Driver: Failed to init load counter for %s\n", + mpc->name); + + while (!kthread_should_stop()) { + t_cm_mpc_load_counter loadCounter; + s8 load = -1; + unsigned long expire; + + __set_current_state(TASK_UNINTERRUPTIBLE); + + expire = msecs_to_jiffies(dspLoadMonitorPeriod) + jiffies; + + mod_timer(&timer, expire); + schedule(); + /* We can be woken up before the expiration of the timer + but we don't need to handle that case as the + computation of the DSP load takes that into account */ + + if (!test_bit(i, &running_dsp)) + continue; + + if (CM_GetMpcLoadCounter(mpc->coreId, + &loadCounter) != CM_OK) + loadCounter = mpc->oldLoadCounter; + + load = computeDspLoad(&mpc->oldLoadCounter, &loadCounter); + mpc->oldLoadCounter = loadCounter; + + if (load == -1) + continue; + /* check if we must request more opp */ + if ((current_opp_request == HALF_OPP) + && (load > dspLoadHighThreshold)) { + current_opp_request = FULL_OPP; + if (cm_debug_level) + pr_info("CM Driver: Request QoS OPP %d for %s\n", + current_opp_request, mpc->name); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + (char*)mpc->name, + current_opp_request); + } + /* check if we can request less opp */ + else if ((current_opp_request == FULL_OPP) + && (load < dspLoadLowThreshold)) { + current_opp_request = HALF_OPP; + if (cm_debug_level) + pr_info("CM Driver: Request QoS OPP %d for %s\n", + current_opp_request, mpc->name); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + (char*)mpc->name, + current_opp_request); + } + } + + del_singleshot_timer_sync(&timer); + if (cm_debug_level) + pr_info("CM Driver: Remove QoS OPP for %s\n", mpc->name); + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char*)mpc->name); + return 0; +} + +static int enable_auto_pm = 0; +module_param(enable_auto_pm, bool, S_IWUSR|S_IRUGO); + +/** \ingroup OSAL_IMPLEMENTATION + * Used by CM to disable a power resource + */ +void OSAL_DisablePwrRessource(t_nmf_power_resource resource, t_uint32 firstParam, t_uint32 secondParam) +{ + switch (resource) { + case CM_OSAL_POWER_SxA_CLOCK: { + unsigned idx = COREIDX(firstParam); + struct osal_msg msg; + + if (idx >= NB_MPC) { + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", + __func__, (int)resource, (unsigned)firstParam); + return; + } + + /* Stop the DSP load monitoring */ + clear_bit(idx, &running_dsp); + if (osalEnv.mpc[idx].monitor_tsk) { + kthread_stop(osalEnv.mpc[idx].monitor_tsk); + osalEnv.mpc[idx].monitor_tsk = NULL; + } + + /* Stop the DSP */ + if (regulator_disable(osalEnv.mpc[idx].mmdsp_regulator) < 0) + pr_err("CM Driver(%s): can't disable regulator %s-mmsdp\n", + __func__, osalEnv.mpc[idx].name); +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&osalEnv.mpc[idx].wakelock); +#endif + + /* Create and dispatch a shutdown service message */ + msg.msg_type = MSG_SERVICE; + msg.d.srv.srvType = NMF_SERVICE_SHUTDOWN; + msg.d.srv.srvData.shutdown.coreid = firstParam; + dispatch_service_msg(&msg); + break; + } + case CM_OSAL_POWER_SxA_AUTOIDLE: + switch (firstParam) { + case SVA_CORE_ID: + osalEnv.dsp_sleep.sva_auto_pm_enable = PRCMU_AUTO_PM_OFF; + osalEnv.dsp_sleep.sva_power_on = 0; + osalEnv.dsp_sleep.sva_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF; + break; + case SIA_CORE_ID: + osalEnv.dsp_sleep.sia_auto_pm_enable = PRCMU_AUTO_PM_OFF; + osalEnv.dsp_sleep.sia_power_on = 0; + osalEnv.dsp_sleep.sia_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF; + break; + default: + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", __func__, (int)resource, (unsigned)firstParam); + return; + } + if (enable_auto_pm) + prcmu_configure_auto_pm(&osalEnv.dsp_sleep, &osalEnv.dsp_idle); + break; + case CM_OSAL_POWER_SxA_HARDWARE: { + unsigned idx = COREIDX(firstParam); + if (idx >= NB_MPC) { + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", + __func__, (int)resource, (unsigned)firstParam); + return; + } + if (regulator_disable(osalEnv.mpc[idx].pipe_regulator) < 0) + pr_err("CM Driver(%s): can't disable regulator %s-pipe\n", + __func__, osalEnv.mpc[idx].name); + break; + } + case CM_OSAL_POWER_HSEM: + break; + case CM_OSAL_POWER_SDRAM: + break; + case CM_OSAL_POWER_ESRAM: { + int i; + /* firstParam: base address; secondParam: size + U8500_ESRAM_BASE is the start address of BANK 0, + BANK size=0x20000 */ + + /* Compute the relative end address of the range, + relative to base address of BANK1 */ + secondParam = (firstParam+secondParam-(U8500_ESRAM_BASE+0x20000)-1); + + /* if end is below base address of BANK1, it means that full + range of addresses is on Bank0 */ + if (((int)secondParam) < 0) + break; + /* Compute the index of the last bank accessed among + esram 1+2 and esram 3+4 banks */ + secondParam /= 0x40000; + WARN_ON(secondParam > 1); + + /* Compute the index of the first bank accessed among esram 1+2 + and esram 3+4 banks + Do not manage Bank 0 (secured, must be always ON) */ + if (firstParam < (U8500_ESRAM_BASE+0x20000)) + firstParam = 0; + else + firstParam = (firstParam-(U8500_ESRAM_BASE+0x20000))/0x40000; + + /* power off the banks 1+2 and 3+4 if accessed. */ + for (i=firstParam; i<=secondParam; i++) { + if (regulator_disable(osalEnv.esram_regulator[i]) < 0) + pr_err("CM Driver(%s): can't disable regulator" + "for esram bank %s\n", __func__, + i ? "34" : "12"); + } + break; + } + default: + pr_err("CM Driver(%s): resource %d unknown/not supported\n", + __func__, (int)resource); + } +} + +/** \ingroup OSAL_IMPLEMENTATION + * Used by CM to enable a power resource + */ +t_cm_error OSAL_EnablePwrRessource(t_nmf_power_resource resource, t_uint32 firstParam, t_uint32 secondParam) +{ + switch (resource) { + case CM_OSAL_POWER_SxA_CLOCK: { + unsigned idx = COREIDX(firstParam); + + if (idx > NB_MPC) { + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", __func__, (int)resource, (unsigned)firstParam); + return CM_INVALID_PARAMETER; + } + + /* Start the DSP */ +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&osalEnv.mpc[idx].wakelock); +#endif + if (regulator_enable(osalEnv.mpc[idx].mmdsp_regulator) < 0) + pr_err("CM Driver(%s): can't enable regulator %s-mmsdp\n", __func__, osalEnv.mpc[idx].name); + + /* Start the DSP load monitoring for this dsp */ + set_bit(idx, &running_dsp); + osalEnv.mpc[idx].monitor_tsk = kthread_run(&dspload_monitor, + (void*)idx, + "%s-loadd", + osalEnv.mpc[idx].name); + if (IS_ERR(osalEnv.mpc[idx].monitor_tsk)) { + pr_err("CM Driver: failed to start dspmonitord " + "thread: %ld\n", PTR_ERR(osalEnv.mpc[idx].monitor_tsk)); + osalEnv.mpc[idx].monitor_tsk = NULL; + } + break; + } + case CM_OSAL_POWER_SxA_AUTOIDLE: + switch (firstParam) { + case SVA_CORE_ID: + osalEnv.dsp_sleep.sva_auto_pm_enable = PRCMU_AUTO_PM_ON; + osalEnv.dsp_sleep.sva_power_on = PRCMU_AUTO_PM_POWER_ON_HSEM | PRCMU_AUTO_PM_POWER_ON_ABB_FIFO_IT; + osalEnv.dsp_sleep.sva_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_RAMRET_HWP_OFF; + break; + case SIA_CORE_ID: + osalEnv.dsp_sleep.sia_auto_pm_enable = PRCMU_AUTO_PM_ON; + osalEnv.dsp_sleep.sia_power_on = PRCMU_AUTO_PM_POWER_ON_HSEM | PRCMU_AUTO_PM_POWER_ON_ABB_FIFO_IT; + osalEnv.dsp_sleep.sia_policy = PRCMU_AUTO_PM_POLICY_DSP_OFF_RAMRET_HWP_OFF; + break; + default: + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", __func__, (int)resource, (unsigned)firstParam); + return CM_INVALID_PARAMETER; + } + if (enable_auto_pm) + prcmu_configure_auto_pm(&osalEnv.dsp_sleep, &osalEnv.dsp_idle); + break; + case CM_OSAL_POWER_SxA_HARDWARE: { + unsigned idx = COREIDX(firstParam); + + if (idx > NB_MPC) { + pr_err("CM Driver(%s(res=%d)): core %u unknown\n", __func__, (int)resource, (unsigned)firstParam); + return CM_INVALID_PARAMETER; + } + if (regulator_enable(osalEnv.mpc[idx].pipe_regulator) < 0) + pr_err("CM Driver(%s): can't enable regulator %s-pipe\n", __func__, osalEnv.mpc[idx].name); + break; + } + case CM_OSAL_POWER_HSEM: + return CM_OK; + case CM_OSAL_POWER_SDRAM: + break; + case CM_OSAL_POWER_ESRAM: + { + int i; + /* firstParam: base address; secondParam: size + U8500_ESRAM_BASE is the start address of BANK 0, + BANK size=0x20000 */ + + /* Compute the relative end address of the range, relative + to base address of BANK1 */ + secondParam = (firstParam+secondParam-(U8500_ESRAM_BASE+0x20000)-1); + + /* if end is below base address of BANK1, it means that full + range of addresses is on Bank0 */ + if (((int)secondParam) < 0) + break; + /* Compute the index of the last bank accessed among esram 1+2 + and esram 3+4 banks */ + secondParam /= 0x40000; + WARN_ON(secondParam > 1); + + /* Compute the index of the first bank accessed among esram 1+2 + and esram 3+4 banks + Do not manage Bank 0 (secured, must be always ON) */ + if (firstParam < (U8500_ESRAM_BASE+0x20000)) + firstParam = 0; + else + firstParam = (firstParam-(U8500_ESRAM_BASE+0x20000))/0x40000; + + /* power on the banks 1+2 and 3+4 if accessed. */ + for (i=firstParam; i<=secondParam; i++) { + if (regulator_enable(osalEnv.esram_regulator[i]) < 0) + pr_err("CM Driver(%s): can't enable regulator " + "for esram bank %s\n", __func__, + i ? "34" : "12"); + } + break; + } + default: + pr_err("CM Driver(%s): resource %x unknown/not supported\n", + __func__, (int)resource); + return CM_INVALID_PARAMETER; + } + + return CM_OK; +} + +/*! + * \brief Generate an OS-Panic. Called in from CM_ASSERT(). + * \ingroup CM_ENGINE_OSAL_API + */ +void OSAL_Panic(void) +{ + panic("FATAL ISSUE IN THE CM DRIVER !!"); +} +#include <mach/dcache.h> +/*! + * \brief Clean data cache in DDR in order to be accessible from peripheral. + * + * \ingroup CM_ENGINE_OSAL_API + */ +void OSAL_CleanDCache(t_uint32 startAddr, t_uint32 size) +{ +#if 0 + /* + * Currently, the code sections are non-cached/buffered, + * which normally doesn't required the maintenance done below. + * As the cost is low (doesn't do much thing), I keep it in case + * of the memory settings are changed later. + */ + + struct hwmem_region region; + struct mpcConfig *mpc; + t_uint32 endAddr = startAddr + size; + + if (startAddr >= (u32)osalEnv.mpc[0].sdramCodeL + && endAddr <= (u32)(osalEnv.mpc[0].sdramCodeL + + osalEnv.mpc[0].sdramCodeSize)) { + mpc = &osalEnv.mpc[0]; + } else if (startAddr >= (u32)osalEnv.mpc[1].sdramCodeL + && endAddr <= (u32)(osalEnv.mpc[1].sdramCodeL + + osalEnv.mpc[1].sdramCodeSize)) { + mpc = &osalEnv.mpc[1]; + } else { + /* The code may be in esram, in that case, nothing to do */ + return; + } + + region.offset = startAddr - (u32)mpc->sdramCodeL; + region.count = 1; + region.start = 0; + region.end = size; + region.size = size; + hwmem_set_domain(mpc->hwmemCode, HWMEM_ACCESS_READ, + HWMEM_DOMAIN_SYNC, ®ion); + /* + * The hwmem keep track of region being sync or not. + * Mark the region as being write-accessed here right now + * to let following clean being done as expected. Today, + * there is no other place to do that in CM Core right now + */ + hwmem_set_domain(mpc->hwmemCode, HWMEM_ACCESS_WRITE, + HWMEM_DOMAIN_CPU, ®ion); +#else + dsb(); + outer_cache.sync(); +#endif +} + +/*! + * \brief Flush write-buffer of L2 cache + * + * \ingroup CM_ENGINE_OSAL_API + */ +void OSAL_mb(void) +{ + mb(); +} + +/*! + * \brief return prcmu timer value. + * + * This is need for perfmeter api (see \ref t_nmf_power_resource) + * + * \ingroup CM_ENGINE_OSAL_API + */ +t_uint64 OSAL_GetPrcmuTimer() +{ + t_uint64 msbBefore; + t_uint32 lsb; + t_uint64 msbAfter; + + /* read prcmu timers */ + msbBefore = ~ioread32(prcmu_tcdm_base+0xDE4); + lsb = ~ioread32(prcmu_base+0x454); + msbAfter = ~ioread32(prcmu_tcdm_base+0xDE4); + + /* handle rollover test case */ + // NOTE : there is still a window in prcmu side between counter rollover + // and prcmu interrupt handling + // to update msb register => this can lead to erroneous value return here + if (msbBefore == msbAfter || lsb >= 0x80000000UL) + return (((msbBefore & 0xffffffUL) << 32) + lsb); + else + return (((msbAfter & 0xffffffUL) << 32) + lsb); +} + +/*! + * \brief Disable the service message handling (panic, etc) + * + * It must disable the handling of all service messages + * If a service message is currently handled, it must wait till the end + * of its managment before returning. + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_DisableServiceMessages(void) { + tasklet_disable(&cmld_service_tasklet); +} + +/*! + * \brief Enable the service message handling (panic, etc) + * + * It enables the handling of all service messages + * + * \ingroup CM_ENGINE_OSAL_API + */ +PUBLIC void OSAL_EnableServiceMessages(void) { + tasklet_enable(&cmld_service_tasklet); +} diff --git a/drivers/staging/nmf-cm/osal-kernel.h b/drivers/staging/nmf-cm/osal-kernel.h new file mode 100644 index 00000000000..fd3b0acc301 --- /dev/null +++ b/drivers/staging/nmf-cm/osal-kernel.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef OSAL_KERNEL_H +#define OSAL_KERNEL_H + +#include <linux/interrupt.h> +#include <linux/hwmem.h> +#include <linux/regulator/consumer.h> +#ifdef CONFIG_HAS_WAKELOCK +#include <linux/wakelock.h> +#endif +#include <mach/prcmu.h> +#include <cm/engine/api/channel_engine.h> +#include <cm/engine/api/control/configuration_engine.h> +#include <cm/engine/api/perfmeter_engine.h> +#include <cm/engine/os_adaptation_layer/inc/os_adaptation_layer.h> + +#include "configuration.h" + +/** Per-MPC configuration structure */ +struct mpcConfig { + const t_nmf_core_id coreId; /**< MPC coreId */ + const char *name; /**< MPC name */ + t_uint8 nbYramBanks; /**< number of TCM ram banks to reserve for y memory */ + t_nmf_executive_engine_id eeId; /**< Type of Executive Engine */ + const void *baseP; /**< Physical base address of the MPC */ + void *baseL; /**< Remapped base address of the MPC */ + struct hwmem_alloc *hwmemCode; /**< hwmem code segment */ + u32 sdramCodeP; /**< Physical base address for MPC SDRAM Code region */ + void *sdramCodeL; /**< Remapped base address for MPC SDRAM Code region */ + size_t sdramCodeSize; /**< Size of MPC SDRAM Code region */ + struct hwmem_alloc *hwmemData; /**< hwmem data segment */ + u32 sdramDataP; /**< Physical base address for MPC SDRAM Data region */ + void *sdramDataL; /**< Remapped base address for MPC SDRAM Data region */ + size_t sdramDataSize; /**< Size of MPC SDRAM Data region */ + const unsigned int interrupt0; /**< interrupt line triggered by the MPC, for MPC events (if HSEM not used) */ + const unsigned int interrupt1; /**< interrupt line triggered by the MPC, for PANIC events */ + struct tasklet_struct tasklet; /**< taskket used to process MPC events */ + struct regulator *mmdsp_regulator; /**< mmdsp regulator linked to this MPC */ + struct regulator *pipe_regulator; /**< hardware pipe linked to this MPC */ +#ifdef CONFIG_HAS_WAKELOCK + struct wake_lock wakelock; /**< wakelock for this MPC to prevent ARM to go in APSLEEP state */ +#endif + struct task_struct *monitor_tsk;/**< task to monitor the dsp load; */ + t_cm_mpc_load_counter oldLoadCounter; /**< previous load counter of the DSP */ +}; + +/** Describes current Kernel OSAL environment + * + * Note about mpc.tasklet : we declare one tasklet per MPC but their usage depends + * on cfgSemaphoreTypeHSEM. + * + * This tasklet is scheduled by the interrupt handler to process MPC Events. + * - If we use Hardware Semaphore, there is only one interrupt handler used + * and thus only one tasklet, tasklet of MPC 0 (ie osalEnv.mpc[0].tasklet) + * - If we use local semaphore, there is one interrupt handler and tasklet per mpc + */ +struct OsalEnvironment +{ + struct mpcConfig mpc[NB_MPC]; + void* hwsem_base; /** < Remapped base address of the hardware semaphores */ + void* esram_base; /** < Remapped base address for embedded RAM used within the CM */ + struct regulator *esram_regulator[NB_ESRAM]; /**< regulator for ESRAM bank 1+2 and 3+4 */ + struct prcmu_auto_pm_config dsp_sleep; + struct prcmu_auto_pm_config dsp_idle; +}; + + +/** Structure used to store the skeleton related data. + * It is used for communicattion from a MPC to a user process (=host) + */ +typedef struct { + struct list_head entry; /**< Doubly linked list descriptor */ + t_cm_bf_mpc2host_handle mpc2hostId; /**< mpc2host ID */ + t_nmf_mpc2host_handle upperLayerThis;/**< upper-layer handle */ + struct cm_channel_priv* channelPriv; /**< Per-channel private data. The actual message queue is hold here */ +} t_skelwrapper; + +/** Message description for MPC to HOST communication + */ +struct osal_msg { + struct { + struct plist_node entry; /**< Doubly linked list descriptor */ + t_message_type type; /**< Type of message (callback, service or interrupt for now) */ + } hdr; /**< Header of the message */ +#define msg_entry hdr.entry +#define msg_type hdr.type + union { + struct { + t_skelwrapper *skelwrap; /**< Link to the skelwrapper, to retrieve the channel on which this message has to be forwarded */ + t_uint32 methodIdx; /**< callback data: method index*/ + t_event_params_handle anyPtr; /**< callback data: method parameters */ + t_uint32 ptrSize; /**< size of the parameters */ + } itf; /**< structure holding callback data */ + struct { + t_nmf_service_type srvType; /**< Type of the service */ + t_nmf_service_data srvData; /**< Data of the service */ + } srv; /**< structure holding service data */ + } d; /**< data */ +}; + +extern struct OsalEnvironment osalEnv; + +/** Environment initialization/deinitialization */ +int remapRegions(void); +void unmapRegions(void); + +/** Component manager configuration getters for CM_ENGINE_Init() */ +int getNmfHwMappingDesc(t_nmf_hw_mapping_desc* nmfHwMappingDesc); + +/** Component manager configuration getters for CM_ConfigureMediaProcessorCore (SVA and SIA) */ +void getMpcSystemAddress(unsigned i, t_cm_system_address* mpcSystemAddress); +void getMpcSdramSegments(unsigned i, t_nmf_memory_segment* codeSegment, t_nmf_memory_segment* dataSegment); + +#ifdef CM_DEBUG_ALLOC +struct cm_alloc { + spinlock_t lock; + struct list_head chain; +}; + +struct cm_alloc_elem { + struct list_head elem; + void *caller; + size_t size; + char addr[0]; +}; + +void init_debug_alloc(void); +void cleanup_debug_alloc(void); +#endif /* CM_DEBUG_ALLOC */ + +/* TODO: To remove later */ +extern __iomem void *prcmu_base; +extern __iomem void *prcmu_tcdm_base; +extern const char *cmld_devname[]; + +#define PRCM_SVAMMDSPCLK_MGT (prcmu_base + 0x008) +#define PRCM_SIAMMDSPCLK_MGT (prcmu_base + 0x00c) + +#endif /* OSAL_KERNEL_H */ diff --git a/drivers/staging/nmf-cm/share/communication/inc/communication_fifo.h b/drivers/staging/nmf-cm/share/communication/inc/communication_fifo.h new file mode 100644 index 00000000000..ea24e82ceae --- /dev/null +++ b/drivers/staging/nmf-cm/share/communication/inc/communication_fifo.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_NMF_COM_FIFO +#define __INC_NMF_COM_FIFO + +#include <inc/typedef.h> + +#define EVENT_ELEM_METHOD_IDX 0 +#define EVENT_ELEM_PARAM_IDX 1 +#define EVENT_ELEM_EXTFIELD_IDX 2 + +#define EVENT_ELEM_SIZE_IN_BYTE (3 * sizeof(t_shared_field)) + +#endif /* __INC_NMF_COM_FIFO */ diff --git a/drivers/staging/nmf-cm/share/communication/inc/initializer.h b/drivers/staging/nmf-cm/share/communication/inc/initializer.h new file mode 100644 index 00000000000..ea5aa68f2dc --- /dev/null +++ b/drivers/staging/nmf-cm/share/communication/inc/initializer.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_SHARE_INITIALIZER +#define __INC_SHARE_INITIALIZER + +#define NMF_CONSTRUCT_INDEX 0 +#define NMF_START_INDEX 1 +#define NMF_STOP_INDEX 2 +#define NMF_DESTROY_INDEX 3 +#define NMF_UPDATE_STACK 4 +#define NMF_LOCK_CACHE 5 +#define NMF_UNLOCK_CACHE 6 +#define NMF_ULP_FORCEWAKEUP 7 +#define NMF_ULP_ALLOWSLEEP 8 +#define NMF_CONSTRUCT_SYNC_INDEX 9 +#define NMF_START_SYNC_INDEX 10 + +/* + * Index of datas in command parameter format + */ +#define INIT_COMPONENT_CMD_HANDLE_INDEX 0 +#define INIT_COMPONENT_CMD_THIS_INDEX 2 +#define INIT_COMPONENT_CMD_METHOD_INDEX 4 +#define INIT_COMPONENT_CMD_SIZE 6 + +/* + * Index of datas in acknowledge parameter format + */ +#define INIT_COMPONENT_ACK_HANDLE_INDEX 0 +#define INIT_COMPONENT_ACK_SIZE 2 + +#endif /* __INC_SHARE_INITIALIZER */ diff --git a/drivers/staging/nmf-cm/share/communication/inc/nmf_fifo_desc.h b/drivers/staging/nmf-cm/share/communication/inc/nmf_fifo_desc.h new file mode 100644 index 00000000000..99caa48b05c --- /dev/null +++ b/drivers/staging/nmf-cm/share/communication/inc/nmf_fifo_desc.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_NMF_FIFO_DESC +#define __INC_NMF_FIFO_DESC + +#include <inc/typedef.h> +#include <share/semaphores/inc/semaphores.h> + +/* + * SHOULD be mapped onto a AHB burst (16 bytes=8x16-bit) + */ +typedef struct { + t_semaphore_id semId; + + t_uint16 elemSize; + t_uint16 fifoFullValue; + t_uint16 readIndex; + t_uint16 writeIndex; + t_uint16 wrappingValue; + + t_uint32 extendedField; /* in DSP 24 memory when to MPC in Logical Host when to ARM */ +} t_nmf_fifo_desc; + +#define EXTENDED_FIELD_BCTHIS_OR_TOP 0 //<! This field will be used: + //<! - as hostBCThis for DSP->HOST binding + //<! - as TOP else +#define EXTENDED_FIELD_BCDESC 1 //<! This field will be used for: + //<! - interface method address for ->MPC binding + //<! - for params size for ->Host binding (today only [0] is used as max size) + +#endif /* __INC_NMF_FIFO */ diff --git a/drivers/staging/nmf-cm/share/communication/inc/nmf_service.h b/drivers/staging/nmf-cm/share/communication/inc/nmf_service.h new file mode 100644 index 00000000000..5ec08434492 --- /dev/null +++ b/drivers/staging/nmf-cm/share/communication/inc/nmf_service.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_NMF_SERVICE_H +#define __INC_NMF_SERVICE_H + +/* 1 - 0xff Reserved for Panic Reason */ +#define MPC_SERVICE_NONE 0 +#define MPC_SERVICE_BOOT 0xB001 +#define MPC_SERVICE_PRINT 0x1234 + +#endif diff --git a/drivers/staging/nmf-cm/share/inc/macros.h b/drivers/staging/nmf-cm/share/inc/macros.h new file mode 100644 index 00000000000..c96fe031c25 --- /dev/null +++ b/drivers/staging/nmf-cm/share/inc/macros.h @@ -0,0 +1,214 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief NMF Macro API. + */ + +#ifndef _COMMON_MACROS_H_ +#define _COMMON_MACROS_H_ + +#undef ALIGN_VALUE +#define ALIGN_VALUE(value, alignment) (((value) + (alignment - 1)) & ~(alignment - 1)) + +#undef MIN +#define MIN(a,b) (((a)>(b))?(b):(a)) + +#undef MAX +#define MAX(a,b) (((a)<(b))?(b):(a)) + +/*----------------------------------------------------------------------------- + * endianess switch macros (32 bits and 16 bits) + *---------------------------------------------------------------------------*/ +#define ENDIANESS_32_SWITCH(value) ( \ + (((value) & MASK_BYTE3) >> SHIFT_BYTE3) | \ + (((value) & MASK_BYTE2) >> SHIFT_BYTE1) | \ + (((value) & MASK_BYTE1) << SHIFT_BYTE1) | \ + (((value) & MASK_BYTE0) << SHIFT_BYTE3) \ + ) + +#define ENDIANESS_16_SWITCH(value) ( \ + (((value) & MASK_BYTE0) << SHIFT_BYTE1) | \ + (((value) & MASK_BYTE1) >> SHIFT_BYTE1) \ + ) + +/*----------------------------------------------------------------------------- + * field offset extraction from a structure + *---------------------------------------------------------------------------*/ +#undef FIELD_OFFSET +#define FIELD_OFFSET(typeName, fieldName) ((t_uint32)(&(((typeName *)0)->fieldName))) + +#undef MASK_BIT +#define MASK_BIT(n) (1UL << ((n) - 1)) + +/*----------------------------------------------------------------------------- + * Misc definition + *---------------------------------------------------------------------------*/ + +#undef ONE_KB +#define ONE_KB (1024) +#undef ONE_MB +#define ONE_MB (ONE_KB * ONE_KB) + +/*----------------------------------------------------------------------------- + * Bit mask definition + *---------------------------------------------------------------------------*/ +#undef MASK_NULL8 +#define MASK_NULL8 0x00U +#undef MASK_NULL16 +#define MASK_NULL16 0x0000U +#undef MASK_NULL32 +#define MASK_NULL32 0x00000000UL +#undef MASK_ALL8 +#define MASK_ALL8 0xFFU +#undef MASK_ALL16 +#define MASK_ALL16 0xFFFFU +#undef MASK_ALL32 +#define MASK_ALL32 0xFFFFFFFFUL + +#undef MASK_BIT0 +#define MASK_BIT0 (1UL<<0) +#undef MASK_BIT1 +#define MASK_BIT1 (1UL<<1) +#undef MASK_BIT2 +#define MASK_BIT2 (1UL<<2) +#undef MASK_BIT3 +#define MASK_BIT3 (1UL<<3) +#undef MASK_BIT4 +#define MASK_BIT4 (1UL<<4) +#undef MASK_BIT5 +#define MASK_BIT5 (1UL<<5) +#undef MASK_BIT6 +#define MASK_BIT6 (1UL<<6) +#undef MASK_BIT7 +#define MASK_BIT7 (1UL<<7) +#undef MASK_BIT8 +#define MASK_BIT8 (1UL<<8) +#undef MASK_BIT9 +#define MASK_BIT9 (1UL<<9) +#undef MASK_BIT10 +#define MASK_BIT10 (1UL<<10) +#undef MASK_BIT11 +#define MASK_BIT11 (1UL<<11) +#undef MASK_BIT12 +#define MASK_BIT12 (1UL<<12) +#undef MASK_BIT13 +#define MASK_BIT13 (1UL<<13) +#undef MASK_BIT14 +#define MASK_BIT14 (1UL<<14) +#undef MASK_BIT15 +#define MASK_BIT15 (1UL<<15) +#undef MASK_BIT16 +#define MASK_BIT16 (1UL<<16) +#undef MASK_BIT17 +#define MASK_BIT17 (1UL<<17) +#undef MASK_BIT18 +#define MASK_BIT18 (1UL<<18) +#undef MASK_BIT19 +#define MASK_BIT19 (1UL<<19) +#undef MASK_BIT20 +#define MASK_BIT20 (1UL<<20) +#undef MASK_BIT21 +#define MASK_BIT21 (1UL<<21) +#undef MASK_BIT22 +#define MASK_BIT22 (1UL<<22) +#undef MASK_BIT23 +#define MASK_BIT23 (1UL<<23) +#undef MASK_BIT24 +#define MASK_BIT24 (1UL<<24) +#undef MASK_BIT25 +#define MASK_BIT25 (1UL<<25) +#undef MASK_BIT26 +#define MASK_BIT26 (1UL<<26) +#undef MASK_BIT27 +#define MASK_BIT27 (1UL<<27) +#undef MASK_BIT28 +#define MASK_BIT28 (1UL<<28) +#undef MASK_BIT29 +#define MASK_BIT29 (1UL<<29) +#undef MASK_BIT30 +#define MASK_BIT30 (1UL<<30) +#undef MASK_BIT31 +#define MASK_BIT31 (1UL<<31) + +/*----------------------------------------------------------------------------- + * quartet shift definition + *---------------------------------------------------------------------------*/ +#undef MASK_QUARTET +#define MASK_QUARTET (0xFUL) +#undef SHIFT_QUARTET0 +#define SHIFT_QUARTET0 0 +#undef SHIFT_QUARTET1 +#define SHIFT_QUARTET1 4 +#undef SHIFT_QUARTET2 +#define SHIFT_QUARTET2 8 +#undef SHIFT_QUARTET3 +#define SHIFT_QUARTET3 12 +#undef SHIFT_QUARTET4 +#define SHIFT_QUARTET4 16 +#undef SHIFT_QUARTET5 +#define SHIFT_QUARTET5 20 +#undef SHIFT_QUARTET6 +#define SHIFT_QUARTET6 24 +#undef SHIFT_QUARTET7 +#define SHIFT_QUARTET7 28 +#undef MASK_QUARTET0 +#define MASK_QUARTET0 (MASK_QUARTET << SHIFT_QUARTET0) +#undef MASK_QUARTET1 +#define MASK_QUARTET1 (MASK_QUARTET << SHIFT_QUARTET1) +#undef MASK_QUARTET2 +#define MASK_QUARTET2 (MASK_QUARTET << SHIFT_QUARTET2) +#undef MASK_QUARTET3 +#define MASK_QUARTET3 (MASK_QUARTET << SHIFT_QUARTET3) +#undef MASK_QUARTET4 +#define MASK_QUARTET4 (MASK_QUARTET << SHIFT_QUARTET4) +#undef MASK_QUARTET5 +#define MASK_QUARTET5 (MASK_QUARTET << SHIFT_QUARTET5) +#undef MASK_QUARTET6 +#define MASK_QUARTET6 (MASK_QUARTET << SHIFT_QUARTET6) +#undef MASK_QUARTET7 +#define MASK_QUARTET7 (MASK_QUARTET << SHIFT_QUARTET7) + +/*----------------------------------------------------------------------------- + * Byte shift definition + *---------------------------------------------------------------------------*/ +#undef MASK_BYTE +#define MASK_BYTE (0xFFUL) +#undef SHIFT_BYTE0 +#define SHIFT_BYTE0 0U +#undef SHIFT_BYTE1 +#define SHIFT_BYTE1 8U +#undef SHIFT_BYTE2 +#define SHIFT_BYTE2 16U +#undef SHIFT_BYTE3 +#define SHIFT_BYTE3 24U +#undef MASK_BYTE0 +#define MASK_BYTE0 (MASK_BYTE << SHIFT_BYTE0) +#undef MASK_BYTE1 +#define MASK_BYTE1 (MASK_BYTE << SHIFT_BYTE1) +#undef MASK_BYTE2 +#define MASK_BYTE2 (MASK_BYTE << SHIFT_BYTE2) +#undef MASK_BYTE3 +#define MASK_BYTE3 (MASK_BYTE << SHIFT_BYTE3) + +/*----------------------------------------------------------------------------- + * Halfword shift definition + *---------------------------------------------------------------------------*/ +#undef MASK_HALFWORD +#define MASK_HALFWORD (0xFFFFUL) +#undef SHIFT_HALFWORD0 +#define SHIFT_HALFWORD0 0U +#undef SHIFT_HALFWORD1 +#define SHIFT_HALFWORD1 16U +#undef MASK_HALFWORD0 +#define MASK_HALFWORD0 (MASK_HALFWORD << SHIFT_HALFWORD0) +#undef MASK_HALFWORD1 +#define MASK_HALFWORD1 (MASK_HALFWORD << SHIFT_HALFWORD1) + +#endif /* _COMMON_MACROS_H_ */ + diff --git a/drivers/staging/nmf-cm/share/inc/nmf.h b/drivers/staging/nmf-cm/share/inc/nmf.h new file mode 100644 index 00000000000..8be8b41e5e3 --- /dev/null +++ b/drivers/staging/nmf-cm/share/inc/nmf.h @@ -0,0 +1,47 @@ +/* + * 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, with + * user space exemption described in the top-level COPYING file in + * the Linux kernel source tree. + */ + +/*! + * \brief Common Nomadik Multiprocessing Framework type definition + * + * This file contains the shared type definitions used into NMF. + */ + +#ifndef __INC_NMF_H +#define __INC_NMF_H + +#include <inc/typedef.h> + +/*! + * \brief Identification of the various cores (host cpu and Media Processors) into Nomadik Platform + * In order to improve performance, these ids are those used to interconnect HW Semaphores IP with Cores (Interrupt lines) + * \ingroup NMF_COMMON + */ +#if defined(__STN_8500) + //#warning "TODO : mapping below is not correct, need to think how to change it" +#endif +typedef t_uint8 t_nmf_core_id; +#define ARM_CORE_ID ((t_nmf_core_id)0) //!< HOST CPU Id +#define SVA_CORE_ID ((t_nmf_core_id)1) //!< Smart Video Accelerator Media Processor Code Id +#define SIA_CORE_ID ((t_nmf_core_id)2) //!< Smart Imaging Accelerator Media Processor Code Id +#define NB_CORE_IDS ((t_nmf_core_id)3) + +#define FIRST_CORE_ID ((t_nmf_core_id)ARM_CORE_ID) +#define FIRST_MPC_ID ((t_nmf_core_id)SVA_CORE_ID) +#define LAST_CORE_ID ((t_nmf_core_id)SIA_CORE_ID) +#define LAST_MPC_ID ((t_nmf_core_id)SIA_CORE_ID) + + +/*! + * \brief Define minimal stack size use by execution engine + */ +#define MIN_STACK_SIZE 128 + + + +#endif /* __INC_NMF_H */ diff --git a/drivers/staging/nmf-cm/share/inc/nomadik_mapping.h b/drivers/staging/nmf-cm/share/inc/nomadik_mapping.h new file mode 100644 index 00000000000..bec221aa111 --- /dev/null +++ b/drivers/staging/nmf-cm/share/inc/nomadik_mapping.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_NOMADIK_MAPPING_H +#define __INC_NOMADIK_MAPPING_H + +/*--------------------------------------------------------------------------*/ +#if defined(__STN_8810) + +/* XTI (CPU OSMO/OSMOT address space) */ +#define XTI_CPU_BASE_ADDR 0x10000000 +#define XTI_CPU_END_ADDR 0x100FFFFF + +/* XTI configuration registers */ +#define XTI_CFG_REG_BASE_ADDR 0x101A0000 +#define XTI_CFG_REG_END_ADDR 0x101AFFFF + +/* Core APB Peripherals */ +#define CORE_APB_BASE_ADDR 0x101E0000 +#define CORE_APB_END_ADDR 0x101EFFFF + +/* DMA APB Peripherals */ +#define DMA_APB_BASE_ADDR 0x101F0000 +#define DMA_APB_END_ADDR 0x101FFFFF + +/* XTI (DSP OSMO/OSMOT address space) */ +#define XTI_DSP_BASE_ADDR 0x10200000 +#define XTI_DSP_END_ADDR 0x1020FFFF + +#endif /* defined(__STN_8810) */ + +/*--------------------------------------------------------------------------*/ +#if defined(__STN_8815) + +/* XTI (CPU OSMO/OSMOT address space) */ +#define XTI_CPU_BASE_ADDR 0x10000000 +#define XTI_CPU_END_ADDR 0x100FFFFF + +/* XTI configuration registers */ +#define XTI_CFG_REG_BASE_ADDR 0x101A0000 +#define XTI_CFG_REG_END_ADDR 0x101AFFFF + +/* Core APB Peripherals */ +#define CORE_APB_BASE_ADDR 0x101E0000 +#define CORE_APB_END_ADDR 0x101EFFFF + +/* DMA APB Peripherals */ +#define DMA_APB_BASE_ADDR 0x101F0000 +#define DMA_APB_END_ADDR 0x101FFFFF + +/* XTI (DSP OSMO/OSMOT address space) */ +#define XTI_DSP_BASE_ADDR 0x10220000 +#define XTI_DSP_END_ADDR 0x1022FFFF + +#endif /* defined(__STN_8815) */ + + +/*--------------------------------------------------------------------------*/ +#if defined(__STN_8820) + +/* STM (System Trace Module address space) */ +#define STM_BASE_ADDR 0x700F0000 +#define STM_END_ADDR 0x700FFFFF + +/* AHB2 Peripherals */ +#define AHB2_PERIPH_BASE_ADDR 0x70100000 +#define AHB2_PERIPH_END_ADDR 0x7010FFFF + +/* APB2 Peripherals */ +#define APB2_PERIPH_BASE_ADDR 0x70110000 +#define APB2_PERIPH_END_ADDR 0x7011FFFF + +/* APB1 Peripherals */ +#define APB1_PERIPH_BASE_ADDR 0x70120000 +#define APB1_PERIPH_END_ADDR 0x7012FFFF + +#endif /* defined(__STN_8820) */ + +/*--------------------------------------------------------------------------*/ +#if defined(__STN_8500) +/* STM (System Trace Module address space) */ +#define STM_BASE_ADDR 0x80100000 +#define STM_END_ADDR 0x8010FFFF + +#define HSEM_BASE_ADDR 0x80140000 +#define HSEM_END_ADDR 0x8014FFFF + +#define DMA_CTRL_BASE_ADDR 0x801C0000 +#define DMA_CTRL_END_ADDR 0x801C0FFF + + +#endif /* defined(__STN_8500) */ + +#endif /*__INC_NOMADIK_MAPPING_H */ diff --git a/drivers/staging/nmf-cm/share/semaphores/inc/hwsem_hwp.h b/drivers/staging/nmf-cm/share/semaphores/inc/hwsem_hwp.h new file mode 100644 index 00000000000..b573627beae --- /dev/null +++ b/drivers/staging/nmf-cm/share/semaphores/inc/hwsem_hwp.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_HWSEM_HWP_H +#define __INC_HWSEM_HWP_H + +#include <share/semaphores/inc/semaphores.h> + +#define CORE_ID_2_HW_CORE_ID(coreId) (1U << (coreId)) + +/* + * Definition of the number of hw semaphores into the Nomadik IP + */ +#define NUM_HW_SEMAPHORES 32 + + +/* + * Definition of how HSEM IP interrupts are interconnected with cores + */ +typedef enum { + HSEM_FIRST_INTR = 0, + HSEM_INTRA = HSEM_FIRST_INTR, + HSEM_INTRB = 1, + HSEM_INTRC = 2, + HSEM_INTRD = 3, + HSEM_INTRE = 4, + HSEM_MAX_INTR +} t_hw_semaphore_irq_id; + +/* + * Description of the registers of the HW Sem IP + */ +#define HSEM_INTRA_MASK (1<<(4+HSEM_INTRA)) +#define HSEM_INTRB_MASK (1<<(4+HSEM_INTRB)) +#define HSEM_INTRC_MASK (1<<(4+HSEM_INTRC)) +#define HSEM_INTRD_MASK (1<<(4+HSEM_INTRD)) +#define HSEM_INTRE_MASK (1<<(4+HSEM_INTRE)) + +typedef struct { + t_shared_reg imsc; + t_shared_reg ris; + t_shared_reg mis; + t_shared_reg icr; +} t_hsem_it_regs; + +typedef volatile struct { +#if defined(__STN_8500) + t_shared_reg cr; + t_shared_reg dummy; +#endif + t_shared_reg sem[NUM_HW_SEMAPHORES]; +#if defined(__STN_8820) + t_shared_reg RESERVED1[(0x90 - 0x80)>>2]; +#elif defined(__STN_8500) + t_shared_reg RESERVED1[(0x90 - 0x88)>>2]; +#else /* __STN_8820 or __STN_8500 -> _STN_8815 */ + t_shared_reg RESERVED1[(0x90 - 0x40)>>2]; +#endif /* __STN_8820 or __STN_8500 -> _STN_8815 */ + t_shared_reg icrall; + t_shared_reg RESERVED2[(0xa0 - 0x94)>>2]; + t_hsem_it_regs it[HSEM_MAX_INTR]; +#if defined(__STN_8820) || defined(__STN_8500) + t_shared_reg RESERVED3[(0x100 - 0xf0)>>2]; +#else /* __STN_8820 or __STN_8500 -> _STN_8815 */ + t_shared_reg RESERVED3[(0x100 - 0xe0)>>2]; +#endif /* __STN_8820 or __STN_8500 -> _STN_8815 */ + t_shared_reg itcr; + t_shared_reg RESERVED4; + t_shared_reg itop; + t_shared_reg RESERVED5[(0xfe0 - 0x10c)>>2]; + t_shared_reg pid0; + t_shared_reg pid1; + t_shared_reg pid2; + t_shared_reg pid3; + t_shared_reg pcid0; + t_shared_reg pcid1; + t_shared_reg pcid2; + t_shared_reg pcid3; +} t_hw_semaphore_regs, *tp_hw_semaphore_regs; + +#endif /* __INC_HWSEM_HWP_H */ diff --git a/drivers/staging/nmf-cm/share/semaphores/inc/semaphores.h b/drivers/staging/nmf-cm/share/semaphores/inc/semaphores.h new file mode 100644 index 00000000000..c72b64cd709 --- /dev/null +++ b/drivers/staging/nmf-cm/share/semaphores/inc/semaphores.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) ST-Ericsson SA 2010. All rights reserved. + * This code is ST-Ericsson proprietary and confidential. + * Any use of the code for whatever purpose is subject to + * specific written permission of ST-Ericsson SA. + */ + +#ifndef __INC_SHARED_SEMAPHORE_H +#define __INC_SHARED_SEMAPHORE_H + +#include <share/inc/nmf.h> + +typedef t_uint16 t_semaphore_id; + +/* + * HW semaphore allocation + * ----------------------- + * We want to optimize interrupt demultiplexing at dsp interrupt handler level + * so a good solution would be to have sequentially the semaphores for each neighbors + * + * STn8500 : + * --------- + * ARM <- SVA COMS => 0 + * ARM <- SIA COMS => 1 + * SVA <- ARM COMS => 2 + * SVA <- SIA COMS => 3 + * SIA <- ARM COMS => 4 + * SIA <- SVA COMS => 5 + + * The first neighbor is always the ARM, then the other ones (SVA,SIA) + */ + +/* + * Local semaphore allocation + * ----------------------- + * 0 : ARM <- DSP + * 1 : DSP <- ARM + */ + +#define NB_USED_HSEM_PER_CORE (NB_CORE_IDS - 1) +#define FIRST_NEIGHBOR_SEMID(coreId) ((coreId)*NB_USED_HSEM_PER_CORE) + +#endif /* __INC_SHARED_SEMAPHORE_H */ diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 07b41951e3f..4ed293cccec 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -164,7 +164,7 @@ struct kparam_array /* We don't get oldget: it's often a new-style param_get_uint, etc. */ static inline int -__check_old_set_param(int (*oldset)(const char *, struct kernel_param *)) +__check_old_set_param(int (*oldset)(const char *, const struct kernel_param *)) { return 0; } |