summaryrefslogtreecommitdiff
path: root/drivers/dsp/bridge/rmgr
diff options
context:
space:
mode:
authorSantosh Shilimkar <santosh.shilimkar@ti.com>2009-11-07 06:59:47 +0530
committerSantosh Shilimkar <santosh.shilimkar@ti.com>2009-11-07 06:59:47 +0530
commit9e034c986287a3338c393836f27e838b8f87539e (patch)
tree2a7cdc1384ad5f3ce230310e275cf17aa35db735 /drivers/dsp/bridge/rmgr
parent8aa5e79648ce7b16943456f2578b9b68573aac9c (diff)
parent3d8b36e8e6725484d6a5d7fc258afaf37ca2db96 (diff)
Merge branch 'tesla-dev-v2.6.31_wakeup' of git://dev.omapzoom.org/pub/scm/tisyslink/kernel-syslink into L24x-20091106
Conflicts: arch/arm/Kconfig arch/arm/plat-omap/include/mach/irqs.h drivers/Makefile
Diffstat (limited to 'drivers/dsp/bridge/rmgr')
-rw-r--r--drivers/dsp/bridge/rmgr/dbdcd.c1573
-rw-r--r--drivers/dsp/bridge/rmgr/disp.c916
-rwxr-xr-xdrivers/dsp/bridge/rmgr/drv.c1936
-rw-r--r--drivers/dsp/bridge/rmgr/drv_interface.c760
-rw-r--r--drivers/dsp/bridge/rmgr/drv_interface.h40
-rw-r--r--drivers/dsp/bridge/rmgr/dspdrv.c276
-rw-r--r--drivers/dsp/bridge/rmgr/mgr.c491
-rw-r--r--drivers/dsp/bridge/rmgr/nldr.c1967
-rw-r--r--drivers/dsp/bridge/rmgr/node.c3550
-rwxr-xr-xdrivers/dsp/bridge/rmgr/proc.c2111
-rw-r--r--drivers/dsp/bridge/rmgr/pwr.c184
-rw-r--r--drivers/dsp/bridge/rmgr/rmm.c604
-rw-r--r--drivers/dsp/bridge/rmgr/strm.c1066
13 files changed, 15474 insertions, 0 deletions
diff --git a/drivers/dsp/bridge/rmgr/dbdcd.c b/drivers/dsp/bridge/rmgr/dbdcd.c
new file mode 100644
index 000000000000..c5ec8f905c99
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/dbdcd.c
@@ -0,0 +1,1573 @@
+/*
+ * dbdcd.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== dbdcd.c ========
+ * Description:
+ * This file contains the implementation of the DSP/BIOS Bridge
+ * Configuration Database (DCD).
+ *
+ * Notes:
+ * The fxn DCD_GetObjects can apply a callback fxn to each DCD object
+ * that is located in a specified COFF file. At the moment,
+ * DCD_AutoRegister, DCD_AutoUnregister, and NLDR module all use
+ * DCD_GetObjects.
+ *
+ *! Revision History
+ *! ================
+ *! 03-Dec-2003 map Changed DCD_OBJTYPE to DSP_DCDOBJTYPE
+ *! 17-Dec-2002 map Modified DCD_GetDepLibs, DCD_GetNumDepLibs, GetDepLibInfo
+ *! to include phase information
+ *! 02-Dec-2002 map Modified DCD_GetLibraryName for phases in different
+ *! libraries
+ *! 26-Feb-2003 kc Updated DCD_AutoUnregister and DCD_GetObjects to simplify
+ *! DCD implementation.
+ *! 17-Jul-2002 jeh Call COD_Open() instead of COD_OpenBase(), call COD_Close()
+ *! 11-Jul-2002 jeh Added DCD_GetDepLibs(), DCD_GetNumDepLibs().
+ *! 18-Feb-2003 vp Code review updates
+ *! 18-Oct-2002 vp Ported to Linux platform
+ *! 15-Mar-2002 jeh Read dynamic loading memory requirements into node object
+ *! data. Added DCD_GetLibraryName().
+ *! 13-Feb-2002 jeh Get system stack size in GetAttrsFromBuf().
+ *! 01-Aug-2001 ag: Added check for PROC "extended" attributes used for
+ *! DSP-MMU setup. These are private attributes.
+ *! 18-Apr-2001 jeh Use COD_OpenBase instead of COD_LoadBase.
+ *! 03-Apr-2001 sg: Changed error names to DSP_EDCD* format.
+ *! 11-Jan-2001 jeh Changes to DCD_GetObjectDef to match node.cdb, proc.cdb.
+ *! 12-Dec-2000 kc: Added DCD_AutoUnregister. MSGNODE, DAISNODE added in
+ *! GetAttrsFromBuf
+ *! 22-Nov-2000 kc: Replaced sprintf() calls with strncat.
+ *! 09-Nov-2000 kc: Optimized DCD module.
+ *! 30-Oct-2000 kc: Added DCD_AutoRegister function; changed local var. names.
+ *! 29-Sep-2000 kc: Added code review changes (src/reviews/dcd_reviews.txt).
+ *! 06-Sep-2000 jeh Get message segid, message notification type. Added Atoi()
+ *! to replace atoi(), until cdb generation can output in
+ *! decimal format.
+ *! 26-Jul-2000 kc: Created.
+ *!
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/csl.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/reg.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cod.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/uuidutil.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dbdcd.h>
+
+/* ----------------------------------- Global defines. */
+#define SIGNATURE 0x5f444344 /* "DCD_" (in reverse). */
+
+#define IsValidHandle(h) (((h) != NULL) && (h->dwSignature == SIGNATURE))
+
+#define MAX_INT2CHAR_LENGTH 16 /* Maximum int2char len of 32 bit int. */
+
+/* Name of section containing dependent libraries */
+#define DEPLIBSECT ".dspbridge_deplibs"
+
+/* DCD specific structures. */
+struct DCD_MANAGER {
+ u32 dwSignature; /* Used for object validation. */
+ struct COD_MANAGER *hCodMgr; /* Handle to COD manager object. */
+};
+
+/* Global reference variables. */
+static u32 cRefs;
+static u32 cEnumRefs;
+
+extern struct GT_Mask curTrace;
+
+/* helper function prototypes. */
+static s32 Atoi(char *pszBuf);
+
+static DSP_STATUS GetAttrsFromBuf(char *pszBuf, u32 ulBufSize,
+ enum DSP_DCDOBJTYPE objType,
+ struct DCD_GENERICOBJ *pGenObj);
+
+static void CompressBuf(char *pszBuf, u32 ulBufSize, s32 cCharSize);
+
+static char DspChar2GppChar(char *pWord, s32 cDspCharSize);
+
+static DSP_STATUS GetDepLibInfo(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pUuid,
+ IN OUT u16 *pNumLibs,
+ OPTIONAL OUT u16 *pNumPersLibs,
+ OPTIONAL OUT struct DSP_UUID *pDepLibUuids,
+ OPTIONAL OUT bool *pPersistentDepLibs,
+ IN enum NLDR_PHASE phase);
+
+/*
+ * ======== DCD_AutoRegister ========
+ * Purpose:
+ * Parses the supplied image and resigsters with DCD.
+ */
+
+DSP_STATUS DCD_AutoRegister(IN struct DCD_MANAGER *hDcdMgr,
+ IN char *pszCoffPath)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_AutoRegister: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ if (IsValidHandle(hDcdMgr)) {
+ status = DCD_GetObjects(hDcdMgr, pszCoffPath,
+ (DCD_REGISTERFXN)DCD_RegisterObject,
+ (void *)pszCoffPath);
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_AutoRegister: invalid DCD manager handle.\n");
+ }
+
+ return status;
+}
+
+/*
+ * ======== DCD_AutoUnregister ========
+ * Purpose:
+ * Parses the supplied DSP image and unresiters from DCD.
+ */
+DSP_STATUS DCD_AutoUnregister(IN struct DCD_MANAGER *hDcdMgr,
+ IN char *pszCoffPath)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_AutoUnregister: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ if (IsValidHandle(hDcdMgr)) {
+ status = DCD_GetObjects(hDcdMgr, pszCoffPath,
+ (DCD_REGISTERFXN)DCD_RegisterObject,
+ NULL);
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_AutoUnregister: invalid DCD manager"
+ " handle.\n");
+ }
+
+ return status;
+}
+
+/*
+ * ======== DCD_CreateManager ========
+ * Purpose:
+ * Creates DCD manager.
+ */
+DSP_STATUS DCD_CreateManager(IN char *pszZlDllName,
+ OUT struct DCD_MANAGER **phDcdMgr)
+{
+ struct COD_MANAGER *hCodMgr; /* COD manager handle */
+ struct DCD_MANAGER *pDcdMgr = NULL; /* DCD Manager pointer */
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs >= 0);
+ DBC_Require(phDcdMgr);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_CreateManager: phDcdMgr 0x%x\n",
+ phDcdMgr);
+
+ status = COD_Create(&hCodMgr, pszZlDllName, NULL);
+ if (DSP_SUCCEEDED(status)) {
+
+ /* Create a DCD object. */
+ MEM_AllocObject(pDcdMgr, struct DCD_MANAGER, SIGNATURE);
+ if (pDcdMgr != NULL) {
+
+ /* Fill out the object. */
+ pDcdMgr->hCodMgr = hCodMgr;
+
+ /* Return handle to this DCD interface. */
+ *phDcdMgr = pDcdMgr;
+
+ GT_2trace(curTrace, GT_5CLASS,
+ "DCD_CreateManager: pDcdMgr 0x%x, "
+ " hCodMgr 0x%x", pDcdMgr, hCodMgr);
+ } else {
+ status = DSP_EMEMORY;
+
+ /*
+ * If allocation of DcdManager object failed, delete the
+ * COD manager.
+ */
+ COD_Delete(hCodMgr);
+
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_CreateManager: MEM_AllocObject failed\n");
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_CreateManager: COD_Create failed\n");
+ }
+
+ DBC_Ensure((DSP_SUCCEEDED(status)) || ((hCodMgr == NULL) &&
+ (status == DSP_EFAIL)) || ((pDcdMgr == NULL) &&
+ (status == DSP_EMEMORY)));
+
+ return status;
+}
+
+/*
+ * ======== DCD_DestroyManager ========
+ * Purpose:
+ * Frees DCD Manager object.
+ */
+DSP_STATUS DCD_DestroyManager(IN struct DCD_MANAGER *hDcdMgr)
+{
+ struct DCD_MANAGER *pDcdMgr = hDcdMgr;
+ DSP_STATUS status = DSP_EHANDLE;
+
+ DBC_Require(cRefs >= 0);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_DestroyManager: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ if (IsValidHandle(hDcdMgr)) {
+
+ /* Delete the COD manager. */
+ COD_Delete(pDcdMgr->hCodMgr);
+
+ /* Deallocate a DCD manager object. */
+ MEM_FreeObject(pDcdMgr);
+
+ status = DSP_SOK;
+ } else {
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_DestroyManager: invalid DCD manager handle.\n");
+ }
+
+ return status;
+}
+
+/*
+ * ======== DCD_EnumerateObject ========
+ * Purpose:
+ * Enumerates objects in the DCD.
+ */
+DSP_STATUS DCD_EnumerateObject(IN s32 cIndex, IN enum DSP_DCDOBJTYPE objType,
+ OUT struct DSP_UUID *pUuid)
+{
+ DSP_STATUS status = DSP_SOK;
+ char szRegKey[REG_MAXREGPATHLENGTH];
+ char szValue[REG_MAXREGPATHLENGTH];
+ char szData[REG_MAXREGPATHLENGTH];
+ u32 dwValueSize;
+ u32 dwDataSize;
+ struct DSP_UUID dspUuid;
+ char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */
+ u32 dwKeyLen = 0;
+
+ DBC_Require(cRefs >= 0);
+ DBC_Require(cIndex >= 0);
+ DBC_Require(pUuid != NULL);
+
+ GT_3trace(curTrace, GT_ENTER,
+ "DCD_EnumerateObject: cIndex %d, objType %d, "
+ " pUuid 0x%x\n", cIndex, objType, pUuid);
+
+ if ((cIndex != 0) && (cEnumRefs == 0)) {
+ /*
+ * If an enumeration is being performed on an index greater
+ * than zero, then the current cEnumRefs must have been
+ * incremented to greater than zero.
+ */
+ status = DSP_ECHANGEDURINGENUM;
+ } else {
+ /* Enumerate a specific key in the registry by index. */
+ dwValueSize = REG_MAXREGPATHLENGTH;
+ dwDataSize = REG_MAXREGPATHLENGTH;
+
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of szObjType string + terminating NULL.
+ */
+ dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1;
+ DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH);
+
+ /* Create proper REG key; concatenate DCD_REGKEY with
+ * objType. */
+ strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(szRegKey) + strlen("_\0")) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, "_\0", 2);
+ } else {
+ status = DSP_EFAIL;
+ }
+
+ /* This snprintf is guaranteed not to exceed max size of an
+ * integer. */
+ status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d",
+ objType);
+
+ if (status == -1) {
+ status = DSP_EFAIL;
+ } else {
+ status = DSP_SOK;
+ if ((strlen(szRegKey) + strlen(szObjType)) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szObjType,
+ strlen(szObjType) + 1);
+ } else {
+ status = DSP_EFAIL;
+ }
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ status = REG_EnumValue(NULL, cIndex, szRegKey, szValue,
+ &dwValueSize, szData,
+ &dwDataSize);
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Create UUID value using string retrieved from
+ * registry. */
+ UUID_UuidFromString(szValue, &dspUuid);
+
+ *pUuid = dspUuid;
+
+ /* Increment cEnumRefs to update reference count. */
+ cEnumRefs++;
+
+ status = DSP_SOK;
+ } else if (status == REG_E_NOMOREITEMS) {
+ /* At the end of enumeration. Reset cEnumRefs. */
+ cEnumRefs = 0;
+
+ status = DSP_SENUMCOMPLETE;
+ } else {
+ status = DSP_EFAIL;
+ GT_1trace(curTrace, GT_6CLASS,
+ "DCD_EnumerateObject: REG_EnumValue"
+ " failed, status = 0x%x\n", status);
+ }
+ }
+
+ DBC_Ensure(pUuid || (status == DSP_EFAIL));
+
+ return status;
+}
+
+/*
+ * ======== DCD_Exit ========
+ * Purpose:
+ * Discontinue usage of the DCD module.
+ */
+void DCD_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ GT_1trace(curTrace, GT_5CLASS, "DCD_Exit: cRefs 0x%x\n", cRefs);
+
+ cRefs--;
+ if (cRefs == 0) {
+ REG_Exit();
+ COD_Exit();
+ MEM_Exit();
+ }
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== DCD_GetDepLibs ========
+ */
+DSP_STATUS DCD_GetDepLibs(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pUuid,
+ u16 numLibs, OUT struct DSP_UUID *pDepLibUuids,
+ OUT bool *pPersistentDepLibs, IN enum NLDR_PHASE phase)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(IsValidHandle(hDcdMgr));
+ DBC_Require(pUuid != NULL);
+ DBC_Require(pDepLibUuids != NULL);
+ DBC_Require(pPersistentDepLibs != NULL);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_GetDepLibs: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ status = GetDepLibInfo(hDcdMgr, pUuid, &numLibs, NULL, pDepLibUuids,
+ pPersistentDepLibs, phase);
+
+ return status;
+}
+
+/*
+ * ======== DCD_GetNumDepLibs ========
+ */
+DSP_STATUS DCD_GetNumDepLibs(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pUuid, OUT u16 *pNumLibs,
+ OUT u16 *pNumPersLibs, IN enum NLDR_PHASE phase)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(IsValidHandle(hDcdMgr));
+ DBC_Require(pNumLibs != NULL);
+ DBC_Require(pNumPersLibs != NULL);
+ DBC_Require(pUuid != NULL);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_GetNumDepLibs: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ status = GetDepLibInfo(hDcdMgr, pUuid, pNumLibs, pNumPersLibs,
+ NULL, NULL, phase);
+
+ return status;
+}
+
+/*
+ * ======== DCD_GetObjectDef ========
+ * Purpose:
+ * Retrieves the properties of a node or processor based on the UUID and
+ * object type.
+ */
+DSP_STATUS DCD_GetObjectDef(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pObjUuid,
+ IN enum DSP_DCDOBJTYPE objType,
+ OUT struct DCD_GENERICOBJ *pObjDef)
+{
+ struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */
+ struct COD_LIBRARYOBJ *lib = NULL;
+ DSP_STATUS status = DSP_SOK;
+ u32 ulAddr = 0; /* Used by COD_GetSection */
+ u32 ulLen = 0; /* Used by COD_GetSection */
+ u32 dwBufSize; /* Used by REG functions */
+ char szRegKey[REG_MAXREGPATHLENGTH];
+ char *szUuid; /*[MAXUUIDLEN];*/
+ char szRegData[REG_MAXREGPATHLENGTH];
+ char szSectName[MAXUUIDLEN + 2]; /* ".[UUID]\0" */
+ char *pszCoffBuf;
+ u32 dwKeyLen; /* Len of REG key. */
+ char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pObjDef != NULL);
+ DBC_Require(pObjUuid != NULL);
+
+ GT_4trace(curTrace, GT_ENTER,
+ "DCD_GetObjectDef: hDcdMgr 0x%x, " "objUuid"
+ " 0x%x, objType 0x%x, pObjDef 0x%x\n", hDcdMgr, pObjUuid,
+ objType, pObjDef);
+ szUuid = (char *)MEM_Calloc(MAXUUIDLEN, MEM_PAGED);
+ if (!szUuid)
+ return status = DSP_EMEMORY;
+
+ if (!IsValidHandle(hDcdMgr)) {
+ status = DSP_EHANDLE;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: invalid "
+ "DCD manager handle.\n");
+ goto func_end;
+ }
+ /* Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of szObjType string + terminating NULL */
+ dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1;
+ DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH);
+ /* Create proper REG key; concatenate DCD_REGKEY with objType. */
+ strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+
+ if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, "_\0", 2);
+ else
+ status = DSP_EFAIL;
+
+ status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d", objType);
+ if (status == -1) {
+ status = DSP_EFAIL;
+ } else {
+ status = DSP_SOK;
+
+ if ((strlen(szRegKey) + strlen(szObjType)) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szObjType, strlen(szObjType) + 1);
+ } else {
+ status = DSP_EFAIL;
+ }
+ /* Create UUID value to set in registry. */
+ UUID_UuidToString(pObjUuid, szUuid, MAXUUIDLEN);
+
+ if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, szUuid, MAXUUIDLEN);
+ else
+ status = DSP_EFAIL;
+
+ /* Retrieve paths from the registry based on struct DSP_UUID */
+ dwBufSize = REG_MAXREGPATHLENGTH;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = REG_GetValue(NULL, szRegKey, szRegKey, (u8 *)szRegData,
+ &dwBufSize);
+ }
+ if (DSP_FAILED(status)) {
+ status = DSP_EUUID;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: "
+ "REG_GetValue() failed\n");
+ goto func_end;
+ }
+ /* Open COFF file. */
+ status = COD_Open(pDcdMgr->hCodMgr, szRegData, COD_NOLOAD, &lib);
+ if (DSP_FAILED(status)) {
+ status = DSP_EDCDLOADBASE;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: "
+ "COD_OpenBase() failed\n");
+ goto func_end;
+ }
+ /* Ensure szUuid + 1 is not greater than sizeof szSectName. */
+ DBC_Assert((strlen(szUuid) + 1) < sizeof(szSectName));
+ /* Create section name based on node UUID. A period is
+ * pre-pended to the UUID string to form the section name.
+ * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
+ strncpy(szSectName, ".", 2);
+ strncat(szSectName, szUuid, strlen(szUuid));
+ /* Get section information. */
+ status = COD_GetSection(lib, szSectName, &ulAddr, &ulLen);
+ if (DSP_FAILED(status)) {
+ status = DSP_EDCDGETSECT;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef:"
+ " COD_GetSection() failed\n");
+ goto func_end;
+ }
+ /* Allocate zeroed buffer. */
+ pszCoffBuf = MEM_Calloc(ulLen + 4, MEM_PAGED);
+#ifdef _DB_TIOMAP
+ if (strstr(szRegData, "iva") == NULL) {
+ /* Locate section by objectID and read its content. */
+ status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen);
+ } else {
+ status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen);
+ GT_0trace(curTrace, GT_4CLASS,
+ "Skipped Byte swap for IVA !!\n");
+ }
+#else
+ status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen);
+#endif
+ if (DSP_SUCCEEDED(status)) {
+ /* Compres DSP buffer to conform to PC format. */
+ if (strstr(szRegData, "iva") == NULL) {
+ CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE);
+ } else {
+ CompressBuf(pszCoffBuf, ulLen, 1);
+ GT_0trace(curTrace, GT_4CLASS, "Compressing IVA "
+ "COFF buffer by 1 for IVA !!\n");
+ }
+ /* Parse the content of the COFF buffer. */
+ status = GetAttrsFromBuf(pszCoffBuf, ulLen, objType, pObjDef);
+ if (DSP_FAILED(status)) {
+ status = DSP_EDCDPARSESECT;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: "
+ "GetAttrsFromBuf() failed\n");
+ }
+ } else {
+ status = DSP_EDCDREADSECT;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: "
+ "COD_ReadSection() failed\n");
+ }
+ /* Free the previously allocated dynamic buffer. */
+ MEM_Free(pszCoffBuf);
+func_end:
+ if (lib)
+ COD_Close(lib);
+
+ if (szUuid)
+ MEM_Free(szUuid);
+ return status;
+}
+
+/*
+ * ======== DCD_GetObjects ========
+ */
+DSP_STATUS DCD_GetObjects(IN struct DCD_MANAGER *hDcdMgr, IN char *pszCoffPath,
+ DCD_REGISTERFXN registerFxn, void *handle)
+{
+ struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */
+ DSP_STATUS status = DSP_SOK;
+ char *pszCoffBuf;
+ char *pszCur;
+ struct COD_LIBRARYOBJ *lib = NULL;
+ u32 ulAddr = 0; /* Used by COD_GetSection */
+ u32 ulLen = 0; /* Used by COD_GetSection */
+ char seps[] = ":, ";
+ char *pToken = NULL;
+ struct DSP_UUID dspUuid;
+ s32 cObjectType;
+
+ DBC_Require(cRefs > 0);
+ GT_1trace(curTrace, GT_ENTER,
+ "DCD_GetObjects: hDcdMgr 0x%x\n", hDcdMgr);
+ if (!IsValidHandle(hDcdMgr)) {
+ status = DSP_EHANDLE;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_GetObjects: invalid DCD manager handle.\n");
+ goto func_end;
+ }
+ /* Open DSP coff file, don't load symbols. */
+ status = COD_Open(pDcdMgr->hCodMgr, pszCoffPath, COD_NOLOAD, &lib);
+ if (DSP_FAILED(status)) {
+ status = DSP_EDCDLOADBASE;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_AutoRegister: COD_Open() failed\n");
+ goto func_cont;
+ }
+ /* Get DCD_RESIGER_SECTION section information. */
+ status = COD_GetSection(lib, DCD_REGISTER_SECTION, &ulAddr, &ulLen);
+ if (DSP_FAILED(status) || !(ulLen > 0)) {
+ status = DSP_EDCDNOAUTOREGISTER;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_GetObjects: COD_GetSection() "
+ "- no auto register section\n");
+ goto func_cont;
+ }
+ /* Allocate zeroed buffer. */
+ pszCoffBuf = MEM_Calloc(ulLen + 4, MEM_PAGED);
+#ifdef _DB_TIOMAP
+ if (strstr(pszCoffPath, "iva") == NULL) {
+ /* Locate section by objectID and read its content. */
+ status = COD_ReadSection(lib, DCD_REGISTER_SECTION,
+ pszCoffBuf, ulLen);
+ } else {
+ GT_0trace(curTrace, GT_4CLASS, "Skipped Byte swap for IVA!!\n");
+ status = COD_ReadSection(lib, DCD_REGISTER_SECTION,
+ pszCoffBuf, ulLen);
+ }
+#else
+ status = COD_ReadSection(lib, DCD_REGISTER_SECTION, pszCoffBuf, ulLen);
+#endif
+ if (DSP_SUCCEEDED(status)) {
+ /* Compress DSP buffer to conform to PC format. */
+ GT_0trace(curTrace, GT_4CLASS,
+ "Successfully read section !!\n");
+ if (strstr(pszCoffPath, "iva") == NULL) {
+ CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE);
+ } else {
+ CompressBuf(pszCoffBuf, ulLen, 1);
+ GT_0trace(curTrace, GT_4CLASS, "Compress COFF buffer "
+ "with 1 word for IVA !!\n");
+ }
+ /* Read from buffer and register object in buffer. */
+ pszCur = pszCoffBuf;
+ while ((pToken = strsep(&pszCur, seps)) && *pToken != '\0') {
+ /* Retrieve UUID string. */
+ UUID_UuidFromString(pToken, &dspUuid);
+ /* Retrieve object type */
+ pToken = strsep(&pszCur, seps);
+ /* Retrieve object type */
+ cObjectType = Atoi(pToken);
+ /*
+ * Apply registerFxn to the found DCD object.
+ * Possible actions include:
+ *
+ * 1) Register found DCD object.
+ * 2) Unregister found DCD object (when handle == NULL)
+ * 3) Add overlay node.
+ */
+ GT_1trace(curTrace, GT_4CLASS, "Registering objtype "
+ "%d \n", cObjectType);
+ status = registerFxn(&dspUuid, cObjectType, handle);
+ if (DSP_SUCCEEDED(status)) {
+ GT_1trace(curTrace, GT_5CLASS,
+ "DCD_GetObjects: status 0x%x\n",
+ status);
+ } else {
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_GetObjects: "
+ "registration() failed\n");
+ /* if error occurs, break from while loop. */
+ break;
+ }
+ }
+ } else {
+ status = DSP_EDCDREADSECT;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjects: "
+ "COD_ReadSection() failed\n");
+ }
+ /* Free the previously allocated dynamic buffer. */
+ MEM_Free(pszCoffBuf);
+func_cont:
+ if (lib)
+ COD_Close(lib);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== DCD_GetLibraryName ========
+ * Purpose:
+ * Retrieves the library name for the given UUID.
+ *
+ */
+DSP_STATUS DCD_GetLibraryName(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pUuid,
+ IN OUT char *pstrLibName, IN OUT u32 *pdwSize,
+ enum NLDR_PHASE phase, OUT bool *fPhaseSplit)
+{
+ char szRegKey[REG_MAXREGPATHLENGTH];
+ char szUuid[MAXUUIDLEN];
+ u32 dwKeyLen; /* Len of REG key. */
+ char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(pUuid != NULL);
+ DBC_Require(pstrLibName != NULL);
+ DBC_Require(pdwSize != NULL);
+ DBC_Require(IsValidHandle(hDcdMgr));
+
+ GT_4trace(curTrace, GT_ENTER,
+ "DCD_GetLibraryName: hDcdMgr 0x%x, pUuid 0x%x, "
+ " pstrLibName 0x%x, pdwSize 0x%x\n", hDcdMgr, pUuid,
+ pstrLibName, pdwSize);
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of szObjType string + terminating NULL.
+ */
+ dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1;
+ DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH);
+ /* Create proper REG key; concatenate DCD_REGKEY with objType. */
+ strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, "_\0", 2);
+ else
+ status = DSP_EFAIL;
+
+ switch (phase) {
+ case NLDR_CREATE:
+ /* create phase type */
+ sprintf(szObjType, "%d", DSP_DCDCREATELIBTYPE);
+ break;
+ case NLDR_EXECUTE:
+ /* execute phase type */
+ sprintf(szObjType, "%d", DSP_DCDEXECUTELIBTYPE);
+ break;
+ case NLDR_DELETE:
+ /* delete phase type */
+ sprintf(szObjType, "%d", DSP_DCDDELETELIBTYPE);
+ break;
+ case NLDR_NOPHASE:
+ /* known to be a dependent library */
+ sprintf(szObjType, "%d", DSP_DCDLIBRARYTYPE);
+ break;
+ default:
+ status = -1;
+ DBC_Assert(false);
+ }
+ if (status == -1) {
+ status = DSP_EFAIL;
+ } else {
+ status = DSP_SOK;
+ if ((strlen(szRegKey) + strlen(szObjType))
+ < REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szObjType, strlen(szObjType) + 1);
+ } else {
+ status = DSP_EFAIL;
+ }
+ /* Create UUID value to find match in registry. */
+ UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN);
+ if ((strlen(szRegKey) + MAXUUIDLEN) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szUuid, MAXUUIDLEN);
+ } else {
+ status = DSP_EFAIL;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Retrieve path from the registry based on DSP_UUID */
+ status = REG_GetValue(NULL, szRegKey, szRegKey,
+ (u8 *)pstrLibName, pdwSize);
+ }
+ /* If can't find, phases might be registered as generic LIBRARYTYPE */
+ if (DSP_FAILED(status) && phase != NLDR_NOPHASE) {
+ if (fPhaseSplit)
+ *fPhaseSplit = false;
+
+ strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(szRegKey) + strlen("_\0")) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, "_\0", 2);
+ } else {
+ status = DSP_EFAIL;
+ }
+ sprintf(szObjType, "%d", DSP_DCDLIBRARYTYPE);
+ if ((strlen(szRegKey) + strlen(szObjType))
+ < REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szObjType, strlen(szObjType) + 1);
+ } else {
+ status = DSP_EFAIL;
+ }
+ UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN);
+ if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, szUuid, MAXUUIDLEN);
+ else
+ status = DSP_EFAIL;
+
+ status = REG_GetValue(NULL, szRegKey, szRegKey,
+ (u8 *)pstrLibName, pdwSize);
+ }
+
+ return status;
+}
+
+/*
+ * ======== DCD_Init ========
+ * Purpose:
+ * Initialize the DCD module.
+ */
+bool DCD_Init(void)
+{
+ bool fInitMEM;
+ bool fInitREG;
+ bool fInitCOD;
+ bool fInit = true;
+
+ DBC_Require(cRefs >= 0);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_Init: (on enter) cRefs = 0x%x\n",
+ cRefs);
+
+ if (cRefs == 0) {
+
+ /* Initialize required modules. */
+ fInitMEM = MEM_Init();
+ fInitCOD = COD_Init();
+ fInitREG = REG_Init();
+ if (!fInitMEM || !fInitCOD || !fInitREG) {
+ fInit = false;
+ GT_0trace(curTrace, GT_6CLASS, "DCD_Init failed\n");
+ /* Exit initialized modules. */
+ if (fInitMEM)
+ MEM_Exit();
+
+ if (fInitCOD)
+ COD_Exit();
+
+ if (fInitREG)
+ REG_Exit();
+
+ }
+ }
+
+ if (fInit)
+ cRefs++;
+
+
+ GT_1trace(curTrace, GT_5CLASS, "DCD_Init: (on exit) cRefs = 0x%x\n",
+ cRefs);
+
+ DBC_Ensure((fInit && (cRefs > 0)) || (!fInit && (cRefs == 0)));
+
+ return fInit;
+}
+
+/*
+ * ======== DCD_RegisterObject ========
+ * Purpose:
+ * Registers a node or a processor with the DCD.
+ * If pszPathName == NULL, unregister the specified DCD object.
+ */
+DSP_STATUS DCD_RegisterObject(IN struct DSP_UUID *pUuid,
+ IN enum DSP_DCDOBJTYPE objType,
+ IN char *pszPathName)
+{
+ DSP_STATUS status = DSP_SOK;
+ char szRegKey[REG_MAXREGPATHLENGTH];
+ char szUuid[MAXUUIDLEN + 1];
+ u32 dwPathSize = 0;
+ u32 dwKeyLen; /* Len of REG key. */
+ char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pUuid != NULL);
+ DBC_Require((objType == DSP_DCDNODETYPE) ||
+ (objType == DSP_DCDPROCESSORTYPE) ||
+ (objType == DSP_DCDLIBRARYTYPE) ||
+ (objType == DSP_DCDCREATELIBTYPE) ||
+ (objType == DSP_DCDEXECUTELIBTYPE) ||
+ (objType == DSP_DCDDELETELIBTYPE));
+
+ GT_3trace(curTrace, GT_ENTER, "DCD_RegisterObject: object UUID 0x%x, "
+ "objType %d, szPathName %s\n", pUuid, objType, pszPathName);
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of szObjType string + terminating NULL.
+ */
+ dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1;
+ DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH);
+ /* Create proper REG key; concatenate DCD_REGKEY with objType. */
+ strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, "_\0", 2);
+ else
+ status = DSP_EFAIL;
+
+ status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d", objType);
+ if (status == -1) {
+ status = DSP_EFAIL;
+ } else {
+ status = DSP_SOK;
+ if ((strlen(szRegKey) + strlen(szObjType)) <
+ REG_MAXREGPATHLENGTH) {
+ strncat(szRegKey, szObjType, strlen(szObjType) + 1);
+ } else {
+ status = DSP_EFAIL;
+ }
+ /* Create UUID value to set in registry. */
+ UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN);
+ if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH)
+ strncat(szRegKey, szUuid, MAXUUIDLEN);
+ else
+ status = DSP_EFAIL;
+
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /*
+ * If pszPathName != NULL, perform registration, otherwise,
+ * perform unregistration.
+ */
+ if (pszPathName) {
+ /* Add new reg value (UUID+objType) with COFF path
+ * info. */
+ dwPathSize = strlen(pszPathName) + 1;
+ status = REG_SetValue(NULL, szRegKey, szRegKey, REG_SZ,
+ (u8 *)pszPathName, dwPathSize);
+ GT_3trace(curTrace, GT_6CLASS,
+ "REG_SetValue REG_SZ=%d, "
+ "(u8 *)pszPathName=%s, dwPathSize=%d\n",
+ REG_SZ, pszPathName, dwPathSize);
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_RegisterObject: REG_SetValue failed!\n");
+ }
+ } else {
+ /* Deregister an existing object. */
+ status = REG_DeleteValue(NULL, szRegKey, szRegKey);
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_6CLASS,
+ "DCD_UnregisterObject: "
+ "REG_DeleteValue failed!\n");
+ }
+ }
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /*
+ * Because the node database has been updated through a
+ * successful object registration/de-registration operation,
+ * we need to reset the object enumeration counter to allow
+ * current enumerations to reflect this update in the node
+ * database.
+ */
+
+ cEnumRefs = 0;
+ }
+
+ return status;
+}
+
+/*
+ * ======== DCD_UnregisterObject ========
+ * Call DCD_Register object with pszPathName set to NULL to
+ * perform actual object de-registration.
+ */
+DSP_STATUS DCD_UnregisterObject(IN struct DSP_UUID *pUuid,
+ IN enum DSP_DCDOBJTYPE objType)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pUuid != NULL);
+ DBC_Require((objType == DSP_DCDNODETYPE) ||
+ (objType == DSP_DCDPROCESSORTYPE) ||
+ (objType == DSP_DCDLIBRARYTYPE) ||
+ (objType == DSP_DCDCREATELIBTYPE) ||
+ (objType == DSP_DCDEXECUTELIBTYPE) ||
+ (objType == DSP_DCDDELETELIBTYPE));
+
+ GT_2trace(curTrace, GT_ENTER,
+ "DCD_UnregisterObject: object UUID 0x%x, "
+ "objType %d\n", pUuid, objType);
+
+ /*
+ * When DCD_RegisterObject is called with NULL as pathname,
+ * it indicates an unregister object operation.
+ */
+ status = DCD_RegisterObject(pUuid, objType, NULL);
+
+ return status;
+}
+
+/*
+ **********************************************************************
+ * DCD Helper Functions
+ **********************************************************************
+ */
+
+/*
+ * ======== Atoi ========
+ * Purpose:
+ * This function converts strings in decimal or hex format to integers.
+ */
+static s32 Atoi(char *pszBuf)
+{
+ s32 result = 0;
+ char *pch = pszBuf;
+ char c;
+ char first;
+ s32 base = 10;
+ s32 len;
+
+ while (isspace(*pch))
+ pch++;
+
+ first = *pch;
+ if (first == '-' || first == '+') {
+ pch++;
+ } else {
+ /* Determine if base 10 or base 16 */
+ len = strlen(pch);
+ if (len > 1) {
+ c = pch[1];
+ if ((*pch == '0' && (c == 'x' || c == 'X'))) {
+ base = 16;
+ pch += 2;
+ }
+ c = pch[len - 1];
+ if (c == 'h' || c == 'H')
+ base = 16;
+
+ }
+ }
+
+ while (isdigit(c = *pch) || ((base == 16) && isxdigit(c))) {
+ result *= base;
+ if ('A' <= c && c <= 'F') {
+ c = c - 'A' + 10;
+ } else {
+ if ('a' <= c && c <= 'f')
+ c = c - 'a' + 10;
+ else
+ c -= '0';
+
+ }
+ result += c;
+ ++pch;
+ }
+
+ return result;
+}
+
+/*
+ * ======== GetAttrsFromBuf ========
+ * Purpose:
+ * Parse the content of a buffer filled with DSP-side data and
+ * retrieve an object's attributes from it. IMPORTANT: Assume the
+ * buffer has been converted from DSP format to GPP format.
+ */
+static DSP_STATUS GetAttrsFromBuf(char *pszBuf, u32 ulBufSize,
+ enum DSP_DCDOBJTYPE objType,
+ struct DCD_GENERICOBJ *pGenObj)
+{
+ DSP_STATUS status = DSP_SOK;
+ char seps[] = ", ";
+ char *pszCur;
+ char *token;
+ s32 cLen = 0;
+ u32 i = 0;
+#ifdef _DB_TIOMAP
+ s32 iEntry;
+#endif
+
+ DBC_Require(pszBuf != NULL);
+ DBC_Require(ulBufSize != 0);
+ DBC_Require((objType == DSP_DCDNODETYPE)
+ || (objType == DSP_DCDPROCESSORTYPE));
+ DBC_Require(pGenObj != NULL);
+
+
+ switch (objType) {
+ case DSP_DCDNODETYPE:
+ /*
+ * Parse COFF sect buffer to retrieve individual tokens used
+ * to fill in object attrs.
+ */
+ pszCur = pszBuf;
+ token = strsep(&pszCur, seps);
+
+ /* u32 cbStruct */
+ pGenObj->objData.nodeObj.ndbProps.cbStruct =
+ (u32) Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* DSP_UUID uiNodeID */
+ UUID_UuidFromString(token,
+ &pGenObj->objData.nodeObj.ndbProps.uiNodeID);
+ token = strsep(&pszCur, seps);
+
+ /* acName */
+ DBC_Require(token);
+ cLen = strlen(token);
+ if (cLen > DSP_MAXNAMELEN - 1)
+ cLen = DSP_MAXNAMELEN - 1;
+
+ strncpy(pGenObj->objData.nodeObj.ndbProps.acName,
+ token, cLen);
+ pGenObj->objData.nodeObj.ndbProps.acName[cLen] = '\0';
+ token = strsep(&pszCur, seps);
+ /* u32 uNodeType */
+ pGenObj->objData.nodeObj.ndbProps.uNodeType = Atoi(token);
+ token = strsep(&pszCur, seps);
+ /* u32 bCacheOnGPP */
+ pGenObj->objData.nodeObj.ndbProps.bCacheOnGPP = Atoi(token);
+ token = strsep(&pszCur, seps);
+ /* DSP_RESOURCEREQMTS dspResourceReqmts */
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.cbStruct =
+ (u32) Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uStaticDataSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uGlobalDataSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uProgramMemSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uWCExecutionTime = Atoi(token);
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uWCPeriod = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uWCDeadline = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uAvgExectionTime = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.
+ uMinimumPeriod = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* s32 iPriority */
+ pGenObj->objData.nodeObj.ndbProps.iPriority = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uStackSize */
+ pGenObj->objData.nodeObj.ndbProps.uStackSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uSysStackSize */
+ pGenObj->objData.nodeObj.ndbProps.uSysStackSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uStackSeg */
+ pGenObj->objData.nodeObj.ndbProps.uStackSeg = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uMessageDepth */
+ pGenObj->objData.nodeObj.ndbProps.uMessageDepth = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uNumInputStreams */
+ pGenObj->objData.nodeObj.ndbProps.uNumInputStreams =
+ Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uNumOutputStreams */
+ pGenObj->objData.nodeObj.ndbProps.uNumOutputStreams =
+ Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* u32 uTimeout */
+ pGenObj->objData.nodeObj.ndbProps.uTimeout =
+ Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* char * pstrCreatePhaseFxn */
+ DBC_Require(token);
+ cLen = strlen(token);
+ pGenObj->objData.nodeObj.pstrCreatePhaseFxn =
+ MEM_Calloc(cLen + 1, MEM_PAGED);
+ strncpy(pGenObj->objData.nodeObj.pstrCreatePhaseFxn,
+ token, cLen);
+ pGenObj->objData.nodeObj.pstrCreatePhaseFxn[cLen] = '\0';
+ token = strsep(&pszCur, seps);
+
+ /* char * pstrExecutePhaseFxn */
+ DBC_Require(token);
+ cLen = strlen(token);
+ pGenObj->objData.nodeObj.pstrExecutePhaseFxn =
+ MEM_Calloc(cLen + 1, MEM_PAGED);
+ strncpy(pGenObj->objData.nodeObj.pstrExecutePhaseFxn,
+ token, cLen);
+ pGenObj->objData.nodeObj.pstrExecutePhaseFxn[cLen] = '\0';
+ token = strsep(&pszCur, seps);
+
+ /* char * pstrDeletePhaseFxn */
+ DBC_Require(token);
+ cLen = strlen(token);
+ pGenObj->objData.nodeObj.pstrDeletePhaseFxn =
+ MEM_Calloc(cLen + 1, MEM_PAGED);
+ strncpy(pGenObj->objData.nodeObj.pstrDeletePhaseFxn,
+ token, cLen);
+ pGenObj->objData.nodeObj.pstrDeletePhaseFxn[cLen] = '\0';
+ token = strsep(&pszCur, seps);
+
+ /* Segment id for message buffers */
+ pGenObj->objData.nodeObj.uMsgSegid = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* Message notification type */
+ pGenObj->objData.nodeObj.uMsgNotifyType = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ /* char * pstrIAlgName */
+ if (token) {
+ cLen = strlen(token);
+ pGenObj->objData.nodeObj.pstrIAlgName =
+ MEM_Calloc(cLen + 1, MEM_PAGED);
+ strncpy(pGenObj->objData.nodeObj.pstrIAlgName,
+ token, cLen);
+ pGenObj->objData.nodeObj.pstrIAlgName[cLen] = '\0';
+ token = strsep(&pszCur, seps);
+ }
+
+ /* Load type (static, dynamic, or overlay) */
+ if (token) {
+ pGenObj->objData.nodeObj.usLoadType = Atoi(token);
+ token = strsep(&pszCur, seps);
+ }
+
+ /* Dynamic load data requirements */
+ if (token) {
+ pGenObj->objData.nodeObj.ulDataMemSegMask = Atoi(token);
+ token = strsep(&pszCur, seps);
+ }
+
+ /* Dynamic load code requirements */
+ if (token) {
+ pGenObj->objData.nodeObj.ulCodeMemSegMask = Atoi(token);
+ token = strsep(&pszCur, seps);
+ }
+
+ /* Extract node profiles into node properties */
+ if (token) {
+
+ pGenObj->objData.nodeObj.ndbProps.uCountProfiles =
+ Atoi(token);
+ for (i = 0; i < pGenObj->objData.nodeObj.ndbProps.
+ uCountProfiles; i++) {
+ token = strsep(&pszCur, seps);
+ if (token) {
+ /* Heap Size for the node */
+ pGenObj->objData.nodeObj.ndbProps.
+ aProfiles[i].ulHeapSize =
+ Atoi(token);
+ }
+ }
+ }
+ token = strsep(&pszCur, seps);
+ if (token) {
+ pGenObj->objData.nodeObj.ndbProps.uStackSegName =
+ (u32)(token);
+ }
+
+ break;
+
+ case DSP_DCDPROCESSORTYPE:
+ /*
+ * Parse COFF sect buffer to retrieve individual tokens used
+ * to fill in object attrs.
+ */
+ pszCur = pszBuf;
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.cbStruct = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.uProcessorFamily = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.uProcessorType = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.uClockRate = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.ulInternalMemSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.ulExternalMemSize = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.uProcessorID = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.tyRunningRTOS = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.nNodeMinPriority = Atoi(token);
+ token = strsep(&pszCur, seps);
+
+ pGenObj->objData.procObj.nNodeMaxPriority = Atoi(token);
+
+#ifdef _DB_TIOMAP
+ /* Proc object may contain additional(extended) attributes. */
+ /* attr must match proc.hxx */
+ for (iEntry = 0; iEntry < 7; iEntry++) {
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.extProcObj.tyTlb[iEntry].ulGppPhys =
+ Atoi(token);
+
+ token = strsep(&pszCur, seps);
+ pGenObj->objData.extProcObj.tyTlb[iEntry].ulDspVirt =
+ Atoi(token);
+ }
+#endif
+
+ break;
+
+ default:
+ status = DSP_EFAIL;
+ break;
+ }
+
+ return status;
+}
+
+/*
+ * ======== CompressBuffer ========
+ * Purpose:
+ * Compress the DSP buffer, if necessary, to conform to PC format.
+ */
+static void CompressBuf(char *pszBuf, u32 ulBufSize, s32 cCharSize)
+{
+ char *p;
+ char ch;
+ char *q;
+
+ p = pszBuf;
+ if (p == NULL)
+ return;
+
+ for (q = pszBuf; q < (pszBuf + ulBufSize);) {
+
+ ch = DspChar2GppChar(q, cCharSize);
+ if (ch == '\\') {
+ q += cCharSize;
+ ch = DspChar2GppChar(q, cCharSize);
+ switch (ch) {
+ case 't':
+ *p = '\t';
+ break;
+
+ case 'n':
+ *p = '\n';
+ break;
+
+ case 'r':
+ *p = '\r';
+ break;
+
+ case '0':
+ *p = '\0';
+ break;
+
+ default:
+ *p = ch;
+ break;
+ }
+ } else {
+ *p = ch;
+ }
+ p++;
+ q += cCharSize;
+ }
+
+ /* NULL out remainder of buffer. */
+ while (p < q)
+ *p++ = '\0';
+
+}
+
+/*
+ * ======== DspChar2GppChar ========
+ * Purpose:
+ * Convert DSP char to host GPP char in a portable manner
+ */
+static char DspChar2GppChar(char *pWord, s32 cDspCharSize)
+{
+ char ch = '\0';
+ char *chSrc;
+ s32 i;
+
+ for (chSrc = pWord, i = cDspCharSize; i > 0; i--)
+ ch |= *chSrc++;
+
+ return ch;
+}
+
+/*
+ * ======== GetDepLibInfo ========
+ */
+static DSP_STATUS GetDepLibInfo(IN struct DCD_MANAGER *hDcdMgr,
+ IN struct DSP_UUID *pUuid,
+ IN OUT u16 *pNumLibs,
+ OPTIONAL OUT u16 *pNumPersLibs,
+ OPTIONAL OUT struct DSP_UUID *pDepLibUuids,
+ OPTIONAL OUT bool *pPersistentDepLibs,
+ enum NLDR_PHASE phase)
+{
+ struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */
+ char *pszCoffBuf = NULL;
+ char *pszCur;
+ char *pszFileName = NULL;
+ struct COD_LIBRARYOBJ *lib = NULL;
+ u32 ulAddr = 0; /* Used by COD_GetSection */
+ u32 ulLen = 0; /* Used by COD_GetSection */
+ u32 dwDataSize = COD_MAXPATHLENGTH;
+ char seps[] = ", ";
+ char *pToken = NULL;
+ bool fGetUuids = (pDepLibUuids != NULL);
+ u16 nDepLibs = 0;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+
+ DBC_Require(IsValidHandle(hDcdMgr));
+ DBC_Require(pNumLibs != NULL);
+ DBC_Require(pUuid != NULL);
+
+ GT_1trace(curTrace, GT_ENTER, "DCD_GetNumDepLibs: hDcdMgr 0x%x\n",
+ hDcdMgr);
+
+ /* Initialize to 0 dependent libraries, if only counting number of
+ * dependent libraries */
+ if (!fGetUuids) {
+ *pNumLibs = 0;
+ *pNumPersLibs = 0;
+ }
+
+ /* Allocate a buffer for file name */
+ pszFileName = MEM_Calloc(dwDataSize, MEM_PAGED);
+ if (pszFileName == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ /* Get the name of the library */
+ status = DCD_GetLibraryName(hDcdMgr, pUuid, pszFileName,
+ &dwDataSize, phase, NULL);
+ }
+ /* Open the library */
+ if (DSP_SUCCEEDED(status)) {
+ status = COD_Open(pDcdMgr->hCodMgr, pszFileName,
+ COD_NOLOAD, &lib);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Get dependent library section information. */
+ status = COD_GetSection(lib, DEPLIBSECT, &ulAddr, &ulLen);
+
+ if (DSP_FAILED(status)) {
+ /* Ok, no dependent libraries */
+ ulLen = 0;
+ status = DSP_SNODEPENDENTLIBS;
+ }
+ }
+
+ if (DSP_FAILED(status) || !(ulLen > 0))
+ goto func_cont;
+
+ /* Allocate zeroed buffer. */
+ pszCoffBuf = MEM_Calloc(ulLen, MEM_PAGED);
+ if (pszCoffBuf == NULL)
+ status = DSP_EMEMORY;
+
+ /* Read section contents. */
+ status = COD_ReadSection(lib, DEPLIBSECT, pszCoffBuf, ulLen);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ /* Compress and format DSP buffer to conform to PC format. */
+ CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE);
+ /* Read from buffer */
+ pszCur = pszCoffBuf;
+ while ((pToken = strsep(&pszCur, seps)) && *pToken != '\0') {
+ if (fGetUuids) {
+ if (nDepLibs >= *pNumLibs) {
+ /* Gone beyond the limit */
+ break;
+ } else {
+ /* Retrieve UUID string. */
+ UUID_UuidFromString(pToken,
+ &(pDepLibUuids[nDepLibs]));
+ /* Is this library persistent? */
+ pToken = strsep(&pszCur, seps);
+ pPersistentDepLibs[nDepLibs] = Atoi(pToken);
+ nDepLibs++;
+ }
+ } else {
+ /* Advanc to next token */
+ pToken = strsep(&pszCur, seps);
+ if (Atoi(pToken))
+ (*pNumPersLibs)++;
+
+ /* Just counting number of dependent libraries */
+ (*pNumLibs)++;
+ }
+ }
+func_cont:
+ if (lib)
+ COD_Close(lib);
+
+ /* Free previously allocated dynamic buffers. */
+ if (pszFileName)
+ MEM_Free(pszFileName);
+
+ if (pszCoffBuf)
+ MEM_Free(pszCoffBuf);
+
+ return status;
+}
+
diff --git a/drivers/dsp/bridge/rmgr/disp.c b/drivers/dsp/bridge/rmgr/disp.c
new file mode 100644
index 000000000000..3fbbf0199e33
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/disp.c
@@ -0,0 +1,916 @@
+/*
+ * disp.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== disp.c ========
+ *
+ * Description:
+ * Node Dispatcher interface. Communicates with Resource Manager Server
+ * (RMS) on DSP. Access to RMS is synchronized in NODE.
+ *
+ * Public Functions:
+ * DISP_Create
+ * DISP_Delete
+ * DISP_Exit
+ * DISP_Init
+ * DISP_NodeChangePriority
+ * DISP_NodeCreate
+ * DISP_NodeDelete
+ * DISP_NodePause
+ * DISP_NodeRun
+ *
+ *! Revision History:
+ *! =================
+ *! 18-Feb-2003 vp Code review updates
+ *! 18-Oct-2002 vp Ported to Linux platform
+ *! 16-May-2002 jeh Added DISP_DoCinit().
+ *! 24-Apr-2002 jeh Added DISP_MemWrite().
+ *! 13-Feb-2002 jeh Pass system stack size to RMS.
+ *! 16-Jan-2002 ag Added bufsize param to _ChnlAddIOReq() fxn
+ *! 10-May-2001 jeh Code Review cleanup.
+ *! 26-Sep-2000 jeh Fixed status values in SendMessage().
+ *! 19-Jun-2000 jeh Created.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/gt.h>
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/dev.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/csl.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/wmd.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/chnldefs.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/rms_sh.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/disp.h>
+
+#define DISP_SIGNATURE 0x50534944 /* "PSID" */
+
+/* Size of a reply from RMS */
+#define REPLYSIZE (3 * sizeof(RMS_WORD))
+
+/* Reserved channel offsets for communication with RMS */
+#define CHNLTORMSOFFSET 0
+#define CHNLFROMRMSOFFSET 1
+
+#define CHNLIOREQS 1
+
+#define SwapWord(x) (((u32)(x) >> 16) | ((u32)(x) << 16))
+
+/*
+ * ======== DISP_OBJECT ========
+ */
+struct DISP_OBJECT {
+ u32 dwSignature; /* Used for object validation */
+ struct DEV_OBJECT *hDevObject; /* Device for this processor */
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+ struct CHNL_MGR *hChnlMgr; /* Channel manager */
+ struct CHNL_OBJECT *hChnlToDsp; /* Channel for commands to RMS */
+ struct CHNL_OBJECT *hChnlFromDsp; /* Channel for replies from RMS */
+ u8 *pBuf; /* Buffer for commands, replies */
+ u32 ulBufsize; /* pBuf size in bytes */
+ u32 ulBufsizeRMS; /* pBuf size in RMS words */
+ u32 uCharSize; /* Size of DSP character */
+ u32 uWordSize; /* Size of DSP word */
+ u32 uDataMauSize; /* Size of DSP Data MAU */
+};
+
+static u32 cRefs;
+
+/* Debug msgs: */
+#if GT_TRACE
+static struct GT_Mask DISP_DebugMask = { NULL, NULL };
+#endif
+
+static void DeleteDisp(struct DISP_OBJECT *hDisp);
+static DSP_STATUS FillStreamDef(RMS_WORD *pdwBuf, u32 *ptotal, u32 offset,
+ struct NODE_STRMDEF strmDef, u32 max,
+ u32 uCharsInRMSWord);
+static DSP_STATUS SendMessage(struct DISP_OBJECT *hDisp, u32 dwTimeout,
+ u32 ulBytes, OUT u32 *pdwArg);
+
+/*
+ * ======== DISP_Create ========
+ * Create a NODE Dispatcher object.
+ */
+DSP_STATUS DISP_Create(OUT struct DISP_OBJECT **phDispObject,
+ struct DEV_OBJECT *hDevObject,
+ IN CONST struct DISP_ATTRS *pDispAttrs)
+{
+ struct DISP_OBJECT *pDisp;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ u32 ulChnlId;
+ struct CHNL_ATTRS chnlAttrs;
+ DSP_STATUS status = DSP_SOK;
+ u32 devType;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(phDispObject != NULL);
+ DBC_Require(pDispAttrs != NULL);
+ DBC_Require(hDevObject != NULL);
+
+ GT_3trace(DISP_DebugMask, GT_ENTER, "DISP_Create: phDispObject: 0x%x\t"
+ "hDevObject: 0x%x\tpDispAttrs: 0x%x\n", phDispObject,
+ hDevObject, pDispAttrs);
+
+ *phDispObject = NULL;
+
+ /* Allocate Node Dispatcher object */
+ MEM_AllocObject(pDisp, struct DISP_OBJECT, DISP_SIGNATURE);
+ if (pDisp == NULL) {
+ status = DSP_EMEMORY;
+ GT_0trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: MEM_AllocObject() failed!\n");
+ } else {
+ pDisp->hDevObject = hDevObject;
+ }
+
+ /* Get Channel manager and WMD function interface */
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetChnlMgr(hDevObject, &(pDisp->hChnlMgr));
+ if (DSP_SUCCEEDED(status)) {
+ (void) DEV_GetIntfFxns(hDevObject, &pIntfFxns);
+ pDisp->pIntfFxns = pIntfFxns;
+ } else {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: Failed to get "
+ "channel manager! status = 0x%x\n", status);
+ }
+ }
+
+ /* check device type and decide if streams or messag'ing is used for
+ * RMS/EDS */
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ status = DEV_GetDevType(hDevObject, &devType);
+ GT_1trace(DISP_DebugMask, GT_6CLASS, "DISP_Create: Creating DISP for "
+ "device = 0x%x\n", devType);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ if (devType != DSP_UNIT) {
+ GT_0trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: Unkown device "
+ "type in Device object !! \n");
+ status = DSP_EFAIL;
+ goto func_cont;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ pDisp->uCharSize = DSPWORDSIZE;
+ pDisp->uWordSize = DSPWORDSIZE;
+ pDisp->uDataMauSize = DSPWORDSIZE;
+ /* Open channels for communicating with the RMS */
+ chnlAttrs.uIOReqs = CHNLIOREQS;
+ chnlAttrs.hEvent = NULL;
+ ulChnlId = pDispAttrs->ulChnlOffset + CHNLTORMSOFFSET;
+ status = (*pIntfFxns->pfnChnlOpen)(&(pDisp->hChnlToDsp),
+ pDisp->hChnlMgr, CHNL_MODETODSP, ulChnlId, &chnlAttrs);
+ if (DSP_FAILED(status)) {
+ GT_2trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: Channel to RMS "
+ "open failed, chnl id = %d, status = 0x%x\n",
+ ulChnlId, status);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ ulChnlId = pDispAttrs->ulChnlOffset + CHNLFROMRMSOFFSET;
+ status = (*pIntfFxns->pfnChnlOpen)(&(pDisp->hChnlFromDsp),
+ pDisp->hChnlMgr, CHNL_MODEFROMDSP, ulChnlId,
+ &chnlAttrs);
+ if (DSP_FAILED(status)) {
+ GT_2trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: Channel from RMS "
+ "open failed, chnl id = %d, status = 0x%x\n",
+ ulChnlId, status);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Allocate buffer for commands, replies */
+ pDisp->ulBufsize = pDispAttrs->ulChnlBufSize;
+ pDisp->ulBufsizeRMS = RMS_COMMANDBUFSIZE;
+ pDisp->pBuf = MEM_Calloc(pDisp->ulBufsize, MEM_PAGED);
+ if (pDisp->pBuf == NULL) {
+ status = DSP_EMEMORY;
+ GT_0trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Create: Failed "
+ "to allocate channel buffer!\n");
+ }
+ }
+func_cont:
+ if (DSP_SUCCEEDED(status))
+ *phDispObject = pDisp;
+ else
+ DeleteDisp(pDisp);
+
+ DBC_Ensure(((DSP_FAILED(status)) && ((*phDispObject == NULL))) ||
+ ((DSP_SUCCEEDED(status)) &&
+ (MEM_IsValidHandle((*phDispObject), DISP_SIGNATURE))));
+ return status;
+}
+
+/*
+ * ======== DISP_Delete ========
+ * Delete the NODE Dispatcher.
+ */
+void DISP_Delete(struct DISP_OBJECT *hDisp)
+{
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+
+ GT_1trace(DISP_DebugMask, GT_ENTER,
+ "DISP_Delete: hDisp: 0x%x\n", hDisp);
+
+ DeleteDisp(hDisp);
+
+ DBC_Ensure(!MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+}
+
+/*
+ * ======== DISP_Exit ========
+ * Discontinue usage of DISP module.
+ */
+void DISP_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ cRefs--;
+
+ GT_1trace(DISP_DebugMask, GT_5CLASS,
+ "Entered DISP_Exit, ref count: 0x%x\n", cRefs);
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== DISP_Init ========
+ * Initialize the DISP module.
+ */
+bool DISP_Init(void)
+{
+ bool fRetVal = true;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+ DBC_Assert(!DISP_DebugMask.flags);
+ GT_create(&DISP_DebugMask, "DI"); /* "DI" for DIspatcher */
+ }
+
+ if (fRetVal)
+ cRefs++;
+
+ GT_1trace(DISP_DebugMask, GT_5CLASS,
+ "DISP_Init(), ref count: 0x%x\n", cRefs);
+
+ DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0)));
+ return fRetVal;
+}
+
+/*
+ * ======== DISP_NodeChangePriority ========
+ * Change the priority of a node currently running on the target.
+ */
+DSP_STATUS DISP_NodeChangePriority(struct DISP_OBJECT *hDisp,
+ struct NODE_OBJECT *hNode,
+ u32 ulRMSFxn, NODE_ENV nodeEnv,
+ s32 nPriority)
+{
+ u32 dwArg;
+ struct RMS_Command *pCommand;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+ DBC_Require(hNode != NULL);
+
+ GT_5trace(DISP_DebugMask, GT_ENTER, "DISP_NodeChangePriority: hDisp: "
+ "0x%x\thNode: 0x%x\tulRMSFxn: 0x%x\tnodeEnv: 0x%x\tnPriority\n",
+ hDisp, hNode, ulRMSFxn, nodeEnv, nPriority);
+
+ /* Send message to RMS to change priority */
+ pCommand = (struct RMS_Command *)(hDisp->pBuf);
+ pCommand->fxn = (RMS_WORD)(ulRMSFxn);
+ pCommand->arg1 = (RMS_WORD)nodeEnv;
+ pCommand->arg2 = nPriority;
+ status = SendMessage(hDisp, NODE_GetTimeout(hNode),
+ sizeof(struct RMS_Command), &dwArg);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeChangePriority failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+
+/*
+ * ======== DISP_NodeCreate ========
+ * Create a node on the DSP by remotely calling the node's create function.
+ */
+DSP_STATUS DISP_NodeCreate(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode,
+ u32 ulRMSFxn, u32 ulCreateFxn,
+ IN CONST struct NODE_CREATEARGS *pArgs,
+ OUT NODE_ENV *pNodeEnv)
+{
+ struct NODE_MSGARGS msgArgs;
+ struct NODE_TASKARGS taskArgs;
+ struct RMS_Command *pCommand;
+ struct RMS_MsgArgs *pMsgArgs;
+ struct RMS_MoreTaskArgs *pMoreTaskArgs;
+ enum NODE_TYPE nodeType;
+ u32 dwLength;
+ RMS_WORD *pdwBuf = NULL;
+ u32 ulBytes;
+ u32 i;
+ u32 total;
+ u32 uCharsInRMSWord;
+ s32 taskArgsOffset;
+ s32 sioInDefOffset;
+ s32 sioOutDefOffset;
+ s32 sioDefsOffset;
+ s32 argsOffset = -1;
+ s32 offset;
+ struct NODE_STRMDEF strmDef;
+ u32 max;
+ DSP_STATUS status = DSP_SOK;
+ struct DSP_NODEINFO nodeInfo;
+ u32 devType;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+ DBC_Require(hNode != NULL);
+ DBC_Require(NODE_GetType(hNode) != NODE_DEVICE);
+ DBC_Require(pNodeEnv != NULL);
+
+ GT_6trace(DISP_DebugMask, GT_ENTER,
+ "DISP_NodeCreate: hDisp: 0x%x\thNode:"
+ " 0x%x\tulRMSFxn: 0x%x\tulCreateFxn: 0x%x\tpArgs: 0x%x\tpNodeEnv:"
+ " 0x%x\n", hDisp, hNode, ulRMSFxn, ulCreateFxn, pArgs, pNodeEnv);
+
+ status = DEV_GetDevType(hDisp->hDevObject, &devType);
+
+ GT_1trace(DISP_DebugMask, GT_6CLASS, "DISP_Create: Creating DISP "
+ "for device = 0x%x\n", devType);
+
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ if (devType != DSP_UNIT) {
+ GT_1trace(DISP_DebugMask, GT_7CLASS,
+ "DISP_NodeCreate unknown device "
+ "type = 0x%x\n", devType);
+ goto func_end;
+ }
+ DBC_Require(pArgs != NULL);
+ nodeType = NODE_GetType(hNode);
+ msgArgs = pArgs->asa.msgArgs;
+ max = hDisp->ulBufsizeRMS; /*Max # of RMS words that can be sent */
+ DBC_Assert(max == RMS_COMMANDBUFSIZE);
+ uCharsInRMSWord = sizeof(RMS_WORD) / hDisp->uCharSize;
+ /* Number of RMS words needed to hold arg data */
+ dwLength = (msgArgs.uArgLength + uCharsInRMSWord - 1) / uCharsInRMSWord;
+ /* Make sure msg args and command fit in buffer */
+ total = sizeof(struct RMS_Command) / sizeof(RMS_WORD) +
+ sizeof(struct RMS_MsgArgs)
+ / sizeof(RMS_WORD) - 1 + dwLength;
+ if (total >= max) {
+ status = DSP_EFAIL;
+ GT_2trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeCreate: Message args too"
+ " large for buffer! Message args size = %d, max = %d\n",
+ total, max);
+ }
+ /*
+ * Fill in buffer to send to RMS.
+ * The buffer will have the following format:
+ *
+ * RMS command:
+ * Address of RMS_CreateNode()
+ * Address of node's create function
+ * dummy argument
+ * node type
+ *
+ * Message Args:
+ * max number of messages
+ * segid for message buffer allocation
+ * notification type to use when message is received
+ * length of message arg data
+ * message args data
+ *
+ * Task Args (if task or socket node):
+ * priority
+ * stack size
+ * system stack size
+ * stack segment
+ * misc
+ * number of input streams
+ * pSTRMInDef[] - offsets of STRM definitions for input streams
+ * number of output streams
+ * pSTRMOutDef[] - offsets of STRM definitions for output
+ * streams
+ * STRMInDef[] - array of STRM definitions for input streams
+ * STRMOutDef[] - array of STRM definitions for output streams
+ *
+ * Socket Args (if DAIS socket node):
+ *
+ */
+ if (DSP_SUCCEEDED(status)) {
+ total = 0; /* Total number of words in buffer so far */
+ pdwBuf = (RMS_WORD *)hDisp->pBuf;
+ pCommand = (struct RMS_Command *)pdwBuf;
+ pCommand->fxn = (RMS_WORD)(ulRMSFxn);
+ pCommand->arg1 = (RMS_WORD)(ulCreateFxn);
+ if (NODE_GetLoadType(hNode) == NLDR_DYNAMICLOAD) {
+ /* Flush ICACHE on Load */
+ pCommand->arg2 = 1; /* dummy argument */
+ } else {
+ /* Do not flush ICACHE */
+ pCommand->arg2 = 0; /* dummy argument */
+ }
+ pCommand->data = NODE_GetType(hNode);
+ /*
+ * argsOffset is the offset of the data field in struct
+ * RMS_Command structure. We need this to calculate stream
+ * definition offsets.
+ */
+ argsOffset = 3;
+ total += sizeof(struct RMS_Command) / sizeof(RMS_WORD);
+ /* Message args */
+ pMsgArgs = (struct RMS_MsgArgs *) (pdwBuf + total);
+ pMsgArgs->maxMessages = msgArgs.uMaxMessages;
+ pMsgArgs->segid = msgArgs.uSegid;
+ pMsgArgs->notifyType = msgArgs.uNotifyType;
+ pMsgArgs->argLength = msgArgs.uArgLength;
+ total += sizeof(struct RMS_MsgArgs) / sizeof(RMS_WORD) - 1;
+ memcpy(pdwBuf + total, msgArgs.pData, msgArgs.uArgLength);
+ total += dwLength;
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* If node is a task node, copy task create arguments into buffer */
+ if (nodeType == NODE_TASK || nodeType == NODE_DAISSOCKET) {
+ taskArgs = pArgs->asa.taskArgs;
+ taskArgsOffset = total;
+ total += sizeof(struct RMS_MoreTaskArgs) / sizeof(RMS_WORD) +
+ 1 + taskArgs.uNumInputs + taskArgs.uNumOutputs;
+ /* Copy task arguments */
+ if (total < max) {
+ total = taskArgsOffset;
+ pMoreTaskArgs = (struct RMS_MoreTaskArgs *)(pdwBuf +
+ total);
+ /*
+ * Get some important info about the node. Note that we
+ * don't just reach into the hNode struct because
+ * that would break the node object's abstraction.
+ */
+ GetNodeInfo(hNode, &nodeInfo);
+ GT_2trace(DISP_DebugMask, GT_ENTER,
+ "uExecutionPriority %x, nPriority %x\n",
+ nodeInfo.uExecutionPriority,
+ taskArgs.nPriority);
+ pMoreTaskArgs->priority = nodeInfo.uExecutionPriority;
+ pMoreTaskArgs->stackSize = taskArgs.uStackSize;
+ pMoreTaskArgs->sysstackSize = taskArgs.uSysStackSize;
+ pMoreTaskArgs->stackSeg = taskArgs.uStackSeg;
+ pMoreTaskArgs->heapAddr = taskArgs.uDSPHeapAddr;
+ pMoreTaskArgs->heapSize = taskArgs.uHeapSize;
+ pMoreTaskArgs->misc = taskArgs.ulDaisArg;
+ pMoreTaskArgs->numInputStreams = taskArgs.uNumInputs;
+ total +=
+ sizeof(struct RMS_MoreTaskArgs) / sizeof(RMS_WORD);
+ GT_2trace(DISP_DebugMask, GT_7CLASS,
+ "DISP::::uDSPHeapAddr %x, "
+ "uHeapSize %x\n", taskArgs.uDSPHeapAddr,
+ taskArgs.uHeapSize);
+ /* Keep track of pSIOInDef[] and pSIOOutDef[]
+ * positions in the buffer, since this needs to be
+ * filled in later. */
+ sioInDefOffset = total;
+ total += taskArgs.uNumInputs;
+ pdwBuf[total++] = taskArgs.uNumOutputs;
+ sioOutDefOffset = total;
+ total += taskArgs.uNumOutputs;
+ sioDefsOffset = total;
+ /* Fill SIO defs and offsets */
+ offset = sioDefsOffset;
+ for (i = 0; i < taskArgs.uNumInputs; i++) {
+ if (DSP_FAILED(status))
+ break;
+
+ pdwBuf[sioInDefOffset + i] =
+ (offset - argsOffset)
+ * (sizeof(RMS_WORD) / DSPWORDSIZE);
+ strmDef = taskArgs.strmInDef[i];
+ status = FillStreamDef(pdwBuf, &total, offset,
+ strmDef, max, uCharsInRMSWord);
+ offset = total;
+ }
+ for (i = 0; (i < taskArgs.uNumOutputs) &&
+ (DSP_SUCCEEDED(status)); i++) {
+ pdwBuf[sioOutDefOffset + i] =
+ (offset - argsOffset)
+ * (sizeof(RMS_WORD) / DSPWORDSIZE);
+ strmDef = taskArgs.strmOutDef[i];
+ status = FillStreamDef(pdwBuf, &total, offset,
+ strmDef, max, uCharsInRMSWord);
+ offset = total;
+ }
+ if (DSP_FAILED(status)) {
+ GT_2trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeCreate: Message"
+ " args to large for buffer! Message args"
+ " size = %d, max = %d\n", total, max);
+ }
+ } else {
+ /* Args won't fit */
+ status = DSP_EFAIL;
+ GT_2trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeCreate: Message args "
+ " too large for buffer! Message args size = %d"
+ ", max = %d\n", total, max);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ ulBytes = total * sizeof(RMS_WORD);
+ DBC_Assert(ulBytes < (RMS_COMMANDBUFSIZE * sizeof(RMS_WORD)));
+ status = SendMessage(hDisp, NODE_GetTimeout(hNode),
+ ulBytes, pNodeEnv);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeCreate failed! "
+ "status = 0x%x\n", status);
+ } else {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's create function
+ * on the DSP-side
+ */
+ status = (((RMS_WORD *)(hDisp->pBuf))[0]);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeCreate, "
+ "DSP-side Node Create failed: 0x%x\n",
+ status);
+ }
+
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== DISP_NodeDelete ========
+ * purpose:
+ * Delete a node on the DSP by remotely calling the node's delete function.
+ *
+ */
+DSP_STATUS DISP_NodeDelete(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode,
+ u32 ulRMSFxn, u32 ulDeleteFxn, NODE_ENV nodeEnv)
+{
+ u32 dwArg;
+ struct RMS_Command *pCommand;
+ DSP_STATUS status = DSP_SOK;
+ u32 devType;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+ DBC_Require(hNode != NULL);
+
+ GT_5trace(DISP_DebugMask, GT_ENTER,
+ "DISP_NodeDelete: hDisp: 0x%xthNode: "
+ "0x%x\tulRMSFxn: 0x%x\tulDeleteFxn: 0x%x\tnodeEnv: 0x%x\n",
+ hDisp, hNode, ulRMSFxn, ulDeleteFxn, nodeEnv);
+
+ status = DEV_GetDevType(hDisp->hDevObject, &devType);
+
+ if (DSP_SUCCEEDED(status)) {
+
+ if (devType == DSP_UNIT) {
+
+ /*
+ * Fill in buffer to send to RMS
+ */
+ pCommand = (struct RMS_Command *)hDisp->pBuf;
+ pCommand->fxn = (RMS_WORD)(ulRMSFxn);
+ pCommand->arg1 = (RMS_WORD)nodeEnv;
+ pCommand->arg2 = (RMS_WORD)(ulDeleteFxn);
+ pCommand->data = NODE_GetType(hNode);
+
+ status = SendMessage(hDisp, NODE_GetTimeout(hNode),
+ sizeof(struct RMS_Command), &dwArg);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeDelete failed!"
+ "status = 0x%x\n", status);
+ } else {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's delete
+ * function on the DSP-side
+ */
+ status = (((RMS_WORD *)(hDisp->pBuf))[0]);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeDelete, "
+ "DSP-side Node Delete failed: 0x%x\n",
+ status);
+ }
+ }
+
+
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== DISP_NodeRun ========
+ * purpose:
+ * Start execution of a node's execute phase, or resume execution of a node
+ * that has been suspended (via DISP_NodePause()) on the DSP.
+ */
+DSP_STATUS DISP_NodeRun(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode,
+ u32 ulRMSFxn, u32 ulExecuteFxn, NODE_ENV nodeEnv)
+{
+ u32 dwArg;
+ struct RMS_Command *pCommand;
+ DSP_STATUS status = DSP_SOK;
+ u32 devType;
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE));
+ DBC_Require(hNode != NULL);
+
+ GT_5trace(DISP_DebugMask, GT_ENTER, "DISP_NodeRun: hDisp: 0x%xthNode: \
+ 0x%x\tulRMSFxn: 0x%x\tulExecuteFxn: 0x%x\tnodeEnv: 0x%x\n", \
+ hDisp, hNode, ulRMSFxn, ulExecuteFxn, nodeEnv);
+
+ status = DEV_GetDevType(hDisp->hDevObject, &devType);
+
+ if (DSP_SUCCEEDED(status)) {
+
+ if (devType == DSP_UNIT) {
+
+ /*
+ * Fill in buffer to send to RMS.
+ */
+ pCommand = (struct RMS_Command *) hDisp->pBuf;
+ pCommand->fxn = (RMS_WORD) (ulRMSFxn);
+ pCommand->arg1 = (RMS_WORD) nodeEnv;
+ pCommand->arg2 = (RMS_WORD) (ulExecuteFxn);
+ pCommand->data = NODE_GetType(hNode);
+
+ status = SendMessage(hDisp, NODE_GetTimeout(hNode),
+ sizeof(struct RMS_Command), &dwArg);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeRun failed!"
+ "status = 0x%x\n", status);
+ } else {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's execute
+ * function on the DSP-side
+ */
+ status = (((RMS_WORD *)(hDisp->pBuf))[0]);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_NodeRun, DSP-side Node "
+ "Execute failed: 0x%x\n",
+ status);
+ }
+ }
+
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== DeleteDisp ========
+ * purpose:
+ * Frees the resources allocated for the dispatcher.
+ */
+static void DeleteDisp(struct DISP_OBJECT *hDisp)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+
+ if (MEM_IsValidHandle(hDisp, DISP_SIGNATURE)) {
+ pIntfFxns = hDisp->pIntfFxns;
+
+ /* Free Node Dispatcher resources */
+ if (hDisp->hChnlFromDsp) {
+ /* Channel close can fail only if the channel handle
+ * is invalid. */
+ status = (*pIntfFxns->pfnChnlClose)
+ (hDisp->hChnlFromDsp);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Delete: Failed to "
+ "close channel from RMS: 0x%x\n",
+ status);
+ }
+ }
+ if (hDisp->hChnlToDsp) {
+ status = (*pIntfFxns->pfnChnlClose)(hDisp->hChnlToDsp);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "DISP_Delete: Failed to "
+ "close channel to RMS: 0x%x\n",
+ status);
+ }
+ }
+ if (hDisp->pBuf)
+ MEM_Free(hDisp->pBuf);
+
+ MEM_FreeObject(hDisp);
+ }
+}
+
+/*
+ * ======== FillStreamDef ========
+ * purpose:
+ * Fills stream definitions.
+ */
+static DSP_STATUS FillStreamDef(RMS_WORD *pdwBuf, u32 *ptotal, u32 offset,
+ struct NODE_STRMDEF strmDef, u32 max,
+ u32 uCharsInRMSWord)
+{
+ struct RMS_StrmDef *pStrmDef;
+ u32 total = *ptotal;
+ u32 uNameLen;
+ u32 dwLength;
+ DSP_STATUS status = DSP_SOK;
+
+ if (total + sizeof(struct RMS_StrmDef) / sizeof(RMS_WORD) >= max) {
+ status = DSP_EFAIL;
+ } else {
+ pStrmDef = (struct RMS_StrmDef *)(pdwBuf + total);
+ pStrmDef->bufsize = strmDef.uBufsize;
+ pStrmDef->nbufs = strmDef.uNumBufs;
+ pStrmDef->segid = strmDef.uSegid;
+ pStrmDef->align = strmDef.uAlignment;
+ pStrmDef->timeout = strmDef.uTimeout;
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /*
+ * Since we haven't added the device name yet, subtract
+ * 1 from total.
+ */
+ total += sizeof(struct RMS_StrmDef) / sizeof(RMS_WORD) - 1;
+ DBC_Require(strmDef.szDevice);
+ dwLength = strlen(strmDef.szDevice) + 1;
+
+ /* Number of RMS_WORDS needed to hold device name */
+ uNameLen = (dwLength + uCharsInRMSWord - 1) / uCharsInRMSWord;
+
+ if (total + uNameLen >= max) {
+ status = DSP_EFAIL;
+ } else {
+ /*
+ * Zero out last word, since the device name may not
+ * extend to completely fill this word.
+ */
+ pdwBuf[total + uNameLen - 1] = 0;
+ /** TODO USE SERVICES **/
+ memcpy(pdwBuf + total, strmDef.szDevice, dwLength);
+ total += uNameLen;
+ *ptotal = total;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== SendMessage ======
+ * Send command message to RMS, get reply from RMS.
+ */
+static DSP_STATUS SendMessage(struct DISP_OBJECT *hDisp, u32 dwTimeout,
+ u32 ulBytes, u32 *pdwArg)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct CHNL_OBJECT *hChnl;
+ u32 dwArg = 0;
+ u8 *pBuf;
+ struct CHNL_IOC chnlIOC;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(pdwArg != NULL);
+
+ *pdwArg = (u32) NULL;
+ pIntfFxns = hDisp->pIntfFxns;
+ hChnl = hDisp->hChnlToDsp;
+ pBuf = hDisp->pBuf;
+
+ /* Send the command */
+ status = (*pIntfFxns->pfnChnlAddIOReq) (hChnl, pBuf, ulBytes, 0,
+ 0L, dwArg);
+
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage: Channel AddIOReq to"
+ " RMS failed! Status = 0x%x\n", status);
+ goto func_cont;
+ }
+ status = (*pIntfFxns->pfnChnlGetIOC) (hChnl, dwTimeout, &chnlIOC);
+ if (DSP_SUCCEEDED(status)) {
+ if (!CHNL_IsIOComplete(chnlIOC)) {
+ if (CHNL_IsTimedOut(chnlIOC)) {
+ status = DSP_ETIMEOUT;
+ } else {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage failed! "
+ "Channel IOC status = 0x%x\n",
+ chnlIOC.status);
+ status = DSP_EFAIL;
+ }
+ }
+ } else {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage: Channel GetIOC to"
+ " RMS failed! Status = 0x%x\n", status);
+ }
+func_cont:
+ /* Get the reply */
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ hChnl = hDisp->hChnlFromDsp;
+ ulBytes = REPLYSIZE;
+ status = (*pIntfFxns->pfnChnlAddIOReq)(hChnl, pBuf, ulBytes,
+ 0, 0L, dwArg);
+ if (DSP_FAILED(status)) {
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage: Channel AddIOReq "
+ "from RMS failed! Status = 0x%x\n", status);
+ goto func_end;
+ }
+ status = (*pIntfFxns->pfnChnlGetIOC) (hChnl, dwTimeout, &chnlIOC);
+ if (DSP_SUCCEEDED(status)) {
+ if (CHNL_IsTimedOut(chnlIOC)) {
+ status = DSP_ETIMEOUT;
+ } else if (chnlIOC.cBytes < ulBytes) {
+ /* Did not get all of the reply from the RMS */
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage: Did not get all"
+ "of reply from RMS! Bytes received: %d\n",
+ chnlIOC.cBytes);
+ status = DSP_EFAIL;
+ } else {
+ if (CHNL_IsIOComplete(chnlIOC)) {
+ DBC_Assert(chnlIOC.pBuf == pBuf);
+ status = (*((RMS_WORD *)chnlIOC.pBuf));
+ *pdwArg = (((RMS_WORD *)(chnlIOC.pBuf))[1]);
+ } else {
+ status = DSP_EFAIL;
+ }
+ }
+ } else {
+ /* GetIOC failed */
+ GT_1trace(DISP_DebugMask, GT_6CLASS,
+ "SendMessage: Failed to get "
+ "reply from RMS! Status = 0x%x\n", status);
+ }
+func_end:
+ return status;
+}
diff --git a/drivers/dsp/bridge/rmgr/drv.c b/drivers/dsp/bridge/rmgr/drv.c
new file mode 100755
index 000000000000..8690f08b0288
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/drv.c
@@ -0,0 +1,1936 @@
+/*
+ * drv.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== drv.c ========
+ * Description:
+ * DSP/BIOS Bridge resource allocation module.
+ *
+ * Public Functions:
+ * DRV_Create
+ * DRV_Destroy
+ * DRV_Exit
+ * DRV_GetDevObject
+ * DRV_GetDevExtension
+ * DRV_GetFirstDevObject
+ * DRV_GetNextDevObject
+ * DRV_GetNextDevExtension
+ * DRV_Init
+ * DRV_InsertDevObject
+ * DRV_RemoveDevObject
+ * DRV_RequestResources
+ * DRV_ReleaseResources
+ *
+ *! Revision History
+ *! ======== ========
+ *! 19-Apr-2004 sb: Replaced OS specific APIs with MEM_AllocPhysMem and
+ MEM_FreePhysMem. Fixed warnings. Cosmetic updates.
+ *! 12-Apr-2004 hp: IVA clean up during bridge-uninstall
+ *! 05-Jan-2004 vp: Updated for 24xx platform
+ *! 21-Mar-2003 sb: Get SHM size from registry
+ *! 10-Feb-2003 vp: Code review updates
+ *! 18-Oct-2002 vp: Ported to Linux platform
+ *! 30-Oct-2000 kc: Modified usage of REG_SetValue.
+ *! 06-Sep-2000 jeh Read channel info into struct CFG_HOSTRES in
+ *! RequestISAResources()
+ *! 21-Sep-2000 rr: numwindows is calculated instead of default value in
+ *! RequestISAResources.
+ *! 07-Aug-2000 rr: static list of dev objects removed.
+ *! 27-Jul-2000 rr: RequestResources split into two(Request and Release)
+ *! Device extension created to hold the DevNodeString.
+ *! 17-Jul-2000 rr: Driver Object holds the list of Device Objects.
+ *! Added DRV_Create, DRV_Destroy, DRV_GetDevObject,
+ *! DRV_GetFirst/NextDevObject, DRV_Insert/RemoveDevObject.
+ *! 09-May-2000 rr: PCI Support is not L301 specific.Use of MEM_Calloc
+ *! instead of MEM_Alloc.
+ *! 28-Mar-2000 rr: PCI Support added. L301 Specific. TBD.
+ *! 03-Feb-2000 rr: GT and Module Init/exit Changes. Merged with kc.
+ *! 19-Jan-2000 rr: DBC_Ensure in RequestPCMCIA moved within PCCARD ifdef
+ *! 29-Dec-1999 rr: PCCard support for any slot.Bus type stored in the
+ *! struct CFG_HOSTRES Structure.
+ *! 17-Dec-1999 rr: if PCCARD_Init fails we return DSP_EFAIL.
+ *! DBC_Ensure checks for sucess and pDevice != NULL
+ *! 11-Dec-1999 ag: #define "Isa" renamed to "IsaBus".
+ *! 09-Dec-1999 rr: windows.h included to remove warnings.
+ *! 02-Dec-1999 rr: struct GT_Mask is with in if DEBUG. Request resources checks
+ *! status while making call to Reg functions.
+ *! 23-Nov-1999 rr: windows.h included
+ *! 19-Nov-1999 rr: DRV_RELEASE bug while setting the registry to zero.
+ *! fixed.
+ *! 12-Nov-1999 rr: RequestResources() reads values from the registry.
+ *! Hardcoded bIRQRegister define removed.
+ *! 05-Nov-1999 rr: Added hardcoded device interrupt.
+ *! 25-Oct-1999 rr: Resource structure removed. Now it uses the Host
+ *! Resource structure directly.
+ *! 15-Oct-1999 rr: Resource Structure modified. See drv.h
+ *! dwBusType taken from the registry.Hard coded
+ *! registry entries removed.
+ *! 05-Oct-1999 rr: Calling DEV_StartDevice moved to wcdce.c. DRV_Register
+ *! MiniDriver has been renamed to DRV_RequestResources.
+ *! DRV_UnRegisterMiniDriver fxn removed.
+ *! 24-Sep-1999 rr: Significant changes to the RegisterMiniDriver fxns.
+ *! Now it is simpler. IT stores the dev node in the
+ *! registry, assign resources and calls the DEV_Start.
+ *! 10-Sep-1999 rr: Register Minidriver modified.
+ *! - Resource structure follows the NT model
+ *! 08-Aug-1999 rr: Adopted for WinCE. Exports Fxns removed. Hull Created.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/csl.h>
+#include <dspbridge/list.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/reg.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbreg.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+
+#ifndef RES_CLEANUP_DISABLE
+#include <dspbridge/node.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/strm.h>
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/wmdchnl.h>
+#include <dspbridge/resourcecleanup.h>
+#endif
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define SIGNATURE 0x5f52474d /* "DRV_" (in reverse) */
+
+struct DRV_OBJECT {
+ u32 dwSignature;
+ struct LST_LIST *devList;
+ struct LST_LIST *devNodeString;
+#ifndef RES_CLEANUP_DISABLE
+ struct PROCESS_CONTEXT *procCtxtList;
+#endif
+};
+
+/*
+ * This is the Device Extension. Named with the Prefix
+ * DRV_ since it is living in this module
+ */
+struct DRV_EXT {
+ struct LST_ELEM link;
+ char szString[MAXREGPATHLENGTH];
+};
+
+/* ----------------------------------- Globals */
+static s32 cRefs;
+
+#if GT_TRACE
+extern struct GT_Mask curTrace;
+#endif
+
+/* ----------------------------------- Function Prototypes */
+static DSP_STATUS RequestBridgeResources(u32 dwContext, s32 fRequest);
+static DSP_STATUS RequestBridgeResourcesDSP(u32 dwContext, s32 fRequest);
+
+#ifndef RES_CLEANUP_DISABLE
+/* GPP PROCESS CLEANUP CODE */
+
+static DSP_STATUS PrintProcessInformation(void);
+static DSP_STATUS DRV_ProcFreeNodeRes(HANDLE hPCtxt);
+static DSP_STATUS DRV_ProcFreeSTRMRes(HANDLE hPCtxt);
+extern enum NODE_STATE NODE_GetState(HANDLE hNode);
+
+/* Get the process context list from driver object */
+
+/* Set the Process ID */
+DSP_STATUS DRV_ProcSetPID(HANDLE hPCtxt, s32 hProcess)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Assert(hPCtxt != NULL);
+
+ pCtxt->pid = hProcess;
+ return status;
+}
+
+
+/* Getting the head of the process context list */
+DSP_STATUS DRV_GetProcCtxtList(struct PROCESS_CONTEXT **pPctxt,
+ struct DRV_OBJECT *hDrvObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject;
+
+ DBC_Assert(hDrvObject != NULL);
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_GetProcCtxtList: 2 *pPctxt:%x, pDrvObject"
+ ":%x", *pPctxt, pDrvObject);
+ *pPctxt = pDrvObject->procCtxtList;
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_GetProcCtxtList: 3 *pPctxt:%x, pDrvObject"
+ ":%x", *pPctxt, pDrvObject);
+ return status;
+}
+
+
+
+/* Get a particular process context based on process handle (phProcess) */
+DSP_STATUS DRV_GetProcContext(u32 phProcess,
+ struct DRV_OBJECT *hDrvObject,
+ HANDLE hPCtxt, DSP_HNODE hNode,
+ u32 pMapAddr)
+{
+ struct PROCESS_CONTEXT **pCtxt = (struct PROCESS_CONTEXT **)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct PROCESS_CONTEXT *pCtxtList = NULL;
+ struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject;
+ struct NODE_RES_OBJECT *pTempNode2 = NULL;
+ struct NODE_RES_OBJECT *pTempNode = NULL;
+ struct DMM_RES_OBJECT *pTempDMM2 = NULL;
+ struct DMM_RES_OBJECT *pTempDMM = NULL;
+ s32 pCtxtFound = 0;
+
+ DBC_Assert(pDrvObject != NULL);
+ pCtxtList = pDrvObject->procCtxtList;
+ GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 2");
+ while ((pCtxtList != NULL) && (pCtxtList->pid != phProcess)) {
+ pCtxtList = pCtxtList->next;
+ GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 3");
+ }
+ if (pCtxtList == NULL) {
+ if (hNode != NULL) {
+ pCtxtList = pDrvObject->procCtxtList;
+ while ((pCtxtList != NULL) && (pCtxtFound == 0)) {
+ pTempNode = pCtxtList->pNodeList;
+ while ((pTempNode != NULL) &&
+ (pTempNode->hNode != hNode)) {
+ pTempNode2 = pTempNode;
+ pTempNode = pTempNode->next;
+ }
+ if (pTempNode != NULL) {
+ pCtxtFound = 1;
+ status = DSP_SOK;
+ } else {
+ pCtxtList = pCtxtList->next;
+ }
+ }
+ } else if ((pMapAddr != 0) && (pCtxtFound == 0)) {
+ pCtxtList = pDrvObject->procCtxtList;
+ while ((pCtxtList != NULL) && (pCtxtFound == 0)) {
+ pTempDMM = pCtxtList->pDMMList;
+ while ((pTempDMM != NULL) &&
+ (pTempDMM->ulDSPAddr != pMapAddr)) {
+ pTempDMM2 = pTempDMM;
+ pTempDMM = pTempDMM->next;
+ }
+ if (pTempDMM != NULL) {
+ pCtxtFound = 1;
+ status = DSP_SOK;
+ } else {
+ pCtxtList = pCtxtList->next;
+ }
+ }
+ if (pCtxtList == NULL)
+ status = DSP_ENOTFOUND;
+
+ }
+ } else{
+ status = DSP_SOK;
+ }
+ GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 4");
+ *pCtxt = pCtxtList;
+ return status;
+}
+
+
+/* Add a new process context to process context list */
+DSP_STATUS DRV_InsertProcContext(struct DRV_OBJECT *hDrVObject, HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT **pCtxt = (struct PROCESS_CONTEXT **)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct PROCESS_CONTEXT *pCtxtList = NULL;
+ struct DRV_OBJECT *hDRVObject;
+
+ GT_0trace(curTrace, GT_ENTER, "\n In DRV_InsertProcContext\n");
+ status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT);
+ DBC_Assert(hDRVObject != NULL);
+ *pCtxt = MEM_Calloc(1 * sizeof(struct PROCESS_CONTEXT), MEM_PAGED);
+ GT_0trace(curTrace, GT_ENTER,
+ "\n In DRV_InsertProcContext Calling "
+ "DRV_GetProcCtxtList\n");
+ DRV_GetProcCtxtList(&pCtxtList, hDRVObject);
+ GT_0trace(curTrace, GT_ENTER,
+ "\n In DRV_InsertProcContext After Calling "
+ "DRV_GetProcCtxtList\n");
+ if (pCtxtList != NULL) {
+ GT_0trace(curTrace, GT_ENTER,
+ "\n In DRV_InsertProcContext and pCtxt is "
+ "not Null\n");
+ while (pCtxtList->next != NULL)
+ pCtxtList = pCtxtList->next;
+
+ pCtxtList->next = *pCtxt;
+ } else {
+ GT_0trace(curTrace, GT_ENTER,
+ "\n In DRV_InsertProcContext and "
+ "pCtxt is Null\n");
+ hDRVObject->procCtxtList = *pCtxt;
+ }
+ return status;
+}
+
+/* Delete a process context from process resource context list */
+DSP_STATUS DRV_RemoveProcContext(struct DRV_OBJECT *hDRVObject,
+ HANDLE hPCtxt, HANDLE hProcess)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROCESS_CONTEXT *pCtxt2 = NULL;
+ struct PROCESS_CONTEXT *pTmp = NULL;
+ struct PROCESS_CONTEXT *pCtxtList = NULL;
+
+ DBC_Assert(hDRVObject != NULL);
+ DRV_GetProcContext((u32)hProcess, hDRVObject, &pCtxt2, NULL, 0);
+
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 12");
+ DRV_GetProcCtxtList(&pCtxtList, hDRVObject);
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 13");
+ pTmp = pCtxtList;
+ while ((pCtxtList != NULL) && (pCtxtList != pCtxt2)) {
+ pTmp = pCtxtList;
+ pCtxtList = pCtxtList->next;
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_RemoveProcContext: 2");
+ }
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 3");
+ if (hDRVObject->procCtxtList == pCtxt2)
+ hDRVObject->procCtxtList = pCtxt2->next;
+
+ if (pCtxtList == NULL)
+ return DSP_ENOTFOUND;
+ else if (pTmp->next != NULL)
+ pTmp->next = pTmp->next->next;
+
+ MEM_Free(pCtxt2);
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 7");
+
+ return status;
+}
+
+/* Update the state of process context */
+DSP_STATUS DRV_ProcUpdatestate(HANDLE hPCtxt, enum GPP_PROC_RES_STATE status)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status1 = DSP_SOK;
+ if (pCtxt != NULL) {
+ pCtxt->resState = status;
+ } else {
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_ProcUpdatestate: Failed to update "
+ "process state");
+ }
+ return status1;
+}
+
+/* Allocate and add a node resource element
+* This function is called from .Node_Allocate. */
+DSP_STATUS DRV_InsertNodeResElement(HANDLE hNode, HANDLE hNodeRes,
+ HANDLE hPCtxt)
+{
+ struct NODE_RES_OBJECT **pNodeRes = (struct NODE_RES_OBJECT **)hNodeRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_RES_OBJECT *pTempNodeRes = NULL;
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 1");
+ *pNodeRes = (struct NODE_RES_OBJECT *)MEM_Calloc
+ (1 * sizeof(struct NODE_RES_OBJECT), MEM_PAGED);
+ DBC_Assert(hPCtxt != NULL);
+ if ((*pNodeRes == NULL) || (hPCtxt == NULL)) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 12");
+ status = DSP_EHANDLE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ (*pNodeRes)->hNode = hNode;
+ if (pCtxt->pNodeList != NULL) {
+ pTempNodeRes = pCtxt->pNodeList;
+ while (pTempNodeRes->next != NULL)
+ pTempNodeRes = pTempNodeRes->next;
+
+ pTempNodeRes->next = *pNodeRes;
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_InsertNodeResElement: 2");
+ } else {
+ pCtxt->pNodeList = *pNodeRes;
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_InsertNodeResElement: 3");
+ }
+ }
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 4");
+ return status;
+}
+
+/* Release all Node resources and its context
+* This is called from .Node_Delete. */
+DSP_STATUS DRV_RemoveNodeResElement(HANDLE hNodeRes, HANDLE hPCtxt)
+{
+ struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_RES_OBJECT *pTempNode2 = pCtxt->pNodeList;
+ struct NODE_RES_OBJECT *pTempNode = pCtxt->pNodeList;
+
+ DBC_Assert(hPCtxt != NULL);
+ GT_0trace(curTrace, GT_ENTER, "\nDRV_RemoveNodeResElement: 1\n");
+ while ((pTempNode != NULL) && (pTempNode != pNodeRes)) {
+ pTempNode2 = pTempNode;
+ pTempNode = pTempNode->next;
+ }
+ if (pCtxt->pNodeList == pNodeRes)
+ pCtxt->pNodeList = pNodeRes->next;
+
+ if (pTempNode == NULL)
+ return DSP_ENOTFOUND;
+ else if (pTempNode2->next != NULL)
+ pTempNode2->next = pTempNode2->next->next;
+
+ MEM_Free(pTempNode);
+ return status;
+}
+
+/* Actual Node De-Allocation */
+static DSP_STATUS DRV_ProcFreeNodeRes(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_RES_OBJECT *pNodeList = NULL;
+ struct NODE_RES_OBJECT *pNodeRes = NULL;
+ u32 nState;
+
+ DBC_Assert(hPCtxt != NULL);
+ pNodeList = pCtxt->pNodeList;
+ while (pNodeList != NULL) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_ProcFreeNodeRes: 1");
+ pNodeRes = pNodeList;
+ pNodeList = pNodeList->next;
+ if (pNodeRes->nodeAllocated) {
+ nState = NODE_GetState(pNodeRes->hNode) ;
+ GT_1trace(curTrace, GT_5CLASS,
+ "DRV_ProcFreeNodeRes: Node state %x\n", nState);
+ if (nState <= NODE_DELETING) {
+ if ((nState == NODE_RUNNING) ||
+ (nState == NODE_PAUSED) ||
+ (nState == NODE_TERMINATING)) {
+ GT_1trace(curTrace, GT_5CLASS,
+ "Calling Node_Terminate for Node:"
+ " 0x%x\n", pNodeRes->hNode);
+ status = NODE_Terminate
+ (pNodeRes->hNode, &status);
+ GT_1trace(curTrace, GT_5CLASS,
+ "Calling Node_Delete for Node:"
+ " 0x%x\n", pNodeRes->hNode);
+ status = NODE_Delete(pNodeRes->hNode);
+ GT_1trace(curTrace, GT_5CLASS,
+ "the status after the NodeDelete %x\n",
+ status);
+ } else if ((nState == NODE_ALLOCATED)
+ || (nState == NODE_CREATED))
+ status = NODE_Delete(pNodeRes->hNode);
+ }
+ }
+ pNodeRes->nodeAllocated = 0;
+ }
+ return status;
+}
+
+/* Allocate the DMM resource element
+* This is called from Proc_Map. after the actual resource is allocated */
+DSP_STATUS DRV_InsertDMMResElement(HANDLE hDMMRes, HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ struct DMM_RES_OBJECT **pDMMRes = (struct DMM_RES_OBJECT **)hDMMRes;
+ DSP_STATUS status = DSP_SOK;
+ struct DMM_RES_OBJECT *pTempDMMRes = NULL;
+
+ *pDMMRes = (struct DMM_RES_OBJECT *)
+ MEM_Calloc(1 * sizeof(struct DMM_RES_OBJECT), MEM_PAGED);
+ DBC_Assert(hPCtxt != NULL);
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertDMMResElement: 1");
+ if ((*pDMMRes == NULL) || (hPCtxt == NULL)) {
+ GT_0trace(curTrace, GT_5CLASS, "DRV_InsertDMMResElement: 2");
+ status = DSP_EHANDLE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ if (pCtxt->pDMMList != NULL) {
+ GT_0trace(curTrace, GT_5CLASS,
+ "DRV_InsertDMMResElement: 3");
+ pTempDMMRes = pCtxt->pDMMList;
+ while (pTempDMMRes->next != NULL)
+ pTempDMMRes = pTempDMMRes->next;
+
+ pTempDMMRes->next = *pDMMRes;
+ } else {
+ pCtxt->pDMMList = *pDMMRes;
+ GT_0trace(curTrace, GT_5CLASS,
+ "DRV_InsertDMMResElement: 4");
+ }
+ }
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertDMMResElement: 5");
+ return status;
+}
+
+
+
+/* Release DMM resource element context
+* This is called from Proc_UnMap. after the actual resource is freed */
+DSP_STATUS DRV_RemoveDMMResElement(HANDLE hDMMRes, HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ struct DMM_RES_OBJECT *pDMMRes = (struct DMM_RES_OBJECT *)hDMMRes;
+ DSP_STATUS status = DSP_SOK;
+ struct DMM_RES_OBJECT *pTempDMMRes2 = NULL;
+ struct DMM_RES_OBJECT *pTempDMMRes = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ pTempDMMRes2 = pCtxt->pDMMList;
+ pTempDMMRes = pCtxt->pDMMList;
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 1");
+ while ((pTempDMMRes != NULL) && (pTempDMMRes != pDMMRes)) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 2");
+ pTempDMMRes2 = pTempDMMRes;
+ pTempDMMRes = pTempDMMRes->next;
+ }
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 3");
+ if (pCtxt->pDMMList == pTempDMMRes)
+ pCtxt->pDMMList = pTempDMMRes->next;
+
+ if (pTempDMMRes == NULL)
+ return DSP_ENOTFOUND;
+ else if (pTempDMMRes2->next != NULL)
+ pTempDMMRes2->next = pTempDMMRes2->next->next;
+
+ MEM_Free(pDMMRes);
+ GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 4");
+ return status;
+}
+
+/* Update DMM resource status */
+DSP_STATUS DRV_UpdateDMMResElement(HANDLE hDMMRes, u32 pMpuAddr, u32 ulSize,
+ u32 pReqAddr, u32 pMapAddr,
+ HANDLE hProcessor)
+{
+ struct DMM_RES_OBJECT *pDMMRes = (struct DMM_RES_OBJECT *)hDMMRes;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Assert(hDMMRes != NULL);
+ pDMMRes->ulMpuAddr = pMpuAddr;
+ pDMMRes->ulDSPAddr = pMapAddr;
+ pDMMRes->ulDSPResAddr = pReqAddr;
+ pDMMRes->dmmSize = ulSize;
+ pDMMRes->hProcessor = hProcessor;
+ pDMMRes->dmmAllocated = 1;
+
+ return status;
+}
+
+/* Actual DMM De-Allocation */
+DSP_STATUS DRV_ProcFreeDMMRes(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct DMM_RES_OBJECT *pDMMList = pCtxt->pDMMList;
+ struct DMM_RES_OBJECT *pDMMRes = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ GT_0trace(curTrace, GT_ENTER, "\nDRV_ProcFreeDMMRes: 1\n");
+ while (pDMMList != NULL) {
+ pDMMRes = pDMMList;
+ pDMMList = pDMMList->next;
+ if (pDMMRes->dmmAllocated) {
+ status = PROC_UnMap(pDMMRes->hProcessor,
+ (void *)pDMMRes->ulDSPResAddr);
+ status = PROC_UnReserveMemory(pDMMRes->hProcessor,
+ (void *)pDMMRes->ulDSPResAddr);
+ pDMMRes->dmmAllocated = 0;
+ }
+ }
+ return status;
+}
+
+
+/* Release all DMM resources and its context
+* This is called from .bridge_release. */
+DSP_STATUS DRV_RemoveAllDMMResElements(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct DMM_RES_OBJECT *pTempDMMRes2 = NULL;
+ struct DMM_RES_OBJECT *pTempDMMRes = NULL;
+
+ DBC_Assert(pCtxt != NULL);
+ DRV_ProcFreeDMMRes(pCtxt);
+ pTempDMMRes = pCtxt->pDMMList;
+ while (pTempDMMRes != NULL) {
+ pTempDMMRes2 = pTempDMMRes;
+ pTempDMMRes = pTempDMMRes->next;
+ MEM_Free(pTempDMMRes2);
+ }
+ pCtxt->pDMMList = NULL;
+ return status;
+}
+
+DSP_STATUS DRV_GetDMMResElement(u32 pMapAddr, HANDLE hDMMRes, HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ struct DMM_RES_OBJECT **pDMMRes = (struct DMM_RES_OBJECT **)hDMMRes;
+ DSP_STATUS status = DSP_SOK;
+ struct DMM_RES_OBJECT *pTempDMM2 = NULL;
+ struct DMM_RES_OBJECT *pTempDMM = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ pTempDMM = pCtxt->pDMMList;
+ while ((pTempDMM != NULL) && (pTempDMM->ulDSPAddr != pMapAddr)) {
+ GT_3trace(curTrace, GT_ENTER,
+ "DRV_GetDMMResElement: 2 pTempDMM:%x "
+ "pTempDMM->ulDSPAddr:%x pMapAddr:%x\n", pTempDMM,
+ pTempDMM->ulDSPAddr, pMapAddr);
+ pTempDMM2 = pTempDMM;
+ pTempDMM = pTempDMM->next;
+ }
+ if (pTempDMM != NULL) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetDMMResElement: 3");
+ *pDMMRes = pTempDMM;
+ } else {
+ status = DSP_ENOTFOUND;
+ } GT_0trace(curTrace, GT_ENTER, "DRV_GetDMMResElement: 4");
+ return status;
+}
+
+/* Update Node allocation status */
+void DRV_ProcNodeUpdateStatus(HANDLE hNodeRes, s32 status)
+{
+ struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes;
+ DBC_Assert(hNodeRes != NULL);
+ pNodeRes->nodeAllocated = status;
+}
+
+/* Update Node Heap status */
+void DRV_ProcNodeUpdateHeapStatus(HANDLE hNodeRes, s32 status)
+{
+ struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes;
+ DBC_Assert(hNodeRes != NULL);
+ pNodeRes->heapAllocated = status;
+}
+
+/* Release all Node resources and its context
+* This is called from .bridge_release.
+*/
+DSP_STATUS DRV_RemoveAllNodeResElements(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_RES_OBJECT *pTempNode2 = NULL;
+ struct NODE_RES_OBJECT *pTempNode = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ DRV_ProcFreeNodeRes(pCtxt);
+ pTempNode = pCtxt->pNodeList;
+ while (pTempNode != NULL) {
+ pTempNode2 = pTempNode;
+ pTempNode = pTempNode->next;
+ MEM_Free(pTempNode2);
+ }
+ pCtxt->pNodeList = NULL;
+ return status;
+}
+
+/* Getting the node resource element */
+
+DSP_STATUS DRV_GetNodeResElement(HANDLE hNode, HANDLE hNodeRes, HANDLE hPCtxt)
+{
+ struct NODE_RES_OBJECT **nodeRes = (struct NODE_RES_OBJECT **)hNodeRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_RES_OBJECT *pTempNode2 = NULL;
+ struct NODE_RES_OBJECT *pTempNode = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ pTempNode = pCtxt->pNodeList;
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetNodeResElement: 1");
+ while ((pTempNode != NULL) && (pTempNode->hNode != hNode)) {
+ pTempNode2 = pTempNode;
+ pTempNode = pTempNode->next;
+ }
+ if (pTempNode != NULL)
+ *nodeRes = pTempNode;
+ else
+ status = DSP_ENOTFOUND;
+
+ return status;
+}
+
+
+
+/* Allocate the STRM resource element
+* This is called after the actual resource is allocated
+*/
+DSP_STATUS DRV_ProcInsertSTRMResElement(HANDLE hStreamHandle, HANDLE hSTRMRes,
+ HANDLE hPCtxt)
+{
+ struct STRM_RES_OBJECT **pSTRMRes = (struct STRM_RES_OBJECT **)hSTRMRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct STRM_RES_OBJECT *pTempSTRMRes = NULL;
+ DBC_Assert(hPCtxt != NULL);
+
+ *pSTRMRes = (struct STRM_RES_OBJECT *)
+ MEM_Calloc(1 * sizeof(struct STRM_RES_OBJECT), MEM_PAGED);
+ if ((*pSTRMRes == NULL) || (hPCtxt == NULL)) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_InsertSTRMResElement: 2");
+ status = DSP_EHANDLE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ (*pSTRMRes)->hStream = hStreamHandle;
+ if (pCtxt->pSTRMList != NULL) {
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_InsertiSTRMResElement: 3");
+ pTempSTRMRes = pCtxt->pSTRMList;
+ while (pTempSTRMRes->next != NULL)
+ pTempSTRMRes = pTempSTRMRes->next;
+
+ pTempSTRMRes->next = *pSTRMRes;
+ } else {
+ pCtxt->pSTRMList = *pSTRMRes;
+ GT_0trace(curTrace, GT_ENTER,
+ "DRV_InsertSTRMResElement: 4");
+ }
+ }
+ return status;
+}
+
+
+
+/* Release Stream resource element context
+* This function called after the actual resource is freed
+*/
+DSP_STATUS DRV_ProcRemoveSTRMResElement(HANDLE hSTRMRes, HANDLE hPCtxt)
+{
+ struct STRM_RES_OBJECT *pSTRMRes = (struct STRM_RES_OBJECT *)hSTRMRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct STRM_RES_OBJECT *pTempSTRMRes2 = pCtxt->pSTRMList;
+ struct STRM_RES_OBJECT *pTempSTRMRes = pCtxt->pSTRMList;
+
+ DBC_Assert(hPCtxt != NULL);
+ while ((pTempSTRMRes != NULL) && (pTempSTRMRes != pSTRMRes)) {
+ pTempSTRMRes2 = pTempSTRMRes;
+ pTempSTRMRes = pTempSTRMRes->next;
+ }
+ if (pCtxt->pSTRMList == pTempSTRMRes)
+ pCtxt->pSTRMList = pTempSTRMRes->next;
+
+ if (pTempSTRMRes == NULL)
+ status = DSP_ENOTFOUND;
+ else if (pTempSTRMRes2->next != NULL)
+ pTempSTRMRes2->next = pTempSTRMRes2->next->next;
+
+ MEM_Free(pSTRMRes);
+ return status;
+}
+
+
+/* Actual Stream De-Allocation */
+static DSP_STATUS DRV_ProcFreeSTRMRes(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ DSP_STATUS status1 = DSP_SOK;
+ u8 **apBuffer = NULL;
+ struct STRM_RES_OBJECT *pSTRMList = NULL;
+ struct STRM_RES_OBJECT *pSTRMRes = NULL;
+ u8 *pBufPtr;
+ u32 ulBytes;
+ u32 dwArg;
+ s32 ulBufSize;
+
+
+ DBC_Assert(hPCtxt != NULL);
+ pSTRMList = pCtxt->pSTRMList;
+ while (pSTRMList != NULL) {
+ pSTRMRes = pSTRMList;
+ pSTRMList = pSTRMList->next;
+ if (pSTRMRes->uNumBufs != 0) {
+ apBuffer = MEM_Alloc((pSTRMRes->uNumBufs *
+ sizeof(u8 *)), MEM_NONPAGED);
+ status = STRM_FreeBuffer(pSTRMRes->hStream, apBuffer,
+ pSTRMRes->uNumBufs);
+ MEM_Free(apBuffer);
+ }
+ status = STRM_Close(pSTRMRes->hStream);
+ if (DSP_FAILED(status)) {
+ if (status == DSP_EPENDING) {
+ status = STRM_Reclaim(pSTRMRes->hStream,
+ &pBufPtr, &ulBytes,
+ (u32 *)&ulBufSize, &dwArg);
+ if (DSP_SUCCEEDED(status))
+ status = STRM_Close(pSTRMRes->hStream);
+
+ }
+ }
+ }
+ return status1;
+}
+
+/* Release all Stream resources and its context
+* This is called from .bridge_release.
+*/
+DSP_STATUS DRV_RemoveAllSTRMResElements(HANDLE hPCtxt)
+{
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct STRM_RES_OBJECT *pTempSTRMRes2 = NULL;
+ struct STRM_RES_OBJECT *pTempSTRMRes = NULL;
+
+ DBC_Assert(hPCtxt != NULL);
+ DRV_ProcFreeSTRMRes(pCtxt);
+ pTempSTRMRes = pCtxt->pSTRMList;
+ while (pTempSTRMRes != NULL) {
+ pTempSTRMRes2 = pTempSTRMRes;
+ pTempSTRMRes = pTempSTRMRes->next;
+ MEM_Free(pTempSTRMRes2);
+ }
+ pCtxt->pSTRMList = NULL;
+ return status;
+}
+
+
+/* Getting the stream resource element */
+DSP_STATUS DRV_GetSTRMResElement(HANDLE hStrm, HANDLE hSTRMRes, HANDLE hPCtxt)
+{
+ struct STRM_RES_OBJECT **STRMRes = (struct STRM_RES_OBJECT **)hSTRMRes;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ DSP_STATUS status = DSP_SOK;
+ struct STRM_RES_OBJECT *pTempSTRM2 = NULL;
+ struct STRM_RES_OBJECT *pTempSTRM = pCtxt->pSTRMList;
+
+ DBC_Assert(hPCtxt != NULL);
+ while ((pTempSTRM != NULL) && (pTempSTRM->hStream != hStrm)) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 2");
+ pTempSTRM2 = pTempSTRM;
+ pTempSTRM = pTempSTRM->next;
+ }
+ if (pTempSTRM != NULL) {
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 3");
+ *STRMRes = pTempSTRM;
+ } else {
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 4");
+ status = DSP_ENOTFOUND;
+ }
+ GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 5");
+ return status;
+}
+
+/* Updating the stream resource element */
+DSP_STATUS DRV_ProcUpdateSTRMRes(u32 uNumBufs, HANDLE hSTRMRes, HANDLE hPCtxt)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct STRM_RES_OBJECT **STRMRes = (struct STRM_RES_OBJECT **)hSTRMRes;
+
+ DBC_Assert(hPCtxt != NULL);
+ (*STRMRes)->uNumBufs = uNumBufs;
+ return status;
+}
+
+/* Displaying the resources allocated by a process */
+DSP_STATUS DRV_ProcDisplayResInfo(u8 *pBuf1, u32 *pSize)
+{
+ struct PROCESS_CONTEXT *pCtxt = NULL;
+ struct NODE_RES_OBJECT *pNodeRes = NULL;
+ struct DMM_RES_OBJECT *pDMMRes = NULL;
+ struct STRM_RES_OBJECT *pSTRMRes = NULL;
+ struct DSPHEAP_RES_OBJECT *pDSPHEAPRes = NULL;
+ u32 tempCount = 1;
+ HANDLE hDrvObject = NULL;
+ void *pBuf = pBuf1;
+ u8 pTempBuf[250];
+ u32 tempStrLen = 0, tempStrLen2 = 0;
+ DSP_STATUS status = DSP_SOK;
+
+ CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ DRV_GetProcCtxtList(&pCtxt, (struct DRV_OBJECT *)hDrvObject);
+ GT_0trace(curTrace, GT_ENTER, "*********************"
+ "DRV_ProcDisplayResourceInfo:*\n");
+ while (pCtxt != NULL) {
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "-------------------------------------"
+ "-----------------------------------\n");
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ if (pCtxt->resState == PROC_RES_ALLOCATED) {
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "GPP Process Resource State: "
+ "pCtxt->resState = PROC_RES_ALLOCATED, "
+ " Process ID: %d\n", pCtxt->pid);
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ } else {
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "GPP Resource State: pCtxt->resState"
+ " = PROC_RES_DEALLOCATED, Process ID:%d\n",
+ pCtxt->pid);
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ }
+ pNodeRes = pCtxt->pNodeList;
+ tempCount = 1;
+ while (pNodeRes != NULL) {
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_ProcDisplayResourceInfo: #:%d "
+ "pCtxt->pNodeList->hNode:%x\n",
+ tempCount, pNodeRes->hNode);
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "Node Resource Information: Node #"
+ " %d Node Handle hNode:0X%x\n",
+ tempCount, (u32)pNodeRes->hNode);
+ pNodeRes = pNodeRes->next;
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ tempCount++;
+ }
+ tempCount = 1;
+ pDSPHEAPRes = pCtxt->pDSPHEAPList;
+ while (pDSPHEAPRes != NULL) {
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_ProcDisplayResourceInfo: #:%d "
+ "pCtxt->pDSPHEAPRList->ulMpuAddr:%x\n",
+ tempCount, pDSPHEAPRes->ulMpuAddr);
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "DSP Heap Resource Info: HEAP # %d"
+ " Mapped GPP Address: 0x%x, size: 0x%x\n",
+ tempCount, (u32)pDSPHEAPRes->ulMpuAddr,
+ (u32)pDSPHEAPRes->heapSize);
+ pDSPHEAPRes = pDSPHEAPRes->next;
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ tempCount++;
+ }
+ tempCount = 1;
+ pDMMRes = pCtxt->pDMMList;
+ while (pDMMRes != NULL) {
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_ProcDisplayResourceInfo: #:%d "
+ " pCtxt->pDMMList->ulMpuAddr:%x\n",
+ tempCount,
+ pDMMRes->ulMpuAddr);
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "DMM Resource Info: DMM # %d Mapped"
+ " GPP Address: 0x%x, size: 0x%x\n",
+ tempCount, (u32)pDMMRes->ulMpuAddr,
+ (u32)pDMMRes->dmmSize);
+ pDMMRes = pDMMRes->next;
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ tempCount++;
+ }
+ tempCount = 1;
+ pSTRMRes = pCtxt->pSTRMList;
+ while (pSTRMRes != NULL) {
+ GT_2trace(curTrace, GT_ENTER,
+ "DRV_ProcDisplayResourceInfo: #:%d "
+ "pCtxt->pSTRMList->hStream:%x\n", tempCount,
+ pSTRMRes->hStream);
+ tempStrLen2 = sprintf((char *)pTempBuf,
+ "Stream Resource info: STRM # %d "
+ "Stream Handle: 0x%x \n",
+ tempCount, (u32)pSTRMRes->hStream);
+ pSTRMRes = pSTRMRes->next;
+ tempStrLen2 += 2;
+ memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2);
+ tempStrLen += tempStrLen2;
+ tempCount++;
+ }
+ pCtxt = pCtxt->next;
+ }
+ *pSize = tempStrLen;
+ status = PrintProcessInformation();
+ GT_0trace(curTrace, GT_ENTER, "*********************"
+ "DRV_ProcDisplayResourceInfo:**\n");
+ return status;
+}
+
+/*
+ * ======== PrintProcessInformation ========
+ * Purpose:
+ * This function prints the Process's information stored in
+ * the process context list. Some of the information that
+ * it displays is Process's state, Node, Stream, DMM, and
+ * Heap information.
+ */
+static DSP_STATUS PrintProcessInformation(void)
+{
+ struct DRV_OBJECT *hDrvObject = NULL;
+ struct PROCESS_CONTEXT *pCtxtList = NULL;
+ struct NODE_RES_OBJECT *pNodeRes = NULL;
+ struct DMM_RES_OBJECT *pDMMRes = NULL;
+ struct STRM_RES_OBJECT *pSTRMRes = NULL;
+ struct DSPHEAP_RES_OBJECT *pDSPHEAPRes = NULL;
+ DSP_STATUS status = DSP_SOK;
+ u32 tempCount;
+ u32 procID;
+
+ /* Get the Process context list */
+ CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ DRV_GetProcCtxtList(&pCtxtList, hDrvObject);
+ GT_0trace(curTrace, GT_4CLASS, "\n### Debug information"
+ " for DSP bridge ##\n");
+ GT_0trace(curTrace, GT_4CLASS, " \n ###The processes"
+ " information is as follows ### \n") ;
+ GT_0trace(curTrace, GT_4CLASS, " ====================="
+ "============ \n");
+ /* Go through the entries in the Process context list */
+ while (pCtxtList != NULL) {
+ GT_1trace(curTrace, GT_4CLASS, "\nThe process"
+ " id is %d\n", pCtxtList->pid);
+ GT_0trace(curTrace, GT_4CLASS, " -------------------"
+ "---------\n");
+ if (pCtxtList->resState == PROC_RES_ALLOCATED) {
+ GT_0trace(curTrace, GT_4CLASS, " \nThe Process"
+ " is in Allocated state\n");
+ } else {
+ GT_0trace(curTrace, GT_4CLASS, "\nThe Process"
+ " is in DeAllocated state\n");
+ }
+ GT_1trace(curTrace, GT_4CLASS, "\nThe hProcessor"
+ " handle is: 0X%x\n",
+ (u32)pCtxtList->hProcessor);
+ if (pCtxtList->hProcessor != NULL) {
+ PROC_GetProcessorId(pCtxtList->hProcessor, &procID);
+ if (procID == DSP_UNIT) {
+ GT_0trace(curTrace, GT_4CLASS,
+ "\nProcess connected to"
+ " DSP Processor\n");
+ } else if (procID == IVA_UNIT) {
+ GT_0trace(curTrace, GT_4CLASS,
+ "\nProcess connected to"
+ " IVA Processor\n");
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ "\n***ERROR:Invalid Processor Id***\n");
+ }
+ }
+ pNodeRes = pCtxtList->pNodeList;
+ tempCount = 1;
+ while (pNodeRes != NULL) {
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n***The Nodes allocated by"
+ " this Process are***\n");
+ GT_2trace(curTrace, GT_4CLASS,
+ "Node # %d Node Handle hNode:0x%x\n",
+ tempCount, (u32)pNodeRes->hNode);
+ pNodeRes = pNodeRes->next;
+ tempCount++;
+ }
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n ***There are no Nodes"
+ " allocated by this Process***\n");
+ tempCount = 1;
+ pDSPHEAPRes = pCtxtList->pDSPHEAPList;
+ while (pDSPHEAPRes != NULL) {
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n***The Heaps allocated by"
+ " this Process are***\n");
+ GT_3trace(curTrace, GT_4CLASS,
+ "DSP Heap Resource Info: HEAP # %d "
+ "Mapped GPP Address:0x%x, Size: 0x%lx\n",
+ tempCount, (u32)pDSPHEAPRes->ulMpuAddr,
+ pDSPHEAPRes->heapSize);
+ pDSPHEAPRes = pDSPHEAPRes->next;
+ tempCount++;
+ }
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n ***There are no Heaps allocated"
+ " by this Process***\n");
+ tempCount = 1;
+ pDMMRes = pCtxtList->pDMMList;
+ while (pDMMRes != NULL) {
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n ***The DMM resources allocated by"
+ " this Process are***\n");
+ GT_3trace(curTrace, GT_4CLASS,
+ "DMM Resource Info: DMM # %d "
+ "Mapped GPP Address:0X%lx, Size: 0X%lx\n",
+ tempCount, pDMMRes->ulMpuAddr,
+ pDMMRes->dmmSize);
+ pDMMRes = pDMMRes->next;
+ tempCount++;
+ }
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n ***There are no DMM resources"
+ " allocated by this Process***\n");
+ tempCount = 1;
+ pSTRMRes = pCtxtList->pSTRMList;
+ while (pSTRMRes != NULL) {
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n***The Stream resources allocated by"
+ " this Process are***\n");
+ GT_2trace(curTrace, GT_4CLASS,
+ "Stream Resource info: STRM # %d"
+ "Stream Handle:0X%x\n", tempCount,
+ (u32)pSTRMRes->hStream);
+ pSTRMRes = pSTRMRes->next;
+ tempCount++;
+ }
+ if (tempCount == 1)
+ GT_0trace(curTrace, GT_4CLASS,
+ "\n ***There are no Stream resources"
+ "allocated by this Process***\n");
+ pCtxtList = pCtxtList->next;
+ }
+ return status;
+}
+
+/* GPP PROCESS CLEANUP CODE END */
+#endif
+
+/*
+ * ======== = DRV_Create ======== =
+ * Purpose:
+ * DRV Object gets created only once during Driver Loading.
+ */
+DSP_STATUS DRV_Create(OUT struct DRV_OBJECT **phDRVObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDRVObject = NULL;
+
+ DBC_Require(phDRVObject != NULL);
+ DBC_Require(cRefs > 0);
+ GT_1trace(curTrace, GT_ENTER, "Entering DRV_Create"
+ " phDRVObject 0x%x\n", phDRVObject);
+ MEM_AllocObject(pDRVObject, struct DRV_OBJECT, SIGNATURE);
+ if (pDRVObject) {
+ /* Create and Initialize List of device objects */
+ pDRVObject->devList = LST_Create();
+ if (pDRVObject->devList) {
+ /* Create and Initialize List of device Extension */
+ pDRVObject->devNodeString = LST_Create();
+ if (!(pDRVObject->devNodeString)) {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to Create DRV_EXT list ");
+ MEM_FreeObject(pDRVObject);
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to Create Dev List ");
+ MEM_FreeObject(pDRVObject);
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to Allocate Memory for DRV Obj");
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Store the DRV Object in the Registry */
+ if (DSP_SUCCEEDED
+ (CFG_SetObject((u32) pDRVObject, REG_DRV_OBJECT))) {
+ GT_1trace(curTrace, GT_1CLASS,
+ "DRV Obj Created pDrvObject 0x%x\n ",
+ pDRVObject);
+ *phDRVObject = pDRVObject;
+ } else {
+ /* Free the DRV Object */
+ status = DSP_EFAIL;
+ MEM_Free(pDRVObject);
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to update the Registry with "
+ "DRV Object ");
+ }
+ }
+ GT_2trace(curTrace, GT_ENTER,
+ "Exiting DRV_Create: phDRVObject: 0x%x\tstatus:"
+ "0x%x\n", phDRVObject, status);
+ DBC_Ensure(DSP_FAILED(status) ||
+ MEM_IsValidHandle(pDRVObject, SIGNATURE));
+ return status;
+}
+
+/*
+ * ======== DRV_Exit ========
+ * Purpose:
+ * Discontinue usage of the DRV module.
+ */
+void DRV_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ GT_0trace(curTrace, GT_5CLASS, "Entering DRV_Exit \n");
+
+ cRefs--;
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== = DRV_Destroy ======== =
+ * purpose:
+ * Invoked during bridge de-initialization
+ */
+DSP_STATUS DRV_Destroy(struct DRV_OBJECT *hDRVObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE));
+
+ GT_1trace(curTrace, GT_ENTER, "Entering DRV_Destroy"
+ " hDRVObject 0x%x\n", hDRVObject);
+ /*
+ * Delete the List if it exists.Should not come here
+ * as the DRV_RemoveDevObject and the Last DRV_RequestResources
+ * removes the list if the lists are empty.
+ */
+ if (pDRVObject->devList) {
+ /* Could assert if the list is not empty */
+ LST_Delete(pDRVObject->devList);
+ }
+ if (pDRVObject->devNodeString) {
+ /* Could assert if the list is not empty */
+ LST_Delete(pDRVObject->devNodeString);
+ }
+ MEM_FreeObject(pDRVObject);
+ /* Update the DRV Object in Registry to be 0 */
+ (void)CFG_SetObject(0, REG_DRV_OBJECT);
+ GT_2trace(curTrace, GT_ENTER,
+ "Exiting DRV_Destroy: hDRVObject: 0x%x\tstatus:"
+ "0x%x\n", hDRVObject, status);
+ DBC_Ensure(!MEM_IsValidHandle(pDRVObject, SIGNATURE));
+ return status;
+}
+
+/*
+ * ======== DRV_GetDevObject ========
+ * Purpose:
+ * Given a index, returns a handle to DevObject from the list.
+ */
+DSP_STATUS DRV_GetDevObject(u32 uIndex, struct DRV_OBJECT *hDrvObject,
+ struct DEV_OBJECT **phDevObject)
+{
+ DSP_STATUS status = DSP_SOK;
+#if GT_TRACE /* pDrvObject is used only for Assertions and debug messages.*/
+ struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject;
+#endif
+ struct DEV_OBJECT *pDevObject;
+ u32 i;
+ DBC_Require(MEM_IsValidHandle(pDrvObject, SIGNATURE));
+ DBC_Require(phDevObject != NULL);
+ DBC_Require(uIndex >= 0);
+ DBC_Require(cRefs > 0);
+ DBC_Assert(!(LST_IsEmpty(pDrvObject->devList)));
+ GT_3trace(curTrace, GT_ENTER,
+ "Entered DRV_GetDevObject, args:\n\tuIndex: "
+ "0x%x\n\thDrvObject: 0x%x\n\tphDevObject: 0x%x\n",
+ uIndex, hDrvObject, phDevObject);
+ pDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
+ for (i = 0; i < uIndex; i++) {
+ pDevObject =
+ (struct DEV_OBJECT *)DRV_GetNextDevObject((u32)pDevObject);
+ }
+ if (pDevObject) {
+ *phDevObject = (struct DEV_OBJECT *) pDevObject;
+ status = DSP_SOK;
+ } else {
+ *phDevObject = NULL;
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS,
+ "DRV: Could not get the DevObject\n");
+ }
+ GT_2trace(curTrace, GT_ENTER,
+ "Exiting Drv_GetDevObject\n\tstatus: 0x%x\n\t"
+ "hDevObject: 0x%x\n", status, *phDevObject);
+ return status;
+}
+
+/*
+ * ======== DRV_GetFirstDevObject ========
+ * Purpose:
+ * Retrieve the first Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DRV.
+ */
+u32 DRV_GetFirstDevObject(void)
+{
+ u32 dwDevObject = 0;
+ struct DRV_OBJECT *pDrvObject;
+
+ if (DSP_SUCCEEDED
+ (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) {
+ if ((pDrvObject->devList != NULL) &&
+ !LST_IsEmpty(pDrvObject->devList))
+ dwDevObject = (u32) LST_First(pDrvObject->devList);
+ }
+
+ return dwDevObject;
+}
+
+/*
+ * ======== DRV_GetFirstDevNodeString ========
+ * Purpose:
+ * Retrieve the first Device Extension from an internal linked list of
+ * of Pointer to DevNode Strings maintained by DRV.
+ */
+u32 DRV_GetFirstDevExtension(void)
+{
+ u32 dwDevExtension = 0;
+ struct DRV_OBJECT *pDrvObject;
+
+ if (DSP_SUCCEEDED
+ (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) {
+
+ if ((pDrvObject->devNodeString != NULL) &&
+ !LST_IsEmpty(pDrvObject->devNodeString)) {
+ dwDevExtension = (u32)LST_First(pDrvObject->
+ devNodeString);
+ }
+ }
+
+ return dwDevExtension;
+}
+
+/*
+ * ======== DRV_GetNextDevObject ========
+ * Purpose:
+ * Retrieve the next Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DRV, after having previously called
+ * DRV_GetFirstDevObject() and zero or more DRV_GetNext.
+ */
+u32 DRV_GetNextDevObject(u32 hDevObject)
+{
+ u32 dwNextDevObject = 0;
+ struct DRV_OBJECT *pDrvObject;
+
+ DBC_Require(hDevObject != 0);
+
+ if (DSP_SUCCEEDED
+ (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) {
+
+ if ((pDrvObject->devList != NULL) &&
+ !LST_IsEmpty(pDrvObject->devList)) {
+ dwNextDevObject = (u32)LST_Next(pDrvObject->devList,
+ (struct LST_ELEM *)hDevObject);
+ }
+ }
+ return dwNextDevObject;
+}
+
+/*
+ * ======== DRV_GetNextDevExtension ========
+ * Purpose:
+ * Retrieve the next Device Extension from an internal linked list of
+ * of pointer to DevNodeString maintained by DRV, after having previously
+ * called DRV_GetFirstDevExtension() and zero or more
+ * DRV_GetNextDevExtension().
+ */
+u32 DRV_GetNextDevExtension(u32 hDevExtension)
+{
+ u32 dwDevExtension = 0;
+ struct DRV_OBJECT *pDrvObject;
+
+ DBC_Require(hDevExtension != 0);
+
+ if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&pDrvObject,
+ REG_DRV_OBJECT))) {
+ if ((pDrvObject->devNodeString != NULL) &&
+ !LST_IsEmpty(pDrvObject->devNodeString)) {
+ dwDevExtension = (u32)LST_Next(pDrvObject->
+ devNodeString,
+ (struct LST_ELEM *)hDevExtension);
+ }
+ }
+
+ return dwDevExtension;
+}
+
+/*
+ * ======== DRV_Init ========
+ * Purpose:
+ * Initialize DRV module private state.
+ */
+DSP_STATUS DRV_Init(void)
+{
+ s32 fRetval = 1; /* function return value */
+
+ DBC_Require(cRefs >= 0);
+
+ if (fRetval)
+ cRefs++;
+
+ GT_1trace(curTrace, GT_5CLASS, "Entering DRV_Entry crefs 0x%x \n",
+ cRefs);
+
+ DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0)));
+
+ return fRetval;
+}
+
+/*
+ * ======== DRV_InsertDevObject ========
+ * Purpose:
+ * Insert a DevObject into the list of Manager object.
+ */
+DSP_STATUS DRV_InsertDevObject(struct DRV_OBJECT *hDRVObject,
+ struct DEV_OBJECT *hDevObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hDevObject != NULL);
+ DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE));
+ DBC_Assert(pDRVObject->devList);
+
+ GT_2trace(curTrace, GT_ENTER,
+ "Entering DRV_InsertProcObject hDRVObject "
+ "0x%x\n, hDevObject 0x%x\n", hDRVObject, hDevObject);
+
+ LST_PutTail(pDRVObject->devList, (struct LST_ELEM *)hDevObject);
+
+ GT_1trace(curTrace, GT_ENTER,
+ "Exiting InsertDevObject status 0x%x\n", status);
+
+ DBC_Ensure(DSP_SUCCEEDED(status) && !LST_IsEmpty(pDRVObject->devList));
+
+ return status;
+}
+
+/*
+ * ======== DRV_RemoveDevObject ========
+ * Purpose:
+ * Search for and remove a DeviceObject from the given list of DRV
+ * objects.
+ */
+DSP_STATUS DRV_RemoveDevObject(struct DRV_OBJECT *hDRVObject,
+ struct DEV_OBJECT *hDevObject)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject;
+ struct LST_ELEM *pCurElem;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE));
+ DBC_Require(hDevObject != NULL);
+
+ DBC_Require(pDRVObject->devList != NULL);
+ DBC_Require(!LST_IsEmpty(pDRVObject->devList));
+
+ GT_2trace(curTrace, GT_ENTER,
+ "Entering DRV_RemoveDevObject hDevObject "
+ "0x%x\n, hDRVObject 0x%x\n", hDevObject, hDRVObject);
+ /* Search list for pProcObject: */
+ for (pCurElem = LST_First(pDRVObject->devList); pCurElem != NULL;
+ pCurElem = LST_Next(pDRVObject->devList, pCurElem)) {
+ /* If found, remove it. */
+ if ((struct DEV_OBJECT *) pCurElem == hDevObject) {
+ LST_RemoveElem(pDRVObject->devList, pCurElem);
+ status = DSP_SOK;
+ break;
+ }
+ }
+ /* Remove list if empty. */
+ if (LST_IsEmpty(pDRVObject->devList)) {
+ LST_Delete(pDRVObject->devList);
+ pDRVObject->devList = NULL;
+ }
+ DBC_Ensure((pDRVObject->devList == NULL) ||
+ !LST_IsEmpty(pDRVObject->devList));
+ GT_1trace(curTrace, GT_ENTER,
+ "DRV_RemoveDevObject returning 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ======== DRV_RequestResources ========
+ * Purpose:
+ * Requests resources from the OS.
+ */
+DSP_STATUS DRV_RequestResources(u32 dwContext, u32 *pDevNodeString)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDRVObject;
+ struct DRV_EXT *pszdevNode;
+
+ DBC_Require(dwContext != 0);
+ DBC_Require(pDevNodeString != NULL);
+ GT_0trace(curTrace, GT_ENTER, "Entering DRV_RequestResources\n");
+ /*
+ * Allocate memory to hold the string. This will live untill
+ * it is freed in the Release resources. Update the driver object
+ * list.
+ */
+ if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&pDRVObject,
+ REG_DRV_OBJECT))) {
+ pszdevNode = MEM_Calloc(sizeof(struct DRV_EXT), MEM_NONPAGED);
+ if (pszdevNode) {
+ LST_InitElem(&pszdevNode->link);
+ strncpy((char *) pszdevNode->szString,
+ (char *)dwContext, MAXREGPATHLENGTH);
+ /* Update the Driver Object List */
+ *pDevNodeString = (u32)pszdevNode->szString;
+ LST_PutTail(pDRVObject->devNodeString,
+ (struct LST_ELEM *)pszdevNode);
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to Allocate Memory devNodeString ");
+ status = DSP_EFAIL;
+ *pDevNodeString = 0;
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to get Driver Object from Registry");
+ *pDevNodeString = 0;
+ }
+
+ if (!(strcmp((char *) dwContext, "TIOMAP1510"))) {
+ GT_0trace(curTrace, GT_1CLASS,
+ " Allocating resources for UMA \n");
+ status = RequestBridgeResourcesDSP(dwContext, DRV_ASSIGN);
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(curTrace, GT_7CLASS, "Unknown Device ");
+ }
+
+ if (DSP_FAILED(status)) {
+ GT_0trace(curTrace, GT_7CLASS,
+ "Failed to reserve bridge resources ");
+ }
+ DBC_Ensure((DSP_SUCCEEDED(status) && pDevNodeString != NULL &&
+ !LST_IsEmpty(pDRVObject->devNodeString)) ||
+ (DSP_FAILED(status) && *pDevNodeString == 0));
+
+ return status;
+}
+
+/*
+ * ======== DRV_ReleaseResources ========
+ * Purpose:
+ * Releases resources from the OS.
+ */
+DSP_STATUS DRV_ReleaseResources(u32 dwContext, struct DRV_OBJECT *hDrvObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDrvObject;
+ struct DRV_EXT *pszdevNode;
+
+ GT_0trace(curTrace, GT_ENTER, "Entering DRV_Release Resources\n");
+
+ if (!(strcmp((char *)((struct DRV_EXT *)dwContext)->szString,
+ "TIOMAP1510"))) {
+ GT_0trace(curTrace, GT_1CLASS,
+ " Releasing DSP-Bridge resources \n");
+ status = RequestBridgeResources(dwContext, DRV_RELEASE);
+ } else {
+ GT_0trace(curTrace, GT_1CLASS, " Unknown device\n");
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(curTrace, GT_1CLASS,
+ "Failed to relese bridge resources\n");
+ }
+
+ /*
+ * Irrespective of the status go ahead and clean it
+ * The following will over write the status.
+ */
+ for (pszdevNode = (struct DRV_EXT *)DRV_GetFirstDevExtension();
+ pszdevNode != NULL; pszdevNode = (struct DRV_EXT *)
+ DRV_GetNextDevExtension((u32)pszdevNode)) {
+ if ((u32)pszdevNode == dwContext) {
+ /* Found it */
+ /* Delete from the Driver object list */
+ LST_RemoveElem(pDRVObject->devNodeString,
+ (struct LST_ELEM *)pszdevNode);
+ MEM_Free((void *) pszdevNode);
+ break;
+ }
+ /* Delete the List if it is empty */
+ if (LST_IsEmpty(pDRVObject->devNodeString)) {
+ LST_Delete(pDRVObject->devNodeString);
+ pDRVObject->devNodeString = NULL;
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== RequestBridgeResources ========
+ * Purpose:
+ * Reserves shared memory for bridge.
+ */
+static DSP_STATUS RequestBridgeResources(u32 dwContext, s32 bRequest)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct CFG_HOSTRES *pResources;
+ u32 dwBuffSize;
+
+ struct DRV_EXT *driverExt;
+ u32 shm_size;
+
+ DBC_Require(dwContext != 0);
+
+ GT_0trace(curTrace, GT_ENTER, "->RequestBridgeResources \n");
+
+ if (!bRequest) {
+ driverExt = (struct DRV_EXT *)dwContext;
+ /* Releasing resources by deleting the registry key */
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+ pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED);
+ if (DSP_FAILED(REG_GetValue(NULL, (char *)driverExt->szString,
+ CURRENTCONFIG, (u8 *)pResources, &dwBuffSize))) {
+ status = CFG_E_RESOURCENOTAVAIL;
+ GT_0trace(curTrace, GT_1CLASS,
+ "REG_GetValue Failed \n");
+ } else {
+ GT_0trace(curTrace, GT_1CLASS,
+ "REG_GetValue Succeeded \n");
+ }
+
+ if (pResources != NULL) {
+ dwBuffSize = sizeof(shm_size);
+ status = REG_GetValue(NULL, CURRENTCONFIG, SHMSIZE,
+ (u8 *)&shm_size, &dwBuffSize);
+ if (DSP_SUCCEEDED(status)) {
+ if ((pResources->dwMemBase[1]) &&
+ (pResources->dwMemPhys[1])) {
+ MEM_FreePhysMem((void *)pResources->
+ dwMemBase[1], pResources->dwMemPhys[1],
+ shm_size);
+ }
+ } else {
+ GT_1trace(curTrace, GT_7CLASS,
+ "Error getting SHM size from registry: "
+ "%x. Not calling MEM_FreePhysMem\n",
+ status);
+ }
+ pResources->dwMemBase[1] = 0;
+ pResources->dwMemPhys[1] = 0;
+
+ if (pResources->dwPrmBase)
+ iounmap(pResources->dwPrmBase);
+#ifdef OMAP_3430
+ if (pResources->dwCmBase)
+ iounmap((void *)pResources->dwCmBase);
+#endif
+#ifdef OMAP_44XX
+ if (pResources->dwCm1Base)
+ iounmap((void *)pResources->dwCm1Base);
+ if (pResources->dwCm2Base)
+ iounmap((void *)pResources->dwCm2Base);
+#endif
+ if (pResources->dwMboxBase)
+ iounmap(pResources->dwMboxBase);
+ if (pResources->dwMemBase[0])
+ iounmap((void *)pResources->dwMemBase[0]);
+ if (pResources->dwMemBase[2])
+ iounmap((void *)pResources->dwMemBase[2]);
+ if (pResources->dwMemBase[3])
+ iounmap((void *)pResources->dwMemBase[3]);
+ if (pResources->dwMemBase[4])
+ iounmap((void *)pResources->dwMemBase[4]);
+ if (pResources->dwWdTimerDspBase)
+ iounmap(pResources->dwWdTimerDspBase);
+ if (pResources->dwDmmuBase)
+ iounmap(pResources->dwDmmuBase);
+ if (pResources->dwPerBase)
+ iounmap(pResources->dwPerBase);
+ if (pResources->dwPerPmBase)
+ iounmap((void *)pResources->dwPerPmBase);
+ if (pResources->dwCorePmBase)
+ iounmap((void *)pResources->dwCorePmBase);
+ if (pResources->dwSysCtrlBase) {
+ iounmap(pResources->dwSysCtrlBase);
+ /* don't set pResources->dwSysCtrlBase to null
+ * as it is used in BOARD_Stop */
+ }
+ pResources->dwPrmBase = NULL;
+#ifdef OMAP_3430
+ pResources->dwCmBase = NULL;
+#endif
+#ifdef OMAP_44XX
+ pResources->dwCm1Base = (u32) NULL;
+ pResources->dwCm2Base = (u32) NULL;
+#endif
+ pResources->dwMboxBase = NULL;
+ pResources->dwMemBase[0] = (u32) NULL;
+ pResources->dwMemBase[2] = (u32) NULL;
+ pResources->dwMemBase[3] = (u32) NULL;
+ pResources->dwMemBase[4] = (u32) NULL;
+ pResources->dwWdTimerDspBase = NULL;
+ pResources->dwDmmuBase = NULL;
+
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+ status = REG_SetValue(NULL, (char *)driverExt->szString,
+ CURRENTCONFIG, REG_BINARY, (u8 *)pResources,
+ (u32)dwBuffSize);
+ /* Set all the other entries to NULL */
+ MEM_Free(pResources);
+ }
+ GT_0trace(curTrace, GT_ENTER, " <- RequestBridgeResources \n");
+ return status;
+ }
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+ pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED);
+ if (pResources != NULL) {
+ /* wNumMemWindows must not be more than CFG_MAXMEMREGISTERS */
+ pResources->wNumMemWindows = 2;
+ /* First window is for DSP internal memory */
+
+ pResources->dwPrmBase = ioremap(OMAP_IVA2_PRM_BASE,
+ OMAP_IVA2_PRM_SIZE);
+
+#ifdef OMAP44XX
+ pResources->dwCm1Base = (u32)ioremap(OMAP_IVA2_CM1_BASE,
+ OMAP_IVA2_CM1_SIZE);
+ pResources->dwCm2Base = (u32)ioremap(OMAP_IVA2_CM2_BASE,
+ OMAP_IVA2_CM2_SIZE);
+#else
+ pResources->dwCmBase = ioremap(OMAP_IVA2_CM_BASE,
+ OMAP_IVA2_CM_SIZE);
+#endif
+
+ pResources->dwMboxBase = ioremap(OMAP_MBOX_BASE,
+ OMAP_MBOX_SIZE);
+ pResources->dwSysCtrlBase = ioremap(OMAP_SYSC_BASE,
+ OMAP_SYSC_SIZE);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[0] 0x%x\n",
+ pResources->dwMemBase[0]);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[3] 0x%x\n",
+ pResources->dwMemBase[3]);
+ GT_1trace(curTrace, GT_2CLASS, "dwPrmBase 0x%x\n",
+ pResources->dwPrmBase);
+#ifdef OMAP44XX
+ GT_1trace(curTrace, GT_2CLASS, "dwCm1Base 0x%x\n",
+ pResources->dwCm1Base);
+ GT_1trace(curTrace, GT_2CLASS, "dwCm2Base 0x%x\n",
+ pResources->dwCm2Base);
+#else
+ GT_1trace(curTrace, GT_2CLASS, "dwCmBase 0x%x\n",
+ pResources->dwCmBase);
+#endif
+ GT_1trace(curTrace, GT_2CLASS, "dwWdTimerDspBase 0x%x\n",
+ pResources->dwWdTimerDspBase);
+ GT_1trace(curTrace, GT_2CLASS, "dwMboxBase 0x%x\n",
+ pResources->dwMboxBase);
+ GT_1trace(curTrace, GT_2CLASS, "dwDmmuBase 0x%x\n",
+ pResources->dwDmmuBase);
+
+ /* for 24xx base port is not mapping the mamory for DSP
+ * internal memory TODO Do a ioremap here */
+ /* Second window is for DSP external memory shared with MPU */
+ if (DSP_SUCCEEDED(status)) {
+ /* for Linux, these are hard-coded values */
+ pResources->bIRQRegisters = 0;
+ pResources->bIRQAttrib = 0;
+ pResources->dwOffsetForMonitor = 0;
+ pResources->dwChnlOffset = 0;
+ /* CHNL_MAXCHANNELS */
+ pResources->dwNumChnls = CHNL_MAXCHANNELS;
+ pResources->dwChnlBufSize = 0x400;
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+ status = REG_SetValue(NULL, (char *) dwContext,
+ CURRENTCONFIG, REG_BINARY,
+ (u8 *)pResources,
+ sizeof(struct CFG_HOSTRES));
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(curTrace, GT_1CLASS,
+ " Successfully set the registry "
+ "value for CURRENTCONFIG\n");
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ " Failed to set the registry "
+ "value for CURRENTCONFIG\n");
+ }
+ }
+ MEM_Free(pResources);
+ }
+ /* End Mem alloc */
+ return status;
+}
+
+/*
+ * ======== RequestBridgeResourcesDSP ========
+ * Purpose:
+ * Reserves shared memory for bridge.
+ */
+static DSP_STATUS RequestBridgeResourcesDSP(u32 dwContext, s32 bRequest)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct CFG_HOSTRES *pResources;
+ u32 dwBuffSize;
+ u32 dmaAddr;
+ u32 shm_size;
+
+ DBC_Require(dwContext != 0);
+
+ GT_0trace(curTrace, GT_ENTER, "->RequestBridgeResourcesDSP \n");
+
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+
+ pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED);
+
+ if (pResources != NULL) {
+ if (DSP_FAILED(CFG_GetHostResources((struct CFG_DEVNODE *)
+ dwContext, pResources))) {
+ /* Call CFG_GetHostResources to get reserve resouces */
+ status = RequestBridgeResources(dwContext, bRequest);
+ if (DSP_SUCCEEDED(status)) {
+ status = CFG_GetHostResources
+ ((struct CFG_DEVNODE *) dwContext,
+ pResources);
+ }
+ }
+ /* wNumMemWindows must not be more than CFG_MAXMEMREGISTERS */
+ pResources->wNumMemWindows = 4;
+
+ pResources->dwMemBase[0] = 0;
+ pResources->dwMemBase[2] = (u32)ioremap(OMAP_DSP_MEM1_BASE,
+ OMAP_DSP_MEM1_SIZE);
+ pResources->dwMemBase[3] = (u32)ioremap(OMAP_DSP_MEM2_BASE,
+ OMAP_DSP_MEM2_SIZE);
+ pResources->dwMemBase[4] = (u32)ioremap(OMAP_DSP_MEM3_BASE,
+ OMAP_DSP_MEM3_SIZE);
+#ifdef OMAP_3430
+ pResources->dwPerBase = ioremap(OMAP_PER_CM_BASE,
+ OMAP_PER_CM_SIZE);
+ pResources->dwPerPmBase = (u32)ioremap(OMAP_PER_PRM_BASE,
+ OMAP_PER_PRM_SIZE);
+ pResources->dwCorePmBase = (u32)ioremap(OMAP_CORE_PRM_BASE,
+ OMAP_CORE_PRM_SIZE);
+#else
+
+ pResources->dwCm1Base = (u32)ioremap(OMAP_IVA2_CM1_BASE,
+ OMAP_IVA2_CM1_SIZE);
+ pResources->dwCm2Base = (u32)ioremap(OMAP_IVA2_CM2_BASE,
+ OMAP_IVA2_CM2_SIZE);
+#endif
+ pResources->dwDmmuBase = ioremap(OMAP_DMMU_BASE,
+ OMAP_DMMU_SIZE);
+ pResources->dwWdTimerDspBase = NULL;
+
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[0] 0x%x\n",
+ pResources->dwMemBase[0]);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[1] 0x%x\n",
+ pResources->dwMemBase[1]);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[2] 0x%x\n",
+ pResources->dwMemBase[2]);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[3] 0x%x\n",
+ pResources->dwMemBase[3]);
+ GT_1trace(curTrace, GT_2CLASS, "dwMemBase[4] 0x%x\n",
+ pResources->dwMemBase[4]);
+ GT_1trace(curTrace, GT_2CLASS, "dwPrmBase 0x%x\n",
+ pResources->dwPrmBase);
+#ifdef OMAP44XX
+ GT_1trace(curTrace, GT_2CLASS, "dwCm1Base 0x%x\n",
+ pResources->dwCm1Base);
+ GT_1trace(curTrace, GT_2CLASS, "dwCm2Base 0x%x\n",
+ pResources->dwCm2Base);
+#else
+ GT_1trace(curTrace, GT_2CLASS, "dwCmBase 0x%x\n",
+ pResources->dwCmBase);
+#endif
+ GT_1trace(curTrace, GT_2CLASS, "dwWdTimerDspBase 0x%x\n",
+ pResources->dwWdTimerDspBase);
+ GT_1trace(curTrace, GT_2CLASS, "dwMboxBase 0x%x\n",
+ pResources->dwMboxBase);
+ GT_1trace(curTrace, GT_2CLASS, "dwDmmuBase 0x%x\n",
+ pResources->dwDmmuBase);
+ dwBuffSize = sizeof(shm_size);
+ status = REG_GetValue(NULL, CURRENTCONFIG, SHMSIZE,
+ (u8 *)&shm_size, &dwBuffSize);
+ if (DSP_SUCCEEDED(status)) {
+ /* Allocate Physically contiguous,
+ * non-cacheable memory */
+ pResources->dwMemBase[1] =
+ (u32)MEM_AllocPhysMem(shm_size, 0x100000,
+ &dmaAddr);
+ if (pResources->dwMemBase[1] == 0) {
+ status = DSP_EMEMORY;
+ GT_0trace(curTrace, GT_7CLASS,
+ "SHM reservation Failed\n");
+ } else {
+ pResources->dwMemLength[1] = shm_size;
+ pResources->dwMemPhys[1] = dmaAddr;
+
+ GT_3trace(curTrace, GT_1CLASS,
+ "Bridge SHM address 0x%x dmaAddr"
+ " %x size %x\n",
+ pResources->dwMemBase[1],
+ dmaAddr, shm_size);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* for Linux, these are hard-coded values */
+ pResources->bIRQRegisters = 0;
+ pResources->bIRQAttrib = 0;
+ pResources->dwOffsetForMonitor = 0;
+ pResources->dwChnlOffset = 0;
+ /* CHNL_MAXCHANNELS */
+ pResources->dwNumChnls = CHNL_MAXCHANNELS;
+ pResources->dwChnlBufSize = 0x400;
+ dwBuffSize = sizeof(struct CFG_HOSTRES);
+ status = REG_SetValue(NULL, (char *)dwContext,
+ CURRENTCONFIG, REG_BINARY,
+ (u8 *)pResources,
+ sizeof(struct CFG_HOSTRES));
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(curTrace, GT_1CLASS,
+ " Successfully set the registry"
+ " value for CURRENTCONFIG\n");
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ " Failed to set the registry value"
+ " for CURRENTCONFIG\n");
+ }
+ }
+ MEM_Free(pResources);
+ }
+ /* End Mem alloc */
+ return status;
+}
diff --git a/drivers/dsp/bridge/rmgr/drv_interface.c b/drivers/dsp/bridge/rmgr/drv_interface.c
new file mode 100644
index 000000000000..a81b12d21625
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/drv_interface.c
@@ -0,0 +1,760 @@
+/*
+ * drv_interface.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * ======== linux_driver.c ========
+ * Description:
+ * DSP/BIOS Bridge driver interface.
+ *
+ * Public Functions:
+ * driver_init
+ * driver_exit
+ * driver_open
+ * driver_release
+ * driver_ioctl
+ * driver_mmap
+ *
+ *! Revision History
+ *! ================
+ *! 21-Apr-2004 map Deprecated use of MODULE_PARM for kernel versions
+ *! greater than 2.5, use module_param.
+ *! 08-Mar-2004 sb Added the dsp_debug argument, which keeps the DSP in self
+ *! loop after image load and waits in a loop for DSP to start
+ *! 16-Feb-2004 vp Deprecated the usage of MOD_INC_USE_COUNT and
+ *! MOD_DEC_USE_COUNT
+ *! for kernel versions greater than 2.5
+ *! 20-May-2003 vp Added unregister functions for the DPM.
+ *! 24-Mar-2003 sb Pass pid instead of driverContext to DSP_Close
+ *! 24-Mar-2003 vp Added Power Management support.
+ *! 21-Mar-2003 sb Configure SHM size using insmod argument shm_size
+ *! 10-Feb-2003 vp Updated based on code review comments
+ *! 18-Oct-2002 sb Created initial version
+ */
+
+/* ----------------------------------- Host OS */
+
+#include <dspbridge/host_os.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cdev.h>
+#ifdef CONFIG_PM
+#include <mach/board-3430sdp.h>
+#endif
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/gt.h>
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/services.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/reg.h>
+#include <dspbridge/csl.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/wcdioctl.h>
+#include <dspbridge/_dcd.h>
+#include <dspbridge/dspdrv.h>
+#include <dspbridge/dbreg.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/pwr.h>
+
+/* ----------------------------------- This */
+#include <drv_interface.h>
+
+#ifndef RES_CLEANUP_DISABLE
+#include <dspbridge/cfg.h>
+#include <dspbridge/resourcecleanup.h>
+#include <dspbridge/chnl.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/cfg.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/drvdefs.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/dbreg.h>
+#endif
+#ifdef CONFIG_PM
+#include <mach/omap-pm.h>
+#include <mach-omap2/omap3-opp.h>
+#endif
+
+#define BRIDGE_NAME "C6410"
+/* ----------------------------------- Globals */
+#define DRIVER_NAME "DspBridge"
+#define DRIVER_MAJOR 0 /* Linux assigns our Major device number */
+#define DRIVER_MINOR 0 /* Linux assigns our Major device number */
+
+#ifdef OMAP44XX
+s32 dsp_debug = 1;
+#else
+s32 dsp_debug;
+#endif
+
+struct platform_device *omap_dspbridge_dev;
+
+struct bridge_dev {
+ struct cdev cdev;
+};
+
+static struct bridge_dev *bridge_device;
+
+static struct class *bridge_class;
+
+static u32 driverContext;
+#ifdef CONFIG_BRIDGE_DEBUG
+static char *GT_str;
+#endif /* CONFIG_BRIDGE_DEBUG */
+static s32 driver_major = DRIVER_MAJOR;
+static s32 driver_minor = DRIVER_MINOR;
+static char *base_img;
+char *iva_img;
+static char *num_procs = "C55=1";
+static s32 shm_size = 0x400000; /* 4 MB */
+static u32 phys_mempool_base;
+static u32 phys_mempool_size;
+static int tc_wordswapon; /* Default value is always false */
+
+#ifdef CONFIG_PM
+struct omap34xx_bridge_suspend_data {
+ int suspended;
+ wait_queue_head_t suspend_wq;
+};
+
+static struct omap34xx_bridge_suspend_data bridge_suspend_data;
+
+static int omap34xxbridge_suspend_lockout(
+ struct omap34xx_bridge_suspend_data *s, struct file *f)
+{
+ if ((s)->suspended) {
+ if ((f)->f_flags & O_NONBLOCK)
+ return DSP_EDPMSUSPEND;
+ wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0);
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef DEBUG
+module_param(GT_str, charp, 0);
+MODULE_PARM_DESC(GT_str, "GT string, default = NULL");
+
+module_param(dsp_debug, int, 0);
+MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false");
+#endif
+
+module_param(driver_major, int, 0); /* Driver's major number */
+MODULE_PARM_DESC(driver_major, "Major device number, default = 0 (auto)");
+
+module_param(driver_minor, int, 0); /* Driver's major number */
+MODULE_PARM_DESC(driver_minor, "Minor device number, default = 0 (auto)");
+
+module_param(base_img, charp, 0);
+MODULE_PARM_DESC(base_img, "DSP base image, default = NULL");
+
+module_param(shm_size, int, 0);
+MODULE_PARM_DESC(shm_size, "SHM size, default = 4 MB, minimum = 64 KB");
+
+module_param(phys_mempool_base, uint, 0);
+MODULE_PARM_DESC(phys_mempool_base,
+ "Physical memory pool base passed to driver");
+
+module_param(phys_mempool_size, uint, 0);
+MODULE_PARM_DESC(phys_mempool_size,
+ "Physical memory pool size passed to driver");
+module_param(tc_wordswapon, int, 0);
+MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
+
+static char *driver_name = DRIVER_NAME;
+
+#ifdef CONFIG_BRIDGE_DEBUG
+static struct GT_Mask driverTrace;
+#endif /* CONFIG_BRIDGE_DEBUG */
+
+static struct file_operations bridge_fops = {
+ .open = bridge_open,
+ .release = bridge_release,
+ .ioctl = bridge_ioctl,
+ .mmap = bridge_mmap,
+};
+
+#ifdef CONFIG_PM
+static u32 timeOut = 1000;
+#ifdef CONFIG_BRIDGE_DVFS
+static struct clk *clk_handle;
+s32 dsp_max_opps = VDD1_OPP5;
+#endif
+
+/* Maximum Opps that can be requested by IVA*/
+/*vdd1 rate table*/
+#ifdef CONFIG_BRIDGE_DVFS
+const struct omap_opp vdd1_rate_table_bridge[] = {
+ {0, 0, 0},
+ /*OPP1*/
+ {S125M, VDD1_OPP1, 0},
+ /*OPP2*/
+ {S250M, VDD1_OPP2, 0},
+ /*OPP3*/
+ {S500M, VDD1_OPP3, 0},
+ /*OPP4*/
+ {S550M, VDD1_OPP4, 0},
+ /*OPP5*/
+ {S600M, VDD1_OPP5, 0},
+};
+#endif
+#endif
+
+struct dspbridge_platform_data *omap_dspbridge_pdata;
+
+u32 vdd1_dsp_freq[6][4] = {
+ {0, 0, 0, 0},
+ /*OPP1*/
+ {0, 90000, 0, 86000},
+ /*OPP2*/
+ {0, 180000, 80000, 170000},
+ /*OPP3*/
+ {0, 360000, 160000, 340000},
+ /*OPP4*/
+ {0, 396000, 325000, 376000},
+ /*OPP5*/
+ {0, 430000, 355000, 430000},
+};
+
+#ifdef CONFIG_BRIDGE_DVFS
+static int dspbridge_post_scale(struct notifier_block *op, unsigned long level,
+ void *ptr)
+{
+ PWR_PM_PostScale(PRCM_VDD1, level);
+ return 0;
+}
+
+static struct notifier_block iva_clk_notifier = {
+ .notifier_call = dspbridge_post_scale,
+ NULL,
+};
+#endif
+
+static int __devinit omap34xx_bridge_probe(struct platform_device *pdev)
+{
+ int status;
+ u32 initStatus;
+ u32 temp;
+ dev_t dev = 0 ;
+ int result;
+#ifdef CONFIG_BRIDGE_DVFS
+ int i = 0;
+#endif
+ struct dspbridge_platform_data *pdata = pdev->dev.platform_data;
+
+ omap_dspbridge_dev = pdev;
+
+ /* use 2.6 device model */
+ if (driver_major) {
+ dev = MKDEV(driver_major, driver_minor);
+ result = register_chrdev_region(dev, 1, driver_name);
+ } else {
+ result = alloc_chrdev_region(&dev, driver_minor, 1,
+ driver_name);
+ driver_major = MAJOR(dev);
+ }
+
+ if (result < 0) {
+ GT_1trace(driverTrace, GT_7CLASS, "bridge_init: "
+ "Can't get Major %d \n", driver_major);
+ return result;
+ }
+
+ bridge_device = kmalloc(sizeof(struct bridge_dev), GFP_KERNEL);
+ if (!bridge_device) {
+ result = -ENOMEM;
+ unregister_chrdev_region(dev, 1);
+ return result;
+ }
+ memset(bridge_device, 0, sizeof(struct bridge_dev));
+ cdev_init(&bridge_device->cdev, &bridge_fops);
+ bridge_device->cdev.owner = THIS_MODULE;
+ bridge_device->cdev.ops = &bridge_fops;
+
+ status = cdev_add(&bridge_device->cdev, dev, 1);
+
+ if (status) {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "Failed to add the bridge device \n");
+ return status;
+ }
+
+ /* udev support */
+ bridge_class = class_create(THIS_MODULE, "ti_bridge");
+
+ if (IS_ERR(bridge_class))
+ GT_0trace(driverTrace, GT_7CLASS,
+ "Error creating bridge class \n");
+
+ device_create(bridge_class, NULL, MKDEV(driver_major, driver_minor),
+ NULL, "DspBridge");
+
+ GT_init();
+ GT_create(&driverTrace, "LD");
+
+#ifdef DEBUG
+ if (GT_str)
+ GT_set(GT_str);
+#elif defined(DDSP_DEBUG_PRODUCT) && GT_TRACE
+ GT_set("**=67");
+#endif
+
+ GT_0trace(driverTrace, GT_ENTER, "-> driver_init\n");
+
+#ifdef CONFIG_PM
+ /* Initialize the wait queue */
+ if (!status) {
+ bridge_suspend_data.suspended = 0;
+ init_waitqueue_head(&bridge_suspend_data.suspend_wq);
+ }
+#endif
+
+ SERVICES_Init();
+
+ /* Autostart flag. This should be set to true if the DSP image should
+ * be loaded and run during bridge module initialization */
+
+ if (base_img) {
+ temp = true;
+ REG_SetValue(NULL, NULL, AUTOSTART, REG_DWORD, (u8 *)&temp,
+ sizeof(temp));
+ REG_SetValue(NULL, NULL, DEFEXEC, REG_SZ, (u8 *)base_img,
+ strlen(base_img) + 1);
+ } else {
+ temp = false;
+ REG_SetValue(NULL, NULL, AUTOSTART, REG_DWORD, (u8 *)&temp,
+ sizeof(temp));
+ REG_SetValue(NULL, NULL, DEFEXEC, REG_SZ, (u8 *) "\0", (u32)2);
+ }
+ REG_SetValue(NULL, NULL, NUMPROCS, REG_SZ, (u8 *) num_procs,
+ strlen(num_procs) + 1);
+
+ if (shm_size >= 0x10000) { /* 64 KB */
+ initStatus = REG_SetValue(NULL, NULL, SHMSIZE, REG_DWORD,
+ (u8 *)&shm_size, sizeof(shm_size));
+ } else {
+ initStatus = DSP_EINVALIDARG;
+ status = -1;
+ GT_0trace(driverTrace, GT_7CLASS,
+ "SHM size must be at least 64 KB\n");
+ }
+ GT_1trace(driverTrace, GT_7CLASS,
+ "requested shm_size = 0x%x\n", shm_size);
+
+ if (pdata->phys_mempool_base && pdata->phys_mempool_size) {
+ phys_mempool_base = pdata->phys_mempool_base;
+ phys_mempool_size = pdata->phys_mempool_size;
+ }
+
+ if (phys_mempool_base > 0x0) {
+ initStatus = REG_SetValue(NULL, NULL, PHYSMEMPOOLBASE,
+ REG_DWORD, (u8 *)&phys_mempool_base,
+ sizeof(phys_mempool_base));
+ }
+ GT_1trace(driverTrace, GT_7CLASS, "phys_mempool_base = 0x%x \n",
+ phys_mempool_base);
+
+ if (phys_mempool_size > 0x0) {
+ initStatus = REG_SetValue(NULL, NULL, PHYSMEMPOOLSIZE,
+ REG_DWORD, (u8 *)&phys_mempool_size,
+ sizeof(phys_mempool_size));
+ }
+ GT_1trace(driverTrace, GT_7CLASS, "phys_mempool_size = 0x%x\n",
+ phys_mempool_base);
+ if ((phys_mempool_base > 0x0) && (phys_mempool_size > 0x0))
+ MEM_ExtPhysPoolInit(phys_mempool_base, phys_mempool_size);
+ if (tc_wordswapon) {
+ GT_0trace(driverTrace, GT_7CLASS, "TC Word Swap is enabled\n");
+ REG_SetValue(NULL, NULL, TCWORDSWAP, REG_DWORD,
+ (u8 *)&tc_wordswapon, sizeof(tc_wordswapon));
+ } else {
+ GT_0trace(driverTrace, GT_7CLASS, "TC Word Swap is disabled\n");
+ REG_SetValue(NULL, NULL, TCWORDSWAP,
+ REG_DWORD, (u8 *)&tc_wordswapon,
+ sizeof(tc_wordswapon));
+ }
+ if (DSP_SUCCEEDED(initStatus)) {
+#ifdef CONFIG_BRIDGE_DVFS
+ for (i = 0; i < 6; i++)
+ pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate;
+
+ clk_handle = clk_get(NULL, "iva2_ck");
+ if (!clk_handle) {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_get failed to get iva2_ck \n");
+ } else {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_get PASS to get iva2_ck \n");
+ }
+ if (!clk_notifier_register(clk_handle, &iva_clk_notifier)) {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_notifier_register PASS for iva2_ck \n");
+ } else {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_notifier_register FAIL for iva2_ck \n");
+ }
+#endif
+ driverContext = DSP_Init(&initStatus);
+ if (DSP_FAILED(initStatus)) {
+ status = -1;
+ GT_0trace(driverTrace, GT_7CLASS,
+ "DSP/BIOS Bridge initialization Failed\n");
+ } else {
+ GT_0trace(driverTrace, GT_5CLASS,
+ "DSP/BIOS Bridge driver loaded\n");
+ }
+ }
+
+ DBC_Assert(status == 0);
+ DBC_Assert(DSP_SUCCEEDED(initStatus));
+ GT_0trace(driverTrace, GT_ENTER, " <- driver_init\n");
+ return status;
+}
+
+static int __devexit omap34xx_bridge_remove(struct platform_device *pdev)
+{
+ dev_t devno;
+ bool ret;
+ DSP_STATUS dsp_status = DSP_SOK;
+ HANDLE hDrvObject = NULL;
+ struct PROCESS_CONTEXT *pTmp = NULL;
+ struct PROCESS_CONTEXT *pCtxtclosed = NULL;
+
+ GT_0trace(driverTrace, GT_ENTER, "-> driver_exit\n");
+
+ dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(dsp_status))
+ goto func_cont;
+ DRV_GetProcCtxtList(&pCtxtclosed, (struct DRV_OBJECT *)hDrvObject);
+ while (pCtxtclosed != NULL) {
+ GT_1trace(driverTrace, GT_5CLASS, "***Cleanup of "
+ "process***%d\n", pCtxtclosed->pid);
+ DRV_RemoveAllResources(pCtxtclosed);
+ PROC_Detach(pCtxtclosed->hProcessor);
+ pTmp = pCtxtclosed->next;
+ DRV_RemoveProcContext((struct DRV_OBJECT *)hDrvObject,
+ pCtxtclosed, (void *)pCtxtclosed->pid);
+ pCtxtclosed = pTmp;
+ }
+func_cont:
+ if (driverContext) {
+ /* Put the DSP in reset state */
+ ret = DSP_Deinit(driverContext);
+ driverContext = 0;
+ DBC_Assert(ret == true);
+ }
+ SERVICES_Exit();
+ GT_exit();
+ /* unregister the clock notifier */
+#ifdef CONFIG_BRIDGE_DVFS
+ if (!clk_notifier_unregister(clk_handle, &iva_clk_notifier)) {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_notifier_unregister PASS for iva2_ck \n");
+ } else {
+ GT_0trace(driverTrace, GT_7CLASS,
+ "clk_notifier_unregister PASS for iva2_ck \n");
+ }
+
+ clk_put(clk_handle);
+ clk_handle = NULL;
+#endif /* #ifdef CONFIG_BRIDGE_DVFS */
+
+ devno = MKDEV(driver_major, driver_minor);
+ if (bridge_device) {
+ cdev_del(&bridge_device->cdev);
+ kfree(bridge_device);
+ }
+ unregister_chrdev_region(devno, 1);
+ if (bridge_class) {
+ /* remove the device from sysfs */
+ device_destroy(bridge_class, MKDEV(driver_major, driver_minor));
+ class_destroy(bridge_class);
+
+ }
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int bridge_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ u32 status;
+ u32 command = PWR_EMERGENCYDEEPSLEEP;
+
+ status = PWR_SleepDSP(command, timeOut);
+ if (DSP_FAILED(status))
+ return -1;
+
+ bridge_suspend_data.suspended = 1;
+ return 0;
+}
+
+static int bridge_resume(struct platform_device *pdev)
+{
+ u32 status;
+
+ status = PWR_WakeDSP(timeOut);
+ if (DSP_FAILED(status))
+ return -1;
+
+ bridge_suspend_data.suspended = 0;
+ wake_up(&bridge_suspend_data.suspend_wq);
+ return 0;
+}
+#else
+#define bridge_suspend NULL
+#define bridge_resume NULL
+#endif
+
+static struct platform_driver bridge_driver = {
+ .driver = {
+ .name = BRIDGE_NAME,
+ },
+ .probe = omap34xx_bridge_probe,
+ .remove = __devexit_p(omap34xx_bridge_remove),
+ .suspend = bridge_suspend,
+ .resume = bridge_resume,
+};
+
+static int __init bridge_init(void)
+{
+ return platform_driver_register(&bridge_driver);
+}
+
+static void __exit bridge_exit(void)
+{
+ platform_driver_unregister(&bridge_driver);
+}
+
+/* This function is called when an application opens handle to the
+ * bridge driver. */
+
+static int bridge_open(struct inode *ip, struct file *filp)
+{
+ int status = 0;
+#ifndef RES_CLEANUP_DISABLE
+ u32 hProcess;
+ DSP_STATUS dsp_status = DSP_SOK;
+ HANDLE hDrvObject = NULL;
+ struct PROCESS_CONTEXT *pPctxt = NULL;
+ struct PROCESS_CONTEXT *next_node = NULL;
+ struct PROCESS_CONTEXT *pCtxtclosed = NULL;
+ struct PROCESS_CONTEXT *pCtxttraverse = NULL;
+ struct task_struct *tsk = NULL;
+ struct pid *pnr = NULL;
+ GT_0trace(driverTrace, GT_ENTER, "-> driver_open\n");
+ dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+
+ /* Checking weather task structure for all process existing
+ * in the process context list If not removing those processes*/
+ if (DSP_FAILED(dsp_status))
+ goto func_cont;
+
+ DRV_GetProcCtxtList(&pCtxtclosed, (struct DRV_OBJECT *)hDrvObject);
+ while (pCtxtclosed != NULL) {
+ pnr = find_get_pid(pCtxtclosed->pid);
+ tsk = pid_task(pnr, PIDTYPE_PID);
+ next_node = pCtxtclosed->next;
+
+ if ((tsk == NULL) || (tsk->exit_state == EXIT_ZOMBIE)) {
+
+ GT_1trace(driverTrace, GT_5CLASS,
+ "***Task structure not existing for "
+ "process***%d\n", pCtxtclosed->pid);
+ DRV_RemoveAllResources(pCtxtclosed);
+ if (pCtxtclosed->hProcessor != NULL) {
+ DRV_GetProcCtxtList(&pCtxttraverse,
+ (struct DRV_OBJECT *)hDrvObject);
+ if (pCtxttraverse->next == NULL) {
+ PROC_Detach(pCtxtclosed->hProcessor);
+ } else {
+ if ((pCtxtclosed->pid ==
+ pCtxttraverse->pid) &&
+ (pCtxttraverse->next != NULL)) {
+ pCtxttraverse =
+ pCtxttraverse->next;
+ }
+ while ((pCtxttraverse != NULL) &&
+ (pCtxtclosed->hProcessor
+ != pCtxttraverse->hProcessor)) {
+ pCtxttraverse =
+ pCtxttraverse->next;
+ if ((pCtxttraverse != NULL) &&
+ (pCtxtclosed->pid ==
+ pCtxttraverse->pid)) {
+ pCtxttraverse =
+ pCtxttraverse->next;
+ }
+ }
+ if (pCtxttraverse == NULL) {
+ PROC_Detach
+ (pCtxtclosed->hProcessor);
+ }
+ }
+ }
+ DRV_RemoveProcContext((struct DRV_OBJECT *)hDrvObject,
+ pCtxtclosed,
+ (void *)pCtxtclosed->pid);
+ }
+ pCtxtclosed = next_node;
+ }
+func_cont:
+ dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(dsp_status))
+ dsp_status = DRV_InsertProcContext(
+ (struct DRV_OBJECT *)hDrvObject, &pPctxt);
+
+ if (pPctxt != NULL) {
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ DRV_ProcUpdatestate(pPctxt, PROC_RES_ALLOCATED);
+ DRV_ProcSetPID(pPctxt, hProcess);
+ }
+#endif
+
+ GT_0trace(driverTrace, GT_ENTER, " <- driver_open\n");
+ return status;
+}
+
+/* This function is called when an application closes handle to the bridge
+ * driver. */
+static int bridge_release(struct inode *ip, struct file *filp)
+{
+ int status;
+ u32 pid;
+
+ GT_0trace(driverTrace, GT_ENTER, "-> driver_release\n");
+
+ /* Return PID instead of process handle */
+ pid = current->pid;
+
+ status = DSP_Close(pid);
+
+
+ (status == true) ? (status = 0) : (status = -1);
+
+ GT_0trace(driverTrace, GT_ENTER, " <- driver_release\n");
+
+ return status;
+}
+
+/* This function provides IO interface to the bridge driver. */
+static int bridge_ioctl(struct inode *ip, struct file *filp, unsigned int code,
+ unsigned long args)
+{
+ int status;
+ u32 retval = DSP_SOK;
+ union Trapped_Args pBufIn;
+
+ DBC_Require(filp != NULL);
+#ifdef CONFIG_PM
+ status = omap34xxbridge_suspend_lockout(&bridge_suspend_data, filp);
+ if (status != 0)
+ return status;
+#endif
+
+ GT_0trace(driverTrace, GT_ENTER, " -> driver_ioctl\n");
+
+ status = copy_from_user(&pBufIn, (union Trapped_Args *)args,
+ sizeof(union Trapped_Args));
+
+ if (status >= 0) {
+ status = WCD_CallDevIOCtl(code, &pBufIn, &retval);
+
+ if (DSP_SUCCEEDED(status)) {
+ status = retval;
+ } else {
+ GT_1trace(driverTrace, GT_7CLASS,
+ "IOCTL Failed, code : 0x%x\n", code);
+ status = -1;
+ }
+
+ }
+
+ GT_0trace(driverTrace, GT_ENTER, " <- driver_ioctl\n");
+
+ return status;
+}
+
+/* This function maps kernel space memory to user space memory. */
+static int bridge_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+#if GT_TRACE
+ u32 offset = vma->vm_pgoff << PAGE_SHIFT;
+#endif
+ u32 status;
+
+ DBC_Assert(vma->vm_start < vma->vm_end);
+
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ GT_6trace(driverTrace, GT_3CLASS,
+ "vm filp %p offset %lx start %lx end %lx"
+ " page_prot %lx flags %lx\n", filp, offset, vma->vm_start,
+ vma->vm_end, vma->vm_page_prot, vma->vm_flags);
+
+ status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+ if (status != 0)
+ status = -EAGAIN;
+
+ return status;
+}
+
+#ifndef RES_CLEANUP_DISABLE
+/* To remove all process resources before removing the process from the
+ * process context list*/
+DSP_STATUS DRV_RemoveAllResources(HANDLE hPCtxt)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt;
+ if (pCtxt != NULL) {
+ DRV_RemoveAllSTRMResElements(pCtxt);
+ DRV_RemoveAllNodeResElements(pCtxt);
+ DRV_RemoveAllDMMResElements(pCtxt);
+ DRV_ProcUpdatestate(pCtxt, PROC_RES_FREED);
+ }
+ return status;
+}
+#endif
+
+/* Bridge driver initialization and de-initialization functions */
+module_init(bridge_init);
+module_exit(bridge_exit);
+
diff --git a/drivers/dsp/bridge/rmgr/drv_interface.h b/drivers/dsp/bridge/rmgr/drv_interface.h
new file mode 100644
index 000000000000..f5b068e92ec5
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/drv_interface.h
@@ -0,0 +1,40 @@
+/*
+ * drv_interface.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== drv_interface.h ========
+ *
+ *! Revision History
+ *! ================
+ *! 24-Mar-2003 vp Added hooks for Power Management Test
+ *! 18-Feb-2003 vp Code review updates
+ *! 18-Oct-2002 sb Created initial version
+
+ */
+
+#ifndef _DRV_INTERFACE_H_
+#define _DRV_INTERFACE_H_
+
+/* Prototypes for all functions in this bridge */
+static int __init bridge_init(void); /* Initialize bridge */
+static void __exit bridge_exit(void); /* Opposite of initialize */
+static int bridge_open(struct inode *, struct file *); /* Open */
+static int bridge_release(struct inode *, struct file *); /* Release */
+static int bridge_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int bridge_mmap(struct file *filp, struct vm_area_struct *vma);
+#endif /* ifndef _DRV_INTERFACE_H_ */
diff --git a/drivers/dsp/bridge/rmgr/dspdrv.c b/drivers/dsp/bridge/rmgr/dspdrv.c
new file mode 100644
index 000000000000..a7a74fc21d21
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/dspdrv.c
@@ -0,0 +1,276 @@
+/*
+ * dspdrv.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== dspdrv.c ========
+ * Description:
+ * Interface to allocate and free bridge resources.
+ *
+ *! Revision History
+ *! ================
+ *! 12-Apr-2004 hp: Compile IVA only for 24xx.
+ *! 09-Feb-2004 vp: Updated to support IVA.
+ *! 10-Feb-2003 vp: Code review updates.
+ *! 18-oct-2002 vp: Ported to the Linux platform.
+ *! 03-Mar-2002 rr: DSP_Deinit bug fixed (gets the Mgrhandle from registry
+ *! before calling MGR_Destroy.
+ *! 11-Jul-2001 jeh Moved MGR_Create() from DSP_Init() to DEV_StartDevice().
+ *! 02-Apr-2001 rr: WCD_InitComplete2 return value is not checked thus
+ *! sllowing the class driver to load irrespective of
+ *! the image load.
+ *! 30-Oct-2000 kc: Made changes w.r.t. usage of REG_SetValue.
+ *! 05-Oct-2000 rr: WCD_InitComplete2 return value checked for RM.
+ *! Failure in WCD_InitComplete2 will cause the
+ *! DSP_Init to fail.
+ *! 12-Aug-2000 kc: Changed REG_EnumValue to REG_EnumKey.
+ *! 07-Aug-2000 rr: MGR_Create does the job of loading the DCD Dll.
+ *! 26-Jul-2000 rr: Driver Object holds the DevNodeStrings for each
+ *! DevObjects. Static variables removed. Returns
+ *! the Driver Object in DSP_Init.
+ *! 17-Jul-2000 rr: Driver Object is created in DSP_Init and that holds
+ *! the list of Device objects.
+ *! 07-Jul-2000 rr: RM implementaion started.
+ *! 24-May-2000 ag: Cleaned up debug msgs.
+ *! 02-May-2000 rr: DSP_Open returns GetCallerProcess as dwOpenContext.
+ *! 03-Feb-2000 rr: GT Changes.
+ *! 28-Jan-2000 rr: Code Cleaned up.Type void changed to void.
+ *! DSP_Deinit checks return values.dwCode in
+ *! DSP_IO_CONTROL is decoded(not hard coded)
+ *! 27-Jan-2000 rr: REG_EnumValue Used .EnumerateKey fxn removed.
+ *! 13-Jan-2000 rr: CFG_GetPrivateDword renamed to CFG_GetDevObject.
+ *! 29-Dec-1999 rr: Code Cleaned up
+ *! 09-Dec-1999 rr: EnumerateKey changed for retail build.
+ *! 06-Dec-1999 rr: ArrayofInstalledNode, index and ArrayofInstalledDev
+ *! is Global.DevObject stores this pointer as hDevNode.
+ *! 02-Dec-1999 rr: DBG_SetGT and RetailMSG conditionally included.
+ *! Comments changed.Deinit handled.Code cleaned up.
+ *! DSP_IOControl, Close, Deinit returns bool values.
+ *! Calls WCD_InitComplete2 for Board AutoStart.
+ *! 29-Nov-1999 rr: DSP_IOControl returns the result through pBufOut.
+ *! Global Arrays keeps track of installed devices.
+ *! 19-Nov-1999 rr: DSP_Init handles multiple drivers.
+ *! 12-Nov-1999 rr: GetDriverKey and EnumerateKey functions added.
+ *! for multiple mini driver support.PCCARD flag
+ *! checking to include PCMCIA related stuff.
+ *! 25-Oct-1999 rr: GT_Init is called within the Process Attach.
+ *! return value initalized to S_OK upfront in the
+ *! Process Attach.
+ *! 15-Oct-1999 rr: DSP_DeInit handles the return values
+ *! 05-Oct-1999 rr: All the PCMCIA related functions are now in PCCARD.c
+ *! DRV_Request Resources is used instead of the
+ *! RegisterMiniDriver as it sounds close to what we are doing.
+ *! 24-Sep-1999 rr: DRV_RegisterMiniDriver is being called from here. Only
+ *! neccessaryPCMCIA fxns are here. Soon they will move out
+ *! either to a seperate file for bus specific inits.
+ *! 10-Sep-1999 rr: GT Enabled. Considerably changed the driver structure as
+ *! - This is the Class driver. After successfully initialized
+ *! the Class driver will attempt to load the Mini driver.
+ *! - Need to seperate the PCMCIA stuff based on bus type.
+ *! - Changed the name of the file to wcdce.c
+ *! - Made the Media Handle as Global again
+ *!
+ *! 19-Aug-1999 rr: Removed the Global hbhMediaHandle. Included the MemTest.
+ *! Modified the DSP_Init, now three windows are opened.
+ *! Split the driver into PDD so that hardware dependent
+ *! functions will reside in PDD.
+ *! 16-Jul-1999 ag Adapted from rkw's CAC Bullet card driver.
+ *!
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/csl.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/reg.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/_dcd.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/mgr.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbreg.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dspdrv.h>
+
+/* ----------------------------------- Globals */
+struct GT_Mask curTrace;
+
+/*
+ * ======== DSP_Init ========
+ * Allocates bridge resources. Loads a base image onto DSP, if specified.
+ */
+u32 DSP_Init(OUT u32 *initStatus)
+{
+ char devNode[MAXREGPATHLENGTH] = "TIOMAP1510";
+ DSP_STATUS status = DSP_EFAIL;
+ struct DRV_OBJECT *drvObject = NULL;
+ u32 index = 0;
+ u32 deviceNode;
+ u32 deviceNodeString;
+
+ GT_create(&curTrace, "DD");
+
+ GT_0trace(curTrace, GT_ENTER, "Entering DSP_Init \r\n");
+
+ if (DSP_FAILED(WCD_Init())) {
+ GT_0trace(curTrace, GT_7CLASS, "DSP_Init Failed \n");
+ goto func_cont;
+ } /* End WCD_Exit */
+ if (DSP_FAILED(DRV_Create(&drvObject))) {
+ GT_0trace(curTrace, GT_7CLASS, "DSP_Init:DRV_Create Failed \n");
+ WCD_Exit();
+ goto func_cont;
+ } /* End DRV_Create */
+ GT_0trace(curTrace, GT_5CLASS, "DSP_Init:DRV Created \r\n");
+
+ /* Request Resources */
+ if (DSP_SUCCEEDED(DRV_RequestResources((u32)&devNode,
+ &deviceNodeString))) {
+ /* Attempt to Start the Device */
+ if (DSP_SUCCEEDED(DEV_StartDevice(
+ (struct CFG_DEVNODE *)deviceNodeString))) {
+ /* Retreive the DevObject from the Registry */
+ GT_2trace(curTrace, GT_1CLASS,
+ "DSP_Init Succeeded for Device1:"
+ "%d: value: %x\n", index, deviceNodeString);
+ status = DSP_SOK;
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ "DSP_Init:DEV_StartDevice Failed\n");
+ (void)DRV_ReleaseResources
+ ((u32) deviceNodeString, drvObject);
+ status = DSP_EFAIL;
+ }
+ } else {
+ GT_0trace(curTrace, GT_7CLASS,
+ "DSP_Init:DRV_RequestResources Failed \r\n");
+ status = DSP_EFAIL;
+ } /* DRV_RequestResources */
+ index++;
+
+ /* Unwind whatever was loaded */
+ if (DSP_FAILED(status)) {
+ /* irrespective of the status of DEV_RemoveDevice we conitinue
+ * unloading. Get the Driver Object iterate through and remove.
+ * Reset the status to E_FAIL to avoid going through
+ * WCD_InitComplete2. */
+ status = DSP_EFAIL;
+ for (deviceNode = DRV_GetFirstDevExtension(); deviceNode != 0;
+ deviceNode = DRV_GetNextDevExtension(deviceNode)) {
+ (void)DEV_RemoveDevice
+ ((struct CFG_DEVNODE *)deviceNode);
+ (void)DRV_ReleaseResources((u32)deviceNode,
+ drvObject);
+ }
+ /* Remove the Driver Object */
+ (void)DRV_Destroy(drvObject);
+ drvObject = NULL;
+ WCD_Exit();
+ GT_0trace(curTrace, GT_7CLASS,
+ "DSP_Init:Logical device Failed to Load\n");
+ } /* Unwinding the loaded drivers */
+func_cont:
+ /* Attempt to Start the Board */
+ if (DSP_SUCCEEDED(status)) {
+ /* BRD_AutoStart could fail if the dsp execuetable is not the
+ * correct one. We should not propagate that error
+ * into the device loader. */
+ (void)WCD_InitComplete2();
+ GT_0trace(curTrace, GT_1CLASS, "DSP_Init Succeeded\n");
+ } else {
+ GT_0trace(curTrace, GT_7CLASS, "DSP_Init Failed\n");
+ } /* End WCD_InitComplete2 */
+ DBC_Ensure((DSP_SUCCEEDED(status) && drvObject != NULL) ||
+ (DSP_FAILED(status) && drvObject == NULL));
+ *initStatus = status;
+ /* Return the Driver Object */
+ return (u32)drvObject;
+}
+
+/*
+ * ======== DSP_Deinit ========
+ * Frees the resources allocated for bridge.
+ */
+bool DSP_Deinit(u32 deviceContext)
+{
+ bool retVal = true;
+ u32 deviceNode;
+ struct MGR_OBJECT *mgrObject = NULL;
+
+ GT_0trace(curTrace, GT_ENTER, "Entering DSP_Deinit \r\n");
+
+ while ((deviceNode = DRV_GetFirstDevExtension()) != 0) {
+ (void)DEV_RemoveDevice((struct CFG_DEVNODE *)deviceNode);
+
+ (void)DRV_ReleaseResources((u32)deviceNode,
+ (struct DRV_OBJECT *)deviceContext);
+ }
+
+ (void) DRV_Destroy((struct DRV_OBJECT *) deviceContext);
+
+ /* Get the Manager Object from Registry
+ * MGR Destroy will unload the DCD dll */
+ if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&mgrObject, REG_MGR_OBJECT)))
+ (void)MGR_Destroy(mgrObject);
+
+ WCD_Exit();
+
+ return retVal;
+}
+
+/*
+ * ======== DSP_Close ========
+ * The Calling Process handle is passed to DEV_CleanupProcesState
+ * for cleaning up of any resources used by the application
+ */
+bool DSP_Close(u32 dwOpenContext)
+{
+ bool retVal = false;
+
+ DBC_Require(dwOpenContext != 0);
+
+ GT_0trace(curTrace, GT_ENTER, "Entering DSP_Close\n");
+
+#ifdef RES_CLEANUP_DISABLE
+
+ if (DSP_SUCCEEDED(DEV_CleanupProcessState((HANDLE) dwOpenContext))) {
+ GT_0trace(curTrace, GT_1CLASS, "DSP_Close Succeeded \r\n");
+ retVal = true;
+ } else {
+ GT_0trace(curTrace, GT_7CLASS, "DSP_Close failed \r\n");
+ }
+#endif
+
+ return retVal;
+}
diff --git a/drivers/dsp/bridge/rmgr/mgr.c b/drivers/dsp/bridge/rmgr/mgr.c
new file mode 100644
index 000000000000..943cf932a35b
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/mgr.c
@@ -0,0 +1,491 @@
+/*
+ * mgr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== mgr.c ========
+ * Description:
+ * Implementation of Manager interface to the device object at the
+ * driver level. This queries the NDB data base and retrieves the
+ * data about Node and Processor.
+ *
+ *
+ *! Revision History:
+ *! ================
+ *! 12-Feb-2003 vp: Code review updates.
+ *! 18-Oct-2002 vp: Ported to Linux platform
+ *! 01-Aug-2001 ag: Added extended info for DSP-MMU setup support.
+ *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates.
+ *! 22-Nov-2000 kc: Added MGR_GetPerfData.
+ *! 03-Nov-2000 rr: Updated after code review.
+ *! 25-Sep-2000 rr: Updated to Version 0.9
+ *! 10-Aug-2000 rr: dwSignature is not specifically inserted in MGR Obj
+ *! as it is taken care by MEM_AllocObject. stdwin.h added
+ *! for retail build to succeed.
+ *! 07-Aug-2000 rr: MGR_Create does the job of Loading DCD Dll.
+ *! 26-Jul-2000 rr: MGR_Destroy releases the hNDBDll.
+ *! 20-Jun-2000 rr: Created.
+ */
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/dbreg.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/mgr.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define ZLDLLNAME ""
+#define SIGNATURE 0x5f52474d /* "MGR_" (in reverse) */
+
+struct MGR_OBJECT {
+ u32 dwSignature;
+ struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */
+};
+
+/* ----------------------------------- Globals */
+#if GT_TRACE
+static struct GT_Mask MGR_DebugMask = { NULL, NULL };
+#endif
+
+static u32 cRefs;
+
+/*
+ * ========= MGR_Create =========
+ * Purpose:
+ * MGR Object gets created only once during driver Loading.
+ */
+DSP_STATUS MGR_Create(OUT struct MGR_OBJECT **phMgrObject,
+ struct CFG_DEVNODE *hDevNode)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct MGR_OBJECT *pMgrObject = NULL;
+
+ DBC_Require(phMgrObject != NULL);
+ DBC_Require(cRefs > 0);
+ GT_1trace(MGR_DebugMask, GT_ENTER,
+ "Entering MGR_Create phMgrObject 0x%x\n ",
+ phMgrObject);
+ MEM_AllocObject(pMgrObject, struct MGR_OBJECT, SIGNATURE);
+ if (pMgrObject) {
+ if (DSP_SUCCEEDED(DCD_CreateManager(ZLDLLNAME,
+ &pMgrObject->hDcdMgr))) {
+ /* If succeeded store the handle in the MGR Object */
+ if (DSP_SUCCEEDED(CFG_SetObject((u32)pMgrObject,
+ REG_MGR_OBJECT))) {
+ *phMgrObject = pMgrObject;
+ GT_0trace(MGR_DebugMask, GT_1CLASS,
+ "MGR_Create:MGR Created\r\n");
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "MGR_Create:CFG_SetObject "
+ "Failed\r\n");
+ DCD_DestroyManager(pMgrObject->hDcdMgr);
+ MEM_FreeObject(pMgrObject);
+ }
+ } else {
+ /* failed to Create DCD Manager */
+ status = DSP_EFAIL;
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "MGR_Create:DCD_ManagerCreate Failed\r\n");
+ MEM_FreeObject(pMgrObject);
+ }
+ } else {
+ status = DSP_EMEMORY;
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "MGR_Create DSP_FAILED to allocate memory \n");
+ }
+ GT_2trace(MGR_DebugMask, GT_ENTER,
+ "Exiting MGR_Create: phMgrObject: 0x%x\t"
+ "status: 0x%x\n", phMgrObject, status);
+ DBC_Ensure(DSP_FAILED(status) ||
+ MEM_IsValidHandle(pMgrObject, SIGNATURE));
+ return status;
+}
+
+/*
+ * ========= MGR_Destroy =========
+ * This function is invoked during bridge driver unloading.Frees MGR object.
+ */
+DSP_STATUS MGR_Destroy(struct MGR_OBJECT *hMgrObject)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct MGR_OBJECT *pMgrObject = (struct MGR_OBJECT *)hMgrObject;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hMgrObject, SIGNATURE));
+
+ GT_1trace(MGR_DebugMask, GT_ENTER,
+ "Entering MGR_Destroy hMgrObject 0x%x\n", hMgrObject);
+ /* Free resources */
+ if (hMgrObject->hDcdMgr)
+ DCD_DestroyManager(hMgrObject->hDcdMgr);
+
+ MEM_FreeObject(pMgrObject);
+ /* Update the Registry with NULL for MGR Object */
+ (void)CFG_SetObject(0, REG_MGR_OBJECT);
+
+ GT_2trace(MGR_DebugMask, GT_ENTER,
+ "Exiting MGR_Destroy: hMgrObject: 0x%x\t"
+ "status: 0x%x\n", hMgrObject, status);
+
+ DBC_Ensure(DSP_FAILED(status) ||
+ !MEM_IsValidHandle(hMgrObject, SIGNATURE));
+
+ return status;
+}
+
+/*
+ * ======== MGR_EnumNodeInfo ========
+ * Enumerate and get configuration information about nodes configured
+ * in the node database.
+ */
+DSP_STATUS MGR_EnumNodeInfo(u32 uNode, OUT struct DSP_NDBPROPS *pNDBProps,
+ u32 uNDBPropsSize, OUT u32 *puNumNodes)
+{
+ DSP_STATUS status = DSP_SOK;
+ DSP_STATUS status1 = DSP_SOK;
+ struct DSP_UUID Uuid, uTempUuid;
+ u32 uTempIndex = 0;
+ u32 uNodeIndex = 0;
+ struct DCD_GENERICOBJ GenObj;
+ struct MGR_OBJECT *pMgrObject = NULL;
+
+ DBC_Require(pNDBProps != NULL);
+ DBC_Require(puNumNodes != NULL);
+ DBC_Require(uNDBPropsSize >= sizeof(struct DSP_NDBPROPS));
+ DBC_Require(cRefs > 0);
+
+ GT_4trace(MGR_DebugMask, GT_ENTER, "Entered Manager_EnumNodeInfo, "
+ "args:\n\t uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:"
+ "0x%x\tpuNumNodes: 0x%x\n", uNode, pNDBProps,
+ uNDBPropsSize, puNumNodes);
+ *puNumNodes = 0;
+ /* Get The Manager Object from the Registry */
+ if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject,
+ REG_MGR_OBJECT))) {
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumNodeInfo:Failed To Get"
+ " MGR Object from Registry\r\n");
+ goto func_cont;
+ }
+ DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE));
+ /* Forever loop till we hit failed or no more items in the
+ * Enumeration. We will exit the loop other than DSP_SOK; */
+ while (status == DSP_SOK) {
+ status = DCD_EnumerateObject(uTempIndex++, DSP_DCDNODETYPE,
+ &uTempUuid);
+ if (status == DSP_SOK) {
+ uNodeIndex++;
+ if (uNode == (uNodeIndex - 1))
+ Uuid = uTempUuid;
+
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ if (uNode > (uNodeIndex - 1)) {
+ status = DSP_EINVALIDARG;
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumNodeInfo: uNode"
+ " is Invalid \r\n");
+ } else {
+ status1 = DCD_GetObjectDef(pMgrObject->hDcdMgr,
+ (struct DSP_UUID *)&Uuid,
+ DSP_DCDNODETYPE, &GenObj);
+ if (DSP_SUCCEEDED(status1)) {
+ /* Get the Obj def */
+ *pNDBProps = GenObj.objData.nodeObj.ndbProps;
+ *puNumNodes = uNodeIndex;
+ status = DSP_SOK;
+ } else {
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumNodeInfo: "
+ "Failed to Get Node Info \r\n");
+ status = DSP_EFAIL;
+ }
+ }
+ } else {
+ /* This could be changed during enum, EFAIL ... */
+ GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo: "
+ "Enumeration failure\r\n");
+ status = DSP_EFAIL;
+ }
+func_cont:
+ GT_4trace(MGR_DebugMask, GT_ENTER,
+ "Exiting Manager_EnumNodeInfo, args:\n\t"
+ "uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:"
+ " 0x%x\tuNumNodes: 0x%x\n", uNode, pNDBProps,
+ uNDBPropsSize, *puNumNodes);
+ DBC_Ensure((DSP_SUCCEEDED(status) && *puNumNodes > 0) ||
+ (DSP_FAILED(status) && *puNumNodes == 0));
+
+ return status;
+}
+
+/*
+ * ======== MGR_EnumProcessorInfo ========
+ * Enumerate and get configuration information about available
+ * DSP processors.
+ */
+DSP_STATUS MGR_EnumProcessorInfo(u32 uProcessor,
+ OUT struct DSP_PROCESSORINFO *pProcessorInfo,
+ u32 uProcessorInfoSize, OUT u32 *puNumProcs)
+{
+ DSP_STATUS status = DSP_SOK;
+ DSP_STATUS status1 = DSP_SOK;
+ DSP_STATUS status2 = DSP_SOK;
+ struct DSP_UUID uTempUuid;
+ u32 uTempIndex = 0;
+ u32 uProcIndex = 0;
+ struct DCD_GENERICOBJ GenObj;
+ struct MGR_OBJECT *pMgrObject = NULL;
+ struct MGR_PROCESSOREXTINFO *pExtInfo;
+ struct DEV_OBJECT *hDevObject;
+ struct DRV_OBJECT *hDrvObject;
+ s32 devType;
+ struct CFG_DEVNODE *devNode;
+ struct CFG_DSPRES chipResources;
+ bool procDetect = false;
+
+ DBC_Require(pProcessorInfo != NULL);
+ DBC_Require(puNumProcs != NULL);
+ DBC_Require(uProcessorInfoSize >= sizeof(struct DSP_PROCESSORINFO));
+ DBC_Require(cRefs > 0);
+
+ GT_4trace(MGR_DebugMask, GT_ENTER,
+ "Entered Manager_EnumProcessorInfo, "
+ "args:\n\tuProcessor: 0x%x\n\tpProcessorInfo: 0x%x\n\t"
+ "uProcessorInfoSize: 0x%x\tpuNumProcs: 0x%x\n", uProcessor,
+ pProcessorInfo, uProcessorInfoSize, puNumProcs);
+ *puNumProcs = 0;
+ status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(status)) {
+ status = DRV_GetDevObject(uProcessor, hDrvObject, &hDevObject);
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetDevType(hDevObject, (u32 *) &devType);
+ status = DEV_GetDevNode(hDevObject, &devNode);
+ if (devType == DSP_UNIT) {
+ status = CFG_GetDSPResources(devNode,
+ &chipResources);
+ } else {
+ status = DSP_EFAIL;
+ GT_1trace(MGR_DebugMask, GT_7CLASS,
+ "Unsupported dev type gotten"
+ "from device object %d\n", devType);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ pProcessorInfo->uProcessorType =
+ chipResources.uChipType;
+ }
+ }
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Get The Manager Object from the Registry */
+ if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject,
+ REG_MGR_OBJECT))) {
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumProcessorInfo: "
+ "Failed To Get MGR Object from Registry\r\n");
+ goto func_end;
+ }
+ DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE));
+ /* Forever loop till we hit no more items in the
+ * Enumeration. We will exit the loop other than DSP_SOK; */
+ while (status1 == DSP_SOK) {
+ status1 = DCD_EnumerateObject(uTempIndex++,
+ DSP_DCDPROCESSORTYPE,
+ &uTempUuid);
+ if (status1 != DSP_SOK)
+ break;
+
+ uProcIndex++;
+ /* Get the Object properties to find the Device/Processor
+ * Type */
+ if (procDetect != false)
+ continue;
+
+ status2 = DCD_GetObjectDef(pMgrObject->hDcdMgr,
+ (struct DSP_UUID *)&uTempUuid,
+ DSP_DCDPROCESSORTYPE,
+ &GenObj);
+ if (DSP_SUCCEEDED(status2)) {
+ /* Get the Obj def */
+ if (uProcessorInfoSize <
+ sizeof(struct MGR_PROCESSOREXTINFO)) {
+ *pProcessorInfo = GenObj.objData.procObj;
+ } else {
+ /* extended info */
+ pExtInfo = (struct MGR_PROCESSOREXTINFO *)
+ pProcessorInfo;
+ *pExtInfo = GenObj.objData.extProcObj;
+ }
+ GT_1trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumProcessorInfo: Got"
+ " Proctype from DCD %x \r\n",
+ pProcessorInfo->uProcessorType);
+ /* See if we got the needed processor */
+ if (devType == DSP_UNIT) {
+ if (pProcessorInfo->uProcessorType ==
+ DSPPROCTYPE_C64)
+ procDetect = true;
+ } else if (devType == IVA_UNIT) {
+ if (pProcessorInfo->uProcessorType ==
+ IVAPROCTYPE_ARM7)
+ procDetect = true;
+ }
+ /* User applciatiuons aonly check for chip type, so
+ * this clumsy overwrite */
+ pProcessorInfo->uProcessorType =
+ chipResources.uChipType;
+ } else {
+ GT_1trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumProcessorInfo: "
+ "Failed to Get DCD Processor Info %x \r\n",
+ status2);
+ status = DSP_EFAIL;
+ }
+ }
+ *puNumProcs = uProcIndex;
+ if (procDetect == false) {
+ GT_0trace(MGR_DebugMask, GT_7CLASS,
+ "Manager_EnumProcessorInfo: Failed"
+ " to get Proc info from DCD , so use CFG registry\n");
+ pProcessorInfo->uProcessorType = chipResources.uChipType;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== MGR_Exit ========
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ */
+void MGR_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+ cRefs--;
+ if (cRefs == 0)
+ DCD_Exit();
+
+ GT_1trace(MGR_DebugMask, GT_5CLASS,
+ "Entered MGR_Exit, ref count: 0x%x\n", cRefs);
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== MGR_GetDCDHandle ========
+ * Retrieves the MGR handle. Accessor Function.
+ */
+DSP_STATUS MGR_GetDCDHandle(struct MGR_OBJECT *hMGRHandle,
+ OUT u32 *phDCDHandle)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct MGR_OBJECT *pMgrObject = (struct MGR_OBJECT *)hMGRHandle;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(phDCDHandle != NULL);
+
+ *phDCDHandle = (u32)NULL;
+ if (MEM_IsValidHandle(pMgrObject, SIGNATURE)) {
+ *phDCDHandle = (u32) pMgrObject->hDcdMgr;
+ status = DSP_SOK;
+ }
+ DBC_Ensure((DSP_SUCCEEDED(status) && *phDCDHandle != (u32)NULL) ||
+ (DSP_FAILED(status) && *phDCDHandle == (u32)NULL));
+
+ return status;
+}
+
+/*
+ * ======== MGR_Init ========
+ * Initialize MGR's private state, keeping a reference count on each call.
+ */
+bool MGR_Init(void)
+{
+ bool fRetval = true;
+ bool fInitDCD = false;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+
+ /* Set the Trace mask */
+ DBC_Assert(!MGR_DebugMask.flags);
+
+ GT_create(&MGR_DebugMask, "MG"); /* "MG" for Manager */
+ fInitDCD = DCD_Init(); /* DCD Module */
+
+ if (!fInitDCD) {
+ fRetval = false;
+ GT_0trace(MGR_DebugMask, GT_6CLASS,
+ "MGR_Init failed\n");
+ }
+ }
+
+ if (fRetval)
+ cRefs++;
+
+
+ GT_1trace(MGR_DebugMask, GT_5CLASS,
+ "Entered MGR_Init, ref count: 0x%x\n", cRefs);
+ DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0)));
+
+ return fRetval;
+}
+
+/*
+ * ======== MGR_WaitForBridgeEvents ========
+ * Block on any Bridge event(s)
+ */
+DSP_STATUS MGR_WaitForBridgeEvents(struct DSP_NOTIFICATION **aNotifications,
+ u32 uCount, OUT u32 *puIndex, u32 uTimeout)
+{
+ DSP_STATUS status;
+ struct SYNC_OBJECT *hSyncEvents[MAX_EVENTS];
+ u32 i;
+
+ DBC_Require(uCount < MAX_EVENTS);
+
+ for (i = 0; i < uCount; i++)
+ hSyncEvents[i] = aNotifications[i]->handle;
+
+ status = SYNC_WaitOnMultipleEvents(hSyncEvents, uCount, uTimeout,
+ puIndex);
+
+ return status;
+
+}
+
diff --git a/drivers/dsp/bridge/rmgr/nldr.c b/drivers/dsp/bridge/rmgr/nldr.c
new file mode 100644
index 000000000000..79f75059d11b
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/nldr.c
@@ -0,0 +1,1967 @@
+/*
+ * nldr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== nldr.c ========
+ * Description:
+ * DSP/BIOS Bridge dynamic + overlay Node loader.
+ *
+ * Public Functions:
+ * NLDR_Allocate
+ * NLDR_Create
+ * NLDR_Delete
+ * NLDR_Exit
+ * NLDR_Free
+ * NLDR_GetFxnAddr
+ * NLDR_Init
+ * NLDR_Load
+ * NLDR_Unload
+ *
+ * Notes:
+ *
+ *! Revision History
+ *! ================
+ *! 07-Apr-2003 map Removed references to dead DLDR module
+ *! 23-Jan-2003 map Updated RemoteAlloc to support memory granularity
+ *! 20-Jan-2003 map Updated to maintain persistent dependent libraries
+ *! 15-Jan-2003 map Adapted for use with multiple dynamic phase libraries
+ *! 19-Dec-2002 map Fixed overlay bug in AddOvlySect for overlay
+ *! sections > 1024 bytes.
+ *! 13-Dec-2002 map Fixed NLDR_GetFxnAddr bug by searching dependent
+ *! libs for symbols
+ *! 27-Sep-2002 map Added RemoteFree to convert size to words for
+ *! correct deallocation
+ *! 16-Sep-2002 map Code Review Cleanup(from dldr.c)
+ *! 29-Aug-2002 map Adjusted for ARM-side overlay copy
+ *! 05-Aug-2002 jeh Created.
+ */
+
+#include <dspbridge/host_os.h>
+
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+#ifdef DEBUG
+#include <dspbridge/dbg.h>
+#endif
+
+/* OS adaptation layer */
+#include <dspbridge/csl.h>
+#include <dspbridge/mem.h>
+
+/* Platform manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+
+/* Resource manager */
+#include <dspbridge/dbll.h>
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/rmm.h>
+#include <dspbridge/uuidutil.h>
+
+#include <dspbridge/nldr.h>
+
+#define NLDR_SIGNATURE 0x52444c4e /* "RDLN" */
+#define NLDR_NODESIGNATURE 0x4e444c4e /* "NDLN" */
+
+/* Name of section containing dynamic load mem */
+#define DYNMEMSECT ".dspbridge_mem"
+
+/* Name of section containing dependent library information */
+#define DEPLIBSECT ".dspbridge_deplibs"
+
+/* Max depth of recursion for loading node's dependent libraries */
+#define MAXDEPTH 5
+
+/* Max number of persistent libraries kept by a node */
+#define MAXLIBS 5
+
+/*
+ * Defines for extracting packed dynamic load memory requirements from two
+ * masks.
+ * These defines must match node.cdb and dynm.cdb
+ * Format of data/code mask is:
+ * uuuuuuuu|fueeeeee|fudddddd|fucccccc|
+ * where
+ * u = unused
+ * cccccc = prefered/required dynamic mem segid for create phase data/code
+ * dddddd = prefered/required dynamic mem segid for delete phase data/code
+ * eeeeee = prefered/req. dynamic mem segid for execute phase data/code
+ * f = flag indicating if memory is preferred or required:
+ * f = 1 if required, f = 0 if preferred.
+ *
+ * The 6 bits of the segid are interpreted as follows:
+ *
+ * If the 6th bit (bit 5) is not set, then this specifies a memory segment
+ * between 0 and 31 (a maximum of 32 dynamic loading memory segments).
+ * If the 6th bit (bit 5) is set, segid has the following interpretation:
+ * segid = 32 - Any internal memory segment can be used.
+ * segid = 33 - Any external memory segment can be used.
+ * segid = 63 - Any memory segment can be used (in this case the
+ * required/preferred flag is irrelevant).
+ *
+ */
+/* Maximum allowed dynamic loading memory segments */
+#define MAXMEMSEGS 32
+
+#define MAXSEGID 3 /* Largest possible (real) segid */
+#define MEMINTERNALID 32 /* Segid meaning use internal mem */
+#define MEMEXTERNALID 33 /* Segid meaning use external mem */
+#define NULLID 63 /* Segid meaning no memory req/pref */
+#define FLAGBIT 7 /* 7th bit is pref./req. flag */
+#define SEGMASK 0x3f /* Bits 0 - 5 */
+
+#define CREATEBIT 0 /* Create segid starts at bit 0 */
+#define DELETEBIT 8 /* Delete segid starts at bit 8 */
+#define EXECUTEBIT 16 /* Execute segid starts at bit 16 */
+
+/*
+ * Masks that define memory type. Must match defines in dynm.cdb.
+ */
+#define DYNM_CODE 0x2
+#define DYNM_DATA 0x4
+#define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA)
+#define DYNM_INTERNAL 0x8
+#define DYNM_EXTERNAL 0x10
+
+/*
+ * Defines for packing memory requirement/preference flags for code and
+ * data of each of the node's phases into one mask.
+ * The bit is set if the segid is required for loading code/data of the
+ * given phase. The bit is not set, if the segid is preferred only.
+ *
+ * These defines are also used as indeces into a segid array for the node.
+ * eg node's segid[CREATEDATAFLAGBIT] is the memory segment id that the
+ * create phase data is required or preferred to be loaded into.
+ */
+#define CREATEDATAFLAGBIT 0
+#define CREATECODEFLAGBIT 1
+#define EXECUTEDATAFLAGBIT 2
+#define EXECUTECODEFLAGBIT 3
+#define DELETEDATAFLAGBIT 4
+#define DELETECODEFLAGBIT 5
+#define MAXFLAGS 6
+
+#define IsInternal(hNldr, segid) (((segid) <= MAXSEGID && \
+ hNldr->segTable[(segid)] & DYNM_INTERNAL) || \
+ (segid) == MEMINTERNALID)
+
+#define IsExternal(hNldr, segid) (((segid) <= MAXSEGID && \
+ hNldr->segTable[(segid)] & DYNM_EXTERNAL) || \
+ (segid) == MEMEXTERNALID)
+
+#define SWAPLONG(x) ((((x) << 24) & 0xFF000000) | (((x) << 8) & 0xFF0000L) | \
+ (((x) >> 8) & 0xFF00L) | (((x) >> 24) & 0xFF))
+
+#define SWAPWORD(x) ((((x) << 8) & 0xFF00) | (((x) >> 8) & 0xFF))
+
+ /*
+ * These names may be embedded in overlay sections to identify which
+ * node phase the section should be overlayed.
+ */
+#define PCREATE "create"
+#define PDELETE "delete"
+#define PEXECUTE "execute"
+
+#define IsEqualUUID(uuid1, uuid2) (\
+ ((uuid1).ulData1 == (uuid2).ulData1) && \
+ ((uuid1).usData2 == (uuid2).usData2) && \
+ ((uuid1).usData3 == (uuid2).usData3) && \
+ ((uuid1).ucData4 == (uuid2).ucData4) && \
+ ((uuid1).ucData5 == (uuid2).ucData5) && \
+ (strncmp((void *)(uuid1).ucData6, (void *)(uuid2).ucData6, 6)) == 0)
+
+ /*
+ * ======== MemInfo ========
+ * Format of dynamic loading memory segment info in coff file.
+ * Must match dynm.h55.
+ */
+struct MemInfo {
+ u32 segid; /* Dynamic loading memory segment number */
+ u32 base;
+ u32 len;
+ u32 type; /* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */
+};
+
+/*
+ * ======== LibNode ========
+ * For maintaining a tree of library dependencies.
+ */
+struct LibNode {
+ struct DBLL_LibraryObj *lib; /* The library */
+ u16 nDepLibs; /* Number of dependent libraries */
+ struct LibNode *pDepLibs; /* Dependent libraries of lib */
+};
+
+/*
+ * ======== OvlySect ========
+ * Information needed to overlay a section.
+ */
+struct OvlySect {
+ struct OvlySect *pNextSect;
+ u32 loadAddr; /* Load address of section */
+ u32 runAddr; /* Run address of section */
+ u32 size; /* Size of section */
+ u16 page; /* DBL_CODE, DBL_DATA */
+};
+
+/*
+ * ======== OvlyNode ========
+ * For maintaining a list of overlay nodes, with sections that need to be
+ * overlayed for each of the nodes phases.
+ */
+struct OvlyNode {
+ struct DSP_UUID uuid;
+ char *pNodeName;
+ struct OvlySect *pCreateSects;
+ struct OvlySect *pDeleteSects;
+ struct OvlySect *pExecuteSects;
+ struct OvlySect *pOtherSects;
+ u16 nCreateSects;
+ u16 nDeleteSects;
+ u16 nExecuteSects;
+ u16 nOtherSects;
+ u16 createRef;
+ u16 deleteRef;
+ u16 executeRef;
+ u16 otherRef;
+};
+
+/*
+ * ======== NLDR_OBJECT ========
+ * Overlay loader object.
+ */
+struct NLDR_OBJECT {
+ u32 dwSignature; /* For object validation */
+ struct DEV_OBJECT *hDevObject; /* Device object */
+ struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */
+ struct DBLL_TarObj *dbll; /* The DBL loader */
+ struct DBLL_LibraryObj *baseLib; /* Base image library */
+ struct RMM_TargetObj *rmm; /* Remote memory manager for DSP */
+ struct DBLL_Fxns dbllFxns; /* Loader function table */
+ struct DBLL_Attrs dbllAttrs; /* attrs to pass to loader functions */
+ NLDR_OVLYFXN ovlyFxn; /* "write" for overlay nodes */
+ NLDR_WRITEFXN writeFxn; /* "write" for dynamic nodes */
+ struct OvlyNode *ovlyTable; /* Table of overlay nodes */
+ u16 nOvlyNodes; /* Number of overlay nodes in base */
+ u16 nNode; /* Index for tracking overlay nodes */
+ u16 nSegs; /* Number of dynamic load mem segs */
+ u32 *segTable; /* memtypes of dynamic memory segs
+ * indexed by segid
+ */
+ u16 usDSPMauSize; /* Size of DSP MAU */
+ u16 usDSPWordSize; /* Size of DSP word */
+};
+
+/*
+ * ======== NLDR_NODEOBJECT ========
+ * Dynamic node object. This object is created when a node is allocated.
+ */
+struct NLDR_NODEOBJECT {
+ u32 dwSignature; /* For object validation */
+ struct NLDR_OBJECT *pNldr; /* Dynamic loader handle */
+ void *pPrivRef; /* Handle to pass to DBL_WriteFxn */
+ struct DSP_UUID uuid; /* Node's UUID */
+ bool fDynamic; /* Dynamically loaded node? */
+ bool fOverlay; /* Overlay node? */
+ bool *pfPhaseSplit; /* Multiple phase libraries? */
+ struct LibNode root; /* Library containing node phase */
+ struct LibNode createLib; /* Library containing create phase lib */
+ struct LibNode executeLib; /* Library containing execute phase lib */
+ struct LibNode deleteLib; /* Library containing delete phase lib */
+ struct LibNode persLib[MAXLIBS]; /* libs remain loaded until Delete */
+ s32 nPersLib; /* Number of persistent libraries */
+ /* Path in lib dependency tree */
+ struct DBLL_LibraryObj *libPath[MAXDEPTH + 1];
+ enum NLDR_PHASE phase; /* Node phase currently being loaded */
+
+ /*
+ * Dynamic loading memory segments for data and code of each phase.
+ */
+ u16 segId[MAXFLAGS];
+
+ /*
+ * Mask indicating whether each mem segment specified in segId[]
+ * is preferred or required.
+ * For example if (codeDataFlagMask & (1 << EXECUTEDATAFLAGBIT)) != 0,
+ * then it is required to load execute phase data into the memory
+ * specified by segId[EXECUTEDATAFLAGBIT].
+ */
+ u32 codeDataFlagMask;
+};
+
+/* Dynamic loader function table */
+static struct DBLL_Fxns dbllFxns = {
+ (DBLL_CloseFxn) DBLL_close,
+ (DBLL_CreateFxn) DBLL_create,
+ (DBLL_DeleteFxn) DBLL_delete,
+ (DBLL_ExitFxn) DBLL_exit,
+ (DBLL_GetAttrsFxn) DBLL_getAttrs,
+ (DBLL_GetAddrFxn) DBLL_getAddr,
+ (DBLL_GetCAddrFxn) DBLL_getCAddr,
+ (DBLL_GetSectFxn) DBLL_getSect,
+ (DBLL_InitFxn) DBLL_init,
+ (DBLL_LoadFxn) DBLL_load,
+ (DBLL_LoadSectFxn) DBLL_loadSect,
+ (DBLL_OpenFxn) DBLL_open,
+ (DBLL_ReadSectFxn) DBLL_readSect,
+ (DBLL_SetAttrsFxn) DBLL_setAttrs,
+ (DBLL_UnloadFxn) DBLL_unload,
+ (DBLL_UnloadSectFxn) DBLL_unloadSect,
+};
+
+static struct GT_Mask NLDR_debugMask = { NULL, NULL }; /* GT trace variable */
+static u32 cRefs; /* module reference count */
+
+static DSP_STATUS AddOvlyInfo(void *handle, struct DBLL_SectInfo *sectInfo,
+ u32 addr, u32 nBytes);
+static DSP_STATUS AddOvlyNode(struct DSP_UUID *pUuid,
+ enum DSP_DCDOBJTYPE objType,
+ IN void *handle);
+static DSP_STATUS AddOvlySect(struct NLDR_OBJECT *hNldr,
+ struct OvlySect **pList,
+ struct DBLL_SectInfo *pSectInfo, bool *pExists,
+ u32 addr, u32 nBytes);
+static s32 fakeOvlyWrite(void *handle, u32 dspAddr, void *buf, u32 nBytes,
+ s32 mtype);
+static void FreeSects(struct NLDR_OBJECT *hNldr, struct OvlySect *pPhaseSects,
+ u16 nAlloc);
+static bool GetSymbolValue(void *handle, void *pArg, void *rmmHandle,
+ char *symName, struct DBLL_Symbol **sym);
+static DSP_STATUS LoadLib(struct NLDR_NODEOBJECT *hNldrNode,
+ struct LibNode *root, struct DSP_UUID uuid,
+ bool rootPersistent, struct DBLL_LibraryObj **libPath,
+ enum NLDR_PHASE phase, u16 depth);
+static DSP_STATUS LoadOvly(struct NLDR_NODEOBJECT *hNldrNode,
+ enum NLDR_PHASE phase);
+static DSP_STATUS RemoteAlloc(void **pRef, u16 memType, u32 size,
+ u32 align, u32 *dspAddr,
+ OPTIONAL s32 segmentId, OPTIONAL s32 req,
+ bool reserve);
+static DSP_STATUS RemoteFree(void **pRef, u16 space, u32 dspAddr,
+ u32 size, bool reserve);
+
+static void UnloadLib(struct NLDR_NODEOBJECT *hNldrNode, struct LibNode *root);
+static void UnloadOvly(struct NLDR_NODEOBJECT *hNldrNode,
+ enum NLDR_PHASE phase);
+static bool findInPersistentLibArray(struct NLDR_NODEOBJECT *hNldrNode,
+ struct DBLL_LibraryObj *lib);
+static u32 findLcm(u32 a, u32 b);
+static u32 findGcf(u32 a, u32 b);
+
+/*
+ * ======== NLDR_Allocate ========
+ */
+DSP_STATUS NLDR_Allocate(struct NLDR_OBJECT *hNldr, void *pPrivRef,
+ IN CONST struct DCD_NODEPROPS *pNodeProps,
+ OUT struct NLDR_NODEOBJECT **phNldrNode,
+ IN bool *pfPhaseSplit)
+{
+ struct NLDR_NODEOBJECT *pNldrNode = NULL;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pNodeProps != NULL);
+ DBC_Require(phNldrNode != NULL);
+ DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE));
+
+ GT_5trace(NLDR_debugMask, GT_ENTER, "NLDR_Allocate(0x%x, 0x%x, 0x%x, "
+ "0x%x, 0x%x)\n", hNldr, pPrivRef, pNodeProps, phNldrNode,
+ pfPhaseSplit);
+
+ /* Initialize handle in case of failure */
+ *phNldrNode = NULL;
+ /* Allocate node object */
+ MEM_AllocObject(pNldrNode, struct NLDR_NODEOBJECT, NLDR_NODESIGNATURE);
+
+ if (pNldrNode == NULL) {
+ GT_0trace(NLDR_debugMask, GT_6CLASS, "NLDR_Allocate: "
+ "Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ } else {
+ pNldrNode->pfPhaseSplit = pfPhaseSplit;
+ pNldrNode->nPersLib = 0;
+ pNldrNode->pNldr = hNldr;
+ pNldrNode->pPrivRef = pPrivRef;
+ /* Save node's UUID. */
+ pNldrNode->uuid = pNodeProps->ndbProps.uiNodeID;
+ /*
+ * Determine if node is a dynamically loaded node from
+ * ndbProps.
+ */
+ if (pNodeProps->usLoadType == NLDR_DYNAMICLOAD) {
+ /* Dynamic node */
+ pNldrNode->fDynamic = true;
+ /*
+ * Extract memory requirements from ndbProps masks
+ */
+ /* Create phase */
+ pNldrNode->segId[CREATEDATAFLAGBIT] = (u16)
+ (pNodeProps->ulDataMemSegMask >> CREATEBIT) &
+ SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulDataMemSegMask >>
+ (CREATEBIT + FLAGBIT)) & 1) <<
+ CREATEDATAFLAGBIT;
+ pNldrNode->segId[CREATECODEFLAGBIT] = (u16)
+ (pNodeProps->ulCodeMemSegMask >>
+ CREATEBIT) & SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulCodeMemSegMask >>
+ (CREATEBIT + FLAGBIT)) & 1) <<
+ CREATECODEFLAGBIT;
+ /* Execute phase */
+ pNldrNode->segId[EXECUTEDATAFLAGBIT] = (u16)
+ (pNodeProps->ulDataMemSegMask >>
+ EXECUTEBIT) & SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulDataMemSegMask >>
+ (EXECUTEBIT + FLAGBIT)) & 1) <<
+ EXECUTEDATAFLAGBIT;
+ pNldrNode->segId[EXECUTECODEFLAGBIT] = (u16)
+ (pNodeProps->ulCodeMemSegMask >>
+ EXECUTEBIT) & SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulCodeMemSegMask >>
+ (EXECUTEBIT + FLAGBIT)) & 1) <<
+ EXECUTECODEFLAGBIT;
+ /* Delete phase */
+ pNldrNode->segId[DELETEDATAFLAGBIT] = (u16)
+ (pNodeProps->ulDataMemSegMask >> DELETEBIT) &
+ SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulDataMemSegMask >>
+ (DELETEBIT + FLAGBIT)) & 1) <<
+ DELETEDATAFLAGBIT;
+ pNldrNode->segId[DELETECODEFLAGBIT] = (u16)
+ (pNodeProps->ulCodeMemSegMask >>
+ DELETEBIT) & SEGMASK;
+ pNldrNode->codeDataFlagMask |=
+ ((pNodeProps->ulCodeMemSegMask >>
+ (DELETEBIT + FLAGBIT)) & 1) <<
+ DELETECODEFLAGBIT;
+ } else {
+ /* Non-dynamically loaded nodes are part of the
+ * base image */
+ pNldrNode->root.lib = hNldr->baseLib;
+ /* Check for overlay node */
+ if (pNodeProps->usLoadType == NLDR_OVLYLOAD)
+ pNldrNode->fOverlay = true;
+
+ }
+ *phNldrNode = (struct NLDR_NODEOBJECT *) pNldrNode;
+ }
+ /* Cleanup on failure */
+ if (DSP_FAILED(status) && pNldrNode)
+ NLDR_Free((struct NLDR_NODEOBJECT *) pNldrNode);
+
+ DBC_Ensure((DSP_SUCCEEDED(status) &&
+ MEM_IsValidHandle(((struct NLDR_NODEOBJECT *)(*phNldrNode)),
+ NLDR_NODESIGNATURE)) || (DSP_FAILED(status) &&
+ *phNldrNode == NULL));
+ return status;
+}
+
+/*
+ * ======== NLDR_Create ========
+ */
+DSP_STATUS NLDR_Create(OUT struct NLDR_OBJECT **phNldr,
+ struct DEV_OBJECT *hDevObject,
+ IN CONST struct NLDR_ATTRS *pAttrs)
+{
+ struct COD_MANAGER *hCodMgr; /* COD manager */
+ char *pszCoffBuf = NULL;
+ char szZLFile[COD_MAXPATHLENGTH];
+ struct NLDR_OBJECT *pNldr = NULL;
+ struct DBLL_Attrs saveAttrs;
+ struct DBLL_Attrs newAttrs;
+ DBLL_Flags flags;
+ u32 ulEntry;
+ u16 nSegs = 0;
+ struct MemInfo *pMemInfo;
+ u32 ulLen = 0;
+ u32 ulAddr;
+ struct RMM_Segment *rmmSegs = NULL;
+ u16 i;
+ DSP_STATUS status = DSP_SOK;
+ DBC_Require(cRefs > 0);
+ DBC_Require(phNldr != NULL);
+ DBC_Require(hDevObject != NULL);
+ DBC_Require(pAttrs != NULL);
+ DBC_Require(pAttrs->pfnOvly != NULL);
+ DBC_Require(pAttrs->pfnWrite != NULL);
+ GT_3trace(NLDR_debugMask, GT_ENTER, "NLDR_Create(0x%x, 0x%x, 0x%x)\n",
+ phNldr, hDevObject, pAttrs);
+ /* Allocate dynamic loader object */
+ MEM_AllocObject(pNldr, struct NLDR_OBJECT, NLDR_SIGNATURE);
+ if (pNldr) {
+ pNldr->hDevObject = hDevObject;
+ /* warning, lazy status checking alert! */
+ status = DEV_GetCodMgr(hDevObject, &hCodMgr);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ status = COD_GetLoader(hCodMgr, &pNldr->dbll);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ status = COD_GetBaseLib(hCodMgr, &pNldr->baseLib);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ status = COD_GetBaseName(hCodMgr, szZLFile, COD_MAXPATHLENGTH);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ status = DSP_SOK;
+ /* end lazy status checking */
+ pNldr->usDSPMauSize = pAttrs->usDSPMauSize;
+ pNldr->usDSPWordSize = pAttrs->usDSPWordSize;
+ pNldr->dbllFxns = dbllFxns;
+ if (!(pNldr->dbllFxns.initFxn()))
+ status = DSP_EMEMORY;
+
+ } else {
+ GT_0trace(NLDR_debugMask, GT_6CLASS, "NLDR_Create: "
+ "Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ }
+ /* Create the DCD Manager */
+ if (DSP_SUCCEEDED(status))
+ status = DCD_CreateManager(NULL, &pNldr->hDcdMgr);
+
+ /* Get dynamic loading memory sections from base lib */
+ if (DSP_SUCCEEDED(status)) {
+ status = pNldr->dbllFxns.getSectFxn(pNldr->baseLib, DYNMEMSECT,
+ &ulAddr, &ulLen);
+ if (DSP_SUCCEEDED(status)) {
+ pszCoffBuf = MEM_Calloc(ulLen * pNldr->usDSPMauSize,
+ MEM_PAGED);
+ if (!pszCoffBuf) {
+ GT_0trace(NLDR_debugMask, GT_6CLASS,
+ "NLDR_Create: Memory "
+ "allocation failed\n");
+ status = DSP_EMEMORY;
+ }
+ } else {
+ /* Ok to not have dynamic loading memory */
+ status = DSP_SOK;
+ ulLen = 0;
+ GT_1trace(NLDR_debugMask, GT_6CLASS,
+ "NLDR_Create: DBLL_getSect "
+ "failed (no dynamic loading mem segments): "
+ "0x%lx\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status) && ulLen > 0) {
+ /* Read section containing dynamic load mem segments */
+ status = pNldr->dbllFxns.readSectFxn(pNldr->baseLib, DYNMEMSECT,
+ pszCoffBuf, ulLen);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NLDR_debugMask, GT_6CLASS,
+ "NLDR_Create: DBLL_read Section"
+ "failed: 0x%lx\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status) && ulLen > 0) {
+ /* Parse memory segment data */
+ nSegs = (u16)(*((u32 *)pszCoffBuf));
+ if (nSegs > MAXMEMSEGS) {
+ GT_1trace(NLDR_debugMask, GT_6CLASS,
+ "NLDR_Create: Invalid number of "
+ "dynamic load mem segments: 0x%lx\n", nSegs);
+ status = DSP_ECORRUPTFILE;
+ }
+ }
+ /* Parse dynamic load memory segments */
+ if (DSP_SUCCEEDED(status) && nSegs > 0) {
+ rmmSegs = MEM_Calloc(sizeof(struct RMM_Segment) * nSegs,
+ MEM_PAGED);
+ pNldr->segTable = MEM_Calloc(sizeof(u32) * nSegs, MEM_PAGED);
+ if (rmmSegs == NULL || pNldr->segTable == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ pNldr->nSegs = nSegs;
+ pMemInfo = (struct MemInfo *)(pszCoffBuf +
+ sizeof(u32));
+ for (i = 0; i < nSegs; i++) {
+ rmmSegs[i].base = (pMemInfo + i)->base;
+ rmmSegs[i].length = (pMemInfo + i)->len;
+ rmmSegs[i].space = 0;
+ pNldr->segTable[i] = (pMemInfo + i)->type;
+#ifdef DEBUG
+ DBG_Trace(DBG_LEVEL7,
+ "** (proc) DLL MEMSEGMENT: %d, Base: 0x%x, "
+ "Length: 0x%x\n", i, rmmSegs[i].base,
+ rmmSegs[i].length);
+#endif
+ }
+ }
+ }
+ /* Create Remote memory manager */
+ if (DSP_SUCCEEDED(status))
+ status = RMM_create(&pNldr->rmm, rmmSegs, nSegs);
+
+ if (DSP_SUCCEEDED(status)) {
+ /* set the alloc, free, write functions for loader */
+ pNldr->dbllFxns.getAttrsFxn(pNldr->dbll, &saveAttrs);
+ newAttrs = saveAttrs;
+ newAttrs.alloc = (DBLL_AllocFxn) RemoteAlloc;
+ newAttrs.free = (DBLL_FreeFxn) RemoteFree;
+ newAttrs.symLookup = (DBLL_SymLookup) GetSymbolValue;
+ newAttrs.symHandle = pNldr;
+ newAttrs.write = (DBLL_WriteFxn) pAttrs->pfnWrite;
+ pNldr->ovlyFxn = pAttrs->pfnOvly;
+ pNldr->writeFxn = pAttrs->pfnWrite;
+ pNldr->dbllAttrs = newAttrs;
+ }
+ if (rmmSegs)
+ MEM_Free(rmmSegs);
+
+ if (pszCoffBuf)
+ MEM_Free(pszCoffBuf);
+
+ /* Get overlay nodes */
+ if (DSP_SUCCEEDED(status)) {
+ status = COD_GetBaseName(hCodMgr, szZLFile, COD_MAXPATHLENGTH);
+ /* lazy check */
+ DBC_Assert(DSP_SUCCEEDED(status));
+ /* First count number of overlay nodes */
+ status = DCD_GetObjects(pNldr->hDcdMgr, szZLFile, AddOvlyNode,
+ (void *) pNldr);
+ /* Now build table of overlay nodes */
+ if (DSP_SUCCEEDED(status) && pNldr->nOvlyNodes > 0) {
+ /* Allocate table for overlay nodes */
+ pNldr->ovlyTable =
+ MEM_Calloc(sizeof(struct OvlyNode) * pNldr->nOvlyNodes,
+ MEM_PAGED);
+ /* Put overlay nodes in the table */
+ pNldr->nNode = 0;
+ status = DCD_GetObjects(pNldr->hDcdMgr, szZLFile,
+ AddOvlyNode,
+ (void *) pNldr);
+ }
+ }
+ /* Do a fake reload of the base image to get overlay section info */
+ if (DSP_SUCCEEDED(status) && pNldr->nOvlyNodes > 0) {
+ saveAttrs.write = fakeOvlyWrite;
+ saveAttrs.logWrite = AddOvlyInfo;
+ saveAttrs.logWriteHandle = pNldr;
+ flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
+ status = pNldr->dbllFxns.loadFxn(pNldr->baseLib, flags,
+ &saveAttrs, &ulEntry);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ *phNldr = (struct NLDR_OBJECT *) pNldr;
+ } else {
+ if (pNldr)
+ NLDR_Delete((struct NLDR_OBJECT *) pNldr);
+
+ *phNldr = NULL;
+ }
+ /* FIXME:Temp. Fix. Must be removed */
+ DBC_Ensure((DSP_SUCCEEDED(status) &&
+ MEM_IsValidHandle(((struct NLDR_OBJECT *)*phNldr),
+ NLDR_SIGNATURE))
+ || (DSP_FAILED(status) && (*phNldr == NULL)));
+ return status;
+}
+
+/*
+ * ======== NLDR_Delete ========
+ */
+void NLDR_Delete(struct NLDR_OBJECT *hNldr)
+{
+ struct OvlySect *pSect;
+ struct OvlySect *pNext;
+ u16 i;
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE));
+ GT_1trace(NLDR_debugMask, GT_ENTER, "NLDR_Delete(0x%x)\n", hNldr);
+ hNldr->dbllFxns.exitFxn();
+ if (hNldr->rmm)
+ RMM_delete(hNldr->rmm);
+
+ if (hNldr->segTable)
+ MEM_Free(hNldr->segTable);
+
+ if (hNldr->hDcdMgr)
+ DCD_DestroyManager(hNldr->hDcdMgr);
+
+ /* Free overlay node information */
+ if (hNldr->ovlyTable) {
+ for (i = 0; i < hNldr->nOvlyNodes; i++) {
+ pSect = hNldr->ovlyTable[i].pCreateSects;
+ while (pSect) {
+ pNext = pSect->pNextSect;
+ MEM_Free(pSect);
+ pSect = pNext;
+ }
+ pSect = hNldr->ovlyTable[i].pDeleteSects;
+ while (pSect) {
+ pNext = pSect->pNextSect;
+ MEM_Free(pSect);
+ pSect = pNext;
+ }
+ pSect = hNldr->ovlyTable[i].pExecuteSects;
+ while (pSect) {
+ pNext = pSect->pNextSect;
+ MEM_Free(pSect);
+ pSect = pNext;
+ }
+ pSect = hNldr->ovlyTable[i].pOtherSects;
+ while (pSect) {
+ pNext = pSect->pNextSect;
+ MEM_Free(pSect);
+ pSect = pNext;
+ }
+ }
+ MEM_Free(hNldr->ovlyTable);
+ }
+ MEM_FreeObject(hNldr);
+ DBC_Ensure(!MEM_IsValidHandle(hNldr, NLDR_SIGNATURE));
+}
+
+/*
+ * ======== NLDR_Exit ========
+ * Discontinue usage of NLDR module.
+ */
+void NLDR_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ cRefs--;
+
+ GT_1trace(NLDR_debugMask, GT_5CLASS,
+ "Entered NLDR_Exit, ref count: 0x%x\n", cRefs);
+
+ if (cRefs == 0) {
+ RMM_exit();
+ NLDR_debugMask.flags = NULL;
+ }
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== NLDR_Free ========
+ */
+void NLDR_Free(struct NLDR_NODEOBJECT *hNldrNode)
+{
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE));
+
+ GT_1trace(NLDR_debugMask, GT_ENTER, "NLDR_Free(0x%x)\n", hNldrNode);
+
+ MEM_FreeObject(hNldrNode);
+}
+
+/*
+ * ======== NLDR_GetFxnAddr ========
+ */
+DSP_STATUS NLDR_GetFxnAddr(struct NLDR_NODEOBJECT *hNldrNode, char *pstrFxn,
+ u32 *pulAddr)
+{
+ struct DBLL_Symbol *pSym;
+ struct NLDR_OBJECT *hNldr;
+ DSP_STATUS status = DSP_SOK;
+ bool status1 = false;
+ s32 i = 0;
+ struct LibNode root = { NULL, 0, NULL };
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE));
+ DBC_Require(pulAddr != NULL);
+ DBC_Require(pstrFxn != NULL);
+ GT_3trace(NLDR_debugMask, GT_ENTER, "NLDR_GetFxnAddr(0x%x, %s, 0x%x)\n",
+ hNldrNode, pstrFxn, pulAddr);
+
+ hNldr = hNldrNode->pNldr;
+ /* Called from NODE_Create(), NODE_Delete(), or NODE_Run(). */
+ if (hNldrNode->fDynamic && *hNldrNode->pfPhaseSplit) {
+ switch (hNldrNode->phase) {
+ case NLDR_CREATE:
+ root = hNldrNode->createLib;
+ break;
+ case NLDR_EXECUTE:
+ root = hNldrNode->executeLib;
+ break;
+ case NLDR_DELETE:
+ root = hNldrNode->deleteLib;
+ break;
+ default:
+ DBC_Assert(false);
+ break;
+ }
+ } else {
+ /* for Overlay nodes or non-split Dynamic nodes */
+ root = hNldrNode->root;
+ }
+ status1 = hNldr->dbllFxns.getCAddrFxn(root.lib, pstrFxn, &pSym);
+ if (!status1)
+ status1 = hNldr->dbllFxns.getAddrFxn(root.lib, pstrFxn, &pSym);
+
+ /* If symbol not found, check dependent libraries */
+ if (!status1) {
+ for (i = 0; i < root.nDepLibs; i++) {
+ status1 = hNldr->dbllFxns.getAddrFxn(root.pDepLibs[i].
+ lib, pstrFxn, &pSym);
+ if (!status1) {
+ status1 = hNldr->dbllFxns.getCAddrFxn(root.
+ pDepLibs[i].lib, pstrFxn, &pSym);
+ }
+ if (status1) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+ /* Check persistent libraries */
+ if (!status1) {
+ for (i = 0; i < hNldrNode->nPersLib; i++) {
+ status1 = hNldr->dbllFxns.getAddrFxn(hNldrNode->
+ persLib[i].lib, pstrFxn, &pSym);
+ if (!status1) {
+ status1 =
+ hNldr->dbllFxns.getCAddrFxn(hNldrNode->
+ persLib[i].lib, pstrFxn, &pSym);
+ }
+ if (status1) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+
+ if (status1) {
+ *pulAddr = pSym->value;
+ } else {
+ GT_1trace(NLDR_debugMask, GT_6CLASS,
+ "NLDR_GetFxnAddr: Symbol not found: "
+ "%s\n", pstrFxn);
+ status = DSP_ESYMBOL;
+ }
+
+ return status;
+}
+
+/*
+ * ======== NLDR_GetRmmManager ========
+ * Given a NLDR object, retrieve RMM Manager Handle
+ */
+DSP_STATUS NLDR_GetRmmManager(struct NLDR_OBJECT *hNldrObject,
+ OUT struct RMM_TargetObj **phRmmMgr)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct NLDR_OBJECT *pNldrObject = hNldrObject;
+ DBC_Require(phRmmMgr != NULL);
+ GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_GetRmmManager(0x%x, 0x%x)\n",
+ hNldrObject, phRmmMgr);
+ if (MEM_IsValidHandle(hNldrObject, NLDR_SIGNATURE)) {
+ *phRmmMgr = pNldrObject->rmm;
+ } else {
+ *phRmmMgr = NULL;
+ status = DSP_EHANDLE;
+ GT_0trace(NLDR_debugMask, GT_7CLASS,
+ "NLDR_GetRmmManager:Invalid handle");
+ }
+
+ GT_2trace(NLDR_debugMask, GT_ENTER, "Exit NLDR_GetRmmManager: status "
+ "0x%x\n\tphRmmMgr: 0x%x\n", status, *phRmmMgr);
+
+ DBC_Ensure(DSP_SUCCEEDED(status) || ((phRmmMgr != NULL) &&
+ (*phRmmMgr == NULL)));
+
+ return status;
+}
+
+/*
+ * ======== NLDR_Init ========
+ * Initialize the NLDR module.
+ */
+bool NLDR_Init(void)
+{
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+ DBC_Assert(!NLDR_debugMask.flags);
+ GT_create(&NLDR_debugMask, "NL"); /* "NL" for NLdr */
+
+ RMM_init();
+ }
+
+ cRefs++;
+
+ GT_1trace(NLDR_debugMask, GT_5CLASS, "NLDR_Init(), ref count: 0x%x\n",
+ cRefs);
+
+ DBC_Ensure(cRefs > 0);
+ return true;
+}
+
+/*
+ * ======== NLDR_Load ========
+ */
+DSP_STATUS NLDR_Load(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase)
+{
+ struct NLDR_OBJECT *hNldr;
+ struct DSP_UUID libUUID;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE));
+
+ hNldr = hNldrNode->pNldr;
+
+ GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_Load(0x%x, 0x%x)\n",
+ hNldrNode, phase);
+
+ if (hNldrNode->fDynamic) {
+ hNldrNode->phase = phase;
+
+ libUUID = hNldrNode->uuid;
+
+ /* At this point, we may not know if node is split into
+ * different libraries. So we'll go ahead and load the
+ * library, and then save the pointer to the appropriate
+ * location after we know. */
+
+ status = LoadLib(hNldrNode, &hNldrNode->root, libUUID, false,
+ hNldrNode->libPath, phase, 0);
+
+ if (DSP_SUCCEEDED(status)) {
+ if (*hNldrNode->pfPhaseSplit) {
+ switch (phase) {
+ case NLDR_CREATE:
+ hNldrNode->createLib = hNldrNode->root;
+ break;
+
+ case NLDR_EXECUTE:
+ hNldrNode->executeLib = hNldrNode->root;
+ break;
+
+ case NLDR_DELETE:
+ hNldrNode->deleteLib = hNldrNode->root;
+ break;
+
+ default:
+ DBC_Assert(false);
+ break;
+ }
+ }
+ }
+ } else {
+ if (hNldrNode->fOverlay)
+ status = LoadOvly(hNldrNode, phase);
+
+ }
+
+ return status;
+}
+
+/*
+ * ======== NLDR_Unload ========
+ */
+DSP_STATUS NLDR_Unload(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct LibNode *pRootLib = NULL;
+ s32 i = 0;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE));
+ GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_Unload(0x%x, 0x%x)\n",
+ hNldrNode, phase);
+ if (hNldrNode != NULL) {
+ if (hNldrNode->fDynamic) {
+ if (*hNldrNode->pfPhaseSplit) {
+ switch (phase) {
+ case NLDR_CREATE:
+ pRootLib = &hNldrNode->createLib;
+ break;
+ case NLDR_EXECUTE:
+ pRootLib = &hNldrNode->executeLib;
+ break;
+ case NLDR_DELETE:
+ pRootLib = &hNldrNode->deleteLib;
+ /* Unload persistent libraries */
+ for (i = 0; i < hNldrNode->nPersLib;
+ i++) {
+ UnloadLib(hNldrNode,
+ &hNldrNode->persLib[i]);
+ }
+ hNldrNode->nPersLib = 0;
+ break;
+ default:
+ DBC_Assert(false);
+ break;
+ }
+ } else {
+ /* Unload main library */
+ pRootLib = &hNldrNode->root;
+ }
+ UnloadLib(hNldrNode, pRootLib);
+ } else {
+ if (hNldrNode->fOverlay)
+ UnloadOvly(hNldrNode, phase);
+
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== AddOvlyInfo ========
+ */
+static DSP_STATUS AddOvlyInfo(void *handle, struct DBLL_SectInfo *sectInfo,
+ u32 addr, u32 nBytes)
+{
+ char *pNodeName;
+ char *pSectName = (char *)sectInfo->name;
+ bool fExists = false;
+ char seps = ':';
+ char *pch;
+ u16 i;
+ struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle;
+ DSP_STATUS status = DSP_SOK;
+
+ /* Is this an overlay section (load address != run address)? */
+ if (sectInfo->loadAddr == sectInfo->runAddr)
+ goto func_end;
+
+ /* Find the node it belongs to */
+ for (i = 0; i < hNldr->nOvlyNodes; i++) {
+ pNodeName = hNldr->ovlyTable[i].pNodeName;
+ DBC_Require(pNodeName);
+ if (strncmp(pNodeName, pSectName + 1,
+ strlen(pNodeName)) == 0) {
+ /* Found the node */
+ break;
+ }
+ }
+ if (!(i < hNldr->nOvlyNodes))
+ goto func_end;
+
+ /* Determine which phase this section belongs to */
+ for (pch = pSectName + 1; *pch && *pch != seps; pch++)
+ ;;
+
+ if (*pch) {
+ pch++; /* Skip over the ':' */
+ if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) {
+ status = AddOvlySect(hNldr, &hNldr->ovlyTable[i].
+ pCreateSects, sectInfo, &fExists, addr, nBytes);
+ if (DSP_SUCCEEDED(status) && !fExists)
+ hNldr->ovlyTable[i].nCreateSects++;
+
+ } else
+ if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) {
+ status = AddOvlySect(hNldr, &hNldr->ovlyTable[i].
+ pDeleteSects, sectInfo, &fExists,
+ addr, nBytes);
+ if (DSP_SUCCEEDED(status) && !fExists)
+ hNldr->ovlyTable[i].nDeleteSects++;
+
+ } else
+ if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) {
+ status = AddOvlySect(hNldr, &hNldr->ovlyTable[i].
+ pExecuteSects, sectInfo, &fExists,
+ addr, nBytes);
+ if (DSP_SUCCEEDED(status) && !fExists)
+ hNldr->ovlyTable[i].nExecuteSects++;
+
+ } else {
+ /* Put in "other" sectins */
+ status = AddOvlySect(hNldr, &hNldr->ovlyTable[i].
+ pOtherSects, sectInfo, &fExists,
+ addr, nBytes);
+ if (DSP_SUCCEEDED(status) && !fExists)
+ hNldr->ovlyTable[i].nOtherSects++;
+
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== AddOvlyNode =========
+ * Callback function passed to DCD_GetObjects.
+ */
+static DSP_STATUS AddOvlyNode(struct DSP_UUID *pUuid,
+ enum DSP_DCDOBJTYPE objType,
+ IN void *handle)
+{
+ struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle;
+ char *pNodeName = NULL;
+ char *pBuf = NULL;
+ u32 uLen;
+ struct DCD_GENERICOBJ objDef;
+ DSP_STATUS status = DSP_SOK;
+
+ if (objType != DSP_DCDNODETYPE)
+ goto func_end;
+
+ status = DCD_GetObjectDef(hNldr->hDcdMgr, pUuid, objType, &objDef);
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* If overlay node, add to the list */
+ if (objDef.objData.nodeObj.usLoadType == NLDR_OVLYLOAD) {
+ if (hNldr->ovlyTable == NULL) {
+ hNldr->nOvlyNodes++;
+ } else {
+ /* Add node to table */
+ hNldr->ovlyTable[hNldr->nNode].uuid = *pUuid;
+ DBC_Require(objDef.objData.nodeObj.ndbProps.acName);
+ uLen = strlen(objDef.objData.nodeObj.ndbProps.acName);
+ pNodeName = objDef.objData.nodeObj.ndbProps.acName;
+ pBuf = MEM_Calloc(uLen + 1, MEM_PAGED);
+ if (pBuf == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ strncpy(pBuf, pNodeName, uLen);
+ hNldr->ovlyTable[hNldr->nNode].pNodeName = pBuf;
+ hNldr->nNode++;
+ }
+ }
+ }
+ /* These were allocated in DCD_GetObjectDef */
+ if (objDef.objData.nodeObj.pstrCreatePhaseFxn)
+ MEM_Free(objDef.objData.nodeObj.pstrCreatePhaseFxn);
+
+ if (objDef.objData.nodeObj.pstrExecutePhaseFxn)
+ MEM_Free(objDef.objData.nodeObj.pstrExecutePhaseFxn);
+
+ if (objDef.objData.nodeObj.pstrDeletePhaseFxn)
+ MEM_Free(objDef.objData.nodeObj.pstrDeletePhaseFxn);
+
+ if (objDef.objData.nodeObj.pstrIAlgName)
+ MEM_Free(objDef.objData.nodeObj.pstrIAlgName);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== AddOvlySect ========
+ */
+static DSP_STATUS AddOvlySect(struct NLDR_OBJECT *hNldr,
+ struct OvlySect **pList,
+ struct DBLL_SectInfo *pSectInfo, bool *pExists,
+ u32 addr, u32 nBytes)
+{
+ struct OvlySect *pNewSect = NULL;
+ struct OvlySect *pLastSect;
+ struct OvlySect *pSect;
+ DSP_STATUS status = DSP_SOK;
+
+ pSect = pLastSect = *pList;
+ *pExists = false;
+ while (pSect) {
+ /*
+ * Make sure section has not already been added. Multiple
+ * 'write' calls may be made to load the section.
+ */
+ if (pSect->loadAddr == addr) {
+ /* Already added */
+ *pExists = true;
+ break;
+ }
+ pLastSect = pSect;
+ pSect = pSect->pNextSect;
+ }
+
+ if (!pSect) {
+ /* New section */
+ pNewSect = MEM_Calloc(sizeof(struct OvlySect), MEM_PAGED);
+ if (pNewSect == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ pNewSect->loadAddr = addr;
+ pNewSect->runAddr = pSectInfo->runAddr +
+ (addr - pSectInfo->loadAddr);
+ pNewSect->size = nBytes;
+ pNewSect->page = pSectInfo->type;
+ }
+
+ /* Add to the list */
+ if (DSP_SUCCEEDED(status)) {
+ if (*pList == NULL) {
+ /* First in the list */
+ *pList = pNewSect;
+ } else {
+ pLastSect->pNextSect = pNewSect;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== fakeOvlyWrite ========
+ */
+static s32 fakeOvlyWrite(void *handle, u32 dspAddr, void *buf, u32 nBytes,
+ s32 mtype)
+{
+ return (s32)nBytes;
+}
+
+/*
+ * ======== FreeSects ========
+ */
+static void FreeSects(struct NLDR_OBJECT *hNldr, struct OvlySect *pPhaseSects,
+ u16 nAlloc)
+{
+ struct OvlySect *pSect = pPhaseSects;
+ u16 i = 0;
+ bool fRet;
+
+ while (pSect && i < nAlloc) {
+ /* 'Deallocate' */
+ /* segid - page not supported yet */
+ /* Reserved memory */
+ fRet = RMM_free(hNldr->rmm, 0, pSect->runAddr, pSect->size,
+ true);
+ DBC_Assert(fRet);
+ pSect = pSect->pNextSect;
+ i++;
+ }
+}
+
+/*
+ * ======== GetSymbolValue ========
+ * Find symbol in library's base image. If not there, check dependent
+ * libraries.
+ */
+static bool GetSymbolValue(void *handle, void *pArg, void *rmmHandle,
+ char *name, struct DBLL_Symbol **sym)
+{
+ struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle;
+ struct NLDR_NODEOBJECT *hNldrNode = (struct NLDR_NODEOBJECT *)rmmHandle;
+ struct LibNode *root = (struct LibNode *)pArg;
+ u16 i;
+ bool status = false;
+
+ /* check the base image */
+ status = hNldr->dbllFxns.getAddrFxn(hNldr->baseLib, name, sym);
+ if (!status)
+ status = hNldr->dbllFxns.getCAddrFxn(hNldr->baseLib, name, sym);
+
+ /*
+ * Check in root lib itself. If the library consists of
+ * multiple object files linked together, some symbols in the
+ * library may need to be resolved.
+ */
+ if (!status) {
+ status = hNldr->dbllFxns.getAddrFxn(root->lib, name, sym);
+ if (!status) {
+ status =
+ hNldr->dbllFxns.getCAddrFxn(root->lib, name, sym);
+ }
+ }
+
+ /*
+ * Check in root lib's dependent libraries, but not dependent
+ * libraries' dependents.
+ */
+ if (!status) {
+ for (i = 0; i < root->nDepLibs; i++) {
+ status = hNldr->dbllFxns.getAddrFxn(root->pDepLibs[i].
+ lib, name, sym);
+ if (!status) {
+ status = hNldr->dbllFxns.getCAddrFxn(root->
+ pDepLibs[i].lib, name, sym);
+ }
+ if (status) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+ /*
+ * Check in persistent libraries
+ */
+ if (!status) {
+ for (i = 0; i < hNldrNode->nPersLib; i++) {
+ status = hNldr->dbllFxns.getAddrFxn(hNldrNode->
+ persLib[i].lib, name, sym);
+ if (!status) {
+ status = hNldr->dbllFxns.getCAddrFxn
+ (hNldrNode->persLib[i].lib, name, sym);
+ }
+ if (status) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== LoadLib ========
+ * Recursively load library and all its dependent libraries. The library
+ * we're loading is specified by a uuid.
+ */
+static DSP_STATUS LoadLib(struct NLDR_NODEOBJECT *hNldrNode,
+ struct LibNode *root, struct DSP_UUID uuid,
+ bool rootPersistent, struct DBLL_LibraryObj **libPath,
+ enum NLDR_PHASE phase, u16 depth)
+{
+ struct NLDR_OBJECT *hNldr = hNldrNode->pNldr;
+ u16 nLibs = 0; /* Number of dependent libraries */
+ u16 nPLibs = 0; /* Number of persistent libraries */
+ u16 nLoaded = 0; /* Number of dep. libraries loaded */
+ u16 i;
+ u32 entry;
+ u32 dwBufSize = NLDR_MAXPATHLENGTH;
+ DBLL_Flags flags = DBLL_SYMB | DBLL_CODE | DBLL_DATA | DBLL_DYNAMIC;
+ struct DBLL_Attrs newAttrs;
+ char *pszFileName = NULL;
+ struct DSP_UUID *depLibUUIDs = NULL;
+ bool *persistentDepLibs = NULL;
+ DSP_STATUS status = DSP_SOK;
+ bool fStatus = false;
+ struct LibNode *pDepLib;
+
+ if (depth > MAXDEPTH) {
+ /* Error */
+ DBC_Assert(false);
+ }
+ root->lib = NULL;
+ /* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */
+ pszFileName = MEM_Calloc(DBLL_MAXPATHLENGTH, MEM_PAGED);
+ if (pszFileName == NULL)
+ status = DSP_EMEMORY;
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Get the name of the library */
+ if (depth == 0) {
+ status = DCD_GetLibraryName(hNldrNode->pNldr->hDcdMgr,
+ &uuid, pszFileName, &dwBufSize, phase,
+ hNldrNode->pfPhaseSplit);
+ } else {
+ /* Dependent libraries are registered with a phase */
+ status = DCD_GetLibraryName(hNldrNode->pNldr->hDcdMgr,
+ &uuid, pszFileName, &dwBufSize, NLDR_NOPHASE,
+ NULL);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Open the library, don't load symbols */
+ status = hNldr->dbllFxns.openFxn(hNldr->dbll, pszFileName,
+ DBLL_NOLOAD, &root->lib);
+ }
+ /* Done with file name */
+ if (pszFileName)
+ MEM_Free(pszFileName);
+
+ /* Check to see if library not already loaded */
+ if (DSP_SUCCEEDED(status) && rootPersistent) {
+ fStatus = findInPersistentLibArray(hNldrNode, root->lib);
+ /* Close library */
+ if (fStatus) {
+ hNldr->dbllFxns.closeFxn(root->lib);
+ return DSP_SALREADYLOADED;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Check for circular dependencies. */
+ for (i = 0; i < depth; i++) {
+ if (root->lib == libPath[i]) {
+ /* This condition could be checked by a
+ * tool at build time. */
+ status = DSP_EDYNLOAD;
+ }
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Add library to current path in dependency tree */
+ libPath[depth] = root->lib;
+ depth++;
+ /* Get number of dependent libraries */
+ status = DCD_GetNumDepLibs(hNldrNode->pNldr->hDcdMgr, &uuid,
+ &nLibs, &nPLibs, phase);
+ }
+ DBC_Assert(nLibs >= nPLibs);
+ if (DSP_SUCCEEDED(status)) {
+ if (!(*hNldrNode->pfPhaseSplit))
+ nPLibs = 0;
+
+ /* nLibs = #of dependent libraries */
+ root->nDepLibs = nLibs - nPLibs;
+ if (nLibs > 0) {
+ depLibUUIDs = MEM_Calloc(sizeof(struct DSP_UUID) *
+ nLibs, MEM_PAGED);
+ persistentDepLibs =
+ MEM_Calloc(sizeof(bool) * nLibs, MEM_PAGED);
+ if (!depLibUUIDs || !persistentDepLibs)
+ status = DSP_EMEMORY;
+
+ if (root->nDepLibs > 0) {
+ /* Allocate arrays for dependent lib UUIDs,
+ * lib nodes */
+ root->pDepLibs = MEM_Calloc
+ (sizeof(struct LibNode) *
+ (root->nDepLibs), MEM_PAGED);
+ if (!(root->pDepLibs))
+ status = DSP_EMEMORY;
+
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Get the dependent library UUIDs */
+ status = DCD_GetDepLibs(hNldrNode->pNldr->
+ hDcdMgr, &uuid, nLibs, depLibUUIDs,
+ persistentDepLibs, phase);
+ }
+ }
+ }
+
+ /*
+ * Recursively load dependent libraries.
+ */
+ if (DSP_SUCCEEDED(status) && persistentDepLibs) {
+ for (i = 0; i < nLibs; i++) {
+ /* If root library is NOT persistent, and dep library
+ * is, then record it. If root library IS persistent,
+ * the deplib is already included */
+ if (!rootPersistent && persistentDepLibs[i] &&
+ *hNldrNode->pfPhaseSplit) {
+ if ((hNldrNode->nPersLib) > MAXLIBS) {
+ status = DSP_EDYNLOAD;
+ break;
+ }
+
+ /* Allocate library outside of phase */
+ pDepLib = &hNldrNode->persLib[hNldrNode->
+ nPersLib];
+ } else {
+ if (rootPersistent)
+ persistentDepLibs[i] = true;
+
+
+ /* Allocate library within phase */
+ pDepLib = &root->pDepLibs[nLoaded];
+ }
+
+ if (depLibUUIDs) {
+ status = LoadLib(hNldrNode, pDepLib,
+ depLibUUIDs[i],
+ persistentDepLibs[i], libPath,
+ phase,
+ depth);
+ } else {
+ status = DSP_EMEMORY;
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ if ((status != DSP_SALREADYLOADED) &&
+ !rootPersistent && persistentDepLibs[i] &&
+ *hNldrNode->pfPhaseSplit) {
+ (hNldrNode->nPersLib)++;
+ } else {
+ if (!persistentDepLibs[i] ||
+ !(*hNldrNode->pfPhaseSplit)) {
+ nLoaded++;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* Now we can load the root library */
+ if (DSP_SUCCEEDED(status)) {
+ newAttrs = hNldr->dbllAttrs;
+ newAttrs.symArg = root;
+ newAttrs.rmmHandle = hNldrNode;
+ newAttrs.wHandle = hNldrNode->pPrivRef;
+ newAttrs.baseImage = false;
+
+ status = hNldr->dbllFxns.loadFxn(root->lib, flags, &newAttrs,
+ &entry);
+ }
+
+ /*
+ * In case of failure, unload any dependent libraries that
+ * were loaded, and close the root library.
+ * (Persistent libraries are unloaded from the very top)
+ */
+ if (DSP_FAILED(status)) {
+ if (phase != NLDR_EXECUTE) {
+ for (i = 0; i < hNldrNode->nPersLib; i++)
+ UnloadLib(hNldrNode, &hNldrNode->persLib[i]);
+
+ hNldrNode->nPersLib = 0;
+ }
+ for (i = 0; i < nLoaded; i++)
+ UnloadLib(hNldrNode, &root->pDepLibs[i]);
+
+ if (root->lib)
+ hNldr->dbllFxns.closeFxn(root->lib);
+
+ }
+
+ /* Going up one node in the dependency tree */
+ depth--;
+
+ if (depLibUUIDs) {
+ MEM_Free(depLibUUIDs);
+ depLibUUIDs = NULL;
+ }
+
+ if (persistentDepLibs) {
+ MEM_Free(persistentDepLibs);
+ persistentDepLibs = NULL;
+ }
+
+ return status;
+}
+
+/*
+ * ======== LoadOvly ========
+ */
+static DSP_STATUS LoadOvly(struct NLDR_NODEOBJECT *hNldrNode,
+ enum NLDR_PHASE phase)
+{
+ struct NLDR_OBJECT *hNldr = hNldrNode->pNldr;
+ struct OvlyNode *pONode = NULL;
+ struct OvlySect *pPhaseSects = NULL;
+ struct OvlySect *pOtherSects = NULL;
+ u16 i;
+ u16 nAlloc = 0;
+ u16 nOtherAlloc = 0;
+ u16 *pRefCount = NULL;
+ u16 *pOtherRef = NULL;
+ u32 nBytes;
+ struct OvlySect *pSect;
+ DSP_STATUS status = DSP_SOK;
+
+ /* Find the node in the table */
+ for (i = 0; i < hNldr->nOvlyNodes; i++) {
+ if (IsEqualUUID(hNldrNode->uuid, hNldr->ovlyTable[i].uuid)) {
+ /* Found it */
+ pONode = &(hNldr->ovlyTable[i]);
+ break;
+ }
+ }
+
+ DBC_Assert(i < hNldr->nOvlyNodes);
+ switch (phase) {
+ case NLDR_CREATE:
+ pRefCount = &(pONode->createRef);
+ pOtherRef = &(pONode->otherRef);
+ pPhaseSects = pONode->pCreateSects;
+ pOtherSects = pONode->pOtherSects;
+ break;
+
+ case NLDR_EXECUTE:
+ pRefCount = &(pONode->executeRef);
+ pPhaseSects = pONode->pExecuteSects;
+ break;
+
+ case NLDR_DELETE:
+ pRefCount = &(pONode->deleteRef);
+ pPhaseSects = pONode->pDeleteSects;
+ break;
+
+ default:
+ DBC_Assert(false);
+ break;
+ }
+
+ DBC_Assert(pRefCount != NULL);
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ if (pRefCount == NULL)
+ goto func_end;
+
+ if (*pRefCount != 0)
+ goto func_end;
+
+ /* 'Allocate' memory for overlay sections of this phase */
+ pSect = pPhaseSects;
+ while (pSect) {
+ /* allocate */ /* page not supported yet */
+ /* reserve */ /* align */
+ status = RMM_alloc(hNldr->rmm, 0, pSect->size, 0,
+ &(pSect->runAddr), true);
+ if (DSP_SUCCEEDED(status)) {
+ pSect = pSect->pNextSect;
+ nAlloc++;
+ } else {
+ break;
+ }
+ }
+ if (pOtherRef && *pOtherRef == 0) {
+ /* 'Allocate' memory for other overlay sections
+ * (create phase) */
+ if (DSP_SUCCEEDED(status)) {
+ pSect = pOtherSects;
+ while (pSect) {
+ /* page not supported */ /* align */
+ /* reserve */
+ status = RMM_alloc(hNldr->rmm, 0, pSect->size,
+ 0, &(pSect->runAddr), true);
+ if (DSP_SUCCEEDED(status)) {
+ pSect = pSect->pNextSect;
+ nOtherAlloc++;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if (*pRefCount == 0) {
+ if (DSP_SUCCEEDED(status)) {
+ /* Load sections for this phase */
+ pSect = pPhaseSects;
+ while (pSect && DSP_SUCCEEDED(status)) {
+ nBytes = (*hNldr->ovlyFxn)(hNldrNode->pPrivRef,
+ pSect->runAddr, pSect->loadAddr,
+ pSect->size, pSect->page);
+ if (nBytes != pSect->size)
+ status = DSP_EFAIL;
+
+ pSect = pSect->pNextSect;
+ }
+ }
+ }
+ if (pOtherRef && *pOtherRef == 0) {
+ if (DSP_SUCCEEDED(status)) {
+ /* Load other sections (create phase) */
+ pSect = pOtherSects;
+ while (pSect && DSP_SUCCEEDED(status)) {
+ nBytes = (*hNldr->ovlyFxn)(hNldrNode->pPrivRef,
+ pSect->runAddr, pSect->loadAddr,
+ pSect->size, pSect->page);
+ if (nBytes != pSect->size)
+ status = DSP_EFAIL;
+
+ pSect = pSect->pNextSect;
+ }
+ }
+ }
+ if (DSP_FAILED(status)) {
+ /* 'Deallocate' memory */
+ FreeSects(hNldr, pPhaseSects, nAlloc);
+ FreeSects(hNldr, pOtherSects, nOtherAlloc);
+ }
+func_end:
+ if (DSP_SUCCEEDED(status) && (pRefCount != NULL)) {
+ *pRefCount += 1;
+ if (pOtherRef)
+ *pOtherRef += 1;
+
+ }
+
+ return status;
+}
+
+/*
+ * ======== RemoteAlloc ========
+ */
+static DSP_STATUS RemoteAlloc(void **pRef, u16 space, u32 size,
+ u32 align, u32 *dspAddr,
+ OPTIONAL s32 segmentId, OPTIONAL s32 req,
+ bool reserve)
+{
+ struct NLDR_NODEOBJECT *hNode = (struct NLDR_NODEOBJECT *)pRef;
+ struct NLDR_OBJECT *hNldr;
+ struct RMM_TargetObj *rmm;
+ u16 memPhaseBit = MAXFLAGS;
+ u16 segid = 0;
+ u16 i;
+ u16 memType;
+ u32 nWords;
+ struct RMM_Addr *pRmmAddr = (struct RMM_Addr *)dspAddr;
+ bool fReq = false;
+ DSP_STATUS status = DSP_EMEMORY; /* Set to fail */
+ DBC_Require(MEM_IsValidHandle(hNode, NLDR_NODESIGNATURE));
+ DBC_Require(space == DBLL_CODE || space == DBLL_DATA ||
+ space == DBLL_BSS);
+ hNldr = hNode->pNldr;
+ rmm = hNldr->rmm;
+ /* Convert size to DSP words */
+ nWords = (size + hNldr->usDSPWordSize - 1) / hNldr->usDSPWordSize;
+ /* Modify memory 'align' to account for DSP cache line size */
+ align = findLcm(GEM_CACHE_LINE_SIZE, align);
+ GT_1trace(NLDR_debugMask, GT_7CLASS,
+ "RemoteAlloc: memory align to 0x%x \n", align);
+ if (segmentId != -1) {
+ pRmmAddr->segid = segmentId;
+ segid = segmentId;
+ fReq = req;
+ } else {
+ switch (hNode->phase) {
+ case NLDR_CREATE:
+ memPhaseBit = CREATEDATAFLAGBIT;
+ break;
+ case NLDR_DELETE:
+ memPhaseBit = DELETEDATAFLAGBIT;
+ break;
+ case NLDR_EXECUTE:
+ memPhaseBit = EXECUTEDATAFLAGBIT;
+ break;
+ default:
+ DBC_Assert(false);
+ break;
+ }
+ if (space == DBLL_CODE)
+ memPhaseBit++;
+
+ if (memPhaseBit < MAXFLAGS)
+ segid = hNode->segId[memPhaseBit];
+
+ /* Determine if there is a memory loading requirement */
+ if ((hNode->codeDataFlagMask >> memPhaseBit) & 0x1)
+ fReq = true;
+
+ }
+ memType = (space == DBLL_CODE) ? DYNM_CODE : DYNM_DATA;
+
+ /* Find an appropriate segment based on space */
+ if (segid == NULLID) {
+ /* No memory requirements of preferences */
+ DBC_Assert(!fReq);
+ goto func_cont;
+ }
+ if (segid <= MAXSEGID) {
+ DBC_Assert(segid < hNldr->nSegs);
+ /* Attempt to allocate from segid first. */
+ pRmmAddr->segid = segid;
+ status = RMM_alloc(rmm, segid, nWords, align, dspAddr, false);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NLDR_debugMask, GT_6CLASS,
+ "RemoteAlloc:Unable allocate "
+ "from segment %d.\n", segid);
+ }
+ } else {
+ /* segid > MAXSEGID ==> Internal or external memory */
+ DBC_Assert(segid == MEMINTERNALID || segid == MEMEXTERNALID);
+ /* Check for any internal or external memory segment,
+ * depending on segid.*/
+ memType |= segid == MEMINTERNALID ?
+ DYNM_INTERNAL : DYNM_EXTERNAL;
+ for (i = 0; i < hNldr->nSegs; i++) {
+ if ((hNldr->segTable[i] & memType) != memType)
+ continue;
+
+ status = RMM_alloc(rmm, i, nWords, align, dspAddr,
+ false);
+ if (DSP_SUCCEEDED(status)) {
+ /* Save segid for freeing later */
+ pRmmAddr->segid = i;
+ break;
+ }
+ }
+ }
+func_cont:
+ /* Haven't found memory yet, attempt to find any segment that works */
+ if (status == DSP_EMEMORY && !fReq) {
+ GT_0trace(NLDR_debugMask, GT_6CLASS,
+ "RemoteAlloc: Preferred segment "
+ "unavailable, trying another segment.\n");
+ for (i = 0; i < hNldr->nSegs; i++) {
+ /* All bits of memType must be set */
+ if ((hNldr->segTable[i] & memType) != memType)
+ continue;
+
+ status = RMM_alloc(rmm, i, nWords, align, dspAddr,
+ false);
+ if (DSP_SUCCEEDED(status)) {
+ /* Save segid */
+ pRmmAddr->segid = i;
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+static DSP_STATUS RemoteFree(void **pRef, u16 space, u32 dspAddr,
+ u32 size, bool reserve)
+{
+ struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)pRef;
+ struct RMM_TargetObj *rmm;
+ u32 nWords;
+ DSP_STATUS status = DSP_EMEMORY; /* Set to fail */
+
+ DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE));
+
+ rmm = hNldr->rmm;
+
+ /* Convert size to DSP words */
+ nWords = (size + hNldr->usDSPWordSize - 1) / hNldr->usDSPWordSize;
+
+ if (RMM_free(rmm, space, dspAddr, nWords, reserve))
+ status = DSP_SOK;
+
+ return status;
+}
+
+/*
+ * ======== UnloadLib ========
+ */
+static void UnloadLib(struct NLDR_NODEOBJECT *hNldrNode, struct LibNode *root)
+{
+ struct DBLL_Attrs newAttrs;
+ struct NLDR_OBJECT *hNldr = hNldrNode->pNldr;
+ u16 i;
+
+ DBC_Assert(root != NULL);
+
+ /* Unload dependent libraries */
+ for (i = 0; i < root->nDepLibs; i++)
+ UnloadLib(hNldrNode, &root->pDepLibs[i]);
+
+ root->nDepLibs = 0;
+
+ newAttrs = hNldr->dbllAttrs;
+ newAttrs.rmmHandle = hNldr->rmm;
+ newAttrs.wHandle = hNldrNode->pPrivRef;
+ newAttrs.baseImage = false;
+ newAttrs.symArg = root;
+
+ if (root->lib) {
+ /* Unload the root library */
+ hNldr->dbllFxns.unloadFxn(root->lib, &newAttrs);
+ hNldr->dbllFxns.closeFxn(root->lib);
+ }
+
+ /* Free dependent library list */
+ if (root->pDepLibs) {
+ MEM_Free(root->pDepLibs);
+ root->pDepLibs = NULL;
+ }
+}
+
+/*
+ * ======== UnloadOvly ========
+ */
+static void UnloadOvly(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase)
+{
+ struct NLDR_OBJECT *hNldr = hNldrNode->pNldr;
+ struct OvlyNode *pONode = NULL;
+ struct OvlySect *pPhaseSects = NULL;
+ struct OvlySect *pOtherSects = NULL;
+ u16 i;
+ u16 nAlloc = 0;
+ u16 nOtherAlloc = 0;
+ u16 *pRefCount = NULL;
+ u16 *pOtherRef = NULL;
+ DSP_STATUS status = DSP_SOK;
+
+ /* Find the node in the table */
+ for (i = 0; i < hNldr->nOvlyNodes; i++) {
+ if (IsEqualUUID(hNldrNode->uuid, hNldr->ovlyTable[i].uuid)) {
+ /* Found it */
+ pONode = &(hNldr->ovlyTable[i]);
+ break;
+ }
+ }
+
+ DBC_Assert(i < hNldr->nOvlyNodes);
+ switch (phase) {
+ case NLDR_CREATE:
+ pRefCount = &(pONode->createRef);
+ pPhaseSects = pONode->pCreateSects;
+ nAlloc = pONode->nCreateSects;
+ break;
+ case NLDR_EXECUTE:
+ pRefCount = &(pONode->executeRef);
+ pPhaseSects = pONode->pExecuteSects;
+ nAlloc = pONode->nExecuteSects;
+ break;
+ case NLDR_DELETE:
+ pRefCount = &(pONode->deleteRef);
+ pOtherRef = &(pONode->otherRef);
+ pPhaseSects = pONode->pDeleteSects;
+ /* 'Other' overlay sections are unloaded in the delete phase */
+ pOtherSects = pONode->pOtherSects;
+ nAlloc = pONode->nDeleteSects;
+ nOtherAlloc = pONode->nOtherSects;
+ break;
+ default:
+ DBC_Assert(false);
+ break;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ DBC_Assert(pRefCount && (*pRefCount > 0));
+ if (pRefCount && (*pRefCount > 0)) {
+ *pRefCount -= 1;
+ if (pOtherRef) {
+ DBC_Assert(*pOtherRef > 0);
+ *pOtherRef -= 1;
+ }
+ }
+ }
+ if (pRefCount && (*pRefCount == 0)) {
+ /* 'Deallocate' memory */
+ FreeSects(hNldr, pPhaseSects, nAlloc);
+ }
+ if (pOtherRef && *pOtherRef == 0)
+ FreeSects(hNldr, pOtherSects, nOtherAlloc);
+
+}
+
+/*
+ * ======== findInPersistentLibArray ========
+ */
+static bool findInPersistentLibArray(struct NLDR_NODEOBJECT *hNldrNode,
+ struct DBLL_LibraryObj *lib)
+{
+ s32 i = 0;
+
+ for (i = 0; i < hNldrNode->nPersLib; i++) {
+ if (lib == hNldrNode->persLib[i].lib)
+ return true;
+
+ }
+
+ return false;
+}
+
+/*
+ * ================ Find LCM (Least Common Multiplier ===
+ */
+static u32 findLcm(u32 a, u32 b)
+{
+ u32 retVal;
+
+ retVal = a * b / findGcf(a, b);
+
+ return retVal;
+}
+
+/*
+ * ================ Find GCF (Greatest Common Factor ) ===
+ */
+static u32 findGcf(u32 a, u32 b)
+{
+ u32 c;
+
+ /* Get the GCF (Greatest common factor between the numbers,
+ * using Euclidian Algo */
+ while ((c = (a % b))) {
+ a = b;
+ b = c;
+ }
+ return b;
+}
+
diff --git a/drivers/dsp/bridge/rmgr/node.c b/drivers/dsp/bridge/rmgr/node.c
new file mode 100644
index 000000000000..53a42bf3ca41
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/node.c
@@ -0,0 +1,3550 @@
+/*
+ * node.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * ======== node.c ========
+ *
+ * Description:
+ * DSP/BIOS Bridge Node Manager.
+ *
+ * Public Functions:
+ * NODE_Allocate
+ * NODE_AllocMsgBuf
+ * NODE_ChangePriority
+ * NODE_Connect
+ * NODE_Create
+ * NODE_CreateMgr
+ * NODE_Delete
+ * NODE_DeleteMgr
+ * NODE_EnumNodes
+ * NODE_Exit
+ * NODE_FreeMsgBuf
+ * NODE_GetAttr
+ * NODE_GetChannelId
+ * NODE_GetMessage
+ * NODE_GetStrmMgr
+ * NODE_Init
+ * NODE_OnExit
+ * NODE_Pause
+ * NODE_PutMessage
+ * NODE_RegisterNotify
+ * NODE_Run
+ * NODE_Terminate
+ *
+ *! Revision History:
+ *! =================
+ *! 12-Apr-2004 hp Compile IVA only for 24xx
+ *! 09-Feb-2004 vp Updated to support IVA.
+ *! 07-Apr-2003 map Eliminated references to old DLDR
+ *! 26-Mar-2003 vp Commented the call to DSP deep sleep in Node_Delete
+ *! function.
+ *! 18-Feb-2003 vp Code review updates.
+ *! 06-Feb-2003 kc Fixed FreeStream to release streams correctly.
+ *! 23-Jan-2003 map Removed call to DISP_DoCinit within Write()
+ *! 03-Jan-2003 map Only unload code after phase has executed if
+ *! overlay or split dynload phases
+ *! 18-Oct-2002 vp Ported to Linux platform.
+ *! 06-Nov-2002 map Fixed NODE_Run on NODE_PAUSED bug
+ *! 12-Oct-2002 map Fixed DeleteNode bug in NODE_Create
+ *! 11-Sep-2002 rr DeleteNode frees the memory for strmConnect and dcd obj
+ *! 29-Aug-2002 map Modified Ovly and Write to use ARM-side copy
+ *! 22-May-2002 sg Changed use of cbData for PWR calls.
+ *! 17-May-2002 jeh Removed LoadLoaderFxns(). Get address of RMS_cinit()
+ *! function. Call DISP_DoCinit() from Write(), if .cinit.
+ *! 13-May-2002 sg Added timeout to wake/sleep calls.
+ *! 02-May-2002 sg Added wake/sleep of DSP to support "nap" mode.
+ *! 18-Apr-2002 jeh Use dynamic loader if compile flag is set.
+ *! 13-Feb-2002 jeh Get uSysStackSize from DSP_NDBPROPS.
+ *! 07-Jan-2002 ag STRMMODE_ZEROCOPY(shared memory buffer swap) enabled.
+ *! 17-Dec-2001 ag STRMMODE_RDMA(DDMA) enabled.
+ *! 12-Dec-2001 ag Check for valid stream mode in NODE_Connect().
+ *! 04-Dec-2001 jeh Check for node sufficiently connected in NODE_Create().
+ *! 15-Nov-2001 jeh Removed DBC_Require(pNode->hXlator != NULL) from
+ *! NODE_AllocMsgBuf(), and check node type != NODE_DEVICE.
+ *! 11-Sep-2001 ag Zero-copy messaging support.
+ *! 28-Aug-2001 jeh Overlay/dynamic loader infrastructure added. Removed
+ *! NODE_GetDispatcher, excess node states.
+ *! 07-Aug-2001 jeh Removed critical section for dispatcher.
+ *! 26-Jul-2001 jeh Get ZL dll name through CFG.
+ *! 05-Jun-2001 jeh Assume DSP_STRMATTRS.uBufsize in GPP bytes.
+ *! 11-May-2001 jeh Some code review cleanup.
+ *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates.
+ *! 15-Dec-2000 sg Convert IALG_Fxn address from byte addr to word addr.
+ *! 04-Dec-2000 jeh Call MSG Get and Put functions.
+ *! 04-Dec-2000 ag Added SM support for node messaging.
+ *! 10-Nov-2000 rr: NODE_MIN/MAX Priority is defined in dspdefs.h.
+ *! 27-Oct-2000 jeh Added NODE_AllocMsgBuf(), NODE_FreeMsgBuf().
+ *! 11-Oct-2000 jeh Changed NODE_EnumNodeInfo to NODE_EnumNodes. Added
+ *! NODE_CloseOrphans(). Remove NODE_RegisterNotifyAllNodes
+ *! 19-Jun-2000 jeh Created.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/csl.h>
+#include <dspbridge/list.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/strm.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/ntfy.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cmm.h>
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/msg.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/disp.h>
+#include <dspbridge/rms_sh.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/wmd.h>
+#include <dspbridge/wmdioctl.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/gb.h>
+#ifdef DEBUG
+#include <dspbridge/uuidutil.h>
+#include <dspbridge/dbg.h>
+#endif
+
+/* ----------------------------------- This */
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/node.h>
+
+/* Static/Dynamic Loader includes */
+#include <dspbridge/dbll.h>
+#include <dspbridge/nldr.h>
+
+#ifndef RES_CLEANUP_DISABLE
+#include <dspbridge/drv.h>
+#include <dspbridge/drvdefs.h>
+#include <dspbridge/dbreg.h>
+#include <dspbridge/resourcecleanup.h>
+#endif
+
+
+#define NODE_SIGNATURE 0x45444f4e /* "EDON" */
+#define NODEMGR_SIGNATURE 0x52474d4e /* "RGMN" */
+
+#define HOSTPREFIX "/host"
+#define PIPEPREFIX "/dbpipe"
+
+#define MaxInputs(h) ((h)->dcdProps.objData.nodeObj.ndbProps.uNumInputStreams)
+#define MaxOutputs(h) ((h)->dcdProps.objData.nodeObj.ndbProps.uNumOutputStreams)
+
+#define NODE_GetPriority(h) ((h)->nPriority)
+#define NODE_SetPriority(hNode, nPriority) ((hNode)->nPriority = nPriority)
+#define NODE_SetState(hNode, state) ((hNode)->nState = state)
+
+#define MAXPIPES 100 /* Max # of /pipe connections (CSL limit) */
+#define MAXDEVSUFFIXLEN 2 /* Max(Log base 10 of MAXPIPES, MAXSTREAMS) */
+
+#define PIPENAMELEN (sizeof(PIPEPREFIX) + MAXDEVSUFFIXLEN)
+#define HOSTNAMELEN (sizeof(HOSTPREFIX) + MAXDEVSUFFIXLEN)
+
+#define MAXDEVNAMELEN 32 /* DSP_NDBPROPS.acName size */
+#define CREATEPHASE 1
+#define EXECUTEPHASE 2
+#define DELETEPHASE 3
+
+/* Define default STRM parameters */
+/*
+ * TBD: Put in header file, make global DSP_STRMATTRS with defaults,
+ * or make defaults configurable.
+ */
+#define DEFAULTBUFSIZE 32
+#define DEFAULTNBUFS 2
+#define DEFAULTSEGID 0
+#define DEFAULTALIGNMENT 0
+#define DEFAULTTIMEOUT 10000
+
+#define RMSQUERYSERVER 0
+#define RMSCONFIGURESERVER 1
+#define RMSCREATENODE 2
+#define RMSEXECUTENODE 3
+#define RMSDELETENODE 4
+#define RMSCHANGENODEPRIORITY 5
+#define RMSREADMEMORY 6
+#define RMSWRITEMEMORY 7
+#define RMSCOPY 8
+#define MAXTIMEOUT 2000
+
+#define NUMRMSFXNS 9
+
+#define PWR_TIMEOUT 500 /* default PWR timeout in msec */
+
+#define STACKSEGLABEL "L1DSRAM_HEAP" /* Label for DSP Stack Segment Address */
+
+/*
+ * ======== NODE_MGR ========
+ */
+struct NODE_MGR {
+ u32 dwSignature; /* For object validation */
+ struct DEV_OBJECT *hDevObject; /* Device object */
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+ struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */
+ struct DISP_OBJECT *hDisp; /* Node dispatcher */
+ struct LST_LIST *nodeList; /* List of all allocated nodes */
+ u32 uNumNodes; /* Number of nodes in nodeList */
+ u32 uNumCreated; /* Number of nodes *created* on DSP */
+ struct GB_TMap *pipeMap; /* Pipe connection bit map */
+ struct GB_TMap *pipeDoneMap; /* Pipes that are half free */
+ struct GB_TMap *chnlMap; /* Channel allocation bit map */
+ struct GB_TMap *dmaChnlMap; /* DMA Channel allocation bit map */
+ struct GB_TMap *zChnlMap; /* Zero-Copy Channel alloc bit map */
+ struct NTFY_OBJECT *hNtfy; /* Manages registered notifications */
+ struct SYNC_CSOBJECT *hSync; /* For critical sections */
+ u32 ulFxnAddrs[NUMRMSFXNS]; /* RMS function addresses */
+ struct MSG_MGR *hMsg;
+
+ /* Processor properties needed by Node Dispatcher */
+ u32 ulNumChnls; /* Total number of channels */
+ u32 ulChnlOffset; /* Offset of chnl ids rsvd for RMS */
+ u32 ulChnlBufSize; /* Buffer size for data to RMS */
+ DSP_PROCFAMILY procFamily; /* eg, 5000 */
+ DSP_PROCTYPE procType; /* eg, 5510 */
+ u32 uDSPWordSize; /* Size of DSP word on host bytes */
+ u32 uDSPDataMauSize; /* Size of DSP data MAU */
+ u32 uDSPMauSize; /* Size of MAU */
+ s32 nMinPri; /* Minimum runtime priority for node */
+ s32 nMaxPri; /* Maximum runtime priority for node */
+
+ struct STRM_MGR *hStrmMgr; /* STRM manager */
+
+ /* Loader properties */
+ struct NLDR_OBJECT *hNldr; /* Handle to loader */
+ struct NLDR_FXNS nldrFxns; /* Handle to loader functions */
+ bool fLoaderInit; /* Loader Init function succeeded? */
+};
+
+/*
+ * ======== CONNECTTYPE ========
+ */
+enum CONNECTTYPE {
+ NOTCONNECTED = 0,
+ NODECONNECT,
+ HOSTCONNECT,
+ DEVICECONNECT,
+} ;
+
+/*
+ * ======== STREAM ========
+ */
+struct STREAM {
+ enum CONNECTTYPE type; /* Type of stream connection */
+ u32 devId; /* pipe or channel id */
+};
+
+/*
+ * ======== NODE_OBJECT ========
+ */
+struct NODE_OBJECT {
+ struct LST_ELEM listElem;
+ u32 dwSignature; /* For object validation */
+ struct NODE_MGR *hNodeMgr; /* The manager of this node */
+ struct PROC_OBJECT *hProcessor; /* Back pointer to processor */
+ struct DSP_UUID nodeId; /* Node's ID */
+ s32 nPriority; /* Node's current priority */
+ u32 uTimeout; /* Timeout for blocking NODE calls */
+ u32 uHeapSize; /* Heap Size */
+ u32 uDSPHeapVirtAddr; /* Heap Size */
+ u32 uGPPHeapVirtAddr; /* Heap Size */
+ enum NODE_TYPE nType; /* Type of node: message, task, etc */
+ enum NODE_STATE nState; /* NODE_ALLOCATED, NODE_CREATED, ... */
+ u32 uNumInputs; /* Current number of inputs */
+ u32 uNumOutputs; /* Current number of outputs */
+ u32 uMaxInputIndex; /* Current max input stream index */
+ u32 uMaxOutputIndex; /* Current max output stream index */
+ struct STREAM *inputs; /* Node's input streams */
+ struct STREAM *outputs; /* Node's output streams */
+ struct NODE_CREATEARGS createArgs; /* Args for node create function */
+ NODE_ENV nodeEnv; /* Environment returned by RMS */
+ struct DCD_GENERICOBJ dcdProps; /* Node properties from DCD */
+ struct DSP_CBDATA *pArgs; /* Optional args to pass to node */
+ struct NTFY_OBJECT *hNtfy; /* Manages registered notifications */
+ char *pstrDevName; /* device name, if device node */
+ struct SYNC_OBJECT *hSyncDone; /* Synchronize NODE_Terminate */
+ s32 nExitStatus; /* execute function return status */
+
+ /* Information needed for NODE_GetAttr() */
+ DSP_HNODE hDeviceOwner; /* If dev node, task that owns it */
+ u32 uNumGPPInputs; /* Current # of from GPP streams */
+ u32 uNumGPPOutputs; /* Current # of to GPP streams */
+ /* Current stream connections */
+ struct DSP_STREAMCONNECT *streamConnect;
+
+ /* Message queue */
+ struct MSG_QUEUE *hMsgQueue;
+
+ /* These fields used for SM messaging */
+ struct CMM_XLATOROBJECT *hXlator; /* Node's SM address translator */
+
+ /* Handle to pass to dynamic loader */
+ struct NLDR_NODEOBJECT *hNldrNode;
+ bool fLoaded; /* Code is (dynamically) loaded */
+ bool fPhaseSplit; /* Phases split in many libs or ovly */
+
+} ;
+
+/* Default buffer attributes */
+static struct DSP_BUFFERATTR NODE_DFLTBUFATTRS = {
+ 0, /* cbStruct */
+ 1, /* uSegment */
+ 0, /* uAlignment */
+};
+
+static void DeleteNode(struct NODE_OBJECT *hNode);
+static void DeleteNodeMgr(struct NODE_MGR *hNodeMgr);
+static void FillStreamConnect(struct NODE_OBJECT *hNode1,
+ struct NODE_OBJECT *hNode2, u32 uStream1,
+ u32 uStream2);
+static void FillStreamDef(struct NODE_OBJECT *hNode,
+ struct NODE_STRMDEF *pstrmDef,
+ struct DSP_STRMATTR *pAttrs);
+static void FreeStream(struct NODE_MGR *hNodeMgr, struct STREAM stream);
+static DSP_STATUS GetFxnAddress(struct NODE_OBJECT *hNode, u32 *pulFxnAddr,
+ u32 uPhase);
+static DSP_STATUS GetNodeProps(struct DCD_MANAGER *hDcdMgr,
+ struct NODE_OBJECT *hNode,
+ CONST struct DSP_UUID *pNodeId,
+ struct DCD_GENERICOBJ *pdcdProps);
+static DSP_STATUS GetProcProps(struct NODE_MGR *hNodeMgr,
+ struct DEV_OBJECT *hDevObject);
+static DSP_STATUS GetRMSFxns(struct NODE_MGR *hNodeMgr);
+static u32 Ovly(void *pPrivRef, u32 ulDspRunAddr, u32 ulDspLoadAddr,
+ u32 ulNumBytes, u32 nMemSpace);
+static u32 Write(void *pPrivRef, u32 ulDspAddr, void *pBuf,
+ u32 ulNumBytes, u32 nMemSpace);
+
+#if GT_TRACE
+static struct GT_Mask NODE_debugMask = { NULL, NULL }; /* GT trace variable */
+#endif
+
+#ifdef DSP_DMM_DEBUG
+extern u32 DMM_MemMapDump(struct DMM_OBJECT *hDmmMgr);
+#endif
+
+static u32 cRefs; /* module reference count */
+
+/* Dynamic loader functions. */
+static struct NLDR_FXNS nldrFxns = {
+ NLDR_Allocate,
+ NLDR_Create,
+ NLDR_Delete,
+ NLDR_Exit,
+ NLDR_Free,
+ NLDR_GetFxnAddr,
+ NLDR_Init,
+ NLDR_Load,
+ NLDR_Unload,
+};
+
+enum NODE_STATE NODE_GetState(HANDLE hNode)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ if (!MEM_IsValidHandle(pNode, NODE_SIGNATURE)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_GetState:hNode 0x%x\n", pNode);
+ return -1;
+ } else
+ return pNode->nState;
+
+}
+
+/*
+ * ======== NODE_Allocate ========
+ * Purpose:
+ * Allocate GPP resources to manage a node on the DSP.
+ */
+DSP_STATUS NODE_Allocate(struct PROC_OBJECT *hProcessor,
+ IN CONST struct DSP_UUID *pNodeId,
+ OPTIONAL IN CONST struct DSP_CBDATA *pArgs,
+ OPTIONAL IN CONST struct DSP_NODEATTRIN *pAttrIn,
+ OUT struct NODE_OBJECT **phNode)
+{
+ struct NODE_MGR *hNodeMgr;
+ struct DEV_OBJECT *hDevObject;
+ struct NODE_OBJECT *pNode = NULL;
+ enum NODE_TYPE nodeType = NODE_TASK;
+ struct NODE_MSGARGS *pmsgArgs;
+ struct NODE_TASKARGS *ptaskArgs;
+ u32 uNumStreams;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+ struct CMM_OBJECT *hCmmMgr = NULL; /* Shared memory manager hndl */
+ u32 procId;
+ char *label;
+ u32 pulValue;
+ u32 dynextBase;
+ u32 offSet = 0;
+ u32 ulStackSegAddr, ulStackSegVal;
+ u32 ulGppMemBase;
+ struct CFG_HOSTRES hostRes;
+ u32 pMappedAddr = 0;
+ u32 mapAttrs = 0x0;
+ struct DSP_PROCESSORSTATE procStatus;
+#ifdef DSP_DMM_DEBUG
+ struct DMM_OBJECT *hDmmMgr;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+#endif
+
+#ifndef RES_CLEANUP_DISABLE
+ HANDLE hDrvObject;
+ HANDLE nodeRes;
+ u32 hProcess;
+ struct PROCESS_CONTEXT *pPctxt = NULL;
+ DSP_STATUS res_status = DSP_SOK;
+#endif
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hProcessor != NULL);
+ DBC_Require(phNode != NULL);
+ DBC_Require(pNodeId != NULL);
+
+ GT_5trace(NODE_debugMask, GT_ENTER, "NODE_Allocate: \thProcessor: "
+ "0x%x\tpNodeId: 0x%x\tpArgs: 0x%x\tpAttrIn: "
+ "0x%x\tphNode: 0x%x\n", hProcessor, pNodeId, pArgs, pAttrIn,
+ phNode);
+
+ *phNode = NULL;
+
+ status = PROC_GetProcessorId(hProcessor, &procId);
+
+ status = PROC_GetDevObject(hProcessor, &hDevObject);
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetNodeManager(hDevObject, &hNodeMgr);
+ if (hNodeMgr == NULL)
+ status = DSP_EFAIL;
+
+ }
+ if (procId != DSP_UNIT)
+ goto func_cont;
+
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: proc Status 0x%x\n",
+ procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+
+ /* Assuming that 0 is not a valid function address */
+ if (hNodeMgr->ulFxnAddrs[0] == 0) {
+ /* No RMS on target - we currently can't handle this */
+ GT_0trace(NODE_debugMask, GT_5CLASS, "No RMS functions in base "
+ "image. Node allocation fails.\n");
+ status = DSP_EFAIL;
+ } else {
+ /* Validate pAttrIn fields, if non-NULL */
+ if (pAttrIn) {
+ /* Check if pAttrIn->iPriority is within range */
+ if (pAttrIn->iPriority < hNodeMgr->nMinPri ||
+ pAttrIn->iPriority > hNodeMgr->nMaxPri)
+ status = DSP_ERANGE;
+ }
+ }
+func_cont:
+ /* Allocate node object and fill in */
+ if (DSP_FAILED(status))
+ goto func_cont2;
+
+ MEM_AllocObject(pNode, struct NODE_OBJECT, NODE_SIGNATURE);
+ if (pNode == NULL) {
+ status = DSP_EMEMORY;
+ goto func_cont1;
+ }
+ pNode->hNodeMgr = hNodeMgr;
+ /* This critical section protects GetNodeProps */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (procId != DSP_UNIT)
+ goto func_cont3;
+
+ /* Get DSP_NDBPROPS from node database */
+ status = GetNodeProps(hNodeMgr->hDcdMgr, pNode, pNodeId,
+ &(pNode->dcdProps));
+ if (DSP_FAILED(status))
+ goto func_cont3;
+
+ pNode->nodeId = *pNodeId;
+ pNode->hProcessor = hProcessor;
+ pNode->nType = pNode->dcdProps.objData.nodeObj.ndbProps.uNodeType;
+ pNode->uTimeout = pNode->dcdProps.objData.nodeObj.ndbProps.uTimeout;
+ pNode->nPriority = pNode->dcdProps.objData.nodeObj.ndbProps.iPriority;
+
+ /* Currently only C64 DSP builds support Node Dynamic * heaps */
+ /* Allocate memory for node heap */
+ pNode->createArgs.asa.taskArgs.uHeapSize = 0;
+ pNode->createArgs.asa.taskArgs.uDSPHeapAddr = 0;
+ pNode->createArgs.asa.taskArgs.uDSPHeapResAddr = 0;
+ pNode->createArgs.asa.taskArgs.uGPPHeapAddr = 0;
+ if (!pAttrIn)
+ goto func_cont3;
+
+ /* Check if we have a user allocated node heap */
+ if (!(pAttrIn->pGPPVirtAddr))
+ goto func_cont3;
+
+ /* check for page aligned Heap size */
+ if (((pAttrIn->uHeapSize) & (PG_SIZE_4K - 1))) {
+ GT_1trace(NODE_debugMask, GT_7CLASS,
+ "NODE_Allocate: node heap page size"
+ " not aligned to 4K page, size=0x%x \n",
+ pAttrIn->uHeapSize);
+ status = DSP_EINVALIDARG;
+ } else {
+ pNode->createArgs.asa.taskArgs.uHeapSize = pAttrIn->uHeapSize;
+ pNode->createArgs.asa.taskArgs.uGPPHeapAddr =
+ (u32)pAttrIn->pGPPVirtAddr;
+ }
+ if (DSP_FAILED(status))
+ goto func_cont3;
+
+ status = PROC_ReserveMemory(hProcessor,
+ pNode->createArgs.asa.taskArgs.uHeapSize + PAGE_SIZE,
+ (void **)&(pNode->createArgs.asa.taskArgs.
+ uDSPHeapResAddr));
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate:Failed to reserve "
+ "memory for Heap: 0x%x\n", status);
+ } else {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: DSPProcessor_Reserve"
+ " Memory successful: 0x%x\n", status);
+ }
+#ifdef DSP_DMM_DEBUG
+ status = DMM_GetHandle(pProcObject, &hDmmMgr);
+ if (DSP_SUCCEEDED(status))
+ DMM_MemMapDump(hDmmMgr);
+#endif
+ if (DSP_FAILED(status))
+ goto func_cont3;
+
+ mapAttrs |= DSP_MAPLITTLEENDIAN;
+ mapAttrs |= DSP_MAPELEMSIZE32;
+ mapAttrs |= DSP_MAPVIRTUALADDR;
+ status = PROC_Map(hProcessor, (void *)pAttrIn->pGPPVirtAddr,
+ pNode->createArgs.asa.taskArgs.uHeapSize,
+ (void *)pNode->createArgs.asa.taskArgs.uDSPHeapResAddr,
+ (void **)&pMappedAddr, mapAttrs);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to map memory"
+ " for Heap: 0x%x\n", status);
+ } else {
+ pNode->createArgs.asa.taskArgs.uDSPHeapAddr =
+ (u32) pMappedAddr;
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate:DSPProcessor_Map"
+ " successful: 0x%x\n", status);
+ }
+
+func_cont3:
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+func_cont1:
+ if (pAttrIn != NULL) {
+ /* Overrides of NBD properties */
+ pNode->uTimeout = pAttrIn->uTimeout;
+ pNode->nPriority = pAttrIn->iPriority;
+ }
+func_cont2:
+ /* Create object to manage notifications */
+ if (DSP_SUCCEEDED(status))
+ status = NTFY_Create(&pNode->hNtfy);
+
+ if (DSP_SUCCEEDED(status)) {
+ nodeType = NODE_GetType(pNode);
+ /* Allocate DSP_STREAMCONNECT array for device, task, and
+ * dais socket nodes. */
+ if (nodeType != NODE_MESSAGE) {
+ uNumStreams = MaxInputs(pNode) + MaxOutputs(pNode);
+ pNode->streamConnect = MEM_Calloc(uNumStreams *
+ sizeof(struct DSP_STREAMCONNECT),
+ MEM_PAGED);
+ if (uNumStreams > 0 && pNode->streamConnect == NULL)
+ status = DSP_EMEMORY;
+
+ }
+ if (DSP_SUCCEEDED(status) && (nodeType == NODE_TASK ||
+ nodeType == NODE_DAISSOCKET)) {
+ /* Allocate arrays for maintainig stream connections */
+ pNode->inputs =
+ MEM_Calloc(MaxInputs(pNode) *
+ sizeof(struct STREAM), MEM_PAGED);
+ pNode->outputs =
+ MEM_Calloc(MaxOutputs(pNode) *
+ sizeof(struct STREAM), MEM_PAGED);
+ ptaskArgs = &(pNode->createArgs.asa.taskArgs);
+ ptaskArgs->strmInDef =
+ MEM_Calloc(MaxInputs(pNode) *
+ sizeof(struct NODE_STRMDEF),
+ MEM_PAGED);
+ ptaskArgs->strmOutDef =
+ MEM_Calloc(MaxOutputs(pNode) *
+ sizeof(struct NODE_STRMDEF),
+ MEM_PAGED);
+ if ((MaxInputs(pNode) > 0 && (pNode->inputs == NULL ||
+ ptaskArgs->strmInDef == NULL)) ||
+ (MaxOutputs(pNode) > 0 && (pNode->outputs == NULL ||
+ ptaskArgs->strmOutDef == NULL)))
+ status = DSP_EMEMORY;
+ }
+ }
+ if (DSP_SUCCEEDED(status) && (nodeType != NODE_DEVICE)) {
+ /* Create an event that will be posted when RMS_EXIT is
+ * received. */
+ status = SYNC_OpenEvent(&pNode->hSyncDone, NULL);
+ if (DSP_SUCCEEDED(status)) {
+ /*Get the shared mem mgr for this nodes dev object */
+ status = CMM_GetHandle(hProcessor, &hCmmMgr);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to"
+ " get CMM Mgr handle: 0x%x\n", status);
+ } else {
+ /* Allocate a SM addr translator for this node
+ * w/ deflt attr */
+ status = CMM_XlatorCreate(&pNode->hXlator,
+ hCmmMgr, NULL);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed"
+ " to create SM translator: 0x%x\n",
+ status);
+ }
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Fill in message args */
+ if ((pArgs != NULL) && (pArgs->cbData > 0)) {
+ pmsgArgs = &(pNode->createArgs.asa.msgArgs);
+ pmsgArgs->pData = MEM_Calloc(pArgs->cbData,
+ MEM_PAGED);
+ if (pmsgArgs->pData == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ pmsgArgs->uArgLength = pArgs->cbData;
+ memcpy(pmsgArgs->pData, pArgs->cData,
+ pArgs->cbData);
+ }
+ }
+ }
+ }
+
+ if (DSP_SUCCEEDED(status) && nodeType != NODE_DEVICE) {
+ /* Create a message queue for this node */
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnMsgCreateQueue)(hNodeMgr->hMsg,
+ &pNode->hMsgQueue, 0,
+ pNode->createArgs.asa.msgArgs.uMaxMessages,
+ pNode);
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Create object for dynamic loading */
+
+ status = hNodeMgr->nldrFxns.pfnAllocate(hNodeMgr->hNldr,
+ (void *) pNode,
+ &pNode->dcdProps.objData.nodeObj,
+ &pNode->hNldrNode,
+ &pNode->fPhaseSplit);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to "
+ "allocate NLDR node: 0x%x\n", status);
+ }
+ }
+
+ /* Comapare value read from Node Properties and check if it is same as
+ * STACKSEGLABEL, if yes read the Address of STACKSEGLABEL, calculate
+ * GPP Address, Read the value in that address and override the
+ * uStackSeg value in task args */
+ if (DSP_SUCCEEDED(status) &&
+ (char *)pNode->dcdProps.objData.nodeObj.ndbProps.uStackSegName !=
+ NULL) {
+ label = MEM_Calloc(sizeof(STACKSEGLABEL)+1, MEM_PAGED);
+ strncpy(label, STACKSEGLABEL, sizeof(STACKSEGLABEL)+1);
+
+ if (strcmp((char *)pNode->dcdProps.objData.nodeObj.
+ ndbProps.uStackSegName, label) == 0) {
+ status = hNodeMgr->nldrFxns.pfnGetFxnAddr(pNode->
+ hNldrNode, "DYNEXT_BEG", &dynextBase);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to get Address for "
+ "DYNEXT_BEG: 0x%x\n", status);
+ }
+
+ status = hNodeMgr->nldrFxns.pfnGetFxnAddr(pNode->
+ hNldrNode, "L1DSRAM_HEAP", &pulValue);
+
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to get Address for "
+ "L1DSRAM_HEAP: 0x%x\n", status);
+ }
+
+ status = CFG_GetHostResources((struct CFG_DEVNODE *)
+ DRV_GetFirstDevExtension(), &hostRes);
+
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Allocate: Failed to get host resource "
+ "0x%x\n", status);
+ }
+
+ ulGppMemBase = (u32)hostRes.dwMemBase[1];
+ offSet = pulValue - dynextBase;
+ ulStackSegAddr = ulGppMemBase + offSet;
+ ulStackSegVal = (u32)*((REG_UWORD32 *)
+ ((u32)(ulStackSegAddr)));
+
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "StackSegVal =0x%x\n", ulStackSegVal);
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "ulStackSegAddr = 0x%x\n", ulStackSegAddr);
+
+ pNode->createArgs.asa.taskArgs.uStackSeg =
+ ulStackSegVal;
+
+ }
+
+ if (label)
+ MEM_Free(label);
+
+ }
+
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Add the node to the node manager's list of allocated
+ * nodes. */
+ LST_InitElem((struct LST_ELEM *)pNode);
+ NODE_SetState(pNode, NODE_ALLOCATED);
+
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+
+ if (DSP_SUCCEEDED(status)) {
+ LST_PutTail(hNodeMgr->nodeList,
+ (struct LST_ELEM *) pNode);
+ ++(hNodeMgr->uNumNodes);
+ }
+
+ /* Exit critical section */
+ (void) SYNC_LeaveCS(hNodeMgr->hSync);
+
+ /* Preset this to assume phases are split
+ * (for overlay and dll) */
+ pNode->fPhaseSplit = true;
+
+ if (DSP_SUCCEEDED(status))
+ *phNode = pNode;
+
+
+ /* Notify all clients registered for DSP_NODESTATECHANGE. */
+ PROC_NotifyAllClients(hProcessor, DSP_NODESTATECHANGE);
+ } else {
+ /* Cleanup */
+ if (pNode)
+ DeleteNode(pNode);
+
+ }
+
+#ifndef RES_CLEANUP_DISABLE
+ if (DSP_SUCCEEDED(status)) {
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject,
+ REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDrvObject,
+ &pPctxt, *phNode, 0);
+ if (pPctxt == NULL) {
+ DRV_InsertProcContext(
+ (struct DRV_OBJECT *)hDrvObject,
+ &pPctxt);
+ if (pPctxt != NULL) {
+ DRV_ProcUpdatestate(pPctxt,
+ PROC_RES_ALLOCATED);
+ DRV_ProcSetPID(pPctxt, hProcess);
+ pPctxt->hProcessor =
+ (DSP_HPROCESSOR)hProcessor;
+ }
+ }
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+ res_status = CFG_GetObject((u32 *)&hDrvObject,
+ REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDrvObject,
+ &pPctxt, *phNode, 0);
+ if (pPctxt != NULL) {
+ DRV_InsertNodeResElement(*phNode, &nodeRes,
+ pPctxt);
+ DRV_ProcNodeUpdateHeapStatus(nodeRes, true);
+ DRV_ProcNodeUpdateStatus(nodeRes, true);
+ }
+ }
+ }
+#endif
+ DBC_Ensure((DSP_FAILED(status) && (*phNode == NULL)) ||
+ (DSP_SUCCEEDED(status)
+ && MEM_IsValidHandle((*phNode), NODE_SIGNATURE)));
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_AllocMsgBuf ========
+ * Purpose:
+ * Allocates buffer for zero copy messaging.
+ */
+DBAPI NODE_AllocMsgBuf(struct NODE_OBJECT *hNode, u32 uSize,
+ OPTIONAL IN OUT struct DSP_BUFFERATTR *pAttr,
+ OUT u8 **pBuffer)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ DSP_STATUS status = DSP_SOK;
+ bool bVirtAddr = false;
+ bool bSetInfo;
+ u32 procId;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pBuffer != NULL);
+
+ DBC_Require(uSize > 0);
+
+ GT_4trace(NODE_debugMask, GT_ENTER,
+ "NODE_AllocMsgBuf: hNode: 0x%x\tuSize:"
+ " 0x%x\tpAttr: 0x%x\tpBuffer: %d\n", pNode, uSize, pAttr,
+ pBuffer);
+
+ if (!MEM_IsValidHandle(pNode, NODE_SIGNATURE))
+ status = DSP_EHANDLE;
+ else if (NODE_GetType(pNode) == NODE_DEVICE)
+ status = DSP_ENODETYPE;
+
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ if (pAttr == NULL)
+ pAttr = &NODE_DFLTBUFATTRS; /* set defaults */
+
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+ if (procId != DSP_UNIT) {
+ DBC_Assert(NULL);
+ goto func_end;
+ }
+ /* If segment ID includes MEM_SETVIRTUALSEGID then pBuffer is a
+ * virt address, so set this info in this node's translator
+ * object for future ref. If MEM_GETVIRTUALSEGID then retrieve
+ * virtual address from node's translator. */
+ if ((pAttr->uSegment & MEM_SETVIRTUALSEGID) ||
+ (pAttr->uSegment & MEM_GETVIRTUALSEGID)) {
+ bVirtAddr = true;
+ bSetInfo = (pAttr->uSegment & MEM_SETVIRTUALSEGID) ?
+ true : false;
+ pAttr->uSegment &= ~MEM_MASKVIRTUALSEGID; /* clear mask bits */
+ /* Set/get this node's translators virtual address base/size */
+ status = CMM_XlatorInfo(pNode->hXlator, pBuffer, uSize,
+ pAttr->uSegment, bSetInfo);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_7CLASS,
+ "NODE_AllocMsgBuf "
+ "failed: 0x%lx\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status) && (!bVirtAddr)) {
+ if (pAttr->uSegment != 1) {
+ /* Node supports single SM segment only. */
+ status = DSP_EBADSEGID;
+ }
+ /* Arbitrary SM buffer alignment not supported for host side
+ * allocs, but guaranteed for the following alignment
+ * values. */
+ switch (pAttr->uAlignment) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ /* alignment value not suportted */
+ status = DSP_EALIGNMENT;
+ break;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* allocate physical buffer from segId in node's
+ * translator */
+ (void)CMM_XlatorAllocBuf(pNode->hXlator, pBuffer,
+ uSize);
+ if (*pBuffer == NULL) {
+ GT_0trace(NODE_debugMask, GT_7CLASS,
+ "NODE_AllocMsgBuf: "
+ "ERROR: Out of shared memory.\n");
+ status = DSP_EMEMORY;
+ }
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_ChangePriority ========
+ * Purpose:
+ * Change the priority of a node in the allocated state, or that is
+ * currently running or paused on the target.
+ */
+DSP_STATUS NODE_ChangePriority(struct NODE_OBJECT *hNode, s32 nPriority)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ struct NODE_MGR *hNodeMgr = NULL;
+ enum NODE_TYPE nodeType;
+ enum NODE_STATE state;
+ DSP_STATUS status = DSP_SOK;
+ u32 procId;
+
+ DBC_Require(cRefs > 0);
+
+ GT_2trace(NODE_debugMask, GT_ENTER, "NODE_ChangePriority: "
+ "hNode: 0x%x\tnPriority: %d\n", hNode, nPriority);
+
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ GT_1trace(NODE_debugMask, GT_7CLASS,
+ "Invalid NODE Handle: 0x%x\n", hNode);
+ status = DSP_EHANDLE;
+ } else {
+ hNodeMgr = hNode->hNodeMgr;
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET)
+ status = DSP_ENODETYPE;
+ else if (nPriority < hNodeMgr->nMinPri ||
+ nPriority > hNodeMgr->nMaxPri)
+ status = DSP_ERANGE;
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ state = NODE_GetState(hNode);
+ if (state == NODE_ALLOCATED || state == NODE_PAUSED) {
+ NODE_SetPriority(hNode, nPriority);
+ } else {
+ if (state != NODE_RUNNING) {
+ status = DSP_EWRONGSTATE;
+ goto func_cont;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = PROC_GetProcessorId(pNode->hProcessor,
+ &procId);
+ if (procId == DSP_UNIT) {
+ status = DISP_NodeChangePriority(hNodeMgr->
+ hDisp, hNode,
+ hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY],
+ hNode->nodeEnv, nPriority);
+ }
+ if (DSP_SUCCEEDED(status))
+ NODE_SetPriority(hNode, nPriority);
+
+ }
+ }
+func_cont:
+ /* Leave critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_Connect ========
+ * Purpose:
+ * Connect two nodes on the DSP, or a node on the DSP to the GPP.
+ */
+DSP_STATUS NODE_Connect(struct NODE_OBJECT *hNode1, u32 uStream1,
+ struct NODE_OBJECT *hNode2,
+ u32 uStream2, OPTIONAL IN struct DSP_STRMATTR *pAttrs,
+ OPTIONAL IN struct DSP_CBDATA *pConnParam)
+{
+ struct NODE_MGR *hNodeMgr;
+ char *pstrDevName = NULL;
+ enum NODE_TYPE node1Type = NODE_TASK;
+ enum NODE_TYPE node2Type = NODE_TASK;
+ struct NODE_STRMDEF *pstrmDef;
+ struct NODE_STRMDEF *pInput = NULL;
+ struct NODE_STRMDEF *pOutput = NULL;
+ struct NODE_OBJECT *hDevNode;
+ struct NODE_OBJECT *hNode;
+ struct STREAM *pStream;
+ GB_BitNum pipeId = GB_NOBITS;
+ GB_BitNum chnlId = GB_NOBITS;
+ CHNL_MODE uMode;
+ u32 dwLength;
+ DSP_STATUS status = DSP_SOK;
+ DBC_Require(cRefs > 0);
+ GT_5trace(NODE_debugMask, GT_ENTER,
+ "NODE_Connect: hNode1: 0x%x\tuStream1:"
+ " %d\thNode2: 0x%x\tuStream2: %d\tpAttrs: 0x%x\n", hNode1,
+ uStream1, hNode2, uStream2, pAttrs);
+ if (DSP_SUCCEEDED(status)) {
+ if ((hNode1 != (struct NODE_OBJECT *) DSP_HGPPNODE &&
+ !MEM_IsValidHandle(hNode1, NODE_SIGNATURE)) ||
+ (hNode2 != (struct NODE_OBJECT *) DSP_HGPPNODE &&
+ !MEM_IsValidHandle(hNode2, NODE_SIGNATURE)))
+ status = DSP_EHANDLE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* The two nodes must be on the same processor */
+ if (hNode1 != (struct NODE_OBJECT *)DSP_HGPPNODE &&
+ hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE &&
+ hNode1->hNodeMgr != hNode2->hNodeMgr)
+ status = DSP_EFAIL;
+ /* Cannot connect a node to itself */
+ if (hNode1 == hNode2)
+ status = DSP_EFAIL;
+
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* NODE_GetType() will return NODE_GPP if hNode =
+ * DSP_HGPPNODE. */
+ node1Type = NODE_GetType(hNode1);
+ node2Type = NODE_GetType(hNode2);
+ /* Check stream indices ranges */
+ if ((node1Type != NODE_GPP && node1Type != NODE_DEVICE &&
+ uStream1 >= MaxOutputs(hNode1)) || (node2Type != NODE_GPP &&
+ node2Type != NODE_DEVICE && uStream2 >= MaxInputs(hNode2)))
+ status = DSP_EVALUE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /*
+ * Only the following types of connections are allowed:
+ * task/dais socket < == > task/dais socket
+ * task/dais socket < == > device
+ * task/dais socket < == > GPP
+ *
+ * ie, no message nodes, and at least one task or dais
+ * socket node.
+ */
+ if (node1Type == NODE_MESSAGE || node2Type == NODE_MESSAGE ||
+ (node1Type != NODE_TASK && node1Type != NODE_DAISSOCKET &&
+ node2Type != NODE_TASK && node2Type != NODE_DAISSOCKET))
+ status = DSP_EFAIL;
+ }
+ /*
+ * Check stream mode. Default is STRMMODE_PROCCOPY.
+ */
+ if (DSP_SUCCEEDED(status) && pAttrs) {
+ if (pAttrs->lMode != STRMMODE_PROCCOPY)
+ status = DSP_ESTRMMODE; /* illegal stream mode */
+
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ if (node1Type != NODE_GPP) {
+ hNodeMgr = hNode1->hNodeMgr;
+ } else {
+ DBC_Assert(hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE);
+ hNodeMgr = hNode2->hNodeMgr;
+ }
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ /* Nodes must be in the allocated state */
+ if (node1Type != NODE_GPP && NODE_GetState(hNode1) != NODE_ALLOCATED)
+ status = DSP_EWRONGSTATE;
+
+ if (node2Type != NODE_GPP && NODE_GetState(hNode2) != NODE_ALLOCATED)
+ status = DSP_EWRONGSTATE;
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Check that stream indices for task and dais socket nodes
+ * are not already be used. (Device nodes checked later) */
+ if (node1Type == NODE_TASK || node1Type == NODE_DAISSOCKET) {
+ pOutput = &(hNode1->createArgs.asa.taskArgs.
+ strmOutDef[uStream1]);
+ if (pOutput->szDevice != NULL)
+ status = DSP_EALREADYCONNECTED;
+
+ }
+ if (node2Type == NODE_TASK || node2Type == NODE_DAISSOCKET) {
+ pInput = &(hNode2->createArgs.asa.taskArgs.
+ strmInDef[uStream2]);
+ if (pInput->szDevice != NULL)
+ status = DSP_EALREADYCONNECTED;
+
+ }
+ }
+ /* Connecting two task nodes? */
+ if (DSP_SUCCEEDED(status) && ((node1Type == NODE_TASK ||
+ node1Type == NODE_DAISSOCKET) && (node2Type == NODE_TASK ||
+ node2Type == NODE_DAISSOCKET))) {
+ /* Find available pipe */
+ pipeId = GB_findandset(hNodeMgr->pipeMap);
+ if (pipeId == GB_NOBITS) {
+ status = DSP_ENOMORECONNECTIONS;
+ } else {
+ hNode1->outputs[uStream1].type = NODECONNECT;
+ hNode2->inputs[uStream2].type = NODECONNECT;
+ hNode1->outputs[uStream1].devId = pipeId;
+ hNode2->inputs[uStream2].devId = pipeId;
+ pOutput->szDevice = MEM_Calloc(PIPENAMELEN + 1,
+ MEM_PAGED);
+ pInput->szDevice = MEM_Calloc(PIPENAMELEN + 1,
+ MEM_PAGED);
+ if (pOutput->szDevice == NULL ||
+ pInput->szDevice == NULL) {
+ /* Undo the connection */
+ if (pOutput->szDevice)
+ MEM_Free(pOutput->szDevice);
+
+ if (pInput->szDevice)
+ MEM_Free(pInput->szDevice);
+
+ pOutput->szDevice = NULL;
+ pInput->szDevice = NULL;
+ GB_clear(hNodeMgr->pipeMap, pipeId);
+ status = DSP_EMEMORY;
+ } else {
+ /* Copy "/dbpipe<pipId>" name to device names */
+ sprintf(pOutput->szDevice, "%s%d",
+ PIPEPREFIX, pipeId);
+ strcpy(pInput->szDevice, pOutput->szDevice);
+ }
+ }
+ }
+ /* Connecting task node to host? */
+ if (DSP_SUCCEEDED(status) && (node1Type == NODE_GPP ||
+ node2Type == NODE_GPP)) {
+ if (node1Type == NODE_GPP) {
+ uMode = CHNL_MODETODSP;
+ } else {
+ DBC_Assert(node2Type == NODE_GPP);
+ uMode = CHNL_MODEFROMDSP;
+ }
+ /* Reserve a channel id. We need to put the name "/host<id>"
+ * in the node's createArgs, but the host
+ * side channel will not be opened until DSPStream_Open is
+ * called for this node. */
+ if (pAttrs) {
+ if (pAttrs->lMode == STRMMODE_RDMA) {
+ chnlId = GB_findandset(hNodeMgr->dmaChnlMap);
+ /* dma chans are 2nd transport chnl set
+ * ids(e.g. 16-31)*/
+ (chnlId != GB_NOBITS) ?
+ (chnlId = chnlId + hNodeMgr->ulNumChnls) :
+ chnlId;
+ } else if (pAttrs->lMode == STRMMODE_ZEROCOPY) {
+ chnlId = GB_findandset(hNodeMgr->zChnlMap);
+ /* zero-copy chans are 3nd transport set
+ * (e.g. 32-47) */
+ (chnlId != GB_NOBITS) ? (chnlId = chnlId +
+ (2 * hNodeMgr->ulNumChnls)) : chnlId;
+ } else { /* must be PROCCOPY */
+ DBC_Assert(pAttrs->lMode == STRMMODE_PROCCOPY);
+ chnlId = GB_findandset(hNodeMgr->chnlMap);
+ /* e.g. 0-15 */
+ }
+ } else {
+ /* default to PROCCOPY */
+ chnlId = GB_findandset(hNodeMgr->chnlMap);
+ }
+ if (chnlId == GB_NOBITS) {
+ status = DSP_ENOMORECONNECTIONS;
+ goto func_cont2;
+ }
+ pstrDevName = MEM_Calloc(HOSTNAMELEN + 1, MEM_PAGED);
+ if (pstrDevName != NULL)
+ goto func_cont2;
+
+ if (pAttrs) {
+ if (pAttrs->lMode == STRMMODE_RDMA) {
+ GB_clear(hNodeMgr->dmaChnlMap, chnlId -
+ hNodeMgr->ulNumChnls);
+ } else if (pAttrs->lMode == STRMMODE_ZEROCOPY) {
+ GB_clear(hNodeMgr->zChnlMap, chnlId -
+ (2*hNodeMgr->ulNumChnls));
+ } else {
+ DBC_Assert(pAttrs->lMode == STRMMODE_PROCCOPY);
+ GB_clear(hNodeMgr->chnlMap, chnlId);
+ }
+ } else {
+ GB_clear(hNodeMgr->chnlMap, chnlId);
+ }
+ status = DSP_EMEMORY;
+func_cont2:
+ if (DSP_SUCCEEDED(status)) {
+ if (hNode1 == (struct NODE_OBJECT *) DSP_HGPPNODE) {
+ hNode2->inputs[uStream2].type = HOSTCONNECT;
+ hNode2->inputs[uStream2].devId = chnlId;
+ pInput->szDevice = pstrDevName;
+ } else {
+ hNode1->outputs[uStream1].type = HOSTCONNECT;
+ hNode1->outputs[uStream1].devId = chnlId;
+ pOutput->szDevice = pstrDevName;
+ }
+ sprintf(pstrDevName, "%s%d", HOSTPREFIX, chnlId);
+ }
+ }
+ /* Connecting task node to device node? */
+ if (DSP_SUCCEEDED(status) && ((node1Type == NODE_DEVICE) ||
+ (node2Type == NODE_DEVICE))) {
+ if (node2Type == NODE_DEVICE) {
+ /* node1 == > device */
+ hDevNode = hNode2;
+ hNode = hNode1;
+ pStream = &(hNode1->outputs[uStream1]);
+ pstrmDef = pOutput;
+ } else {
+ /* device == > node2 */
+ hDevNode = hNode1;
+ hNode = hNode2;
+ pStream = &(hNode2->inputs[uStream2]);
+ pstrmDef = pInput;
+ }
+ /* Set up create args */
+ pStream->type = DEVICECONNECT;
+ dwLength = strlen(hDevNode->pstrDevName);
+ if (pConnParam != NULL) {
+ pstrmDef->szDevice = MEM_Calloc(dwLength + 1 +
+ (u32) pConnParam->cbData,
+ MEM_PAGED);
+ } else {
+ pstrmDef->szDevice = MEM_Calloc(dwLength + 1,
+ MEM_PAGED);
+ }
+ if (pstrmDef->szDevice == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ /* Copy device name */
+ strncpy(pstrmDef->szDevice, hDevNode->pstrDevName,
+ dwLength);
+ if (pConnParam != NULL) {
+ strncat(pstrmDef->szDevice,
+ (char *)pConnParam->cData,
+ (u32)pConnParam->cbData);
+ }
+ hDevNode->hDeviceOwner = hNode;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Fill in create args */
+ if (node1Type == NODE_TASK || node1Type == NODE_DAISSOCKET) {
+ hNode1->createArgs.asa.taskArgs.uNumOutputs++;
+ FillStreamDef(hNode1, pOutput, pAttrs);
+ }
+ if (node2Type == NODE_TASK || node2Type == NODE_DAISSOCKET) {
+ hNode2->createArgs.asa.taskArgs.uNumInputs++;
+ FillStreamDef(hNode2, pInput, pAttrs);
+ }
+ /* Update hNode1 and hNode2 streamConnect */
+ if (node1Type != NODE_GPP && node1Type != NODE_DEVICE) {
+ hNode1->uNumOutputs++;
+ if (uStream1 > hNode1->uMaxOutputIndex)
+ hNode1->uMaxOutputIndex = uStream1;
+
+ }
+ if (node2Type != NODE_GPP && node2Type != NODE_DEVICE) {
+ hNode2->uNumInputs++;
+ if (uStream2 > hNode2->uMaxInputIndex)
+ hNode2->uMaxInputIndex = uStream2;
+
+ }
+ FillStreamConnect(hNode1, hNode2, uStream1, uStream2);
+ }
+func_cont:
+ /* end of SYNC_EnterCS */
+ /* Exit critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_Create ========
+ * Purpose:
+ * Create a node on the DSP by remotely calling the node's create function.
+ */
+DSP_STATUS NODE_Create(struct NODE_OBJECT *hNode)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ struct NODE_MGR *hNodeMgr;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ u32 ulCreateFxn;
+ enum NODE_TYPE nodeType;
+ DSP_STATUS status = DSP_SOK;
+ DSP_STATUS status1 = DSP_SOK;
+ bool bJustWokeDSP = false;
+ struct DSP_CBDATA cbData;
+ u32 procId = 255;
+ struct DSP_PROCESSORSTATE procStatus;
+ struct PROC_OBJECT *hProcessor;
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+#endif
+
+ DBC_Require(cRefs > 0);
+ GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Create: hNode: 0x%x\n",
+ hNode);
+ if (!MEM_IsValidHandle(pNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ hProcessor = hNode->hProcessor;
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt to create
+ new node */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Create:"
+ " proc Status 0x%x\n", procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ /* create struct DSP_CBDATA struct for PWR calls */
+ cbData.cbData = PWR_TIMEOUT;
+ nodeType = NODE_GetType(hNode);
+ hNodeMgr = hNode->hNodeMgr;
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ /* Get access to node dispatcher */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ /* Check node state */
+ if (NODE_GetState(hNode) != NODE_ALLOCATED)
+ status = DSP_EWRONGSTATE;
+
+ if (DSP_SUCCEEDED(status))
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+
+ if (DSP_FAILED(status))
+ goto func_cont2;
+
+ if (procId != DSP_UNIT)
+ goto func_cont2;
+
+ /* Make sure streams are properly connected */
+ if ((hNode->uNumInputs && hNode->uMaxInputIndex >
+ hNode->uNumInputs - 1) ||
+ (hNode->uNumOutputs && hNode->uMaxOutputIndex >
+ hNode->uNumOutputs - 1))
+ status = DSP_ENOTCONNECTED;
+
+ if (DSP_SUCCEEDED(status)) {
+ /* If node's create function is not loaded, load it */
+ /* Boost the OPP level to max level that DSP can be requested */
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq) {
+ (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP3]);
+
+ if (pdata->dsp_get_opp) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "opp level"
+ "after setting to VDD1_OPP3 is %d\n",
+ (*pdata->dsp_get_opp)());
+ }
+ }
+#endif
+ status = hNodeMgr->nldrFxns.pfnLoad(hNode->hNldrNode,
+ NLDR_CREATE);
+ /* Get address of node's create function */
+ if (DSP_SUCCEEDED(status)) {
+ hNode->fLoaded = true;
+ if (nodeType != NODE_DEVICE) {
+ status = GetFxnAddress(hNode, &ulCreateFxn,
+ CREATEPHASE);
+ }
+ } else {
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Create: failed to load"
+ " create code: 0x%x\n", status);
+ }
+ /* Request the lowest OPP level*/
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq) {
+ (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP1]);
+
+ if (pdata->dsp_get_opp) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "opp level"
+ "after setting to VDD1_OPP1 is %d\n",
+ (*pdata->dsp_get_opp)());
+ }
+ }
+#endif
+ /* Get address of iAlg functions, if socket node */
+ if (DSP_SUCCEEDED(status)) {
+ if (nodeType == NODE_DAISSOCKET) {
+ status = hNodeMgr->nldrFxns.pfnGetFxnAddr
+ (hNode->hNldrNode, hNode->dcdProps.
+ objData.nodeObj.pstrIAlgName,
+ &hNode->createArgs.asa.taskArgs.
+ ulDaisArg);
+ }
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ if (nodeType != NODE_DEVICE) {
+ status = DISP_NodeCreate(hNodeMgr->hDisp, hNode,
+ hNodeMgr->ulFxnAddrs[RMSCREATENODE],
+ ulCreateFxn, &(hNode->createArgs),
+ &(hNode->nodeEnv));
+ if (DSP_SUCCEEDED(status)) {
+ /* Set the message queue id to the node env
+ * pointer */
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ (*pIntfFxns->pfnMsgSetQueueId)(hNode->hMsgQueue,
+ hNode->nodeEnv);
+ }
+ }
+ }
+ /* Phase II/Overlays: Create, execute, delete phases possibly in
+ * different files/sections. */
+ if (hNode->fLoaded && hNode->fPhaseSplit) {
+ /* If create code was dynamically loaded, we can now unload
+ * it. */
+ status1 = hNodeMgr->nldrFxns.pfnUnload(hNode->hNldrNode,
+ NLDR_CREATE);
+ hNode->fLoaded = false;
+ }
+ if (DSP_FAILED(status1)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Create: Failed to unload "
+ "create code: 0x%x\n", status1);
+ }
+func_cont2:
+ /* Update node state and node manager state */
+ if (DSP_SUCCEEDED(status)) {
+ NODE_SetState(hNode, NODE_CREATED);
+ hNodeMgr->uNumCreated++;
+ goto func_cont;
+ }
+ if (status != DSP_EWRONGSTATE) {
+ /* Put back in NODE_ALLOCATED state if error occurred */
+ NODE_SetState(hNode, NODE_ALLOCATED);
+ }
+ if (procId == DSP_UNIT) {
+ /* If node create failed, see if should sleep DSP now */
+ if (bJustWokeDSP == true) {
+ /* Check to see if partial create happened on DSP */
+ if (hNode->nodeEnv == (u32)NULL) {
+ /* No environment allocated on DSP, re-sleep
+ * DSP now */
+ PROC_Ctrl(hNode->hProcessor, WMDIOCTL_DEEPSLEEP,
+ &cbData);
+ } else {
+ /* Increment count, sleep later when node fully
+ * deleted */
+ hNodeMgr->uNumCreated++;
+ }
+ }
+ }
+func_cont:
+ /* Free access to node dispatcher */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+func_end:
+ if (DSP_SUCCEEDED(status)) {
+ PROC_NotifyClients(hNode->hProcessor, DSP_NODESTATECHANGE);
+ NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE);
+ }
+
+ return status;
+}
+
+/*
+ * ======== NODE_CreateMgr ========
+ * Purpose:
+ * Create a NODE Manager object.
+ */
+DSP_STATUS NODE_CreateMgr(OUT struct NODE_MGR **phNodeMgr,
+ struct DEV_OBJECT *hDevObject)
+{
+ u32 i;
+ struct NODE_MGR *pNodeMgr = NULL;
+ struct DISP_ATTRS dispAttrs;
+ char *szZLFile = "";
+ struct NLDR_ATTRS nldrAttrs;
+ DSP_STATUS status = DSP_SOK;
+ u32 devType;
+ DBC_Require(cRefs > 0);
+ DBC_Require(phNodeMgr != NULL);
+ DBC_Require(hDevObject != NULL);
+ GT_2trace(NODE_debugMask, GT_ENTER, "NODE_CreateMgr: phNodeMgr: 0x%x\t"
+ "hDevObject: 0x%x\n", phNodeMgr, hDevObject);
+ *phNodeMgr = NULL;
+ /* Allocate Node manager object */
+ MEM_AllocObject(pNodeMgr, struct NODE_MGR, NODEMGR_SIGNATURE);
+ if (pNodeMgr) {
+ pNodeMgr->hDevObject = hDevObject;
+ pNodeMgr->nodeList = LST_Create();
+ pNodeMgr->pipeMap = GB_create(MAXPIPES);
+ pNodeMgr->pipeDoneMap = GB_create(MAXPIPES);
+ if (pNodeMgr->nodeList == NULL || pNodeMgr->pipeMap == NULL ||
+ pNodeMgr->pipeDoneMap == NULL) {
+ status = DSP_EMEMORY;
+ GT_0trace(NODE_debugMask, GT_6CLASS,
+ "NODE_CreateMgr: Memory "
+ "allocation failed\n");
+ } else {
+ status = NTFY_Create(&pNodeMgr->hNtfy);
+ }
+ pNodeMgr->uNumCreated = 0;
+ } else {
+ GT_0trace(NODE_debugMask, GT_6CLASS,
+ "NODE_CreateMgr: Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ }
+ /* get devNodeType */
+ if (DSP_SUCCEEDED(status))
+ status = DEV_GetDevType(hDevObject, &devType);
+
+ /* Create the DCD Manager */
+ if (DSP_SUCCEEDED(status)) {
+ status = DCD_CreateManager(szZLFile, &pNodeMgr->hDcdMgr);
+ if (DSP_SUCCEEDED(status))
+ status = GetProcProps(pNodeMgr, hDevObject);
+
+ }
+ /* Create NODE Dispatcher */
+ if (DSP_SUCCEEDED(status)) {
+ dispAttrs.ulChnlOffset = pNodeMgr->ulChnlOffset;
+ dispAttrs.ulChnlBufSize = pNodeMgr->ulChnlBufSize;
+ dispAttrs.procFamily = pNodeMgr->procFamily;
+ dispAttrs.procType = pNodeMgr->procType;
+ status = DISP_Create(&pNodeMgr->hDisp, hDevObject, &dispAttrs);
+ }
+ /* Create a STRM Manager */
+ if (DSP_SUCCEEDED(status))
+ status = STRM_Create(&pNodeMgr->hStrmMgr, hDevObject);
+
+ if (DSP_SUCCEEDED(status)) {
+ DEV_GetIntfFxns(hDevObject, &pNodeMgr->pIntfFxns);
+ /* Get MSG queue manager */
+ DEV_GetMsgMgr(hDevObject, &pNodeMgr->hMsg);
+ status = SYNC_InitializeCS(&pNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ status = DSP_EMEMORY;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ pNodeMgr->chnlMap = GB_create(pNodeMgr->ulNumChnls);
+ /* dma chnl map. ulNumChnls is # per transport */
+ pNodeMgr->dmaChnlMap = GB_create(pNodeMgr->ulNumChnls);
+ pNodeMgr->zChnlMap = GB_create(pNodeMgr->ulNumChnls);
+ if ((pNodeMgr->chnlMap == NULL) ||
+ (pNodeMgr->dmaChnlMap == NULL) ||
+ (pNodeMgr->zChnlMap == NULL)) {
+ status = DSP_EMEMORY;
+ } else {
+ /* Block out reserved channels */
+ for (i = 0; i < pNodeMgr->ulChnlOffset; i++)
+ GB_set(pNodeMgr->chnlMap, i);
+
+ /* Block out channels reserved for RMS */
+ GB_set(pNodeMgr->chnlMap, pNodeMgr->ulChnlOffset);
+ GB_set(pNodeMgr->chnlMap, pNodeMgr->ulChnlOffset + 1);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* NO RM Server on the IVA */
+ if (devType != IVA_UNIT) {
+ /* Get addresses of any RMS functions loaded */
+ status = GetRMSFxns(pNodeMgr);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_6CLASS,
+ "NODE_CreateMgr: Failed to"
+ " get RMS functions: status = 0x%x", status);
+ }
+ }
+ }
+
+ /* Get loader functions and create loader */
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(NODE_debugMask, GT_1CLASS,
+ "NODE_CreateMgr: using dynamic loader\n");
+ pNodeMgr->nldrFxns = nldrFxns; /* Dynamic loader functions */
+ }
+ if (DSP_SUCCEEDED(status)) {
+ nldrAttrs.pfnOvly = Ovly;
+ nldrAttrs.pfnWrite = Write;
+ nldrAttrs.usDSPWordSize = pNodeMgr->uDSPWordSize;
+ nldrAttrs.usDSPMauSize = pNodeMgr->uDSPMauSize;
+ pNodeMgr->fLoaderInit = pNodeMgr->nldrFxns.pfnInit();
+ status = pNodeMgr->nldrFxns.pfnCreate(&pNodeMgr->hNldr,
+ hDevObject, &nldrAttrs);
+ if (DSP_FAILED(status)) {
+ GT_1trace(NODE_debugMask, GT_6CLASS,
+ "NODE_CreateMgr: Failed to "
+ "create loader: status = 0x%x\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status))
+ *phNodeMgr = pNodeMgr;
+ else
+ DeleteNodeMgr(pNodeMgr);
+
+ DBC_Ensure((DSP_FAILED(status) && (*phNodeMgr == NULL)) ||
+ (DSP_SUCCEEDED(status) &&
+ MEM_IsValidHandle((*phNodeMgr), NODEMGR_SIGNATURE)));
+
+ return status;
+}
+
+/*
+ * ======== NODE_Delete ========
+ * Purpose:
+ * Delete a node on the DSP by remotely calling the node's delete function.
+ * Loads the node's delete function if necessary. Free GPP side resources
+ * after node's delete function returns.
+ */
+DSP_STATUS NODE_Delete(struct NODE_OBJECT *hNode)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ struct NODE_MGR *hNodeMgr;
+ struct PROC_OBJECT *hProcessor;
+ struct DISP_OBJECT *hDisp;
+ u32 ulDeleteFxn;
+ enum NODE_TYPE nodeType;
+ enum NODE_STATE state;
+ DSP_STATUS status = DSP_SOK;
+ DSP_STATUS status1 = DSP_SOK;
+ struct DSP_CBDATA cbData;
+ u32 procId;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+
+#ifndef RES_CLEANUP_DISABLE
+ u32 hProcess;
+ HANDLE nodeRes;
+ HANDLE hDrvObject;
+ struct PROCESS_CONTEXT *pCtxt = NULL;
+ DSP_STATUS res_status = DSP_SOK;
+#endif
+ struct DSP_PROCESSORSTATE procStatus;
+ DBC_Require(cRefs > 0);
+ GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Delete: hNode: 0x%x\n",
+ hNode);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ /* create struct DSP_CBDATA struct for PWR call */
+ cbData.cbData = PWR_TIMEOUT;
+ hNodeMgr = hNode->hNodeMgr;
+ hProcessor = hNode->hProcessor;
+ hDisp = hNodeMgr->hDisp;
+ nodeType = NODE_GetType(hNode);
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ state = NODE_GetState(hNode);
+ /* Execute delete phase code for non-device node in all cases
+ * except when the node was only allocated. Delete phase must be
+ * executed even if create phase was executed, but failed.
+ * If the node environment pointer is non-NULL, the delete phase
+ * code must be executed. */
+ if (!(state == NODE_ALLOCATED && hNode->nodeEnv == (u32)NULL) &&
+ nodeType != NODE_DEVICE) {
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+ if (DSP_FAILED(status))
+ goto func_cont1;
+
+ if (procId == DSP_UNIT || procId == IVA_UNIT) {
+ /* If node has terminated, execute phase code will
+ * have already been unloaded in NODE_OnExit(). If the
+ * node is PAUSED, the execute phase is loaded, and it
+ * is now ok to unload it. If the node is running, we
+ * will unload the execute phase only after deleting
+ * the node. */
+ if (state == NODE_PAUSED && hNode->fLoaded &&
+ hNode->fPhaseSplit) {
+ /* Ok to unload execute code as long as node
+ * is not * running */
+ status1 = hNodeMgr->nldrFxns.pfnUnload(hNode->
+ hNldrNode, NLDR_EXECUTE);
+ hNode->fLoaded = false;
+ NODE_SetState(hNode, NODE_DONE);
+ }
+ /* Load delete phase code if not loaded or if haven't
+ * * unloaded EXECUTE phase */
+ if ((!(hNode->fLoaded) || (state == NODE_RUNNING)) &&
+ hNode->fPhaseSplit) {
+ status = hNodeMgr->nldrFxns.pfnLoad(hNode->
+ hNldrNode, NLDR_DELETE);
+ if (DSP_SUCCEEDED(status)) {
+ hNode->fLoaded = true;
+ } else {
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Delete: failed to "
+ "load delete code: 0x%x\n",
+ status);
+ }
+ }
+ }
+func_cont1:
+ if (DSP_SUCCEEDED(status)) {
+ /* Unblock a thread trying to terminate the node */
+ (void)SYNC_SetEvent(hNode->hSyncDone);
+ if (procId == DSP_UNIT) {
+ /* ulDeleteFxn = address of node's delete
+ * function */
+ status = GetFxnAddress(hNode, &ulDeleteFxn,
+ DELETEPHASE);
+ } else if (procId == IVA_UNIT)
+ ulDeleteFxn = (u32)hNode->nodeEnv;
+ if (DSP_SUCCEEDED(status)) {
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ GT_1trace(NODE_debugMask, GT_4CLASS,
+ "NODE_Delete: proc Status "
+ "0x%x\n", procStatus.iState);
+ if (procStatus.iState != PROC_ERROR) {
+ status = DISP_NodeDelete(hDisp, hNode,
+ hNodeMgr->ulFxnAddrs[RMSDELETENODE],
+ ulDeleteFxn, hNode->nodeEnv);
+ } else
+ NODE_SetState(hNode, NODE_DONE);
+
+ /* Unload execute, if not unloaded, and delete
+ * function */
+ if (state == NODE_RUNNING &&
+ hNode->fPhaseSplit) {
+ status1 = hNodeMgr->nldrFxns.pfnUnload(
+ hNode->hNldrNode, NLDR_EXECUTE);
+ }
+ if (DSP_FAILED(status1)) {
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Delete: failed to"
+ "unload execute code: 0x%x\n",
+ status1);
+ }
+ status1 = hNodeMgr->nldrFxns.pfnUnload(
+ hNode->hNldrNode, NLDR_DELETE);
+ hNode->fLoaded = false;
+ if (DSP_FAILED(status1)) {
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Delete: failed to"
+ "unload delete code: 0x%x\n",
+ status1);
+ }
+ }
+ }
+ }
+ /* Free host side resources even if a failure occurred */
+ /* Remove node from hNodeMgr->nodeList */
+ LST_RemoveElem(hNodeMgr->nodeList, (struct LST_ELEM *) hNode);
+ hNodeMgr->uNumNodes--;
+ /* Decrement count of nodes created on DSP */
+ if ((state != NODE_ALLOCATED) || ((state == NODE_ALLOCATED) &&
+ (hNode->nodeEnv != (u32) NULL)))
+ hNodeMgr->uNumCreated--;
+ /* Free host-side resources allocated by NODE_Create()
+ * DeleteNode() fails if SM buffers not freed by client! */
+#ifndef RES_CLEANUP_DISABLE
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(res_status))
+ goto func_cont;
+ DRV_GetProcContext(0, (struct DRV_OBJECT *)hDrvObject,
+ &pCtxt, hNode, 0);
+ if (pCtxt == NULL)
+ goto func_cont;
+ if (DRV_GetNodeResElement(hNode, &nodeRes, pCtxt) != DSP_ENOTFOUND) {
+ GT_0trace(NODE_debugMask, GT_5CLASS, "\nNODE_Delete12:\n");
+ DRV_ProcNodeUpdateStatus(nodeRes, false);
+ }
+#endif
+func_cont:
+ GT_0trace(NODE_debugMask, GT_ENTER, "\nNODE_Delete13:\n ");
+ DeleteNode(hNode);
+#ifndef RES_CLEANUP_DISABLE
+ GT_0trace(NODE_debugMask, GT_5CLASS, "\nNODE_Delete2:\n ");
+ if (pCtxt != NULL)
+ DRV_RemoveNodeResElement(nodeRes, (HANDLE)pCtxt);
+#endif
+ GT_0trace(NODE_debugMask, GT_ENTER, "\nNODE_Delete3:\n ");
+ /* Exit critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ PROC_NotifyClients(hProcessor, DSP_NODESTATECHANGE);
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_DeleteMgr ========
+ * Purpose:
+ * Delete the NODE Manager.
+ */
+DSP_STATUS NODE_DeleteMgr(struct NODE_MGR *hNodeMgr)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE));
+
+ GT_1trace(NODE_debugMask, GT_ENTER, "NODE_DeleteMgr: hNodeMgr: 0x%x\n",
+ hNodeMgr);
+ DeleteNodeMgr(hNodeMgr);
+
+ return status;
+}
+
+/*
+ * ======== NODE_EnumNodes ========
+ * Purpose:
+ * Enumerate currently allocated nodes.
+ */
+DSP_STATUS NODE_EnumNodes(struct NODE_MGR *hNodeMgr, IN DSP_HNODE *aNodeTab,
+ u32 uNodeTabSize, OUT u32 *puNumNodes,
+ OUT u32 *puAllocated)
+{
+ struct NODE_OBJECT *hNode;
+ u32 i;
+ DSP_STATUS status = DSP_SOK;
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE));
+ DBC_Require(aNodeTab != NULL || uNodeTabSize == 0);
+ DBC_Require(puNumNodes != NULL);
+ DBC_Require(puAllocated != NULL);
+ GT_5trace(NODE_debugMask, GT_ENTER, "NODE_EnumNodes: hNodeMgr: 0x%x\t"
+ "aNodeTab: %d\tuNodeTabSize: 0x%x\tpuNumNodes: 0x%x\t"
+ "puAllocated\n", hNodeMgr, aNodeTab, uNodeTabSize, puNumNodes,
+ puAllocated);
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ if (hNodeMgr->uNumNodes > uNodeTabSize) {
+ *puAllocated = hNodeMgr->uNumNodes;
+ *puNumNodes = 0;
+ status = DSP_ESIZE;
+ } else {
+ hNode = (struct NODE_OBJECT *)LST_First(hNodeMgr->
+ nodeList);
+ for (i = 0; i < hNodeMgr->uNumNodes; i++) {
+ DBC_Assert(MEM_IsValidHandle(hNode,
+ NODE_SIGNATURE));
+ aNodeTab[i] = hNode;
+ hNode = (struct NODE_OBJECT *)LST_Next
+ (hNodeMgr->nodeList,
+ (struct LST_ELEM *)hNode);
+ }
+ *puAllocated = *puNumNodes = hNodeMgr->uNumNodes;
+ }
+ }
+ /* end of SYNC_EnterCS */
+ /* Exit critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ return status;
+}
+
+/*
+ * ======== NODE_Exit ========
+ * Purpose:
+ * Discontinue usage of NODE module.
+ */
+void NODE_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ cRefs--;
+
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "Entered NODE_Exit, ref count: 0x%x\n", cRefs);
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== NODE_FreeMsgBuf ========
+ * Purpose:
+ * Frees the message buffer.
+ */
+DSP_STATUS NODE_FreeMsgBuf(struct NODE_OBJECT *hNode, IN u8 *pBuffer,
+ OPTIONAL struct DSP_BUFFERATTR *pAttr)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ DSP_STATUS status = DSP_SOK;
+ u32 procId;
+ DBC_Require(cRefs > 0);
+ DBC_Require(pBuffer != NULL);
+ DBC_Require(pNode != NULL);
+ DBC_Require(pNode->hXlator != NULL);
+ GT_3trace(NODE_debugMask, GT_ENTER, "NODE_FreeMsgBuf: hNode: 0x%x\t"
+ "pBuffer: 0x%x\tpAttr: 0x%x\n", hNode, pBuffer, pAttr);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+ if (procId == DSP_UNIT) {
+ if (DSP_SUCCEEDED(status)) {
+ if (pAttr == NULL) {
+ /* set defaults */
+ pAttr = &NODE_DFLTBUFATTRS;
+ }
+ /* Node supports single SM segment only */
+ if (pAttr->uSegment != 1)
+ status = DSP_EBADSEGID;
+
+ /* pBuffer is clients Va. */
+ status = CMM_XlatorFreeBuf(pNode->hXlator, pBuffer);
+ if (DSP_FAILED(status))
+ status = DSP_EFAIL;
+ else
+ status = DSP_SOK;
+
+ }
+ } else {
+ DBC_Assert(NULL); /* BUG */
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_GetAttr ========
+ * Purpose:
+ * Copy the current attributes of the specified node into a DSP_NODEATTR
+ * structure.
+ */
+DSP_STATUS NODE_GetAttr(struct NODE_OBJECT *hNode,
+ OUT struct DSP_NODEATTR *pAttr, u32 uAttrSize)
+{
+ struct NODE_MGR *hNodeMgr;
+ DSP_STATUS status = DSP_SOK;
+ DBC_Require(cRefs > 0);
+ DBC_Require(pAttr != NULL);
+ DBC_Require(uAttrSize >= sizeof(struct DSP_NODEATTR));
+ GT_3trace(NODE_debugMask, GT_ENTER, "NODE_GetAttr: hNode: "
+ "0x%x\tpAttr: 0x%x \tuAttrSize: 0x%x\n", hNode, pAttr,
+ uAttrSize);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ hNodeMgr = hNode->hNodeMgr;
+ /* Enter hNodeMgr critical section (since we're accessing
+ * data that could be changed by NODE_ChangePriority() and
+ * NODE_Connect(). */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ pAttr->cbStruct = sizeof(struct DSP_NODEATTR);
+ /* DSP_NODEATTRIN */
+ pAttr->inNodeAttrIn.cbStruct =
+ sizeof(struct DSP_NODEATTRIN);
+ pAttr->inNodeAttrIn.iPriority = hNode->nPriority;
+ pAttr->inNodeAttrIn.uTimeout = hNode->uTimeout;
+ pAttr->inNodeAttrIn.uHeapSize =
+ hNode->createArgs.asa.taskArgs.uHeapSize;
+ pAttr->inNodeAttrIn.pGPPVirtAddr = (void *)
+ hNode->createArgs.asa.taskArgs.uGPPHeapAddr;
+ pAttr->uInputs = hNode->uNumGPPInputs;
+ pAttr->uOutputs = hNode->uNumGPPOutputs;
+ /* DSP_NODEINFO */
+ GetNodeInfo(hNode, &(pAttr->iNodeInfo));
+ }
+ /* end of SYNC_EnterCS */
+ /* Exit critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ }
+ return status;
+}
+
+/*
+ * ======== NODE_GetChannelId ========
+ * Purpose:
+ * Get the channel index reserved for a stream connection between the
+ * host and a node.
+ */
+DSP_STATUS NODE_GetChannelId(struct NODE_OBJECT *hNode, u32 uDir, u32 uIndex,
+ OUT u32 *pulId)
+{
+ enum NODE_TYPE nodeType;
+ DSP_STATUS status = DSP_EVALUE;
+ DBC_Require(cRefs > 0);
+ DBC_Require(uDir == DSP_TONODE || uDir == DSP_FROMNODE);
+ DBC_Require(pulId != NULL);
+ GT_4trace(NODE_debugMask, GT_ENTER, "NODE_GetChannelId: hNode: "
+ "0x%x\tuDir: %d\tuIndex: %d\tpulId: 0x%x\n", hNode, uDir,
+ uIndex, pulId);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ return status;
+ }
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET) {
+ status = DSP_ENODETYPE;
+ return status;
+ }
+ if (uDir == DSP_TONODE) {
+ if (uIndex < MaxInputs(hNode)) {
+ if (hNode->inputs[uIndex].type == HOSTCONNECT) {
+ *pulId = hNode->inputs[uIndex].devId;
+ status = DSP_SOK;
+ }
+ }
+ } else {
+ DBC_Assert(uDir == DSP_FROMNODE);
+ if (uIndex < MaxOutputs(hNode)) {
+ if (hNode->outputs[uIndex].type == HOSTCONNECT) {
+ *pulId = hNode->outputs[uIndex].devId;
+ status = DSP_SOK;
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== NODE_GetMessage ========
+ * Purpose:
+ * Retrieve a message from a node on the DSP.
+ */
+DSP_STATUS NODE_GetMessage(struct NODE_OBJECT *hNode, OUT struct DSP_MSG *pMsg,
+ u32 uTimeout)
+{
+ struct NODE_MGR *hNodeMgr;
+ enum NODE_TYPE nodeType;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+ void *pTmpBuf;
+ struct DSP_PROCESSORSTATE procStatus;
+ struct PROC_OBJECT *hProcessor;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pMsg != NULL);
+ GT_3trace(NODE_debugMask, GT_ENTER,
+ "NODE_GetMessage: hNode: 0x%x\tpMsg: "
+ "0x%x\tuTimeout: 0x%x\n", hNode, pMsg, uTimeout);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ hProcessor = hNode->hProcessor;
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt to get the
+ message */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_GetMessage:"
+ " proc Status 0x%x\n", procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ hNodeMgr = hNode->hNodeMgr;
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_MESSAGE && nodeType != NODE_TASK &&
+ nodeType != NODE_DAISSOCKET) {
+ status = DSP_ENODETYPE;
+ goto func_end;
+ }
+ /* This function will block unless a message is available. Since
+ * DSPNode_RegisterNotify() allows notification when a message
+ * is available, the system can be designed so that
+ * DSPNode_GetMessage() is only called when a message is
+ * available. */
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnMsgGet)(hNode->hMsgQueue, pMsg, uTimeout);
+ /* Check if message contains SM descriptor */
+ if (DSP_FAILED(status) || !(pMsg->dwCmd & DSP_RMSBUFDESC))
+ goto func_end;
+
+ /* Translate DSP byte addr to GPP Va. */
+ pTmpBuf = CMM_XlatorTranslate(hNode->hXlator,
+ (void *)(pMsg->dwArg1 * hNode->hNodeMgr->uDSPWordSize),
+ CMM_DSPPA2PA);
+ if (pTmpBuf != NULL) {
+ /* now convert this GPP Pa to Va */
+ pTmpBuf = CMM_XlatorTranslate(hNode->hXlator, pTmpBuf,
+ CMM_PA2VA);
+ if (pTmpBuf != NULL) {
+ /* Adjust SM size in msg */
+ pMsg->dwArg1 = (u32) pTmpBuf;
+ pMsg->dwArg2 *= hNode->hNodeMgr->uDSPWordSize;
+ } else {
+ GT_0trace(NODE_debugMask, GT_7CLASS, "NODE_GetMessage: "
+ "Failed SM translation!\n");
+ status = DSP_ETRANSLATE;
+ }
+ } else {
+ GT_0trace(NODE_debugMask, GT_7CLASS, "NODE_GetMessage: Failed "
+ "SM Pa/Pa translation!\n");
+ status = DSP_ETRANSLATE;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_GetNldrObj ========
+ */
+DSP_STATUS NODE_GetNldrObj(struct NODE_MGR *hNodeMgr,
+ struct NLDR_OBJECT **phNldrObj)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct NODE_MGR *pNodeMgr = hNodeMgr;
+ DBC_Require(phNldrObj != NULL);
+ GT_2trace(NODE_debugMask, GT_ENTER,
+ "Entered NODE_GetNldrObj, hNodeMgr: "
+ "0x%x\n\tphNldrObj: 0x%x\n", hNodeMgr, phNldrObj);
+ if (!MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE))
+ status = DSP_EHANDLE;
+ else
+ *phNldrObj = pNodeMgr->hNldr;
+
+ GT_2trace(NODE_debugMask, GT_ENTER,
+ "Exit NODE_GetNldrObj: status 0x%x\n\t"
+ "phNldrObj: 0x%x\n", status, *phNldrObj);
+ DBC_Ensure(DSP_SUCCEEDED(status) || ((phNldrObj != NULL) &&
+ (*phNldrObj == NULL)));
+ return status;
+}
+
+/*
+ * ======== NODE_GetStrmMgr ========
+ * Purpose:
+ * Returns the Stream manager.
+ */
+DSP_STATUS NODE_GetStrmMgr(struct NODE_OBJECT *hNode,
+ struct STRM_MGR **phStrmMgr)
+{
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE))
+ status = DSP_EHANDLE;
+ else
+ *phStrmMgr = hNode->hNodeMgr->hStrmMgr;
+
+ return status;
+}
+
+/*
+ * ======== NODE_GetLoadType ========
+ */
+enum NLDR_LOADTYPE NODE_GetLoadType(struct NODE_OBJECT *hNode)
+{
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_GetLoadType: Failed. hNode:"
+ " 0x%x\n", hNode);
+ return -1;
+ } else
+ return hNode->dcdProps.objData.nodeObj.usLoadType;
+}
+
+/*
+ * ======== NODE_GetTimeout ========
+ * Purpose:
+ * Returns the timeout value for this node.
+ */
+u32 NODE_GetTimeout(struct NODE_OBJECT *hNode)
+{
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_GetTimeout: Failed. hNode:"
+ " 0x%x\n", hNode);
+ return 0;
+ } else
+ return hNode->uTimeout;
+}
+
+/*
+ * ======== NODE_GetType ========
+ * Purpose:
+ * Returns the node type.
+ */
+enum NODE_TYPE NODE_GetType(struct NODE_OBJECT *hNode)
+{
+ enum NODE_TYPE nodeType;
+
+ if (hNode == (struct NODE_OBJECT *) DSP_HGPPNODE)
+ nodeType = NODE_GPP;
+ else {
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE))
+ nodeType = -1;
+ else
+ nodeType = hNode->nType;
+ }
+ return nodeType;
+}
+
+/*
+ * ======== NODE_Init ========
+ * Purpose:
+ * Initialize the NODE module.
+ */
+bool NODE_Init(void)
+{
+ bool fRetVal = true;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+ DBC_Assert(!NODE_debugMask.flags);
+ GT_create(&NODE_debugMask, "NO"); /* "NO" for NOde */
+ }
+
+ if (fRetVal)
+ cRefs++;
+
+ GT_1trace(NODE_debugMask, GT_5CLASS, "NODE_Init(), ref count: 0x%x\n",
+ cRefs);
+
+ DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0)));
+ return fRetVal;
+}
+
+/*
+ * ======== NODE_OnExit ========
+ * Purpose:
+ * Gets called when RMS_EXIT is received for a node.
+ */
+void NODE_OnExit(struct NODE_OBJECT *hNode, s32 nStatus)
+{
+ DBC_Assert(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ /* Set node state to done */
+ NODE_SetState(hNode, NODE_DONE);
+ hNode->nExitStatus = nStatus;
+ if (hNode->fLoaded && hNode->fPhaseSplit) {
+ (void)hNode->hNodeMgr->nldrFxns.pfnUnload(hNode->hNldrNode,
+ NLDR_EXECUTE);
+ hNode->fLoaded = false;
+ }
+ /* Unblock call to NODE_Terminate */
+ (void) SYNC_SetEvent(hNode->hSyncDone);
+ /* Notify clients */
+ PROC_NotifyClients(hNode->hProcessor, DSP_NODESTATECHANGE);
+ NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE);
+}
+
+/*
+ * ======== NODE_Pause ========
+ * Purpose:
+ * Suspend execution of a node currently running on the DSP.
+ */
+DSP_STATUS NODE_Pause(struct NODE_OBJECT *hNode)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ enum NODE_TYPE nodeType;
+ enum NODE_STATE state;
+ struct NODE_MGR *hNodeMgr;
+ DSP_STATUS status = DSP_SOK;
+ u32 procId;
+ struct DSP_PROCESSORSTATE procStatus;
+ struct PROC_OBJECT *hProcessor;
+
+ DBC_Require(cRefs > 0);
+
+ GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Pause: hNode: 0x%x\n", hNode);
+
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ } else {
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET)
+ status = DSP_ENODETYPE;
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+
+ if (procId == IVA_UNIT)
+ status = DSP_ENOTIMPL;
+
+ if (DSP_SUCCEEDED(status)) {
+ hNodeMgr = hNode->hNodeMgr;
+
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+
+ if (DSP_SUCCEEDED(status)) {
+ state = NODE_GetState(hNode);
+ /* Check node state */
+ if (state != NODE_RUNNING)
+ status = DSP_EWRONGSTATE;
+
+ hProcessor = hNode->hProcessor;
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS,
+ "NODE_Pause: proc Status 0x%x\n",
+ procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = DISP_NodeChangePriority(hNodeMgr->
+ hDisp, hNode,
+ hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY],
+ hNode->nodeEnv, NODE_SUSPENDEDPRI);
+ }
+
+ /* Update state */
+ if (DSP_SUCCEEDED(status)) {
+ NODE_SetState(hNode, NODE_PAUSED);
+ } else {
+ GT_1trace(NODE_debugMask, GT_6CLASS,
+ "NODE_Pause: Failed. hNode:"
+ " 0x%x\n", hNode);
+ }
+ }
+ /* End of SYNC_EnterCS */
+ /* Leave critical section */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ PROC_NotifyClients(hNode->hProcessor,
+ DSP_NODESTATECHANGE);
+ NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE);
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_PutMessage ========
+ * Purpose:
+ * Send a message to a message node, task node, or XDAIS socket node. This
+ * function will block until the message stream can accommodate the
+ * message, or a timeout occurs.
+ */
+DSP_STATUS NODE_PutMessage(struct NODE_OBJECT *hNode,
+ IN CONST struct DSP_MSG *pMsg, u32 uTimeout)
+{
+ struct NODE_MGR *hNodeMgr = NULL;
+ enum NODE_TYPE nodeType;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ enum NODE_STATE state;
+ DSP_STATUS status = DSP_SOK;
+ void *pTmpBuf;
+ struct DSP_MSG newMsg;
+ struct DSP_PROCESSORSTATE procStatus;
+ struct PROC_OBJECT *hProcessor;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pMsg != NULL);
+ GT_3trace(NODE_debugMask, GT_ENTER,
+ "NODE_PutMessage: hNode: 0x%x\tpMsg: "
+ "0x%x\tuTimeout: 0x%x\n", hNode, pMsg, uTimeout);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ hProcessor = hNode->hProcessor;
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in bad state then don't attempt sending the
+ message */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_PutMessage:"
+ " proc Status 0x%x\n", procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ hNodeMgr = hNode->hNodeMgr;
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_MESSAGE && nodeType != NODE_TASK &&
+ nodeType != NODE_DAISSOCKET)
+ status = DSP_ENODETYPE;
+
+ if (DSP_SUCCEEDED(status)) {
+ /* Check node state. Can't send messages to a node after
+ * we've sent the RMS_EXIT command. There is still the
+ * possibility that NODE_Terminate can be called after we've
+ * checked the state. Could add another SYNC object to
+ * prevent this (can't use hNodeMgr->hSync, since we don't
+ * want to block other NODE functions). However, the node may
+ * still exit on its own, before this message is sent. */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ state = NODE_GetState(hNode);
+ if (state == NODE_TERMINATING || state == NODE_DONE)
+ status = DSP_EWRONGSTATE;
+
+ }
+ /* end of SYNC_EnterCS */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* assign pMsg values to new msg */
+ newMsg = *pMsg;
+ /* Now, check if message contains a SM buffer descriptor */
+ if (pMsg->dwCmd & DSP_RMSBUFDESC) {
+ /* Translate GPP Va to DSP physical buf Ptr. */
+ pTmpBuf = CMM_XlatorTranslate(hNode->hXlator,
+ (void *)newMsg.dwArg1, CMM_VA2DSPPA);
+ if (pTmpBuf != NULL) {
+ /* got translation, convert to MAUs in msg */
+ if (hNode->hNodeMgr->uDSPWordSize != 0) {
+ newMsg.dwArg1 =
+ (u32)pTmpBuf /
+ hNode->hNodeMgr->uDSPWordSize;
+ /* MAUs */
+ newMsg.dwArg2 /= hNode->hNodeMgr->uDSPWordSize;
+ } else {
+ GT_0trace(NODE_debugMask, GT_7CLASS,
+ "NODE_PutMessage: "
+ "uDSPWordSize is zero!\n");
+ status = DSP_EFAIL; /* bad DSPWordSize */
+ }
+ } else { /* failed to translate buffer address */
+ GT_0trace(NODE_debugMask, GT_7CLASS,
+ "NODE_PutMessage: Failed to"
+ " translate SM address\n");
+ status = DSP_ETRANSLATE;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnMsgPut)(hNode->hMsgQueue,
+ &newMsg, uTimeout);
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_RegisterNotify ========
+ * Purpose:
+ * Register to be notified on specific events for this node.
+ */
+DSP_STATUS NODE_RegisterNotify(struct NODE_OBJECT *hNode, u32 uEventMask,
+ u32 uNotifyType,
+ struct DSP_NOTIFICATION *hNotification)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hNotification != NULL);
+
+ GT_4trace(NODE_debugMask, GT_ENTER,
+ "NODE_RegisterNotify: hNode: 0x%x\t"
+ "uEventMask: 0x%x\tuNotifyType: 0x%x\thNotification: 0x%x\n",
+ hNode, uEventMask, uNotifyType, hNotification);
+
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ /* Check if event mask is a valid node related event */
+ if (uEventMask & ~(DSP_NODESTATECHANGE |
+ DSP_NODEMESSAGEREADY))
+ status = DSP_EVALUE;
+
+ /* Check if notify type is valid */
+ if (uNotifyType != DSP_SIGNALEVENT)
+ status = DSP_EVALUE;
+
+ /* Only one Notification can be registered at a
+ * time - Limitation */
+ if (uEventMask == (DSP_NODESTATECHANGE |
+ DSP_NODEMESSAGEREADY))
+ status = DSP_EVALUE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ if (uEventMask == DSP_NODESTATECHANGE) {
+ status = NTFY_Register(hNode->hNtfy, hNotification,
+ uEventMask & DSP_NODESTATECHANGE, uNotifyType);
+ } else {
+ /* Send Message part of event mask to MSG */
+ pIntfFxns = hNode->hNodeMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnMsgRegisterNotify)
+ (hNode->hMsgQueue,
+ uEventMask & DSP_NODEMESSAGEREADY, uNotifyType,
+ hNotification);
+ }
+
+ }
+ return status;
+}
+
+/*
+ * ======== NODE_Run ========
+ * Purpose:
+ * Start execution of a node's execute phase, or resume execution of a node
+ * that has been suspended (via NODE_NodePause()) on the DSP. Load the
+ * node's execute function if necessary.
+ */
+DSP_STATUS NODE_Run(struct NODE_OBJECT *hNode)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ struct NODE_MGR *hNodeMgr;
+ enum NODE_TYPE nodeType;
+ enum NODE_STATE state;
+ u32 ulExecuteFxn;
+ u32 ulFxnAddr;
+ DSP_STATUS status = DSP_SOK;
+ u32 procId;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct DSP_PROCESSORSTATE procStatus;
+ struct PROC_OBJECT *hProcessor;
+
+ DBC_Require(cRefs > 0);
+ GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Run: hNode: 0x%x\n", hNode);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ hProcessor = hNode->hProcessor;
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt to run the node */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Run:"
+ " proc Status 0x%x\n", procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ nodeType = NODE_GetType(hNode);
+ if (nodeType == NODE_DEVICE)
+ status = DSP_ENODETYPE;
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ hNodeMgr = hNode->hNodeMgr;
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ /* Enter critical section */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ state = NODE_GetState(hNode);
+ if (state != NODE_CREATED && state != NODE_PAUSED)
+ status = DSP_EWRONGSTATE;
+
+ if (DSP_SUCCEEDED(status))
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+
+ if (DSP_FAILED(status))
+ goto func_cont1;
+
+ if ((procId != DSP_UNIT) && (procId != IVA_UNIT))
+ goto func_cont1;
+
+ if (state == NODE_CREATED) {
+ /* If node's execute function is not loaded, load it */
+ if (!(hNode->fLoaded) && hNode->fPhaseSplit) {
+ status = hNodeMgr->nldrFxns.pfnLoad(hNode->hNldrNode,
+ NLDR_EXECUTE);
+ if (DSP_SUCCEEDED(status)) {
+ hNode->fLoaded = true;
+ } else {
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Run: failed to load "
+ "execute code:0x%x\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Get address of node's execute function */
+ if (procId == IVA_UNIT)
+ ulExecuteFxn = (u32) hNode->nodeEnv;
+ else {
+ status = GetFxnAddress(hNode, &ulExecuteFxn,
+ EXECUTEPHASE);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ ulFxnAddr = hNodeMgr->ulFxnAddrs[RMSEXECUTENODE];
+ status = DISP_NodeRun(hNodeMgr->hDisp, hNode, ulFxnAddr,
+ ulExecuteFxn, hNode->nodeEnv);
+ }
+ } else if (state == NODE_PAUSED) {
+ ulFxnAddr = hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY];
+ status = DISP_NodeChangePriority(hNodeMgr->hDisp, hNode,
+ ulFxnAddr, hNode->nodeEnv,
+ NODE_GetPriority(hNode));
+ } else {
+ /* We should never get here */
+ DBC_Assert(false);
+ }
+func_cont1:
+ /* Update node state. */
+ if (DSP_SUCCEEDED(status))
+ NODE_SetState(hNode, NODE_RUNNING);
+ else /* Set state back to previous value */
+ NODE_SetState(hNode, state);
+ /*End of SYNC_EnterCS */
+ /* Exit critical section */
+func_cont:
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ PROC_NotifyClients(hNode->hProcessor,
+ DSP_NODESTATECHANGE);
+ NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE);
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== NODE_Terminate ========
+ * Purpose:
+ * Signal a node running on the DSP that it should exit its execute phase
+ * function.
+ */
+DSP_STATUS NODE_Terminate(struct NODE_OBJECT *hNode, OUT DSP_STATUS *pStatus)
+{
+ struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode;
+ struct NODE_MGR *hNodeMgr = NULL;
+ enum NODE_TYPE nodeType;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ enum NODE_STATE state;
+ struct DSP_MSG msg, killmsg;
+ DSP_STATUS status = DSP_SOK;
+ u32 procId, killTimeOut;
+ struct DEH_MGR *hDehMgr;
+ struct DSP_PROCESSORSTATE procStatus;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pStatus != NULL);
+
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Terminate: hNode: 0x%x\n", hNode);
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ if (pNode->hProcessor == NULL) {
+ GT_1trace(NODE_debugMask, GT_4CLASS,
+ "NODE_Terminate: pNode->hProcessor = 0x%x\n",
+ pNode->hProcessor);
+ goto func_end;
+ }
+ status = PROC_GetProcessorId(pNode->hProcessor, &procId);
+
+ if (DSP_SUCCEEDED(status)) {
+ hNodeMgr = hNode->hNodeMgr;
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_TASK && nodeType !=
+ NODE_DAISSOCKET)
+ status = DSP_ENODETYPE;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Check node state */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ if (DSP_SUCCEEDED(status)) {
+ state = NODE_GetState(hNode);
+ if (state != NODE_RUNNING) {
+ status = DSP_EWRONGSTATE;
+ /* Set the exit status if node terminated on
+ * its own. */
+ if (state == NODE_DONE)
+ *pStatus = hNode->nExitStatus;
+
+ } else {
+ NODE_SetState(hNode, NODE_TERMINATING);
+ }
+ }
+ /* end of SYNC_EnterCS */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /*
+ * Send exit message. Do not change state to NODE_DONE
+ * here. That will be done in callback.
+ */
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_Terminate: env = 0x%x\n", hNode->nodeEnv);
+
+ status = PROC_GetState(pNode->hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_cont;
+ /* If processor is in error state then don't attempt to send
+ * A kill task command */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Terminate:"
+ " proc Status 0x%x\n", procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_cont;
+ }
+
+ msg.dwCmd = RMS_EXIT;
+ msg.dwArg1 = hNode->nodeEnv;
+ killmsg.dwCmd = RMS_KILLTASK;
+ killmsg.dwArg1 = hNode->nodeEnv;
+ pIntfFxns = hNodeMgr->pIntfFxns;
+
+ if (hNode->uTimeout > MAXTIMEOUT)
+ killTimeOut = MAXTIMEOUT;
+ else
+ killTimeOut = (hNode->uTimeout)*2;
+
+ status = (*pIntfFxns->pfnMsgPut)(hNode->hMsgQueue, &msg,
+ hNode->uTimeout);
+ if (DSP_SUCCEEDED(status)) {
+ /* Wait on synchronization object that will be
+ * posted in the callback on receiving RMS_EXIT
+ * message, or by NODE_Delete. Check for valid hNode,
+ * in case posted by NODE_Delete(). */
+ status = SYNC_WaitOnEvent(hNode->hSyncDone,
+ killTimeOut/2);
+ if (DSP_FAILED(status)) {
+ if (status == DSP_ETIMEOUT) {
+ status = (*pIntfFxns->pfnMsgPut)
+ (hNode->hMsgQueue, &killmsg,
+ hNode->uTimeout);
+ if (DSP_SUCCEEDED(status)) {
+ status = SYNC_WaitOnEvent
+ (hNode->hSyncDone,
+ killTimeOut/2);
+ if (DSP_FAILED(status)) {
+ /* Here it goes the part
+ * of the simulation of
+ * the DSP exception */
+ DEV_GetDehMgr(hNodeMgr->
+ hDevObject, &hDehMgr);
+ if (hDehMgr) {
+ (*pIntfFxns->
+ pfnDehNotify)(hDehMgr,
+ DSP_SYSERROR,
+ DSP_EXCEPTIONABORT);
+ status = DSP_EFAIL;
+ }
+ } else
+ status = DSP_SOK;
+ }
+ } else
+ status = DSP_EFAIL;
+ } else /* Convert SYNC status to DSP status */
+ status = DSP_SOK;
+ }
+ }
+func_cont:
+ if (DSP_SUCCEEDED(status)) {
+ /* Enter CS before getting exit status, in case node was
+ * deleted. */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+ /* Make sure node wasn't deleted while we blocked */
+ if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) {
+ status = DSP_EFAIL;
+ } else {
+ *pStatus = hNode->nExitStatus;
+ GT_1trace(NODE_debugMask, GT_ENTER,
+ "NODE_Terminate: env = 0x%x "
+ "succeeded.\n", hNode->nodeEnv);
+ }
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ } /*End of SYNC_EnterCS */
+func_end:
+ return status;
+}
+
+/*
+ * ======== DeleteNode ========
+ * Purpose:
+ * Free GPP resources allocated in NODE_Allocate() or NODE_Connect().
+ */
+static void DeleteNode(struct NODE_OBJECT *hNode)
+{
+ struct NODE_MGR *hNodeMgr;
+ struct CMM_XLATOROBJECT *hXlator;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ u32 i;
+ enum NODE_TYPE nodeType;
+ struct STREAM stream;
+ struct NODE_MSGARGS msgArgs;
+ struct NODE_TASKARGS taskArgs;
+#ifdef DSP_DMM_DEBUG
+ struct DMM_OBJECT *hDmmMgr;
+ struct PROC_OBJECT *pProcObject =
+ (struct PROC_OBJECT *)hNode->hProcessor;
+#endif
+ DSP_STATUS status;
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ hNodeMgr = hNode->hNodeMgr;
+ if (!MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE))
+ return;
+ hXlator = hNode->hXlator;
+ nodeType = NODE_GetType(hNode);
+ if (nodeType != NODE_DEVICE) {
+ msgArgs = hNode->createArgs.asa.msgArgs;
+ if (msgArgs.pData)
+ MEM_Free(msgArgs.pData);
+
+ /* Free MSG queue */
+ if (hNode->hMsgQueue) {
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ (*pIntfFxns->pfnMsgDeleteQueue) (hNode->hMsgQueue);
+ hNode->hMsgQueue = NULL;
+
+ }
+ if (hNode->hSyncDone)
+ (void) SYNC_CloseEvent(hNode->hSyncDone);
+
+ /* Free all stream info */
+ if (hNode->inputs) {
+ for (i = 0; i < MaxInputs(hNode); i++) {
+ stream = hNode->inputs[i];
+ FreeStream(hNodeMgr, stream);
+ }
+ MEM_Free(hNode->inputs);
+ hNode->inputs = NULL;
+ }
+ if (hNode->outputs) {
+ for (i = 0; i < MaxOutputs(hNode); i++) {
+ stream = hNode->outputs[i];
+ FreeStream(hNodeMgr, stream);
+ }
+ MEM_Free(hNode->outputs);
+ hNode->outputs = NULL;
+ }
+ taskArgs = hNode->createArgs.asa.taskArgs;
+ if (taskArgs.strmInDef) {
+ for (i = 0; i < MaxInputs(hNode); i++) {
+ if (taskArgs.strmInDef[i].szDevice) {
+ MEM_Free(taskArgs.strmInDef[i].
+ szDevice);
+ taskArgs.strmInDef[i].szDevice = NULL;
+ }
+ }
+ MEM_Free(taskArgs.strmInDef);
+ taskArgs.strmInDef = NULL;
+ }
+ if (taskArgs.strmOutDef) {
+ for (i = 0; i < MaxOutputs(hNode); i++) {
+ if (taskArgs.strmOutDef[i].szDevice) {
+ MEM_Free(taskArgs.strmOutDef[i].
+ szDevice);
+ taskArgs.strmOutDef[i].szDevice = NULL;
+ }
+ }
+ MEM_Free(taskArgs.strmOutDef);
+ taskArgs.strmOutDef = NULL;
+ }
+ if (taskArgs.uDSPHeapResAddr) {
+ status = PROC_UnMap(hNode->hProcessor,
+ (void *)taskArgs.uDSPHeapAddr);
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(NODE_debugMask, GT_5CLASS,
+ "DSPProcessor_UnMap succeeded.\n");
+ } else {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "DSPProcessor_UnMap failed."
+ " Status = 0x%x\n", (u32)status);
+ }
+ status = PROC_UnReserveMemory(hNode->hProcessor,
+ (void *)taskArgs.uDSPHeapResAddr);
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(NODE_debugMask, GT_5CLASS,
+ "DSPProcessor_UnReserveMemory "
+ "succeeded.\n");
+ } else {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "DSPProcessor_UnReserveMemory "
+ "failed. Status = 0x%x\n",
+ (u32)status);
+ }
+#ifdef DSP_DMM_DEBUG
+ status = DMM_GetHandle(pProcObject, &hDmmMgr);
+ if (DSP_SUCCEEDED(status))
+ DMM_MemMapDump(hDmmMgr);
+#endif
+ }
+ }
+ if (nodeType != NODE_MESSAGE) {
+ if (hNode->streamConnect) {
+ MEM_Free(hNode->streamConnect);
+ hNode->streamConnect = NULL;
+ }
+ }
+ if (hNode->pstrDevName) {
+ MEM_Free(hNode->pstrDevName);
+ hNode->pstrDevName = NULL;
+ }
+
+ if (hNode->hNtfy) {
+ NTFY_Delete(hNode->hNtfy);
+ hNode->hNtfy = NULL;
+ }
+
+ /* These were allocated in DCD_GetObjectDef (via NODE_Allocate) */
+ if (hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn) {
+ MEM_Free(hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn);
+ hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn = NULL;
+ }
+
+ if (hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn) {
+ MEM_Free(hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn);
+ hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn = NULL;
+ }
+
+ if (hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn) {
+ MEM_Free(hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn);
+ hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn = NULL;
+ }
+
+ if (hNode->dcdProps.objData.nodeObj.pstrIAlgName) {
+ MEM_Free(hNode->dcdProps.objData.nodeObj.pstrIAlgName);
+ hNode->dcdProps.objData.nodeObj.pstrIAlgName = NULL;
+ }
+
+ /* Free all SM address translator resources */
+ if (hXlator) {
+ (void) CMM_XlatorDelete(hXlator, TRUE); /* force free */
+ hXlator = NULL;
+ }
+
+ if (hNode->hNldrNode) {
+ hNodeMgr->nldrFxns.pfnFree(hNode->hNldrNode);
+ hNode->hNldrNode = NULL;
+ }
+
+ MEM_FreeObject(hNode);
+ hNode = NULL;
+}
+
+/*
+ * ======== DeleteNodeMgr ========
+ * Purpose:
+ * Frees the node manager.
+ */
+static void DeleteNodeMgr(struct NODE_MGR *hNodeMgr)
+{
+ struct NODE_OBJECT *hNode;
+
+ if (MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)) {
+ /* Free resources */
+ if (hNodeMgr->hDcdMgr)
+ DCD_DestroyManager(hNodeMgr->hDcdMgr);
+
+ /* Remove any elements remaining in lists */
+ if (hNodeMgr->nodeList) {
+ while ((hNode =
+ (struct NODE_OBJECT *)LST_GetHead(hNodeMgr->
+ nodeList)))
+ DeleteNode(hNode);
+
+ DBC_Assert(LST_IsEmpty(hNodeMgr->nodeList));
+ LST_Delete(hNodeMgr->nodeList);
+ }
+ if (hNodeMgr->hNtfy)
+ NTFY_Delete(hNodeMgr->hNtfy);
+
+ if (hNodeMgr->pipeMap)
+ GB_delete(hNodeMgr->pipeMap);
+
+ if (hNodeMgr->pipeDoneMap)
+ GB_delete(hNodeMgr->pipeDoneMap);
+
+ if (hNodeMgr->chnlMap)
+ GB_delete(hNodeMgr->chnlMap);
+
+ if (hNodeMgr->dmaChnlMap)
+ GB_delete(hNodeMgr->dmaChnlMap);
+
+ if (hNodeMgr->zChnlMap)
+ GB_delete(hNodeMgr->zChnlMap);
+
+ if (hNodeMgr->hDisp)
+ DISP_Delete(hNodeMgr->hDisp);
+
+ if (hNodeMgr->hSync)
+ SYNC_DeleteCS(hNodeMgr->hSync);
+
+ if (hNodeMgr->hStrmMgr)
+ STRM_Delete(hNodeMgr->hStrmMgr);
+
+ /* Delete the loader */
+ if (hNodeMgr->hNldr)
+ hNodeMgr->nldrFxns.pfnDelete(hNodeMgr->hNldr);
+
+ if (hNodeMgr->fLoaderInit)
+ hNodeMgr->nldrFxns.pfnExit();
+
+ MEM_FreeObject(hNodeMgr);
+ }
+}
+
+/*
+ * ======== FillStreamConnect ========
+ * Purpose:
+ * Fills stream information.
+ */
+static void FillStreamConnect(struct NODE_OBJECT *hNode1,
+ struct NODE_OBJECT *hNode2,
+ u32 uStream1, u32 uStream2)
+{
+ u32 uStrmIndex;
+ struct DSP_STREAMCONNECT *pStrm1 = NULL;
+ struct DSP_STREAMCONNECT *pStrm2 = NULL;
+ enum NODE_TYPE node1Type = NODE_TASK;
+ enum NODE_TYPE node2Type = NODE_TASK;
+
+ node1Type = NODE_GetType(hNode1);
+ node2Type = NODE_GetType(hNode2);
+ if (hNode1 != (struct NODE_OBJECT *)DSP_HGPPNODE) {
+
+ if (node1Type != NODE_DEVICE) {
+ uStrmIndex = hNode1->uNumInputs +
+ hNode1->uNumOutputs - 1;
+ pStrm1 = &(hNode1->streamConnect[uStrmIndex]);
+ pStrm1->cbStruct = sizeof(struct DSP_STREAMCONNECT);
+ pStrm1->uThisNodeStreamIndex = uStream1;
+ }
+
+ if (hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE) {
+ /* NODE == > NODE */
+ if (node1Type != NODE_DEVICE) {
+ pStrm1->hConnectedNode = hNode2;
+ pStrm1->uiConnectedNodeID = hNode2->nodeId;
+ pStrm1->uConnectedNodeStreamIndex = uStream2;
+ pStrm1->lType = CONNECTTYPE_NODEOUTPUT;
+ }
+ if (node2Type != NODE_DEVICE) {
+ uStrmIndex = hNode2->uNumInputs +
+ hNode2->uNumOutputs - 1;
+ pStrm2 = &(hNode2->streamConnect[uStrmIndex]);
+ pStrm2->cbStruct =
+ sizeof(struct DSP_STREAMCONNECT);
+ pStrm2->uThisNodeStreamIndex = uStream2;
+ pStrm2->hConnectedNode = hNode1;
+ pStrm2->uiConnectedNodeID = hNode1->nodeId;
+ pStrm2->uConnectedNodeStreamIndex = uStream1;
+ pStrm2->lType = CONNECTTYPE_NODEINPUT;
+ }
+ } else if (node1Type != NODE_DEVICE)
+ pStrm1->lType = CONNECTTYPE_GPPOUTPUT;
+ } else {
+ /* GPP == > NODE */
+ DBC_Assert(hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE);
+ uStrmIndex = hNode2->uNumInputs + hNode2->uNumOutputs - 1;
+ pStrm2 = &(hNode2->streamConnect[uStrmIndex]);
+ pStrm2->cbStruct = sizeof(struct DSP_STREAMCONNECT);
+ pStrm2->uThisNodeStreamIndex = uStream2;
+ pStrm2->lType = CONNECTTYPE_GPPINPUT;
+ }
+}
+
+/*
+ * ======== FillStreamDef ========
+ * Purpose:
+ * Fills Stream attributes.
+ */
+static void FillStreamDef(struct NODE_OBJECT *hNode,
+ struct NODE_STRMDEF *pstrmDef,
+ struct DSP_STRMATTR *pAttrs)
+{
+ struct NODE_MGR *hNodeMgr = hNode->hNodeMgr;
+
+ if (pAttrs != NULL) {
+ pstrmDef->uNumBufs = pAttrs->uNumBufs;
+ pstrmDef->uBufsize = pAttrs->uBufsize / hNodeMgr->
+ uDSPDataMauSize;
+ pstrmDef->uSegid = pAttrs->uSegid;
+ pstrmDef->uAlignment = pAttrs->uAlignment;
+ pstrmDef->uTimeout = pAttrs->uTimeout;
+ } else {
+ pstrmDef->uNumBufs = DEFAULTNBUFS;
+ pstrmDef->uBufsize = DEFAULTBUFSIZE / hNodeMgr->
+ uDSPDataMauSize;
+ pstrmDef->uSegid = DEFAULTSEGID;
+ pstrmDef->uAlignment = DEFAULTALIGNMENT;
+ pstrmDef->uTimeout = DEFAULTTIMEOUT;
+ }
+}
+
+/*
+ * ======== FreeStream ========
+ * Purpose:
+ * Updates the channel mask and frees the pipe id.
+ */
+static void FreeStream(struct NODE_MGR *hNodeMgr, struct STREAM stream)
+{
+ /* Free up the pipe id unless other node has not yet been deleted. */
+ if (stream.type == NODECONNECT) {
+ if (GB_test(hNodeMgr->pipeDoneMap, stream.devId)) {
+ /* The other node has already been deleted */
+ GB_clear(hNodeMgr->pipeDoneMap, stream.devId);
+ GB_clear(hNodeMgr->pipeMap, stream.devId);
+ } else {
+ /* The other node has not been deleted yet */
+ GB_set(hNodeMgr->pipeDoneMap, stream.devId);
+ }
+ } else if (stream.type == HOSTCONNECT) {
+ if (stream.devId < hNodeMgr->ulNumChnls) {
+ GB_clear(hNodeMgr->chnlMap, stream.devId);
+ } else if (stream.devId < (2 * hNodeMgr->ulNumChnls)) {
+ /* dsp-dma */
+ GB_clear(hNodeMgr->dmaChnlMap, stream.devId -
+ (1 * hNodeMgr->ulNumChnls));
+ } else if (stream.devId < (3 * hNodeMgr->ulNumChnls)) {
+ /* zero-copy */
+ GB_clear(hNodeMgr->zChnlMap, stream.devId -
+ (2 * hNodeMgr->ulNumChnls));
+ }
+ }
+}
+
+/*
+ * ======== GetFxnAddress ========
+ * Purpose:
+ * Retrieves the address for create, execute or delete phase for a node.
+ */
+static DSP_STATUS GetFxnAddress(struct NODE_OBJECT *hNode, u32 *pulFxnAddr,
+ u32 uPhase)
+{
+ char *pstrFxnName = NULL;
+ struct NODE_MGR *hNodeMgr = hNode->hNodeMgr;
+ DSP_STATUS status = DSP_SOK;
+ DBC_Require(NODE_GetType(hNode) == NODE_TASK ||
+ NODE_GetType(hNode) == NODE_DAISSOCKET ||
+ NODE_GetType(hNode) == NODE_MESSAGE);
+
+ switch (uPhase) {
+ case CREATEPHASE:
+ pstrFxnName = hNode->dcdProps.objData.nodeObj.
+ pstrCreatePhaseFxn;
+ break;
+ case EXECUTEPHASE:
+ pstrFxnName = hNode->dcdProps.objData.nodeObj.
+ pstrExecutePhaseFxn;
+ break;
+ case DELETEPHASE:
+ pstrFxnName = hNode->dcdProps.objData.nodeObj.
+ pstrDeletePhaseFxn;
+ break;
+ default:
+ /* Should never get here */
+ DBC_Assert(false);
+ break;
+ }
+
+ status = hNodeMgr->nldrFxns.pfnGetFxnAddr(hNode->hNldrNode, pstrFxnName,
+ pulFxnAddr);
+
+ return status;
+}
+
+/*
+ * ======== GetNodeInfo ========
+ * Purpose:
+ * Retrieves the node information.
+ */
+void GetNodeInfo(struct NODE_OBJECT *hNode, struct DSP_NODEINFO *pNodeInfo)
+{
+ u32 i;
+
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ DBC_Require(pNodeInfo != NULL);
+
+ pNodeInfo->cbStruct = sizeof(struct DSP_NODEINFO);
+ pNodeInfo->nbNodeDatabaseProps = hNode->dcdProps.objData.nodeObj.
+ ndbProps;
+ pNodeInfo->uExecutionPriority = hNode->nPriority;
+ pNodeInfo->hDeviceOwner = hNode->hDeviceOwner;
+ pNodeInfo->uNumberStreams = hNode->uNumInputs + hNode->uNumOutputs;
+ pNodeInfo->uNodeEnv = hNode->nodeEnv;
+
+ pNodeInfo->nsExecutionState = NODE_GetState(hNode);
+
+ /* Copy stream connect data */
+ for (i = 0; i < hNode->uNumInputs + hNode->uNumOutputs; i++)
+ pNodeInfo->scStreamConnection[i] = hNode->streamConnect[i];
+
+}
+
+/*
+ * ======== GetNodeProps ========
+ * Purpose:
+ * Retrieve node properties.
+ */
+static DSP_STATUS GetNodeProps(struct DCD_MANAGER *hDcdMgr,
+ struct NODE_OBJECT *hNode,
+ CONST struct DSP_UUID *pNodeId,
+ struct DCD_GENERICOBJ *pdcdProps)
+{
+ u32 uLen;
+ struct NODE_MSGARGS *pMsgArgs;
+ struct NODE_TASKARGS *pTaskArgs;
+ enum NODE_TYPE nodeType = NODE_TASK;
+ struct DSP_NDBPROPS *pndbProps = &(pdcdProps->objData.nodeObj.ndbProps);
+ DSP_STATUS status = DSP_SOK;
+#ifdef DEBUG
+ char szUuid[MAXUUIDLEN];
+#endif
+
+ status = DCD_GetObjectDef(hDcdMgr, (struct DSP_UUID *)pNodeId,
+ DSP_DCDNODETYPE, pdcdProps);
+
+ if (DSP_SUCCEEDED(status)) {
+ hNode->nType = nodeType = pndbProps->uNodeType;
+
+#ifdef DEBUG
+ /* Create UUID value to set in registry. */
+ UUID_UuidToString((struct DSP_UUID *)pNodeId, szUuid,
+ MAXUUIDLEN);
+ DBG_Trace(DBG_LEVEL7, "\n** (node) UUID: %s\n", szUuid);
+#endif
+
+ /* Fill in message args that come from NDB */
+ if (nodeType != NODE_DEVICE) {
+ pMsgArgs = &(hNode->createArgs.asa.msgArgs);
+ pMsgArgs->uSegid = pdcdProps->objData.nodeObj.uMsgSegid;
+ pMsgArgs->uNotifyType = pdcdProps->objData.nodeObj.
+ uMsgNotifyType;
+ pMsgArgs->uMaxMessages = pndbProps->uMessageDepth;
+#ifdef DEBUG
+ DBG_Trace(DBG_LEVEL7,
+ "** (node) Max Number of Messages: 0x%x\n",
+ pMsgArgs->uMaxMessages);
+#endif
+ } else {
+ /* Copy device name */
+ DBC_Require(pndbProps->acName);
+ uLen = strlen(pndbProps->acName);
+ DBC_Assert(uLen < MAXDEVNAMELEN);
+ hNode->pstrDevName = MEM_Calloc(uLen + 1, MEM_PAGED);
+ if (hNode->pstrDevName == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ strncpy(hNode->pstrDevName,
+ pndbProps->acName, uLen);
+ }
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Fill in create args that come from NDB */
+ if (nodeType == NODE_TASK || nodeType == NODE_DAISSOCKET) {
+ pTaskArgs = &(hNode->createArgs.asa.taskArgs);
+ pTaskArgs->nPriority = pndbProps->iPriority;
+ pTaskArgs->uStackSize = pndbProps->uStackSize;
+ pTaskArgs->uSysStackSize = pndbProps->uSysStackSize;
+ pTaskArgs->uStackSeg = pndbProps->uStackSeg;
+#ifdef DEBUG
+ DBG_Trace(DBG_LEVEL7,
+ "** (node) Priority: 0x%x\n" "** (node) Stack"
+ " Size: 0x%x words\n" "** (node) System Stack"
+ " Size: 0x%x words\n" "** (node) Stack"
+ " Segment: 0x%x\n\n",
+ "** (node) profile count : 0x%x \n \n",
+ pTaskArgs->nPriority, pTaskArgs->uStackSize,
+ pTaskArgs->uSysStackSize,
+ pTaskArgs->uStackSeg,
+ pndbProps->uCountProfiles);
+#endif
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== GetProcProps ========
+ * Purpose:
+ * Retrieve the processor properties.
+ */
+static DSP_STATUS GetProcProps(struct NODE_MGR *hNodeMgr,
+ struct DEV_OBJECT *hDevObject)
+{
+ struct CFG_DEVNODE *hDevNode;
+ struct CFG_HOSTRES hostRes;
+ DSP_STATUS status = DSP_SOK;
+
+ status = DEV_GetDevNode(hDevObject, &hDevNode);
+ if (DSP_SUCCEEDED(status))
+ status = CFG_GetHostResources(hDevNode, &hostRes);
+
+ if (DSP_SUCCEEDED(status)) {
+ hNodeMgr->ulChnlOffset = hostRes.dwChnlOffset;
+ hNodeMgr->ulChnlBufSize = hostRes.dwChnlBufSize;
+ hNodeMgr->ulNumChnls = hostRes.dwNumChnls;
+
+ /*
+ * PROC will add an API to get DSP_PROCESSORINFO.
+ * Fill in default values for now.
+ */
+ /* TODO -- Instead of hard coding, take from registry */
+ hNodeMgr->procFamily = 6000;
+ hNodeMgr->procType = 6410;
+ hNodeMgr->nMinPri = DSP_NODE_MIN_PRIORITY;
+ hNodeMgr->nMaxPri = DSP_NODE_MAX_PRIORITY;
+ hNodeMgr->uDSPWordSize = DSPWORDSIZE;
+ hNodeMgr->uDSPDataMauSize = DSPWORDSIZE;
+ hNodeMgr->uDSPMauSize = 1;
+
+ }
+ return status;
+}
+
+
+
+/*
+ * ======== NODE_GetUUIDProps ========
+ * Purpose:
+ * Fetch Node UUID properties from DCD/DOF file.
+ */
+DSP_STATUS NODE_GetUUIDProps(DSP_HPROCESSOR hProcessor,
+ IN CONST struct DSP_UUID *pNodeId,
+ OUT struct DSP_NDBPROPS *pNodeProps)
+{
+ struct NODE_MGR *hNodeMgr = NULL;
+ struct DEV_OBJECT *hDevObject;
+ DSP_STATUS status = DSP_SOK;
+ struct DCD_NODEPROPS dcdNodeProps;
+ struct DSP_PROCESSORSTATE procStatus;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hProcessor != NULL);
+ DBC_Require(pNodeId != NULL);
+
+ if (hProcessor == NULL || pNodeId == NULL) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ status = PROC_GetState(hProcessor, &procStatus,
+ sizeof(struct DSP_PROCESSORSTATE));
+ if (DSP_FAILED(status))
+ goto func_end;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (procStatus.iState == PROC_ERROR) {
+ GT_1trace(NODE_debugMask, GT_5CLASS,
+ "NODE_GetUUIDProps: proc Status 0x%x\n",
+ procStatus.iState);
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+
+ GT_3trace(NODE_debugMask, GT_ENTER,
+ "NODE_GetUUIDProps: " "\thProcessor: "
+ "0x%x\tpNodeId: 0x%x" "\tpNodeProps: 0x%x\n", hProcessor,
+ pNodeId, pNodeProps);
+
+ status = PROC_GetDevObject(hProcessor, &hDevObject);
+ if (DSP_SUCCEEDED(status) && hDevObject != NULL) {
+ status = DEV_GetNodeManager(hDevObject, &hNodeMgr);
+ if (hNodeMgr == NULL) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ }
+
+ /*
+ * Enter the critical section. This is needed because
+ * DCD_GetObjectDef will ultimately end up calling DBLL_open/close,
+ * which needs to be protected in order to not corrupt the zlib manager
+ * (COD).
+ */
+ status = SYNC_EnterCS(hNodeMgr->hSync);
+
+ if (DSP_SUCCEEDED(status)) {
+ dcdNodeProps.pstrCreatePhaseFxn = NULL;
+ dcdNodeProps.pstrExecutePhaseFxn = NULL;
+ dcdNodeProps.pstrDeletePhaseFxn = NULL;
+ dcdNodeProps.pstrIAlgName = NULL;
+
+ status = DCD_GetObjectDef(hNodeMgr->hDcdMgr,
+ (struct DSP_UUID *) pNodeId,
+ DSP_DCDNODETYPE,
+ (struct DCD_GENERICOBJ *) &dcdNodeProps);
+ if (DSP_SUCCEEDED(status)) {
+ *pNodeProps = dcdNodeProps.ndbProps;
+ if (dcdNodeProps.pstrCreatePhaseFxn)
+ MEM_Free(dcdNodeProps.pstrCreatePhaseFxn);
+
+ if (dcdNodeProps.pstrExecutePhaseFxn)
+ MEM_Free(dcdNodeProps.pstrExecutePhaseFxn);
+
+ if (dcdNodeProps.pstrDeletePhaseFxn)
+ MEM_Free(dcdNodeProps.pstrDeletePhaseFxn);
+
+ if (dcdNodeProps.pstrIAlgName)
+ MEM_Free(dcdNodeProps.pstrIAlgName);
+ }
+ /* Leave the critical section, we're done. */
+ (void)SYNC_LeaveCS(hNodeMgr->hSync);
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== GetRMSFxns ========
+ * Purpose:
+ * Retrieve the RMS functions.
+ */
+static DSP_STATUS GetRMSFxns(struct NODE_MGR *hNodeMgr)
+{
+ s32 i;
+ struct DEV_OBJECT *hDev = hNodeMgr->hDevObject;
+ DSP_STATUS status = DSP_SOK;
+
+ static char *pszFxns[NUMRMSFXNS] = {
+ "RMS_queryServer", /* RMSQUERYSERVER */
+ "RMS_configureServer", /* RMSCONFIGURESERVER */
+ "RMS_createNode", /* RMSCREATENODE */
+ "RMS_executeNode", /* RMSEXECUTENODE */
+ "RMS_deleteNode", /* RMSDELETENODE */
+ "RMS_changeNodePriority", /* RMSCHANGENODEPRIORITY */
+ "RMS_readMemory", /* RMSREADMEMORY */
+ "RMS_writeMemory", /* RMSWRITEMEMORY */
+ "RMS_copy", /* RMSCOPY */
+ };
+
+ for (i = 0; i < NUMRMSFXNS; i++) {
+ status = DEV_GetSymbol(hDev, pszFxns[i],
+ &(hNodeMgr->ulFxnAddrs[i]));
+ if (DSP_FAILED(status)) {
+ if (status == COD_E_SYMBOLNOTFOUND) {
+ /*
+ * May be loaded dynamically (in the future),
+ * but return an error for now.
+ */
+ GT_1trace(NODE_debugMask, GT_6CLASS,
+ "RMS function: %s "
+ "currently not loaded\n", pszFxns[i]);
+ } else {
+ GT_2trace(NODE_debugMask, GT_6CLASS,
+ "GetRMSFxns: Symbol not "
+ "found: %s\tstatus = 0x%x\n",
+ pszFxns[i], status);
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== Ovly ========
+ * Purpose:
+ * Called during overlay.Sends command to RMS to copy a block of data.
+ */
+static u32 Ovly(void *pPrivRef, u32 ulDspRunAddr, u32 ulDspLoadAddr,
+ u32 ulNumBytes, u32 nMemSpace)
+{
+ struct NODE_OBJECT *hNode = (struct NODE_OBJECT *)pPrivRef;
+ struct NODE_MGR *hNodeMgr;
+ u32 ulBytes = 0;
+ u32 ulSize;
+ u32 ulTimeout;
+ DSP_STATUS status = DSP_SOK;
+ struct WMD_DEV_CONTEXT *hWmdContext;
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+
+ hNodeMgr = hNode->hNodeMgr;
+
+ ulSize = ulNumBytes / hNodeMgr->uDSPWordSize;
+ ulTimeout = hNode->uTimeout;
+
+ /* Call new MemCopy function */
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ status = DEV_GetWMDContext(hNodeMgr->hDevObject, &hWmdContext);
+ status = (*pIntfFxns->pfnBrdMemCopy)(hWmdContext, ulDspRunAddr,
+ ulDspLoadAddr, ulNumBytes, (u32) nMemSpace);
+
+ if (DSP_SUCCEEDED(status))
+ ulBytes = ulNumBytes;
+
+ return ulBytes;
+}
+
+/*
+ * ======== Write ========
+ */
+static u32 Write(void *pPrivRef, u32 ulDspAddr, void *pBuf,
+ u32 ulNumBytes, u32 nMemSpace)
+{
+ struct NODE_OBJECT *hNode = (struct NODE_OBJECT *) pPrivRef;
+ struct NODE_MGR *hNodeMgr;
+ u16 memType;
+ u32 ulTimeout;
+ DSP_STATUS status = DSP_SOK;
+ struct WMD_DEV_CONTEXT *hWmdContext;
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+
+ DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE));
+ DBC_Require(nMemSpace & DBLL_CODE || nMemSpace & DBLL_DATA);
+
+ hNodeMgr = hNode->hNodeMgr;
+
+ ulTimeout = hNode->uTimeout;
+ memType = (nMemSpace & DBLL_CODE) ? RMS_CODE : RMS_DATA;
+
+ /* Call new MemWrite function */
+ pIntfFxns = hNodeMgr->pIntfFxns;
+ status = DEV_GetWMDContext(hNodeMgr->hDevObject, &hWmdContext);
+ status = (*pIntfFxns->pfnBrdMemWrite) (hWmdContext, pBuf, ulDspAddr,
+ ulNumBytes, memType);
+
+ return ulNumBytes;
+}
+
diff --git a/drivers/dsp/bridge/rmgr/proc.c b/drivers/dsp/bridge/rmgr/proc.c
new file mode 100755
index 000000000000..34d29696a6b2
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/proc.c
@@ -0,0 +1,2111 @@
+/*
+ * proc.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== proc.c ========
+ * Description:
+ * Processor interface at the driver level.
+ *
+ * Public Functions:
+ * PROC_Attach
+ * PROC_Ctrl
+ * PROC_Detach
+ * PROC_EnumNodes
+ * PROC_GetResourceInfo
+ * PROC_Exit
+ * PROC_FlushMemory
+ * PROC_GetState
+ * PROC_GetProcessorId
+ * PROC_GetTrace
+ * PROC_Init
+ * PROC_Load
+ * PROC_Map
+ * PROC_NotifyClients
+ * PROC_RegisterNotify
+ * PROC_ReserveMemory
+ * PROC_Start
+ * PROC_UnMap
+ * PROC_UnReserveMemory
+ * PROC_InvalidateMemory
+
+ *! Revision History
+ *! ======== ========
+ *! 04-Apr-2007 sh Added PROC_InvalidateMemory API
+ *! 19-Apr-2004 sb Aligned DMM definitions with Symbian
+ *! Used MEM_FlushCache instead of OS specific API
+ *! Integrated Alan's code review updates
+ *! 08-Mar-2004 sb Added the Dynamic Memory Mapping feature
+ *! 08-Mar-2004 vp Added g_pszLastCoff member to PROC_OBJECT.
+ *! This is required for multiprocessor environment.
+ *! 09-Feb-2004 vp Added PROC_GetProcessorID function
+ *! 22-Apr-2003 vp Fixed issue with the string that stores coff file name
+ *! 03-Apr-2003 sb Fix DEH deregistering bug
+ *! 26-Mar-2003 vp Commented the call to DSP deep sleep in PROC_Start function.
+ *! 18-Feb-2003 vp Code review updates.
+ *! 18-Oct-2002 vp Ported to Linux platform.
+ *! 22-May-2002 sg Do IOCTL-to-PWR translation before calling PWR_SleepDSP.
+ *! 14-May-2002 sg Use CSL_Atoi() instead of atoi().
+ *! 13-May-2002 sg Propagate PWR return codes upwards.
+ *! 07-May-2002 sg Added check for, and call to PWR functions in PROC_Ctrl.
+ *! 02-May-2002 sg Added "nap" mode: put DSP to sleep once booted.
+ *! 01-Apr-2002 jeh Assume word addresses in PROC_GetTrace().
+ *! 29-Nov-2001 jeh Don't call DEH function if hDehMgr == NULL.
+ *! 05-Nov-2001 kc: Updated PROC_RegisterNotify and PROC_GetState to support
+ *! DEH module.
+ *! 09-Oct-2001 jeh Fix number of bytes calculated in PROC_GetTrace().
+ *! 11-Sep-2001 jeh Delete MSG manager in PROC_Monitor() to fix memory leak.
+ *! 29-Aug-2001 rr: DCD_AutoRegister and IOOnLoaded moved before COD_LoadBase
+ *! to facilitate the external loading.
+ *! 14-Aug-2001 ag DCD_AutoRegister() now called before IOOnLoaded() fxn.
+ *! 21-Jun-2001 rr: MSG_Create is done only the first time.
+ *! 02-May-2001 jeh Return failure in PROC_Load if IOOnLoaded function returns
+ *! error other than E_NOTIMPL.
+ *! 03-Apr-2001 sg: Changed DSP_DCD_ENOAUTOREGISTER to DSP_EDCDNOAUTOREGISTER.
+ *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates.
+ *! 05-Jan-2001 rr: PROC_LOAD MSG_Create error is checked.
+ *! 15-Dec-2000 rr: IoOnLoaded is checked for WSX_STATUS. We fail to load
+ *! if DEV_Create2 fails; ie, no non-RMS targets can be
+ *! loaded.
+ *! 12-Dec-2000 rr: PROC_Start's DEV_Create2 is checked for WSX_STATUS.
+ *! 28-Nov-2000 jeh Added call to IO OnLoaded function to PROC_Load().
+ *! 29-Nov-2000 rr: Incorporated code review changes.
+ *! 03-Nov-2000 rr: Auto_Register happens after PROC_Load.
+ *! 06-Oct-2000 rr: Updated to ver 0.9. PROC_Start calls DEV_Create2 and
+ *! WMD_BRD_STOP is always followed by DEV_Destroy2.
+ *! 05-Sep-2000 rr: PROC_GetTrace calculates the Trace symbol for 55 in a
+ *! different way.
+ *! 10-Aug-2000 rr: PROC_NotifyClients, PROC_GetProcessorHandle Added
+ *! 07-Aug-2000 rr: PROC_IDLE/SYNCINIT/UNKNOWN state removed.
+ *! WMD fxns are checked for WSX_STATUS.
+ *! PROC_Attach does not alter the state of the BRD.
+ *! PROC_Run removed.
+ *! 04-Aug-2000 rr: All the functions return DSP_EHANDLE if proc handle is
+ *! invalid
+ *! 27-Jul-2000 rr: PROC_GetTrace and PROC_Load implemented. Updated to
+ *! ver 0.8 API.
+ *! 06-Jul-2000 rr: Created.
+ */
+
+/* ------------------------------------ Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/csl.h>
+#include <dspbridge/list.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/ntfy.h>
+#include <dspbridge/sync.h>
+/* ----------------------------------- Mini Driver */
+#include <dspbridge/wmd.h>
+#include <dspbridge/wmddeh.h>
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/procpriv.h>
+#include <dspbridge/dmm.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/mgr.h>
+#include <dspbridge/node.h>
+#include <dspbridge/nldr.h>
+#include <dspbridge/rmm.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/dbreg.h>
+#include <dspbridge/msg.h>
+#include <dspbridge/wmdioctl.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/proc.h>
+#include <dspbridge/pwr.h>
+#ifdef CONFIG_PM
+#include <mach-omap2/omap3-opp.h>
+#endif
+
+#ifndef RES_CLEANUP_DISABLE
+#include <dspbridge/resourcecleanup.h>
+#endif
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define PROC_SIGNATURE 0x434F5250 /* "PROC" (in reverse). */
+#define MAXCMDLINELEN 255
+#define PROC_ENVPROCID "PROC_ID=%d"
+#define MAXPROCIDLEN (8 + 5)
+#define PROC_DFLT_TIMEOUT 10000 /* Time out in milliseconds */
+#define PWR_TIMEOUT 500 /* Sleep/wake timout in msec */
+#define EXTEND "_EXT_END" /* Extmem end addr in DSP binary */
+
+#ifdef OMAP44XX
+/* Start address of memory for dynamic mapping */
+const u32 DEXTMEMMAP_BEG = 0x30000000 ;
+
+/* End address of memory for dynamic mapping */
+
+const u32 DEXTMEMMAP_END = 0x40000000 ;
+#endif
+
+extern char *iva_img;
+
+/* The PROC_OBJECT structure. */
+struct PROC_OBJECT {
+ struct LST_ELEM link; /* Link to next PROC_OBJECT */
+ u32 dwSignature; /* Used for object validation */
+ struct DEV_OBJECT *hDevObject; /* Device this PROC represents */
+ u32 hProcess; /* Process owning this Processor */
+ struct MGR_OBJECT *hMgrObject; /* Manager Object Handle */
+ u32 uAttachCount; /* Processor attach count */
+ u32 uProcessor; /* Processor number */
+ u32 uTimeout; /* Time out count */
+ enum DSP_PROCSTATE sState; /* Processor state */
+ u32 ulUnit; /* DDSP unit number */
+ bool bIsAlreadyAttached; /*
+ * True if the Device below has
+ * GPP Client attached
+ */
+ struct NTFY_OBJECT *hNtfy; /* Manages notifications */
+ struct WMD_DEV_CONTEXT *hWmdContext; /* WMD Context Handle */
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+ char *g_pszLastCoff;
+} ;
+
+/* ----------------------------------- Globals */
+#if GT_TRACE
+static struct GT_Mask PROC_DebugMask = { NULL, NULL }; /* WCD MGR Mask */
+#endif
+
+static u32 cRefs;
+
+struct SYNC_CSOBJECT *hProcLock; /* For critical sections */
+
+#ifndef CONFIG_DISABLE_BRIDGE_PM
+#ifndef CONFIG_DISABLE_BRIDGE_DVFS
+#ifdef status = DSP_EFAILo CONFIG_OMAP3_PM
+extern struct constraint_handle *mpu_constraint_handle;
+#endif
+#endif
+#endif
+
+
+/* ----------------------------------- Function Prototypes */
+static DSP_STATUS PROC_Monitor(struct PROC_OBJECT *hProcessor);
+static s32 GetEnvpCount(char **envp);
+static char **PrependEnvp(char **newEnvp, char **envp, s32 cEnvp, s32 cNewEnvp,
+ char *szVar);
+
+/*
+ * ======== PROC_CleanupAllResources =====
+ * Purpose:
+ * Funtion to clean the process resources.
+ * This function is intended to be called when the
+ * processor is in error state
+ */
+DSP_STATUS PROC_CleanupAllResources(void)
+{
+ DSP_STATUS dsp_status = DSP_SOK;
+ HANDLE hDrvObject = NULL;
+ struct PROCESS_CONTEXT *pCtxtclosed = NULL;
+ GT_0trace(PROC_DebugMask, GT_ENTER, "PROC_CleanupAllResources\n");
+ dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(dsp_status))
+ goto func_end;
+ DRV_GetProcCtxtList(&pCtxtclosed, (struct DRV_OBJECT *)hDrvObject);
+ while (pCtxtclosed != NULL) {
+ if (current->pid != pCtxtclosed->pid) {
+ GT_1trace(PROC_DebugMask, GT_5CLASS,
+ "***Cleanup of "
+ "process***%d\n", pCtxtclosed->pid);
+ if (pCtxtclosed->hProcessor)
+ PROC_Detach(pCtxtclosed->hProcessor);
+ }
+ pCtxtclosed = pCtxtclosed->next;
+ }
+ WMD_DEH_ReleaseDummyMem();
+func_end:
+ return dsp_status;
+}
+
+/*
+ * ======== PROC_Attach ========
+ * Purpose:
+ * Prepare for communication with a particular DSP processor, and return
+ * a handle to the processor object.
+ */
+DSP_STATUS
+PROC_Attach(u32 uProcessor, OPTIONAL CONST struct DSP_PROCESSORATTRIN *pAttrIn,
+ OUT DSP_HPROCESSOR *phProcessor)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct DEV_OBJECT *hDevObject;
+ struct PROC_OBJECT *pProcObject = NULL;
+ struct MGR_OBJECT *hMgrObject = NULL;
+ struct DRV_OBJECT *hDrvObject = NULL;
+ u32 devType;
+
+#ifndef RES_CLEANUP_DISABLE
+ HANDLE hDRVObject;
+ u32 hProcess;
+ DSP_STATUS res_status = DSP_SOK;
+ struct PROCESS_CONTEXT *pPctxt = NULL;
+#endif
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(phProcessor != NULL);
+
+ GT_3trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Attach, args:\n\t"
+ "uProcessor: 0x%x\n\tpAttrIn: 0x%x\n\tphProcessor:"
+ "0x%x\n", uProcessor, pAttrIn, phProcessor);
+ /* Get the Driver and Manager Object Handles */
+ status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(status)) {
+ status = CFG_GetObject((u32 *)&hMgrObject, REG_MGR_OBJECT);
+ if (DSP_FAILED(status)) {
+ /* don't propogate CFG errors from this PROC function */
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: DSP_FAILED to get"
+ "the Manager Object.\n", status);
+ }
+ } else {
+ /* don't propogate CFG errors from this PROC function */
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: failed to get the"
+ " DriverObject, 0x%x!\n", status);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Get the Device Object */
+ status = DRV_GetDevObject(uProcessor, hDrvObject, &hDevObject);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: failed to get"
+ " DevObject, 0x%x!\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetDevType(hDevObject, &devType);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: failed to get"
+ " DevType, 0x%x!\n", status);
+ }
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* If we made it this far, create the Proceesor object: */
+ MEM_AllocObject(pProcObject, struct PROC_OBJECT, PROC_SIGNATURE);
+ /* Fill out the Processor Object: */
+ if (pProcObject == NULL) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach:Out of memeory \n");
+ status = DSP_EFAIL;
+ goto func_end;
+ }
+ pProcObject->hDevObject = hDevObject;
+ pProcObject->hMgrObject = hMgrObject;
+ pProcObject->uProcessor = devType;
+ /* Get Caller Process and store it */
+ /* Return PID instead of process handle */
+ pProcObject->hProcess = current->pid;
+
+ if (pAttrIn)
+ pProcObject->uTimeout = pAttrIn->uTimeout;
+ else
+ pProcObject->uTimeout = PROC_DFLT_TIMEOUT;
+
+ status = DEV_GetIntfFxns(hDevObject, &pProcObject->pIntfFxns);
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetWMDContext(hDevObject,
+ &pProcObject->hWmdContext);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach Could not"
+ " get the WMD Context.\n", status);
+ MEM_FreeObject(pProcObject);
+ }
+ } else {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach Could not get"
+ " the DEV_ Interface fxns.\n", status);
+ MEM_FreeObject(pProcObject);
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Create the Notification Object */
+ /* This is created with no event mask, no notify mask
+ * and no valid handle to the notification. They all get
+ * filled up when PROC_RegisterNotify is called */
+ status = NTFY_Create(&pProcObject->hNtfy);
+ if (DSP_SUCCEEDED(status)) {
+ /* Insert the Processor Object into the DEV List.
+ * Return handle to this Processor Object:
+ * Find out if the Device is already attached to a
+ * Processor. If so, return AlreadyAttached status */
+ LST_InitElem(&pProcObject->link);
+ status = DEV_InsertProcObject(pProcObject->hDevObject,
+ (u32)pProcObject,
+ &pProcObject->bIsAlreadyAttached);
+ if (DSP_SUCCEEDED(status)) {
+ if (pProcObject->bIsAlreadyAttached) {
+ status = DSP_SALREADYATTACHED;
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Attach: Processor "
+ "Already Attached!\n");
+ }
+ } else {
+ if (pProcObject->hNtfy)
+ NTFY_Delete(pProcObject->hNtfy);
+
+ MEM_FreeObject(pProcObject);
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: failed to insert "
+ "Proc Object into DEV, 0x%x!\n", status);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ *phProcessor = (DSP_HPROCESSOR)pProcObject;
+ (void)PROC_NotifyClients(pProcObject,
+ DSP_PROCESSORATTACH);
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Attach: Processor "
+ "Attach Success!\n");
+ }
+ } else {
+ /* Don't leak memory if DSP_FAILED */
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Attach: Could not allocate "
+ "storage for notification \n");
+ MEM_FreeObject(pProcObject);
+ }
+func_end:
+#ifndef RES_CLEANUP_DISABLE
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(res_status))
+ goto func_cont;
+
+ DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDRVObject,
+ &pPctxt, NULL, 0);
+ if (pPctxt == NULL) {
+ DRV_InsertProcContext((struct DRV_OBJECT *)hDRVObject, &pPctxt);
+ if (pPctxt != NULL) {
+ DRV_ProcUpdatestate(pPctxt, PROC_RES_ALLOCATED);
+ DRV_ProcSetPID(pPctxt, hProcess);
+ }
+ }
+func_cont:
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDRVObject, &pPctxt,
+ NULL, 0);
+ if (pPctxt != NULL)
+ pPctxt->hProcessor = (DSP_HPROCESSOR)*phProcessor;
+
+ }
+#endif
+ DBC_Ensure((status == DSP_EFAIL && *phProcessor == NULL) ||
+ (DSP_SUCCEEDED(status) &&
+ MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) ||
+ (status == DSP_SALREADYATTACHED &&
+ MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)));
+ GT_2trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Attach, results:\n\t"
+ "status: 0x%x\n\thProcessor: 0x%x\n", status, *phProcessor);
+
+ return status;
+}
+
+static DSP_STATUS GetExecFile(struct CFG_DEVNODE *hDevNode,
+ struct DEV_OBJECT *hDevObject,
+ u32 size, char *execFile)
+{
+ s32 devType;
+ s32 len;
+
+ DEV_GetDevType(hDevObject, (u32 *) &devType);
+ if (devType == DSP_UNIT) {
+ return CFG_GetExecFile(hDevNode, size, execFile);
+ } else if (devType == IVA_UNIT) {
+ if (iva_img) {
+ len = strlen(iva_img);
+ strncpy(execFile, iva_img, len + 1);
+ return DSP_SOK;
+ }
+ }
+ return DSP_EFILE;
+}
+
+/*
+ * ======== PROC_AutoStart ======== =
+ * Purpose:
+ * A Particular device gets loaded with the default image
+ * if the AutoStart flag is set.
+ * Parameters:
+ * hDevObject: Handle to the Device
+ * Returns:
+ * DSP_SOK: On Successful Loading
+ * DSP_EFAIL General Failure
+ * Requires:
+ * hDevObject != NULL
+ * Ensures:
+ */
+DSP_STATUS PROC_AutoStart(struct CFG_DEVNODE *hDevNode,
+ struct DEV_OBJECT *hDevObject)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ u32 dwAutoStart = 0; /* autostart flag */
+ struct PROC_OBJECT *pProcObject;
+ struct PROC_OBJECT *hProcObject;
+ char szExecFile[MAXCMDLINELEN];
+ char *argv[2];
+ struct MGR_OBJECT *hMgrObject = NULL;
+ s32 devType;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hDevNode != NULL);
+ DBC_Require(hDevObject != NULL);
+
+ GT_2trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_AutoStart, args:\n\t"
+ "hDevNode: 0x%x\thDevObject: 0x%x\n", hDevNode, hDevObject);
+ /* Create a Dummy PROC Object */
+ if (DSP_FAILED(CFG_GetObject((u32 *)&hMgrObject,
+ REG_MGR_OBJECT))) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: DSP_FAILED to "
+ "Get MGR Object\n");
+ goto func_end;
+ }
+ MEM_AllocObject(pProcObject, struct PROC_OBJECT, PROC_SIGNATURE);
+ if (pProcObject == NULL) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: DSP_FAILED "
+ "to Create a dummy Processor\n");
+ goto func_end;
+ }
+ GT_0trace(PROC_DebugMask, GT_1CLASS, "NTFY Created \n");
+ pProcObject->hDevObject = hDevObject;
+ pProcObject->hMgrObject = hMgrObject;
+ hProcObject = pProcObject;
+ if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject,
+ &pProcObject->pIntfFxns))) {
+ if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject,
+ &pProcObject->hWmdContext))) {
+ status = DSP_SOK;
+ } else {
+ MEM_FreeObject(hProcObject);
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: Failed "
+ "to get WMD Context \n");
+ }
+ } else {
+ MEM_FreeObject(hProcObject);
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: Failed to "
+ "get IntFxns \n");
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Stop the Device, put it into standby mode */
+ status = PROC_Stop(hProcObject);
+ if (DSP_FAILED(CFG_GetAutoStart(hDevNode, &dwAutoStart)) ||
+ !dwAutoStart) {
+ status = DSP_EFAIL;
+ /* DSP_FAILED to Get s32 Fxn or Wmd Context */
+ GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_AutoStart: "
+ "CFG_GetAutoStart DSP_FAILED \n");
+ goto func_cont;
+ }
+ /* Get the default executable for this board... */
+ DEV_GetDevType(hDevObject, (u32 *)&devType);
+ pProcObject->uProcessor = devType;
+ if (DSP_SUCCEEDED(GetExecFile(hDevNode, hDevObject,
+ sizeof(szExecFile), szExecFile))) {
+ argv[0] = szExecFile;
+ argv[1] = NULL;
+ /* ...and try to load it: */
+ status = PROC_Load(hProcObject, 1, (CONST char **)argv, NULL);
+ if (DSP_SUCCEEDED(status)) {
+ status = PROC_Start(hProcObject);
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_AutoStart: Processor started "
+ "running\n");
+ } else {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: DSP_FAILED To "
+ "Start \n");
+ }
+ } else {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_AutoStart: DSP_FAILED to Load\n");
+ }
+ } else {
+ status = DSP_EFILE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_AutoStart: "
+ "No Exec file found \n");
+ }
+func_cont:
+ MEM_FreeObject(hProcObject);
+func_end:
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Exiting PROC_AutoStart, status:0x%x\n", status);
+ return status;
+}
+
+/*
+ * ======== PROC_Ctrl ========
+ * Purpose:
+ * Pass control information to the GPP device driver managing the
+ * DSP processor.
+ *
+ * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
+ * application developer's API.
+ * Call the WMD_ICOTL Fxn with the Argument This is a Synchronous
+ * Operation. arg can be null.
+ */
+DSP_STATUS PROC_Ctrl(DSP_HPROCESSOR hProcessor, u32 dwCmd,
+ IN struct DSP_CBDATA *arg)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = hProcessor;
+ u32 timeout = 0;
+
+ DBC_Require(cRefs > 0);
+ GT_3trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_Ctrl, args:\n\thProcessor:"
+ " 0x%x\n\tdwCmd: 0x%x\n\targ: 0x%x\n", hProcessor, dwCmd, arg);
+
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ /* intercept PWR deep sleep command */
+ if (dwCmd == WMDIOCTL_DEEPSLEEP) {
+ timeout = arg->cbData;
+ status = PWR_SleepDSP(PWR_DEEPSLEEP, timeout);
+ }
+ /* intercept PWR emergency sleep command */
+ else if (dwCmd == WMDIOCTL_EMERGENCYSLEEP) {
+ timeout = arg->cbData;
+ status = PWR_SleepDSP(PWR_EMERGENCYDEEPSLEEP, timeout);
+ } else if (dwCmd == PWR_DEEPSLEEP) {
+ /* timeout = arg->cbData; */
+ status = PWR_SleepDSP(PWR_DEEPSLEEP, timeout);
+ }
+ /* intercept PWR wake commands */
+ else if (dwCmd == WMDIOCTL_WAKEUP) {
+ timeout = arg->cbData;
+ status = PWR_WakeDSP(timeout);
+ } else if (dwCmd == PWR_WAKEUP) {
+ /* timeout = arg->cbData; */
+ status = PWR_WakeDSP(timeout);
+ } else
+ if (DSP_SUCCEEDED
+ ((*pProcObject->pIntfFxns->pfnDevCntrl)
+ (pProcObject->hWmdContext, dwCmd, arg))) {
+ status = DSP_SOK;
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Ctrl: Failed \n");
+ }
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Ctrl: InValid Processor Handle \n");
+ }
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Ctrl, 0x%x\n",
+ status);
+ return status;
+}
+
+/*
+ * ======== PROC_Detach ========
+ * Purpose:
+ * Destroys the Processor Object. Removes the notification from the Dev
+ * List.
+ */
+DSP_STATUS PROC_Detach(DSP_HPROCESSOR hProcessor)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+#ifndef RES_CLEANUP_DISABLE
+ HANDLE hDRVObject;
+ u32 hProcess;
+ DSP_STATUS res_status = DSP_SOK;
+ struct PROCESS_CONTEXT *pPctxt = NULL;
+#endif
+ DBC_Require(cRefs > 0);
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Detach, args:\n\t"
+ "hProcessor: 0x%x\n", hProcessor);
+
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+#ifndef RES_CLEANUP_DISABLE
+ /* Return PID instead of process handle */
+ hProcess = pProcObject->hProcess;
+ res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDRVObject, &pPctxt,
+ NULL, 0);
+ if (pPctxt != NULL) {
+ DRV_RemoveAllResources(pPctxt);
+ pPctxt->hProcessor = NULL;
+ }
+ }
+#endif
+ /* Notify the Client */
+ NTFY_Notify(pProcObject->hNtfy, DSP_PROCESSORDETACH);
+ /* Remove the notification memory */
+ if (pProcObject->hNtfy)
+ NTFY_Delete(pProcObject->hNtfy);
+
+ if (pProcObject->g_pszLastCoff) {
+ MEM_Free(pProcObject->g_pszLastCoff);
+ pProcObject->g_pszLastCoff = NULL;
+ }
+ /* Remove the Proc from the DEV List */
+ (void)DEV_RemoveProcObject(pProcObject->hDevObject,
+ (u32)pProcObject);
+ /* Free the Processor Object */
+ MEM_FreeObject(pProcObject);
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Detach: InValid Processor Handle \n");
+ }
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Detach, 0x%x\n",
+ status);
+ return status;
+}
+
+/*
+ * ======== PROC_EnumNodes ========
+ * Purpose:
+ * Enumerate and get configuration information about nodes allocated
+ * on a DSP processor.
+ */
+DSP_STATUS PROC_EnumNodes(DSP_HPROCESSOR hProcessor, OUT DSP_HNODE *aNodeTab,
+ IN u32 uNodeTabSize, OUT u32 *puNumNodes,
+ OUT u32 *puAllocated)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct NODE_MGR *hNodeMgr = NULL;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(aNodeTab != NULL || uNodeTabSize == 0);
+ DBC_Require(puNumNodes != NULL);
+ DBC_Require(puAllocated != NULL);
+
+ GT_5trace(PROC_DebugMask, GT_ENTER, "Entered PROC_EnumNodes, args:\n\t"
+ "hProcessor: 0x%x\n\taNodeTab: 0x%x\n\tuNodeTabSize: "
+ " 0x%x\n\t puNumNodes 0x%x\n\t puAllocated: 0x%x\n",
+ hProcessor, aNodeTab, uNodeTabSize, puNumNodes,
+ puAllocated);
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ if (DSP_SUCCEEDED(DEV_GetNodeManager(pProcObject->hDevObject,
+ &hNodeMgr))) {
+ if (hNodeMgr) {
+ status = NODE_EnumNodes(hNodeMgr, aNodeTab,
+ uNodeTabSize,
+ puNumNodes,
+ puAllocated);
+ }
+ }
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_EnumNodes: "
+ "InValid Processor Handle \n");
+ }
+ GT_6trace(PROC_DebugMask, GT_ENTER, "Exit PROC_EnumNodes, args:\n\t"
+ "hProcessor: 0x%x\n\taNodeTab: 0x%x\n\tuNodeTabSize: "
+ " 0x%x\n\t puNumNodes 0x%x\n\t puAllocated: 0x%x\n\t "
+ "status: 0x%x \n", hProcessor, aNodeTab, uNodeTabSize,
+ puNumNodes, puAllocated, status);
+
+ return status;
+}
+
+/*
+ * ======== PROC_FlushMemory ========
+ * Purpose:
+ * Flush cache
+ */
+DSP_STATUS PROC_FlushMemory(DSP_HPROCESSOR hProcessor, void *pMpuAddr,
+ u32 ulSize, u32 ulFlags)
+{
+ /* Keep STATUS here for future additions to this function */
+ DSP_STATUS status = DSP_SOK;
+ enum DSP_FLUSHTYPE FlushMemType = PROC_WRITEBACK_INVALIDATE_MEM;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ DBC_Require(cRefs > 0);
+
+ GT_4trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_FlushMemory, args:\n\t"
+ "hProcessor: 0x%x pMpuAddr: 0x%x ulSize 0x%x, ulFlags 0x%x\n",
+ hProcessor, pMpuAddr, ulSize, ulFlags);
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ /* Critical section */
+ (void)SYNC_EnterCS(hProcLock);
+ MEM_FlushCache(pMpuAddr, ulSize, FlushMemType);
+ (void)SYNC_LeaveCS(hProcLock);
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_FlushMemory: "
+ "InValid Processor Handle \n");
+ }
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_FlushMemory [0x%x]",
+ status);
+ return status;
+}
+
+
+/*
+ * ======== PROC_InvalidateMemory ========
+ * Purpose:
+ * Invalidates the memory specified
+ */
+DSP_STATUS PROC_InvalidateMemory(DSP_HPROCESSOR hProcessor, void *pMpuAddr,
+ u32 ulSize)
+{
+ /* Keep STATUS here for future additions to this function */
+ DSP_STATUS status = DSP_SOK;
+ enum DSP_FLUSHTYPE FlushMemType = PROC_INVALIDATE_MEM;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ DBC_Require(cRefs > 0);
+ GT_3trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_InvalidateMemory, args:\n\t"
+ "hProcessor: 0x%x pMpuAddr: 0x%x ulSize 0x%x\n", hProcessor,
+ pMpuAddr, ulSize);
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ (void)SYNC_EnterCS(hProcLock);
+ MEM_FlushCache(pMpuAddr, ulSize, FlushMemType);
+ (void)SYNC_LeaveCS(hProcLock);
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_InvalidateMemory: "
+ "InValid Processor Handle \n");
+ }
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Leaving PROC_InvalidateMemory [0x%x]", status);
+ return status;
+}
+
+/*
+ * ======== PROC_GetResourceInfo ========
+ * Purpose:
+ * Enumerate the resources currently available on a processor.
+ */
+DSP_STATUS PROC_GetResourceInfo(DSP_HPROCESSOR hProcessor, u32 uResourceType,
+ OUT struct DSP_RESOURCEINFO *pResourceInfo,
+ u32 uResourceInfoSize)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct NODE_MGR *hNodeMgr = NULL;
+ struct NLDR_OBJECT *hNldr = NULL;
+ struct RMM_TargetObj *rmm = NULL;
+ struct IO_MGR *hIOMgr = NULL; /* IO manager handle */
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pResourceInfo != NULL);
+ DBC_Require(uResourceInfoSize >= sizeof(struct DSP_RESOURCEINFO));
+
+ GT_4trace(PROC_DebugMask, GT_ENTER, "Entered PROC_GetResourceInfo,\n\t"
+ "hProcessor: 0x%x\n\tuResourceType: 0x%x\n\tpResourceInfo:"
+ " 0x%x\n\t uResourceInfoSize 0x%x\n", hProcessor,
+ uResourceType, pResourceInfo, uResourceInfoSize);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_GetResourceInfo: InValid "
+ "Processor Handle \n");
+ goto func_end;
+ }
+ switch (uResourceType) {
+ case DSP_RESOURCE_DYNDARAM:
+ case DSP_RESOURCE_DYNSARAM:
+ case DSP_RESOURCE_DYNEXTERNAL:
+ case DSP_RESOURCE_DYNSRAM:
+ if (DSP_FAILED(DEV_GetNodeManager(pProcObject->hDevObject,
+ &hNodeMgr)))
+ goto func_end;
+
+ if (DSP_SUCCEEDED(NODE_GetNldrObj(hNodeMgr, &hNldr))) {
+ if (DSP_SUCCEEDED(NLDR_GetRmmManager(hNldr, &rmm))) {
+ DBC_Assert(rmm != NULL);
+ status = DSP_EVALUE;
+ if (RMM_stat(rmm,
+ (enum DSP_MEMTYPE)uResourceType,
+ (struct DSP_MEMSTAT *)&(pResourceInfo->
+ result.memStat)))
+ status = DSP_SOK;
+ }
+ }
+ break;
+ case DSP_RESOURCE_PROCLOAD:
+ status = DEV_GetIOMgr(pProcObject->hDevObject, &hIOMgr);
+ status = pProcObject->pIntfFxns->pfnIOGetProcLoad(hIOMgr,
+ (struct DSP_PROCLOADSTAT *)&(pResourceInfo->
+ result.procLoadStat));
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "Error in procLoadStat function 0x%x\n", status);
+ }
+ break;
+ default:
+ status = DSP_EFAIL;
+ break;
+ }
+func_end:
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_GetResourceInfo, "
+ "status 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ======== PROC_Exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ */
+void PROC_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ if (hProcLock)
+ (void)SYNC_DeleteCS(hProcLock);
+
+ cRefs--;
+
+ GT_1trace(PROC_DebugMask, GT_5CLASS,
+ "Entered PROC_Exit, ref count:0x%x\n", cRefs);
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== PROC_GetDevObject ========
+ * Purpose:
+ * Return the Dev Object handle for a given Processor.
+ *
+ */
+DSP_STATUS PROC_GetDevObject(DSP_HPROCESSOR hProcessor,
+ struct DEV_OBJECT **phDevObject)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(phDevObject != NULL);
+
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ *phDevObject = pProcObject->hDevObject;
+ status = DSP_SOK;
+ } else {
+ *phDevObject = NULL;
+ status = DSP_EHANDLE;
+ }
+
+ DBC_Ensure((DSP_SUCCEEDED(status) && *phDevObject != NULL) ||
+ (DSP_FAILED(status) && *phDevObject == NULL));
+
+ return status;
+}
+
+/*
+ * ======== PROC_GetState ========
+ * Purpose:
+ * Report the state of the specified DSP processor.
+ */
+DSP_STATUS PROC_GetState(DSP_HPROCESSOR hProcessor,
+ OUT struct DSP_PROCESSORSTATE *pProcStatus,
+ u32 uStateInfoSize)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ BRD_STATUS brdStatus;
+ struct DEH_MGR *hDehMgr;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pProcStatus != NULL);
+ DBC_Require(uStateInfoSize >= sizeof(struct DSP_PROCESSORSTATE));
+
+ GT_3trace(PROC_DebugMask, GT_ENTER, "Entering PROC_GetState, args:\n\t"
+ "pProcStatus: 0x%x\n\thProcessor: 0x%x\n\t uStateInfoSize"
+ " 0x%x\n", pProcStatus, hProcessor, uStateInfoSize);
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ /* First, retrieve BRD state information */
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus)
+ (pProcObject->hWmdContext, &brdStatus))) {
+ switch (brdStatus) {
+ case BRD_STOPPED:
+ pProcStatus->iState = PROC_STOPPED;
+ break;
+ case BRD_DSP_HIBERNATION:
+ /* Fall through */
+ case BRD_RUNNING:
+ pProcStatus->iState = PROC_RUNNING;
+ break;
+ case BRD_LOADED:
+ pProcStatus->iState = PROC_LOADED;
+ break;
+ case BRD_ERROR:
+ pProcStatus->iState = PROC_ERROR;
+ break;
+ default:
+ pProcStatus->iState = 0xFF;
+ status = DSP_EFAIL;
+ break;
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_GetState: General Failure"
+ " to read the PROC Status \n");
+ }
+ /* Next, retrieve error information, if any */
+ status = DEV_GetDehMgr(pProcObject->hDevObject, &hDehMgr);
+ if (DSP_SUCCEEDED(status) && hDehMgr) {
+ status = (*pProcObject->pIntfFxns->pfnDehGetInfo)
+ (hDehMgr, &(pProcStatus->errInfo));
+ if (DSP_FAILED(status)) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_GetState: Failed "
+ "retrieve exception info.\n");
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_GetState: Failed to "
+ "retrieve DEH handle.\n");
+ }
+ } else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_GetState:InValid Processor Handle \n");
+ }
+ GT_2trace(PROC_DebugMask, GT_ENTER,
+ "Exiting PROC_GetState, results:\n\t"
+ "status: 0x%x\n\tpProcStatus: 0x%x\n", status,
+ pProcStatus->iState);
+ return status;
+}
+
+/*
+ * ======== PROC_GetTrace ========
+ * Purpose:
+ * Retrieve the current contents of the trace buffer, located on the
+ * Processor. Predefined symbols for the trace buffer must have been
+ * configured into the DSP executable.
+ * Details:
+ * We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
+ * trace buffer, only. Treat it as an undocumented feature.
+ * This call is destructive, meaning the processor is placed in the monitor
+ * state as a result of this function.
+ */
+DSP_STATUS PROC_GetTrace(DSP_HPROCESSOR hProcessor, u8 *pBuf, u32 uMaxSize)
+{
+ DSP_STATUS status;
+ status = DSP_ENOTIMPL;
+ return status;
+}
+
+/*
+ * ======== PROC_Init ========
+ * Purpose:
+ * Initialize PROC's private state, keeping a reference count on each call
+ */
+bool PROC_Init(void)
+{
+ bool fRetval = true;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+ /* Set the Trace mask */
+ DBC_Assert(!PROC_DebugMask.flags);
+ GT_create(&PROC_DebugMask, "PR"); /* "PR" for Processor */
+
+ (void)SYNC_InitializeCS(&hProcLock);
+ }
+
+ if (fRetval)
+ cRefs++;
+
+ GT_1trace(PROC_DebugMask, GT_5CLASS,
+ "Entered PROC_Init, ref count:0x%x\n", cRefs);
+ DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0)));
+
+ return fRetval;
+}
+
+/*
+ * ======== PROC_Load ========
+ * Purpose:
+ * Reset a processor and load a new base program image.
+ * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
+ * application developer's API.
+ */
+DSP_STATUS PROC_Load(DSP_HPROCESSOR hProcessor, IN CONST s32 iArgc,
+ IN CONST char **aArgv, IN CONST char **aEnvp)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct IO_MGR *hIOMgr; /* IO manager handle */
+ struct MSG_MGR *hMsgMgr;
+ struct COD_MANAGER *hCodMgr; /* Code manager handle */
+ char *pargv0; /* temp argv[0] ptr */
+ char **newEnvp; /* Updated envp[] array. */
+ char szProcID[MAXPROCIDLEN]; /* Size of "PROC_ID=<n>" */
+ s32 cEnvp; /* Num elements in envp[]. */
+ s32 cNewEnvp; /* " " in newEnvp[] */
+ s32 nProcID = 0; /* Anticipate MP version. */
+ struct DCD_MANAGER *hDCDHandle;
+ struct DMM_OBJECT *hDmmMgr;
+
+#ifdef OMAP_3430
+ u32 dwExtEnd;
+#endif
+ u32 uProcId;
+
+#ifdef OMAP44XX
+ u32 dwDmmStart;
+#endif
+
+#ifdef DEBUG
+ BRD_STATUS uBrdState;
+#endif
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ struct timeval tv1;
+ struct timeval tv2;
+#endif
+ DBC_Require(cRefs > 0);
+ DBC_Require(iArgc > 0);
+ DBC_Require(aArgv != NULL);
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ do_gettimeofday(&tv1);
+#endif
+
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+#endif
+ GT_2trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Load, args:\n\t"
+ "hProcessor: 0x%x\taArgv: 0x%x\n", hProcessor, aArgv[0]);
+ /* Call the WMD_BRD_Load Fxn */
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Load: Invalid Processor Handle..\n");
+ goto func_end;
+ }
+ if (pProcObject->bIsAlreadyAttached) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load GPP "
+ "Client is already attached status \n");
+ }
+ if (DSP_FAILED(DEV_GetCodMgr(pProcObject->hDevObject, &hCodMgr))) {
+ status = DSP_EFAIL;
+ GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_Load: DSP_FAILED in "
+ "DEV_GetCodMgr status 0x%x \n", status);
+ goto func_end;
+ }
+ status = PROC_Stop(hProcessor);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: DSP_FAILED to Place the"
+ " Processor in Stop Mode(PROC_STOP) status 0x%x \n",
+ status);
+ goto func_end;
+ }
+ /* Place the board in the monitor state. */
+ status = PROC_Monitor(hProcessor);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: DSP_FAILED to Place the"
+ " Processor in Monitor Mode(PROC_IDLE) status 0x%x\n",
+ status);
+ goto func_end;
+ }
+ /* Save ptr to original argv[0]. */
+ pargv0 = (char *)aArgv[0];
+ /*Prepend "PROC_ID=<nProcID>"to envp array for target.*/
+ cEnvp = GetEnvpCount((char **)aEnvp);
+ cNewEnvp = (cEnvp ? (cEnvp + 1) : (cEnvp + 2));
+ newEnvp = MEM_Calloc(cNewEnvp * sizeof(char **), MEM_PAGED);
+ if (newEnvp) {
+ status = snprintf(szProcID, MAXPROCIDLEN, PROC_ENVPROCID,
+ nProcID);
+ if (status == -1) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Load: "
+ "Proc ID string overflow \n");
+ status = DSP_EFAIL;
+ } else {
+ newEnvp = PrependEnvp(newEnvp, (char **)aEnvp, cEnvp,
+ cNewEnvp, szProcID);
+ /* Get the DCD Handle */
+ status = MGR_GetDCDHandle(pProcObject->hMgrObject,
+ (u32 *)&hDCDHandle);
+ if (DSP_SUCCEEDED(status)) {
+ /* Before proceeding with new load,
+ * check if a previously registered COFF
+ * exists.
+ * If yes, unregister nodes in previously
+ * registered COFF. If any error occurred,
+ * set previously registered COFF to NULL. */
+ if (pProcObject->g_pszLastCoff != NULL) {
+ status = DCD_AutoUnregister(hDCDHandle,
+ pProcObject->g_pszLastCoff);
+ /* Regardless of auto unregister status,
+ * free previously allocated
+ * memory. */
+ MEM_Free(pProcObject->g_pszLastCoff);
+ pProcObject->g_pszLastCoff = NULL;
+ }
+ }
+ /* On success, do COD_OpenBase() */
+ status = COD_OpenBase(hCodMgr, (char *)aArgv[0],
+ COD_SYMB);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: COD_OpenBase "
+ "failed (0x%x)\n", status);
+ }
+ }
+ } else {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ " PROC_Load:Out of Memory \n");
+ status = DSP_EMEMORY;
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Auto-register data base */
+ /* Get the DCD Handle */
+ status = MGR_GetDCDHandle(pProcObject->hMgrObject,
+ (u32 *)&hDCDHandle);
+ if (DSP_SUCCEEDED(status)) {
+ /* Auto register nodes in specified COFF
+ * file. If registration did not fail,
+ * (status = DSP_SOK or DSP_EDCDNOAUTOREGISTER)
+ * save the name of the COFF file for
+ * de-registration in the future. */
+ status = DCD_AutoRegister(hDCDHandle, (char *)aArgv[0]);
+ if (status == DSP_EDCDNOAUTOREGISTER) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: No Auto "
+ "Register section. Proceeding..\n");
+ status = DSP_SOK;
+ }
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: Failed to "
+ "Auto Register..\n");
+ } else {
+ DBC_Assert(pProcObject->g_pszLastCoff == NULL);
+ /* Allocate memory for pszLastCoff */
+ pProcObject->g_pszLastCoff = MEM_Calloc(
+ (strlen((char *)aArgv[0]) + 1),
+ MEM_PAGED);
+ /* If memory allocated, save COFF file name*/
+ if (pProcObject->g_pszLastCoff) {
+ strncpy(pProcObject->g_pszLastCoff,
+ (char *)aArgv[0],
+ (strlen((char *)aArgv[0]) + 1));
+ }
+ }
+ }
+ }
+ /* Update shared memory address and size */
+ if (DSP_SUCCEEDED(status)) {
+ /* Create the message manager. This must be done
+ * before calling the IOOnLoaded function. */
+ DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr);
+ if (!hMsgMgr) {
+ status = MSG_Create(&hMsgMgr, pProcObject->hDevObject,
+ (MSG_ONEXIT)NODE_OnExit);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ DEV_SetMsgMgr(pProcObject->hDevObject, hMsgMgr);
+ }
+ if (status == DSP_ENOTIMPL) {
+ /* It's OK not to have a message manager */
+ status = DSP_SOK;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Set the Device object's message manager */
+ status = DEV_GetIOMgr(pProcObject->hDevObject, &hIOMgr);
+ DBC_Assert(DSP_SUCCEEDED(status));
+ status = (*pProcObject->pIntfFxns->pfnIOOnLoaded)(hIOMgr);
+ if (status == DSP_ENOTIMPL) {
+ /* Ok not to implement this function */
+ status = DSP_SOK;
+ } else {
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: Failed to get shared "
+ "memory or message buffer address "
+ "from COFF status 0x%x\n", status);
+ status = DSP_EFAIL;
+ }
+ }
+ } else {
+ status = DSP_EFAIL;
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: DSP_FAILED in "
+ "MSG_Create status 0x%x\n", status);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Now, attempt to load an exec: */
+
+ /* Boost the OPP level to Maximum level supported by baseport*/
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP5]);
+#endif
+ status = COD_LoadBase(hCodMgr, iArgc, (char **)aArgv,
+ DEV_BrdWriteFxn,
+ pProcObject->hDevObject, NULL);
+ if (DSP_FAILED(status)) {
+ if (status == COD_E_OPENFAILED) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load:Failure to Load the EXE\n");
+ }
+ if (status == COD_E_SYMBOLNOTFOUND) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load:Could not parse the file\n");
+ } else {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: DSP_FAILED in "
+ "COD_Load status 0x%x \n", status);
+ }
+ }
+ /* Requesting the lowest opp supported*/
+#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP1]);
+#endif
+
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Update the Processor status to loaded */
+ status = (*pProcObject->pIntfFxns->pfnBrdSetState)
+ (pProcObject->hWmdContext, BRD_LOADED);
+ if (DSP_SUCCEEDED(status)) {
+ pProcObject->sState = PROC_LOADED;
+ if (pProcObject->hNtfy) {
+ PROC_NotifyClients(pProcObject,
+ DSP_PROCESSORSTATECHANGE);
+ }
+ } else {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load, pfnBrdSetState "
+ "failed: 0x%x\n", status);
+ status = DSP_EFAIL;
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = PROC_GetProcessorId(hProcessor, &uProcId);
+ if (uProcId == DSP_UNIT) {
+ /* Use all available DSP address space after EXTMEM
+ * for DMM */
+ if (DSP_SUCCEEDED(status)) {
+#ifdef OMAP_3430
+ status = COD_GetSymValue(hCodMgr, EXTEND,
+ &dwExtEnd);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Load: Failed on "
+ "COD_GetSymValue %s.\n",
+ EXTEND);
+ }
+#endif
+ }
+ /* Reset DMM structs and add an initial free chunk*/
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetDmmMgr(pProcObject->hDevObject,
+ &hDmmMgr);
+ if (DSP_SUCCEEDED(status)) {
+#ifdef OMAP_3430
+ /* Set dwExtEnd to DMM START u8
+ * address */
+ dwExtEnd = (dwExtEnd + 1) * DSPWORDSIZE;
+ /* DMM memory is from EXT_END */
+ status = DMM_CreateTables(hDmmMgr,
+ dwExtEnd, DMMPOOLSIZE);
+#else
+ dwDmmStart = (DEXTMEMMAP_BEG) * (DSPWORDSIZE);
+
+ status = DMM_CreateTables(hDmmMgr,dwDmmStart,
+ DMMPOOLSIZE);
+#endif
+
+
+
+
+ }
+ }
+ }
+ }
+ /* Restore the original argv[0] */
+ MEM_Free(newEnvp);
+ aArgv[0] = pargv0;
+#ifdef DEBUG
+ if (DSP_SUCCEEDED(status)) {
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus)
+ (pProcObject->hWmdContext, &uBrdState))) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Load: Processor Loaded\n");
+ DBC_Assert(uBrdState == BRD_LOADED);
+ }
+ }
+#endif
+func_end:
+#ifdef DEBUG
+ if (DSP_FAILED(status)) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_Load: "
+ "Processor Load Failed.\n");
+
+ }
+#endif
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Exiting PROC_Load, status: 0x%x\n", status);
+ DBC_Ensure((DSP_SUCCEEDED(status) && pProcObject->sState == PROC_LOADED)
+ || DSP_FAILED(status));
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ do_gettimeofday(&tv2);
+ if (tv2.tv_usec < tv1.tv_usec) {
+ tv2.tv_usec += 1000000;
+ tv2.tv_sec--;
+ }
+ GT_2trace(PROC_DebugMask, GT_1CLASS,
+ "Proc_Load: time to load %d sec and %d usec \n",
+ tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
+#endif
+ return status;
+}
+
+/*
+ * ======== PROC_Map ========
+ * Purpose:
+ * Maps a MPU buffer to DSP address space.
+ */
+DSP_STATUS PROC_Map(DSP_HPROCESSOR hProcessor, void *pMpuAddr, u32 ulSize,
+ void *pReqAddr, void **ppMapAddr, u32 ulMapAttr)
+{
+ u32 vaAlign;
+ u32 paAlign;
+ struct DMM_OBJECT *hDmmMgr;
+ u32 sizeAlign;
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+
+#ifndef RES_CLEANUP_DISABLE
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE dmmRes;
+ DSP_STATUS res_status = DSP_SOK;
+#endif
+
+ GT_6trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Map, args:\n\t"
+ "hProcessor %x, pMpuAddr %x, ulSize %x, pReqAddr %x, "
+ "ulMapAttr %x, ppMapAddr %x\n", hProcessor, pMpuAddr, ulSize,
+ pReqAddr, ulMapAttr, ppMapAddr);
+ /* Calculate the page-aligned PA, VA and size */
+ vaAlign = PG_ALIGN_LOW((u32) pReqAddr, PG_SIZE_4K);
+ paAlign = PG_ALIGN_LOW((u32) pMpuAddr, PG_SIZE_4K);
+ sizeAlign = PG_ALIGN_HIGH(ulSize + (u32)pMpuAddr - paAlign,
+ PG_SIZE_4K);
+
+ GT_3trace(PROC_DebugMask, GT_ENTER, "PROC_Map: vaAlign %x, paAlign %x, "
+ "sizeAlign %x\n", vaAlign, paAlign, sizeAlign);
+
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Map: "
+ "InValid Processor Handle \n");
+ goto func_end;
+ }
+ /* Critical section */
+ (void)SYNC_EnterCS(hProcLock);
+ status = DMM_GetHandle(pProcObject, &hDmmMgr);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Map: Failed to get DMM Mgr "
+ "handle: 0x%x\n", status);
+ } else {
+ status = DMM_MapMemory(hDmmMgr, vaAlign, sizeAlign);
+ }
+ /* Add mapping to the page tables. */
+ if (DSP_SUCCEEDED(status)) {
+
+ status = (*pProcObject->pIntfFxns->pfnBrdMemMap)
+ (pProcObject->hWmdContext, paAlign, vaAlign, sizeAlign,
+ ulMapAttr);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* Mapped address = MSB of VA | LSB of PA */
+ *ppMapAddr = (void *) (vaAlign | ((u32) pMpuAddr &
+ (PG_SIZE_4K - 1)));
+ } else {
+ DMM_UnMapMemory(hDmmMgr, vaAlign, &sizeAlign);
+ }
+ (void)SYNC_LeaveCS(hProcLock);
+
+#ifndef RES_CLEANUP_DISABLE
+ if (DSP_SUCCEEDED(status)) {
+ /* Update the node and stream resource status */
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject,
+ REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ if (DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDrvObject, &pCtxt, NULL,
+ (u32)pMpuAddr) != DSP_ENOTFOUND) {
+ DRV_InsertDMMResElement(&dmmRes, pCtxt);
+ DRV_UpdateDMMResElement(dmmRes, (u32)pMpuAddr,
+ ulSize, (u32)pReqAddr,
+ (u32)*ppMapAddr, hProcessor);
+ }
+ }
+ }
+#endif
+func_end:
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_Map [0x%x]", status);
+ return status;
+}
+
+/*
+ * ======== PROC_RegisterNotify ========
+ * Purpose:
+ * Register to be notified of specific processor events.
+ */
+DSP_STATUS PROC_RegisterNotify(DSP_HPROCESSOR hProcessor, u32 uEventMask,
+ u32 uNotifyType, struct DSP_NOTIFICATION
+ *hNotification)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct DEH_MGR *hDehMgr;
+
+ DBC_Require(hNotification != NULL);
+ DBC_Require(cRefs > 0);
+
+ GT_4trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_RegisterNotify, args:\n\t"
+ "hProcessor: 0x%x\n\tuEventMask: 0x%x\n\tuNotifyMask:"
+ " 0x%x\n\t hNotification 0x%x\n", hProcessor, uEventMask,
+ uNotifyType, hNotification);
+
+ /* Check processor handle */
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_RegsiterNotify Invalid "
+ "ProcessorHandle 0x%x\n", hProcessor);
+ goto func_end;
+ }
+ /* Check if event mask is a valid processor related event */
+ if (uEventMask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
+ DSP_PROCESSORDETACH | DSP_PROCESSORRESTART | DSP_MMUFAULT |
+ DSP_SYSERROR | DSP_PWRERROR))
+ status = DSP_EVALUE;
+
+ /* Check if notify type is valid */
+ if (uNotifyType != DSP_SIGNALEVENT)
+ status = DSP_EVALUE;
+
+ if (DSP_SUCCEEDED(status)) {
+ /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
+ * or DSP_PWRERROR then register event immediately. */
+ if (uEventMask &
+ ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR)) {
+ status = NTFY_Register(pProcObject->hNtfy,
+ hNotification, uEventMask, uNotifyType);
+ /* Special case alert, special case alert!
+ * If we're trying to *deregister* (i.e. uEventMask
+ * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
+ * we have to deregister with the DEH manager.
+ * There's no way to know, based on uEventMask which
+ * manager the notification event was registered with,
+ * so if we're trying to deregister and NTFY_Register
+ * failed, we'll give the deh manager a shot.
+ */
+ if ((uEventMask == 0) && DSP_FAILED(status)) {
+ status = DEV_GetDehMgr(pProcObject->hDevObject,
+ &hDehMgr);
+ DBC_Assert(pProcObject->pIntfFxns->
+ pfnDehRegisterNotify);
+ status = (*pProcObject->pIntfFxns->
+ pfnDehRegisterNotify)
+ (hDehMgr, uEventMask, uNotifyType,
+ hNotification);
+ }
+ } else {
+ status = DEV_GetDehMgr(pProcObject->hDevObject,
+ &hDehMgr);
+ DBC_Assert(pProcObject->pIntfFxns->
+ pfnDehRegisterNotify);
+ status = (*pProcObject->pIntfFxns->pfnDehRegisterNotify)
+ (hDehMgr, uEventMask, uNotifyType,
+ hNotification);
+ if (DSP_FAILED(status))
+ status = DSP_EFAIL;
+
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== PROC_ReserveMemory ========
+ * Purpose:
+ * Reserve a virtually contiguous region of DSP address space.
+ */
+DSP_STATUS PROC_ReserveMemory(DSP_HPROCESSOR hProcessor, u32 ulSize,
+ void **ppRsvAddr)
+{
+ struct DMM_OBJECT *hDmmMgr;
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+
+ GT_3trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_ReserveMemory, args:\n\t"
+ "hProcessor: 0x%x ulSize: 0x%x ppRsvAddr: 0x%x\n", hProcessor,
+ ulSize, ppRsvAddr);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Map: "
+ "InValid Processor Handle \n");
+ goto func_end;
+ }
+ status = DMM_GetHandle(pProcObject, &hDmmMgr);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_ReserveMemory: "
+ "Failed to get DMM Mgr handle: 0x%x\n", status);
+ } else
+ status = DMM_ReserveMemory(hDmmMgr, ulSize, (u32 *)ppRsvAddr);
+
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_ReserveMemory [0x%x]",
+ status);
+func_end:
+ return status;
+}
+
+/*
+ * ======== PROC_Start ========
+ * Purpose:
+ * Start a processor running.
+ */
+DSP_STATUS PROC_Start(DSP_HPROCESSOR hProcessor)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct COD_MANAGER *hCodMgr; /* Code manager handle */
+ u32 dwDspAddr; /* Loaded code's entry point. */
+#ifdef DEBUG
+ BRD_STATUS uBrdState;
+#endif
+ DBC_Require(cRefs > 0);
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Start, args:\n\t"
+ "hProcessor: 0x%x\n", hProcessor);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Start :InValid Handle \n");
+ goto func_end;
+ }
+ /* Call the WMD_BRD_Start */
+ if (pProcObject->sState != PROC_LOADED) {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Start :Wrong state \n");
+ status = DSP_EWRONGSTATE;
+ goto func_end;
+ }
+ status = DEV_GetCodMgr(pProcObject->hDevObject, &hCodMgr);
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "Processor Start DSP_FAILED "
+ "in Getting DEV_GetCodMgr status 0x%x\n", status);
+ goto func_cont;
+ }
+ status = COD_GetEntry(hCodMgr, &dwDspAddr);
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "Processor Start DSP_FAILED in "
+ "Getting COD_GetEntry status 0x%x\n", status);
+ goto func_cont;
+ }
+ status = (*pProcObject->pIntfFxns->pfnBrdStart)
+ (pProcObject->hWmdContext, dwDspAddr);
+ if (DSP_FAILED(status)) {
+ status = DSP_EFAIL;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Start Failed to Start the board\n");
+ goto func_cont;
+ }
+ /* Call DEV_Create2 */
+ status = DEV_Create2(pProcObject->hDevObject);
+ if (DSP_SUCCEEDED(status)) {
+ pProcObject->sState = PROC_RUNNING;
+ /* Deep sleep switces off the peripheral clocks.
+ * we just put the DSP CPU in idle in the idle loop.
+ * so there is no need to send a command to DSP */
+
+ if (pProcObject->hNtfy) {
+ PROC_NotifyClients(pProcObject,
+ DSP_PROCESSORSTATECHANGE);
+ }
+ GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_Start: Processor "
+ "Started and running \n");
+ } else {
+ /* Failed to Create Node Manager and DISP Object
+ * Stop the Processor from running. Put it in STOPPED State */
+ (void)(*pProcObject->pIntfFxns->pfnBrdStop)(pProcObject->
+ hWmdContext);
+ status = DSP_EFAIL;
+ pProcObject->sState = PROC_STOPPED;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Start "
+ "Failed to Create the Node Manager\n");
+ }
+func_cont:
+#ifdef DEBUG
+ if (DSP_SUCCEEDED(status)) {
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus)
+ (pProcObject->hWmdContext, &uBrdState))) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Start: Processor State is RUNNING \n");
+ DBC_Assert(uBrdState != BRD_HIBERNATION);
+ }
+ }
+#endif
+func_end:
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Exiting PROC_Start, status 0x%x\n", status);
+ DBC_Ensure((DSP_SUCCEEDED(status) && pProcObject->sState ==
+ PROC_RUNNING) || DSP_FAILED(status));
+ return status;
+}
+
+/*
+ * ======== PROC_Stop ========
+ * Purpose:
+ * Stop a processor running.
+ */
+DSP_STATUS PROC_Stop(DSP_HPROCESSOR hProcessor)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct MSG_MGR *hMsgMgr;
+ struct NODE_MGR *hNodeMgr;
+ DSP_HNODE hNode;
+ u32 uNodeTabSize = 1;
+ u32 uNumNodes = 0;
+ u32 uNodesAllocated = 0;
+ BRD_STATUS uBrdState;
+
+ DBC_Require(cRefs > 0);
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Stop, args:\n\t"
+ "hProcessor: 0x%x\n", hProcessor);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Stop :InValid Handle \n");
+ goto func_end;
+ }
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus)
+ (pProcObject->hWmdContext, &uBrdState))) {
+ /* Clean up all the resources except the current running
+ process resources */
+ if (uBrdState == BRD_ERROR)
+ PROC_CleanupAllResources();
+ }
+ /* check if there are any running nodes */
+ status = DEV_GetNodeManager(pProcObject->hDevObject, &hNodeMgr);
+ if (DSP_SUCCEEDED(status) && hNodeMgr) {
+ status = NODE_EnumNodes(hNodeMgr, &hNode, uNodeTabSize,
+ &uNumNodes, &uNodesAllocated);
+ if ((status == DSP_ESIZE) || (uNodesAllocated > 0)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "Can't stop device, Active "
+ "nodes = 0x%x \n", uNodesAllocated);
+ return DSP_EWRONGSTATE;
+ }
+ }
+ /* Call the WMD_BRD_Stop */
+ /* It is OK to stop a device that does n't have nodes OR not started */
+ status = (*pProcObject->pIntfFxns->pfnBrdStop)(pProcObject->
+ hWmdContext);
+ if (DSP_SUCCEEDED(status)) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Stop: Processor Stopped, "
+ "i.e in standby mode \n");
+ pProcObject->sState = PROC_STOPPED;
+ /* Destory the Node Manager, MSG Manager */
+ if (DSP_SUCCEEDED(DEV_Destroy2(pProcObject->hDevObject))) {
+ /* Destroy the MSG by calling MSG_Delete */
+ DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr);
+ if (hMsgMgr) {
+ MSG_Delete(hMsgMgr);
+ DEV_SetMsgMgr(pProcObject->hDevObject, NULL);
+ }
+#ifdef DEBUG
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->
+ pfnBrdStatus)(pProcObject->hWmdContext,
+ &uBrdState))) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Monitor:Processor Stopped \n");
+ DBC_Assert(uBrdState == BRD_STOPPED);
+ }
+#endif
+ } else {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Stop Couldn't delete node manager \n");
+ }
+ } else {
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Stop Failed to Stop the processor/device \n");
+ }
+func_end:
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Stop, status 0x%x\n",
+ status);
+
+ return status;
+}
+
+/*
+ * ======== PROC_UnMap ========
+ * Purpose:
+ * Removes a MPU buffer mapping from the DSP address space.
+ */
+DSP_STATUS PROC_UnMap(DSP_HPROCESSOR hProcessor, void *pMapAddr)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+ struct DMM_OBJECT *hDmmMgr;
+ u32 vaAlign;
+ u32 sizeAlign;
+#ifndef RES_CLEANUP_DISABLE
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE dmmRes;
+ DSP_STATUS res_status = DSP_SOK;
+#endif
+ GT_2trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_UnMap, args:\n\thProcessor:"
+ "0x%x pMapAddr: 0x%x\n", hProcessor, pMapAddr);
+
+ vaAlign = PG_ALIGN_LOW((u32) pMapAddr, PG_SIZE_4K);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_UnMap: "
+ "InValid Processor Handle \n");
+ goto func_end;
+ }
+
+ status = DMM_GetHandle(hProcessor, &hDmmMgr);
+ /* Critical section */
+ (void)SYNC_EnterCS(hProcLock);
+ if (DSP_FAILED(status)) {
+ GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_UnMap: "
+ "Failed to get DMM Mgr handle: 0x%x\n", status);
+ } else {
+ /* Update DMM structures. Get the size to unmap.
+ This function returns error if the VA is not mapped */
+ status = DMM_UnMapMemory(hDmmMgr, (u32) vaAlign, &sizeAlign);
+ }
+ /* Remove mapping from the page tables. */
+ if (DSP_SUCCEEDED(status)) {
+ status = (*pProcObject->pIntfFxns->pfnBrdMemUnMap)
+ (pProcObject->hWmdContext, vaAlign, sizeAlign);
+ }
+ (void)SYNC_LeaveCS(hProcLock);
+#ifndef RES_CLEANUP_DISABLE
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "PROC_UnMap DRV_GetDMMResElement "
+ "pMapAddr:[0x%x]", pMapAddr);
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Update the node and stream resource status */
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(res_status))
+ goto func_end;
+
+ DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject,
+ &pCtxt, NULL, (u32)pMapAddr);
+ if (pCtxt != NULL) {
+ if (DRV_GetDMMResElement((u32)pMapAddr, &dmmRes, pCtxt) !=
+ DSP_ENOTFOUND)
+ DRV_RemoveDMMResElement(dmmRes, pCtxt);
+ }
+func_end:
+#endif
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Leaving PROC_UnMap [0x%x]", status);
+ return status;
+}
+
+/*
+ * ======== PROC_UnReserveMemory ========
+ * Purpose:
+ * Frees a previously reserved region of DSP address space.
+ */
+DSP_STATUS PROC_UnReserveMemory(DSP_HPROCESSOR hProcessor, void *pRsvAddr)
+{
+ struct DMM_OBJECT *hDmmMgr;
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor;
+
+ GT_2trace(PROC_DebugMask, GT_ENTER,
+ "Entered PROC_UnReserveMemory, args:\n\t"
+ "hProcessor: 0x%x pRsvAddr: 0x%x\n", hProcessor, pRsvAddr);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_UnMap: "
+ "InValid Processor Handle \n");
+ goto func_end;
+ }
+ status = DMM_GetHandle(pProcObject, &hDmmMgr);
+ if (DSP_FAILED(status))
+ GT_1trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_UnReserveMemory: Failed to get DMM Mgr "
+ "handle: 0x%x\n", status);
+ else
+ status = DMM_UnReserveMemory(hDmmMgr, (u32) pRsvAddr);
+
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Leaving PROC_UnReserveMemory [0x%x]",
+ status);
+func_end:
+ return status;
+}
+
+/*
+ * ======== = PROC_Monitor ======== ==
+ * Purpose:
+ * Place the Processor in Monitor State. This is an internal
+ * function and a requirement before Processor is loaded.
+ * This does a WMD_BRD_Stop, DEV_Destroy2 and WMD_BRD_Monitor.
+ * In DEV_Destroy2 we delete the node manager.
+ * Parameters:
+ * hProcObject: Handle to Processor Object
+ * Returns:
+ * DSP_SOK: Processor placed in monitor mode.
+ * !DSP_SOK: Failed to place processor in monitor mode.
+ * Requires:
+ * Valid Processor Handle
+ * Ensures:
+ * Success: ProcObject state is PROC_IDLE
+ */
+static DSP_STATUS PROC_Monitor(struct PROC_OBJECT *hProcObject)
+{
+ DSP_STATUS status = DSP_EFAIL;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcObject;
+ struct MSG_MGR *hMsgMgr;
+#ifdef DEBUG
+ BRD_STATUS uBrdState;
+#endif
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE));
+
+ GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Monitor, args:\n\t"
+ "hProcessor: 0x%x\n", hProcObject);
+ /* This is needed only when Device is loaded when it is
+ * already 'ACTIVE' */
+ /* Destory the Node Manager, MSG Manager */
+ if (DSP_SUCCEEDED(DEV_Destroy2(pProcObject->hDevObject))) {
+ /* Destroy the MSG by calling MSG_Delete */
+ DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr);
+ if (hMsgMgr) {
+ MSG_Delete(hMsgMgr);
+ DEV_SetMsgMgr(pProcObject->hDevObject, NULL);
+ }
+ }
+ /* Place the Board in the Monitor State */
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdMonitor)
+ (pProcObject->hWmdContext))) {
+ status = DSP_SOK;
+#ifdef DEBUG
+ if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus)
+ (pProcObject->hWmdContext, &uBrdState))) {
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_Monitor:Processor in "
+ "Monitor State\n");
+ DBC_Assert(uBrdState == BRD_IDLE);
+ }
+#endif
+ } else {
+ /* Monitor Failure */
+ GT_0trace(PROC_DebugMask, GT_7CLASS,
+ "PROC_Monitor: Processor Could not"
+ "be put in Monitor mode \n");
+ }
+ GT_1trace(PROC_DebugMask, GT_ENTER,
+ "Exiting PROC_Monitor, status 0x%x\n",
+ status);
+#ifdef DEBUG
+ DBC_Ensure((DSP_SUCCEEDED(status) && uBrdState == BRD_IDLE) ||
+ DSP_FAILED(status));
+#endif
+ return status;
+}
+
+/*
+ * ======== GetEnvpCount ========
+ * Purpose:
+ * Return the number of elements in the envp array, including the
+ * terminating NULL element.
+ */
+static s32 GetEnvpCount(char **envp)
+{
+ s32 cRetval = 0;
+ if (envp) {
+ while (*envp++)
+ cRetval++;
+
+ cRetval += 1; /* Include the terminating NULL in the count. */
+ }
+
+ return cRetval;
+}
+
+/*
+ * ======== PrependEnvp ========
+ * Purpose:
+ * Prepend an environment variable=value pair to the new envp array, and
+ * copy in the existing var=value pairs in the old envp array.
+ */
+static char **PrependEnvp(char **newEnvp, char **envp, s32 cEnvp, s32 cNewEnvp,
+ char *szVar)
+{
+ char **ppEnvp = newEnvp;
+
+ DBC_Require(newEnvp);
+
+ /* Prepend new environ var=value string */
+ *newEnvp++ = szVar;
+
+ /* Copy user's environment into our own. */
+ while (cEnvp--)
+ *newEnvp++ = *envp++;
+
+ /* Ensure NULL terminates the new environment strings array. */
+ if (cEnvp == 0)
+ *newEnvp = NULL;
+
+ return ppEnvp;
+}
+
+/*
+ * ======== PROC_NotifyClients ========
+ * Purpose:
+ * Notify the processor the events.
+ */
+DSP_STATUS PROC_NotifyClients(DSP_HPROCESSOR hProc, u32 uEvents)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc;
+
+ DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE));
+ DBC_Require(IsValidProcEvent(uEvents));
+ DBC_Require(cRefs > 0);
+ if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_NotifyClients: "
+ "InValid Processor Handle \n");
+ goto func_end;
+ }
+
+ NTFY_Notify(pProcObject->hNtfy, uEvents);
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_NotifyClients :Signaled. \n");
+func_end:
+ return status;
+}
+
+/*
+ * ======== PROC_NotifyAllClients ========
+ * Purpose:
+ * Notify the processor the events. This includes notifying all clients
+ * attached to a particulat DSP.
+ */
+DSP_STATUS PROC_NotifyAllClients(DSP_HPROCESSOR hProc, u32 uEvents)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc;
+
+ DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE));
+ DBC_Require(IsValidProcEvent(uEvents));
+ DBC_Require(cRefs > 0);
+
+ DEV_NotifyClients(pProcObject->hDevObject, uEvents);
+
+ GT_0trace(PROC_DebugMask, GT_1CLASS,
+ "PROC_NotifyAllClients :Signaled. \n");
+
+ return status;
+}
+
+/*
+ * ======== PROC_GetProcessorId ========
+ * Purpose:
+ * Retrieves the processor ID.
+ */
+DSP_STATUS PROC_GetProcessorId(DSP_HPROCESSOR hProc, u32 *procID)
+{
+ DSP_STATUS status = DSP_SOK;
+ struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc;
+
+ if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE))
+ *procID = pProcObject->uProcessor;
+ else {
+ status = DSP_EHANDLE;
+ GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_GetProcessorId: "
+ "InValid Processor Handle \n");
+ }
+ return status;
+}
+
diff --git a/drivers/dsp/bridge/rmgr/pwr.c b/drivers/dsp/bridge/rmgr/pwr.c
new file mode 100644
index 000000000000..50a3f7948a44
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/pwr.c
@@ -0,0 +1,184 @@
+/*
+ * pwr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== PWR.c ========
+ * PWR API for controlling DSP power states.
+ *
+ * Public Functions:
+ * PWR_SleepDSP
+ * PWR_WakeDSP
+ *
+ *! Revision History
+ *! ================
+ *! 18-Feb-2003 vp Code review updates.
+ *! 18-Oct-2002 vp Ported to Linux platform.
+ *! 22-May-2002 sg Do PWR-to-IOCTL code mapping in PWR_SleepDSP.
+ *! 29-Apr-2002 sg Initial.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/pwr.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/devdefs.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/wmdioctl.h>
+
+/*
+ * ======== PWR_SleepDSP ========
+ * Send command to DSP to enter sleep state.
+ */
+DSP_STATUS PWR_SleepDSP(IN CONST u32 sleepCode, IN CONST u32 timeout)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct WMD_DEV_CONTEXT *dwContext;
+ DSP_STATUS status = DSP_EFAIL;
+ struct DEV_OBJECT *hDevObject = NULL;
+ u32 ioctlcode = 0;
+ u32 arg = timeout;
+
+ for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
+ hDevObject != NULL;
+ hDevObject =
+ (struct DEV_OBJECT *)DRV_GetNextDevObject
+ ((u32)hDevObject)) {
+ if (DSP_FAILED(DEV_GetWMDContext(hDevObject,
+ (struct WMD_DEV_CONTEXT **)&dwContext))) {
+ continue;
+ }
+ if (DSP_FAILED(DEV_GetIntfFxns(hDevObject,
+ (struct WMD_DRV_INTERFACE **)&pIntfFxns))) {
+ continue;
+ }
+ if (sleepCode == PWR_DEEPSLEEP)
+ ioctlcode = WMDIOCTL_DEEPSLEEP;
+ else if (sleepCode == PWR_EMERGENCYDEEPSLEEP)
+ ioctlcode = WMDIOCTL_EMERGENCYSLEEP;
+ else
+ status = DSP_EINVALIDARG;
+
+ if (status != DSP_EINVALIDARG) {
+ status = (*pIntfFxns->pfnDevCntrl)(dwContext,
+ ioctlcode, (void *)&arg);
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== PWR_WakeDSP ========
+ * Send command to DSP to wake it from sleep.
+ */
+DSP_STATUS PWR_WakeDSP(IN CONST u32 timeout)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct WMD_DEV_CONTEXT *dwContext;
+ DSP_STATUS status = DSP_EFAIL;
+ struct DEV_OBJECT *hDevObject = NULL;
+ u32 arg = timeout;
+
+ for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
+ hDevObject != NULL;
+ hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject
+ ((u32)hDevObject)) {
+ if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject,
+ (struct WMD_DEV_CONTEXT **)&dwContext))) {
+ if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject,
+ (struct WMD_DRV_INTERFACE **)&pIntfFxns))) {
+ status = (*pIntfFxns->pfnDevCntrl)(dwContext,
+ WMDIOCTL_WAKEUP, (void *)&arg);
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== PWR_PM_PreScale========
+ * Sends pre-notification message to DSP.
+ */
+DSP_STATUS PWR_PM_PreScale(IN u16 voltage_domain, u32 level)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct WMD_DEV_CONTEXT *dwContext;
+ DSP_STATUS status = DSP_EFAIL;
+ struct DEV_OBJECT *hDevObject = NULL;
+ u32 arg[2];
+
+ arg[0] = voltage_domain;
+ arg[1] = level;
+
+ for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
+ hDevObject != NULL;
+ hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject
+ ((u32)hDevObject)) {
+ if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject,
+ (struct WMD_DEV_CONTEXT **)&dwContext))) {
+ if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject,
+ (struct WMD_DRV_INTERFACE **)&pIntfFxns))) {
+ status = (*pIntfFxns->pfnDevCntrl)(dwContext,
+ WMDIOCTL_PRESCALE_NOTIFY,
+ (void *)&arg);
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== PWR_PM_PostScale========
+ * Sends post-notification message to DSP.
+ */
+DSP_STATUS PWR_PM_PostScale(IN u16 voltage_domain, u32 level)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct WMD_DEV_CONTEXT *dwContext;
+ DSP_STATUS status = DSP_EFAIL;
+ struct DEV_OBJECT *hDevObject = NULL;
+ u32 arg[2];
+
+ arg[0] = voltage_domain;
+ arg[1] = level;
+
+ for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
+ hDevObject != NULL;
+ hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject
+ ((u32)hDevObject)) {
+ if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject,
+ (struct WMD_DEV_CONTEXT **)&dwContext))) {
+ if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject,
+ (struct WMD_DRV_INTERFACE **)&pIntfFxns))) {
+ status = (*pIntfFxns->pfnDevCntrl)(dwContext,
+ WMDIOCTL_POSTSCALE_NOTIFY,
+ (void *)&arg);
+ }
+ }
+ }
+ return status;
+
+}
+
+
diff --git a/drivers/dsp/bridge/rmgr/rmm.c b/drivers/dsp/bridge/rmgr/rmm.c
new file mode 100644
index 000000000000..575f6751bac1
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/rmm.c
@@ -0,0 +1,604 @@
+/*
+ * rmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== rmm.c ========
+ * Description:
+ *
+ * This memory manager provides general heap management and arbitrary
+ * alignment for any number of memory segments.
+ *
+ * Notes:
+ *
+ * Memory blocks are allocated from the end of the first free memory
+ * block large enough to satisfy the request. Alignment requirements
+ * are satisfied by "sliding" the block forward until its base satisfies
+ * the alignment specification; if this is not possible then the next
+ * free block large enough to hold the request is tried.
+ *
+ * Since alignment can cause the creation of a new free block - the
+ * unused memory formed between the start of the original free block
+ * and the start of the allocated block - the memory manager must free
+ * this memory to prevent a memory leak.
+ *
+ * Overlay memory is managed by reserving through RMM_alloc, and freeing
+ * it through RMM_free. The memory manager prevents DSP code/data that is
+ * overlayed from being overwritten as long as the memory it runs at has
+ * been allocated, and not yet freed.
+ *
+ *! Revision History
+ *! ================
+ *! 18-Feb-2003 vp Code review updates.
+ *! 18-Oct-2002 vp Ported to Linux Platform.
+ *! 24-Sep-2002 map Updated from Code Review
+ *! 25-Jun-2002 jeh Free from segid passed to RMM_free().
+ *! 24-Apr-2002 jeh Determine segid based on address in RMM_free(). (No way
+ *! to keep track of segid with dynamic loader library.)
+ *! 16-Oct-2001 jeh Based on gen tree rm.c. Added support for overlays.
+ */
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/list.h>
+#include <dspbridge/mem.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/rmm.h>
+
+#define RMM_TARGSIGNATURE 0x544d4d52 /* "TMMR" */
+
+/*
+ * ======== RMM_Header ========
+ * This header is used to maintain a list of free memory blocks.
+ */
+struct RMM_Header {
+ struct RMM_Header *next; /* form a free memory link list */
+ u32 size; /* size of the free memory */
+ u32 addr; /* DSP address of memory block */
+} ;
+
+/*
+ * ======== RMM_OvlySect ========
+ * Keeps track of memory occupied by overlay section.
+ */
+struct RMM_OvlySect {
+ struct LST_ELEM listElem;
+ u32 addr; /* Start of memory section */
+ u32 size; /* Length (target MAUs) of section */
+ s32 page; /* Memory page */
+};
+
+/*
+ * ======== RMM_TargetObj ========
+ */
+struct RMM_TargetObj {
+ u32 dwSignature;
+ struct RMM_Segment *segTab;
+ struct RMM_Header **freeList;
+ u32 numSegs;
+ struct LST_LIST *ovlyList; /* List of overlay memory in use */
+};
+
+#if GT_TRACE
+static struct GT_Mask RMM_debugMask = { NULL, NULL }; /* GT trace variable */
+#endif
+
+static u32 cRefs; /* module reference count */
+
+static bool allocBlock(struct RMM_TargetObj *target, u32 segid, u32 size,
+ u32 align, u32 *dspAddr);
+static bool freeBlock(struct RMM_TargetObj *target, u32 segid, u32 addr,
+ u32 size);
+
+/*
+ * ======== RMM_alloc ========
+ */
+DSP_STATUS RMM_alloc(struct RMM_TargetObj *target, u32 segid, u32 size,
+ u32 align, u32 *dspAddr, bool reserve)
+{
+ struct RMM_OvlySect *sect;
+ struct RMM_OvlySect *prevSect = NULL;
+ struct RMM_OvlySect *newSect;
+ u32 addr;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE));
+ DBC_Require(dspAddr != NULL);
+ DBC_Require(size > 0);
+ DBC_Require(reserve || (target->numSegs > 0));
+ DBC_Require(cRefs > 0);
+
+ GT_6trace(RMM_debugMask, GT_ENTER,
+ "RMM_alloc(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx, 0x%lx)\n", target, segid, size, align, dspAddr,
+ reserve);
+ if (!reserve) {
+ if (!allocBlock(target, segid, size, align, dspAddr)) {
+ status = DSP_EMEMORY;
+ } else {
+ /* Increment the number of allocated blocks in this
+ * segment */
+ target->segTab[segid].number++;
+ }
+ goto func_end;
+ }
+ /* An overlay section - See if block is already in use. If not,
+ * insert into the list in ascending address size. */
+ addr = *dspAddr;
+ sect = (struct RMM_OvlySect *)LST_First(target->ovlyList);
+ /* Find place to insert new list element. List is sorted from
+ * smallest to largest address. */
+ while (sect != NULL) {
+ if (addr <= sect->addr) {
+ /* Check for overlap with sect */
+ if ((addr + size > sect->addr) || (prevSect &&
+ (prevSect->addr + prevSect->size > addr))) {
+ status = DSP_EOVERLAYMEMORY;
+ }
+ break;
+ }
+ prevSect = sect;
+ sect = (struct RMM_OvlySect *)LST_Next(target->ovlyList,
+ (struct LST_ELEM *)sect);
+ }
+ if (DSP_SUCCEEDED(status)) {
+ /* No overlap - allocate list element for new section. */
+ newSect = MEM_Calloc(sizeof(struct RMM_OvlySect), MEM_PAGED);
+ if (newSect == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ LST_InitElem((struct LST_ELEM *)newSect);
+ newSect->addr = addr;
+ newSect->size = size;
+ newSect->page = segid;
+ if (sect == NULL) {
+ /* Put new section at the end of the list */
+ LST_PutTail(target->ovlyList,
+ (struct LST_ELEM *)newSect);
+ } else {
+ /* Put new section just before sect */
+ LST_InsertBefore(target->ovlyList,
+ (struct LST_ELEM *)newSect,
+ (struct LST_ELEM *)sect);
+ }
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== RMM_create ========
+ */
+DSP_STATUS RMM_create(struct RMM_TargetObj **pTarget,
+ struct RMM_Segment segTab[], u32 numSegs)
+{
+ struct RMM_Header *hptr;
+ struct RMM_Segment *sptr, *tmp;
+ struct RMM_TargetObj *target;
+ s32 i;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(pTarget != NULL);
+ DBC_Require(numSegs == 0 || segTab != NULL);
+
+ GT_3trace(RMM_debugMask, GT_ENTER,
+ "RMM_create(0x%lx, 0x%lx, 0x%lx)\n",
+ pTarget, segTab, numSegs);
+
+ /* Allocate DBL target object */
+ MEM_AllocObject(target, struct RMM_TargetObj, RMM_TARGSIGNATURE);
+
+ if (target == NULL) {
+ GT_0trace(RMM_debugMask, GT_6CLASS,
+ "RMM_create: Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ }
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ target->numSegs = numSegs;
+ if (!(numSegs > 0))
+ goto func_cont;
+
+ /* Allocate the memory for freelist from host's memory */
+ target->freeList = MEM_Calloc(numSegs * sizeof(struct RMM_Header *),
+ MEM_PAGED);
+ if (target->freeList == NULL) {
+ GT_0trace(RMM_debugMask, GT_6CLASS,
+ "RMM_create: Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ } else {
+ /* Allocate headers for each element on the free list */
+ for (i = 0; i < (s32) numSegs; i++) {
+ target->freeList[i] =
+ MEM_Calloc(sizeof(struct RMM_Header),
+ MEM_PAGED);
+ if (target->freeList[i] == NULL) {
+ GT_0trace(RMM_debugMask, GT_6CLASS,
+ "RMM_create: Memory "
+ "allocation failed\n");
+ status = DSP_EMEMORY;
+ break;
+ }
+ }
+ /* Allocate memory for initial segment table */
+ target->segTab = MEM_Calloc(numSegs *
+ sizeof(struct RMM_Segment), MEM_PAGED);
+ if (target->segTab == NULL) {
+ GT_0trace(RMM_debugMask, GT_6CLASS,
+ "RMM_create: Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ } else {
+ /* Initialize segment table and free list */
+ sptr = target->segTab;
+ for (i = 0, tmp = segTab; numSegs > 0; numSegs--, i++) {
+ *sptr = *tmp;
+ hptr = target->freeList[i];
+ hptr->addr = tmp->base;
+ hptr->size = tmp->length;
+ hptr->next = NULL;
+ tmp++;
+ sptr++;
+ }
+ }
+ }
+func_cont:
+ /* Initialize overlay memory list */
+ if (DSP_SUCCEEDED(status)) {
+ target->ovlyList = LST_Create();
+ if (target->ovlyList == NULL) {
+ GT_0trace(RMM_debugMask, GT_6CLASS,
+ "RMM_create: Memory allocation failed\n");
+ status = DSP_EMEMORY;
+ }
+ }
+
+ if (DSP_SUCCEEDED(status)) {
+ *pTarget = target;
+ } else {
+ *pTarget = NULL;
+ if (target)
+ RMM_delete(target);
+
+ }
+
+ DBC_Ensure((DSP_SUCCEEDED(status) && MEM_IsValidHandle((*pTarget),
+ RMM_TARGSIGNATURE)) || (DSP_FAILED(status) && *pTarget ==
+ NULL));
+
+ return status;
+}
+
+/*
+ * ======== RMM_delete ========
+ */
+void RMM_delete(struct RMM_TargetObj *target)
+{
+ struct RMM_OvlySect *pSect;
+ struct RMM_Header *hptr;
+ struct RMM_Header *next;
+ u32 i;
+
+ DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE));
+
+ GT_1trace(RMM_debugMask, GT_ENTER, "RMM_delete(0x%lx)\n", target);
+
+ if (target->segTab != NULL)
+ MEM_Free(target->segTab);
+
+ if (target->ovlyList) {
+ while ((pSect = (struct RMM_OvlySect *)LST_GetHead
+ (target->ovlyList))) {
+ MEM_Free(pSect);
+ }
+ DBC_Assert(LST_IsEmpty(target->ovlyList));
+ LST_Delete(target->ovlyList);
+ }
+
+ if (target->freeList != NULL) {
+ /* Free elements on freelist */
+ for (i = 0; i < target->numSegs; i++) {
+ hptr = next = target->freeList[i];
+ while (next) {
+ hptr = next;
+ next = hptr->next;
+ MEM_Free(hptr);
+ }
+ }
+ MEM_Free(target->freeList);
+ }
+
+ MEM_FreeObject(target);
+}
+
+/*
+ * ======== RMM_exit ========
+ */
+void RMM_exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ cRefs--;
+
+ GT_1trace(RMM_debugMask, GT_5CLASS, "RMM_exit() ref count: 0x%x\n",
+ cRefs);
+
+ if (cRefs == 0)
+ MEM_Exit();
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== RMM_free ========
+ */
+bool RMM_free(struct RMM_TargetObj *target, u32 segid, u32 addr, u32 size,
+ bool reserved)
+
+{
+ struct RMM_OvlySect *sect;
+ bool retVal = true;
+
+ DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE));
+
+ DBC_Require(reserved || segid < target->numSegs);
+ DBC_Require(reserved || (addr >= target->segTab[segid].base &&
+ (addr + size) <= (target->segTab[segid].base +
+ target->segTab[segid].length)));
+
+ GT_5trace(RMM_debugMask, GT_ENTER,
+ "RMM_free(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx)\n", target, segid, addr, size, reserved);
+ /*
+ * Free or unreserve memory.
+ */
+ if (!reserved) {
+ retVal = freeBlock(target, segid, addr, size);
+ if (retVal)
+ target->segTab[segid].number--;
+
+ } else {
+ /* Unreserve memory */
+ sect = (struct RMM_OvlySect *)LST_First(target->ovlyList);
+ while (sect != NULL) {
+ if (addr == sect->addr) {
+ DBC_Assert(size == sect->size);
+ /* Remove from list */
+ LST_RemoveElem(target->ovlyList,
+ (struct LST_ELEM *)sect);
+ MEM_Free(sect);
+ break;
+ }
+ sect = (struct RMM_OvlySect *)LST_Next(target->ovlyList,
+ (struct LST_ELEM *)sect);
+ }
+ if (sect == NULL)
+ retVal = false;
+
+ }
+ return retVal;
+}
+
+/*
+ * ======== RMM_init ========
+ */
+bool RMM_init(void)
+{
+ bool retVal = true;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+ DBC_Assert(!RMM_debugMask.flags);
+ GT_create(&RMM_debugMask, "RM"); /* "RM" for RMm */
+
+ retVal = MEM_Init();
+
+ if (!retVal)
+ MEM_Exit();
+
+ }
+
+ if (retVal)
+ cRefs++;
+
+ GT_1trace(RMM_debugMask, GT_5CLASS,
+ "RMM_init(), ref count: 0x%x\n",
+ cRefs);
+
+ DBC_Ensure((retVal && (cRefs > 0)) || (!retVal && (cRefs >= 0)));
+
+ return retVal;
+}
+
+/*
+ * ======== RMM_stat ========
+ */
+bool RMM_stat(struct RMM_TargetObj *target, enum DSP_MEMTYPE segid,
+ struct DSP_MEMSTAT *pMemStatBuf)
+{
+ struct RMM_Header *head;
+ bool retVal = false;
+ u32 maxFreeSize = 0;
+ u32 totalFreeSize = 0;
+ u32 freeBlocks = 0;
+
+ DBC_Require(pMemStatBuf != NULL);
+ DBC_Assert(target != NULL);
+
+ if ((u32) segid < target->numSegs) {
+ head = target->freeList[segid];
+
+ /* Collect data from freeList */
+ while (head != NULL) {
+ maxFreeSize = max(maxFreeSize, head->size);
+ totalFreeSize += head->size;
+ freeBlocks++;
+ head = head->next;
+ }
+
+ /* ulSize */
+ pMemStatBuf->ulSize = target->segTab[segid].length;
+
+ /* ulNumFreeBlocks */
+ pMemStatBuf->ulNumFreeBlocks = freeBlocks;
+
+ /* ulTotalFreeSize */
+ pMemStatBuf->ulTotalFreeSize = totalFreeSize;
+
+ /* ulLenMaxFreeBlock */
+ pMemStatBuf->ulLenMaxFreeBlock = maxFreeSize;
+
+ /* ulNumAllocBlocks */
+ pMemStatBuf->ulNumAllocBlocks = target->segTab[segid].number;
+
+ retVal = true;
+ }
+
+ return retVal;
+}
+
+/*
+ * ======== balloc ========
+ * This allocation function allocates memory from the lowest addresses
+ * first.
+ */
+static bool allocBlock(struct RMM_TargetObj *target, u32 segid, u32 size,
+ u32 align, u32 *dspAddr)
+{
+ struct RMM_Header *head;
+ struct RMM_Header *prevhead = NULL;
+ struct RMM_Header *next;
+ u32 tmpalign;
+ u32 alignbytes;
+ u32 hsize;
+ u32 allocsize;
+ u32 addr;
+
+ alignbytes = (align == 0) ? 1 : align;
+ prevhead = NULL;
+ head = target->freeList[segid];
+
+ do {
+ hsize = head->size;
+ next = head->next;
+
+ addr = head->addr; /* alloc from the bottom */
+
+ /* align allocation */
+ (tmpalign = (u32) addr % alignbytes);
+ if (tmpalign != 0)
+ tmpalign = alignbytes - tmpalign;
+
+ allocsize = size + tmpalign;
+
+ if (hsize >= allocsize) { /* big enough */
+ if (hsize == allocsize && prevhead != NULL) {
+ prevhead->next = next;
+ MEM_Free(head);
+ } else {
+ head->size = hsize - allocsize;
+ head->addr += allocsize;
+ }
+
+ /* free up any hole created by alignment */
+ if (tmpalign)
+ freeBlock(target, segid, addr, tmpalign);
+
+ *dspAddr = addr + tmpalign;
+ return true;
+ }
+
+ prevhead = head;
+ head = next;
+
+ } while (head != NULL);
+
+ return false;
+}
+
+/*
+ * ======== freeBlock ========
+ * TO DO: freeBlock() allocates memory, which could result in failure.
+ * Could allocate an RMM_Header in RMM_alloc(), to be kept in a pool.
+ * freeBlock() could use an RMM_Header from the pool, freeing as blocks
+ * are coalesced.
+ */
+static bool freeBlock(struct RMM_TargetObj *target, u32 segid, u32 addr,
+ u32 size)
+{
+ struct RMM_Header *head;
+ struct RMM_Header *thead;
+ struct RMM_Header *rhead;
+ bool retVal = true;
+
+ /* Create a memory header to hold the newly free'd block. */
+ rhead = MEM_Calloc(sizeof(struct RMM_Header), MEM_PAGED);
+ if (rhead == NULL) {
+ retVal = false;
+ } else {
+ /* search down the free list to find the right place for addr */
+ head = target->freeList[segid];
+
+ if (addr >= head->addr) {
+ while (head->next != NULL && addr > head->next->addr)
+ head = head->next;
+
+ thead = head->next;
+
+ head->next = rhead;
+ rhead->next = thead;
+ rhead->addr = addr;
+ rhead->size = size;
+ } else {
+ *rhead = *head;
+ head->next = rhead;
+ head->addr = addr;
+ head->size = size;
+ thead = rhead->next;
+ }
+
+ /* join with upper block, if possible */
+ if (thead != NULL && (rhead->addr + rhead->size) ==
+ thead->addr) {
+ head->next = rhead->next;
+ thead->size = size + thead->size;
+ thead->addr = addr;
+ MEM_Free(rhead);
+ rhead = thead;
+ }
+
+ /* join with the lower block, if possible */
+ if ((head->addr + head->size) == rhead->addr) {
+ head->next = rhead->next;
+ head->size = head->size + rhead->size;
+ MEM_Free(rhead);
+ }
+ }
+
+ return retVal;
+}
+
diff --git a/drivers/dsp/bridge/rmgr/strm.c b/drivers/dsp/bridge/rmgr/strm.c
new file mode 100644
index 000000000000..bd55fd3d102c
--- /dev/null
+++ b/drivers/dsp/bridge/rmgr/strm.c
@@ -0,0 +1,1066 @@
+/*
+ * strm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * ======== strm.c ========
+ * Description:
+ * DSP/BIOS Bridge Stream Manager.
+ *
+ * Public Functions:
+ * STRM_AllocateBuffer
+ * STRM_Close
+ * STRM_Create
+ * STRM_Delete
+ * STRM_Exit
+ * STRM_FreeBuffer
+ * STRM_GetEventHandle
+ * STRM_GetInfo
+ * STRM_Idle
+ * STRM_Init
+ * STRM_Issue
+ * STRM_Open
+ * STRM_PrepareBuffer
+ * STRM_Reclaim
+ * STRM_RegisterNotify
+ * STRM_Select
+ * STRM_UnprepareBuffer
+ *
+ * Notes:
+ *
+ *! Revision History:
+ *! =================
+ *! 18-Feb-2003 vp Code review updates.
+ *! 18-Oct-2002 vp Ported to Linux platform.
+ *! 13-Mar-2002 map pStrm init'd to NULL in STRM_Open to prevent error
+ *! 12-Mar-2002 map Changed return var to WSX "wStatus" instead of "status"
+ *! in DEV and CMM function calls to avoid confusion.
+ *! Return DSP_SOK instead of S_OK from API fxns.
+ *! 12-Mar-2002 map Changed FAILED(..) to DSP_FAILED(..)
+ *! 25-Jan-2002 ag Allow neg seg ids(e.g. DSP_SHMSEG0) to denote SM.
+ *! 15-Nov-2001 ag Added STRMMODE & SM for DMA/ZCopy streaming.
+ *! Changed DSP_STREAMINFO to STRM_INFO in STRM_GetInfo().
+ *! Use strm timeout value for dma flush timeout.
+ *! 09-May-2001 jeh Code review cleanup.
+ *! 06-Feb-2001 kc Updated DBC_Ensure in STRM_Select to check timeout.
+ *! 23-Oct-2000 jeh Allow NULL STRM_ATTRS passed to STRM_Open() for DLL
+ *! tests to pass.
+ *! 25-Sep-2000 jeh Created.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/mem.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Mini Driver */
+#include <dspbridge/wmd.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/nodepriv.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/cmm.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/strm.h>
+
+#ifndef RES_CLEANUP_DISABLE
+#include <dspbridge/cfg.h>
+#include <dspbridge/dbreg.h>
+#include <dspbridge/resourcecleanup.h>
+#endif
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define STRM_SIGNATURE 0x4d525453 /* "MRTS" */
+#define STRMMGR_SIGNATURE 0x5254534d /* "RTSM" */
+
+#define DEFAULTTIMEOUT 10000
+#define DEFAULTNUMBUFS 2
+
+/*
+ * ======== STRM_MGR ========
+ * The STRM_MGR contains device information needed to open the underlying
+ * channels of a stream.
+ */
+struct STRM_MGR {
+ u32 dwSignature;
+ struct DEV_OBJECT *hDev; /* Device for this processor */
+ struct CHNL_MGR *hChnlMgr; /* Channel manager */
+ struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
+ struct SYNC_CSOBJECT *hSync; /* For critical sections */
+} ;
+
+/*
+ * ======== STRM_OBJECT ========
+ * This object is allocated in STRM_Open().
+ */
+ struct STRM_OBJECT {
+ u32 dwSignature;
+ struct STRM_MGR *hStrmMgr;
+ struct CHNL_OBJECT *hChnl;
+ u32 uDir; /* DSP_TONODE or DSP_FROMNODE */
+ u32 uTimeout;
+ u32 uNumBufs; /* Max # of bufs allowed in stream */
+ u32 uNBufsInStrm; /* Current # of bufs in stream */
+ u32 ulNBytes; /* bytes transferred since idled */
+ enum DSP_STREAMSTATE strmState; /* STREAM_IDLE, STREAM_READY, ... */
+ HANDLE hUserEvent; /* Saved for STRM_GetInfo() */
+ enum DSP_STRMMODE lMode; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */
+ u32 uDMAChnlId; /* DMA chnl id */
+ u32 uDMAPriority; /* DMA priority:DMAPRI_[LOW][HIGH] */
+ u32 uSegment; /* >0 is SM segment.=0 is local heap */
+ u32 uAlignment; /* Alignment for stream bufs */
+ struct CMM_XLATOROBJECT *hXlator; /* Stream's SM address translator */
+} ;
+
+/* ----------------------------------- Globals */
+#if GT_TRACE
+static struct GT_Mask STRM_debugMask = { NULL, NULL }; /* GT trace variable */
+#endif
+static u32 cRefs; /* module reference count */
+
+/* ----------------------------------- Function Prototypes */
+static DSP_STATUS DeleteStrm(struct STRM_OBJECT *hStrm);
+static void DeleteStrmMgr(struct STRM_MGR *hStrmMgr);
+
+/*
+ * ======== STRM_AllocateBuffer ========
+ * Purpose:
+ * Allocates buffers for a stream.
+ */
+DSP_STATUS STRM_AllocateBuffer(struct STRM_OBJECT *hStrm, u32 uSize,
+ OUT u8 **apBuffer, u32 uNumBufs)
+{
+ DSP_STATUS status = DSP_SOK;
+ u32 uAllocated = 0;
+ u32 i;
+ #ifndef RES_CLEANUP_DISABLE
+ DSP_STATUS res_status = DSP_SOK;
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE hSTRMRes;
+ #endif
+ DBC_Require(cRefs > 0);
+ DBC_Require(apBuffer != NULL);
+
+ GT_4trace(STRM_debugMask, GT_ENTER, "STRM_AllocateBuffer: hStrm: 0x%x\t"
+ "uSize: 0x%x\tapBuffer: 0x%x\tuNumBufs: 0x%x\n",
+ hStrm, uSize, apBuffer, uNumBufs);
+ if (MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ /*
+ * Allocate from segment specified at time of stream open.
+ */
+ if (uSize == 0)
+ status = DSP_ESIZE;
+
+ }
+ if (DSP_FAILED(status)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ for (i = 0; i < uNumBufs; i++) {
+ DBC_Assert(hStrm->hXlator != NULL);
+ (void)CMM_XlatorAllocBuf(hStrm->hXlator, &apBuffer[i], uSize);
+ if (apBuffer[i] == NULL) {
+ GT_0trace(STRM_debugMask, GT_7CLASS,
+ "STRM_AllocateBuffer: "
+ "DSP_FAILED to alloc shared memory.\n");
+ status = DSP_EMEMORY;
+ uAllocated = i;
+ break;
+ }
+ }
+ if (DSP_FAILED(status))
+ STRM_FreeBuffer(hStrm, apBuffer, uAllocated);
+
+#ifndef RES_CLEANUP_DISABLE
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(res_status))
+ goto func_end;
+
+ DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject,
+ &pCtxt, NULL, 0);
+ if (pCtxt != NULL) {
+ if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) !=
+ DSP_ENOTFOUND) {
+ DRV_ProcUpdateSTRMRes(uNumBufs, hSTRMRes, pCtxt);
+ }
+ }
+#endif
+func_end:
+ return status;
+}
+
+/*
+ * ======== STRM_Close ========
+ * Purpose:
+ * Close a stream opened with STRM_Open().
+ */
+DSP_STATUS STRM_Close(struct STRM_OBJECT *hStrm)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct CHNL_INFO chnlInfo;
+ DSP_STATUS status = DSP_SOK;
+
+
+#ifndef RES_CLEANUP_DISABLE
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE hSTRMRes;
+ DSP_STATUS res_status = DSP_SOK;
+#endif
+
+
+ DBC_Require(cRefs > 0);
+
+ GT_1trace(STRM_debugMask, GT_ENTER, "STRM_Close: hStrm: 0x%x\n", hStrm);
+
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ /* Have all buffers been reclaimed? If not, return
+ * DSP_EPENDING */
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnChnlGetInfo) (hStrm->hChnl, &chnlInfo);
+ DBC_Assert(DSP_SUCCEEDED(status));
+
+ if (chnlInfo.cIOCs > 0 || chnlInfo.cIOReqs > 0) {
+ status = DSP_EPENDING;
+ } else {
+
+ status = DeleteStrm(hStrm);
+
+ if (DSP_FAILED(status)) {
+ /* we already validated the handle. */
+ DBC_Assert(status != DSP_EHANDLE);
+
+ /* make sure we return a documented result */
+ status = DSP_EFAIL;
+ }
+ }
+ }
+#ifndef RES_CLEANUP_DISABLE
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Update the node and stream resource status */
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_FAILED(res_status))
+ goto func_end;
+
+ DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject,
+ &pCtxt, NULL, 0);
+ if (pCtxt != NULL) {
+ if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) !=
+ DSP_ENOTFOUND) {
+ DRV_ProcRemoveSTRMResElement(hSTRMRes, pCtxt);
+ }
+ }
+func_end:
+#endif
+ DBC_Ensure(status == DSP_SOK || status == DSP_EHANDLE ||
+ status == DSP_EPENDING || status == DSP_EFAIL);
+
+ return status;
+}
+
+/*
+ * ======== STRM_Create ========
+ * Purpose:
+ * Create a STRM manager object.
+ */
+DSP_STATUS STRM_Create(OUT struct STRM_MGR **phStrmMgr, struct DEV_OBJECT *hDev)
+{
+ struct STRM_MGR *pStrmMgr;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(phStrmMgr != NULL);
+ DBC_Require(hDev != NULL);
+
+ GT_2trace(STRM_debugMask, GT_ENTER, "STRM_Create: phStrmMgr: "
+ "0x%x\thDev: 0x%x\n", phStrmMgr, hDev);
+ *phStrmMgr = NULL;
+ /* Allocate STRM manager object */
+ MEM_AllocObject(pStrmMgr, struct STRM_MGR, STRMMGR_SIGNATURE);
+ if (pStrmMgr == NULL) {
+ status = DSP_EMEMORY;
+ GT_0trace(STRM_debugMask, GT_6CLASS, "STRM_Create: "
+ "MEM_AllocObject() failed!\n ");
+ } else {
+ pStrmMgr->hDev = hDev;
+ }
+ /* Get Channel manager and WMD function interface */
+ if (DSP_SUCCEEDED(status)) {
+ status = DEV_GetChnlMgr(hDev, &(pStrmMgr->hChnlMgr));
+ if (DSP_SUCCEEDED(status)) {
+ (void) DEV_GetIntfFxns(hDev, &(pStrmMgr->pIntfFxns));
+ DBC_Assert(pStrmMgr->pIntfFxns != NULL);
+ } else {
+ GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Create: "
+ "Failed to get channel manager! status = "
+ "0x%x\n", status);
+ }
+ }
+ if (DSP_SUCCEEDED(status))
+ status = SYNC_InitializeCS(&pStrmMgr->hSync);
+
+ if (DSP_SUCCEEDED(status))
+ *phStrmMgr = pStrmMgr;
+ else
+ DeleteStrmMgr(pStrmMgr);
+
+ DBC_Ensure(DSP_SUCCEEDED(status) &&
+ (MEM_IsValidHandle((*phStrmMgr), STRMMGR_SIGNATURE) ||
+ (DSP_FAILED(status) && *phStrmMgr == NULL)));
+
+ return status;
+}
+
+/*
+ * ======== STRM_Delete ========
+ * Purpose:
+ * Delete the STRM Manager Object.
+ */
+void STRM_Delete(struct STRM_MGR *hStrmMgr)
+{
+ DBC_Require(cRefs > 0);
+ DBC_Require(MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE));
+
+ GT_1trace(STRM_debugMask, GT_ENTER, "STRM_Delete: hStrmMgr: 0x%x\n",
+ hStrmMgr);
+
+ DeleteStrmMgr(hStrmMgr);
+
+ DBC_Ensure(!MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE));
+}
+
+/*
+ * ======== STRM_Exit ========
+ * Purpose:
+ * Discontinue usage of STRM module.
+ */
+void STRM_Exit(void)
+{
+ DBC_Require(cRefs > 0);
+
+ cRefs--;
+
+ GT_1trace(STRM_debugMask, GT_5CLASS,
+ "Entered STRM_Exit, ref count: 0x%x\n", cRefs);
+
+ DBC_Ensure(cRefs >= 0);
+}
+
+/*
+ * ======== STRM_FreeBuffer ========
+ * Purpose:
+ * Frees the buffers allocated for a stream.
+ */
+DSP_STATUS STRM_FreeBuffer(struct STRM_OBJECT *hStrm, u8 **apBuffer,
+ u32 uNumBufs)
+{
+ DSP_STATUS status = DSP_SOK;
+ u32 i = 0;
+
+ #ifndef RES_CLEANUP_DISABLE
+ DSP_STATUS res_status = DSP_SOK;
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE hSTRMRes = NULL;
+ #endif
+ DBC_Require(cRefs > 0);
+ DBC_Require(apBuffer != NULL);
+
+ GT_3trace(STRM_debugMask, GT_ENTER, "STRM_FreeBuffer: hStrm: 0x%x\t"
+ "apBuffer: 0x%x\tuNumBufs: 0x%x\n", hStrm, apBuffer, uNumBufs);
+
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE))
+ status = DSP_EHANDLE;
+
+ if (DSP_SUCCEEDED(status)) {
+ for (i = 0; i < uNumBufs; i++) {
+ DBC_Assert(hStrm->hXlator != NULL);
+ status = CMM_XlatorFreeBuf(hStrm->hXlator, apBuffer[i]);
+ if (DSP_FAILED(status)) {
+ GT_0trace(STRM_debugMask, GT_7CLASS,
+ "STRM_FreeBuffer: DSP_FAILED"
+ " to free shared memory.\n");
+ break;
+ }
+ apBuffer[i] = NULL;
+ }
+ }
+#ifndef RES_CLEANUP_DISABLE
+ /* Update the node and stream resource status */
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDrvObject, &pCtxt,
+ NULL, 0);
+ if (pCtxt != NULL) {
+ if (DRV_GetSTRMResElement(hStrm, hSTRMRes, pCtxt) !=
+ DSP_ENOTFOUND) {
+ DRV_ProcUpdateSTRMRes(uNumBufs-i, hSTRMRes,
+ pCtxt);
+ }
+ }
+ }
+#endif
+ return status;
+}
+
+/*
+ * ======== STRM_GetInfo ========
+ * Purpose:
+ * Retrieves information about a stream.
+ */
+DSP_STATUS STRM_GetInfo(struct STRM_OBJECT *hStrm,
+ OUT struct STRM_INFO *pStreamInfo,
+ u32 uStreamInfoSize)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct CHNL_INFO chnlInfo;
+ DSP_STATUS status = DSP_SOK;
+ void *pVirtBase = NULL; /* NULL if no SM used */
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pStreamInfo != NULL);
+ DBC_Require(uStreamInfoSize >= sizeof(struct STRM_INFO));
+
+ GT_3trace(STRM_debugMask, GT_ENTER, "STRM_GetInfo: hStrm: 0x%x\t"
+ "pStreamInfo: 0x%x\tuStreamInfoSize: 0x%x\n", hStrm,
+ pStreamInfo, uStreamInfoSize);
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ if (uStreamInfoSize < sizeof(struct STRM_INFO)) {
+ /* size of users info */
+ status = DSP_ESIZE;
+ }
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnChnlGetInfo) (hStrm->hChnl, &chnlInfo);
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ if (hStrm->hXlator) {
+ /* We have a translator */
+ DBC_Assert(hStrm->uSegment > 0);
+ CMM_XlatorInfo(hStrm->hXlator, (u8 **)&pVirtBase, 0,
+ hStrm->uSegment, false);
+ }
+ pStreamInfo->uSegment = hStrm->uSegment;
+ pStreamInfo->lMode = hStrm->lMode;
+ pStreamInfo->pVirtBase = pVirtBase;
+ pStreamInfo->pUser->uNumberBufsAllowed = hStrm->uNumBufs;
+ pStreamInfo->pUser->uNumberBufsInStream = chnlInfo.cIOCs +
+ chnlInfo.cIOReqs;
+ /* # of bytes transferred since last call to DSPStream_Idle() */
+ pStreamInfo->pUser->ulNumberBytes = chnlInfo.cPosition;
+ pStreamInfo->pUser->hSyncObjectHandle = chnlInfo.hEvent;
+ /* Determine stream state based on channel state and info */
+ if (chnlInfo.dwState & CHNL_STATEEOS) {
+ pStreamInfo->pUser->ssStreamState = STREAM_DONE;
+ } else {
+ if (chnlInfo.cIOCs > 0)
+ pStreamInfo->pUser->ssStreamState = STREAM_READY;
+ else if (chnlInfo.cIOReqs > 0)
+ pStreamInfo->pUser->ssStreamState = STREAM_PENDING;
+ else
+ pStreamInfo->pUser->ssStreamState = STREAM_IDLE;
+
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== STRM_Idle ========
+ * Purpose:
+ * Idles a particular stream.
+ */
+DSP_STATUS STRM_Idle(struct STRM_OBJECT *hStrm, bool fFlush)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+
+ GT_2trace(STRM_debugMask, GT_ENTER, "STRM_Idle: hStrm: 0x%x\t"
+ "fFlush: 0x%x\n", hStrm, fFlush);
+
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+
+ status = (*pIntfFxns->pfnChnlIdle) (hStrm->hChnl,
+ hStrm->uTimeout, fFlush);
+ }
+ return status;
+}
+
+/*
+ * ======== STRM_Init ========
+ * Purpose:
+ * Initialize the STRM module.
+ */
+bool STRM_Init(void)
+{
+ bool fRetVal = true;
+
+ DBC_Require(cRefs >= 0);
+
+ if (cRefs == 0) {
+#if GT_TRACE
+ DBC_Assert(!STRM_debugMask.flags);
+ GT_create(&STRM_debugMask, "ST"); /* "ST" for STrm */
+#endif
+ }
+
+ if (fRetVal)
+ cRefs++;
+
+ GT_1trace(STRM_debugMask, GT_5CLASS, "STRM_Init(), ref count: 0x%x\n",
+ cRefs);
+
+ DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0)));
+
+ return fRetVal;
+}
+
+/*
+ * ======== STRM_Issue ========
+ * Purpose:
+ * Issues a buffer on a stream
+ */
+DSP_STATUS STRM_Issue(struct STRM_OBJECT *hStrm, IN u8 *pBuf, u32 ulBytes,
+ u32 ulBufSize, u32 dwArg)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+ void *pTmpBuf = NULL;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pBuf != NULL);
+
+ GT_4trace(STRM_debugMask, GT_ENTER, "STRM_Issue: hStrm: 0x%x\tpBuf: "
+ "0x%x\tulBytes: 0x%x\tdwArg: 0x%x\n", hStrm, pBuf, ulBytes,
+ dwArg);
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else {
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+
+ if (hStrm->uSegment != 0) {
+ pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator,
+ (void *)pBuf, CMM_VA2DSPPA);
+ if (pTmpBuf == NULL)
+ status = DSP_ETRANSLATE;
+
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = (*pIntfFxns->pfnChnlAddIOReq)
+ (hStrm->hChnl, pBuf, ulBytes, ulBufSize,
+ (u32) pTmpBuf, dwArg);
+ }
+ if (DSP_FAILED(status)) {
+ if (status == CHNL_E_NOIORPS)
+ status = DSP_ESTREAMFULL;
+ else
+ status = DSP_EFAIL;
+
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== STRM_Open ========
+ * Purpose:
+ * Open a stream for sending/receiving data buffers to/from a task or
+ * XDAIS socket node on the DSP.
+ */
+DSP_STATUS STRM_Open(struct NODE_OBJECT *hNode, u32 uDir, u32 uIndex,
+ IN struct STRM_ATTR *pAttr, OUT struct STRM_OBJECT **phStrm)
+{
+ struct STRM_MGR *hStrmMgr;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ u32 ulChnlId;
+ struct STRM_OBJECT *pStrm = NULL;
+ CHNL_MODE uMode;
+ struct CHNL_ATTRS chnlAttrs;
+ DSP_STATUS status = DSP_SOK;
+ struct CMM_OBJECT *hCmmMgr = NULL; /* Shared memory manager hndl */
+
+ #ifndef RES_CLEANUP_DISABLE
+ DSP_STATUS res_status = DSP_SOK;
+ u32 hProcess;
+ HANDLE pCtxt = NULL;
+ HANDLE hDrvObject;
+ HANDLE hSTRMRes;
+ #endif
+ DBC_Require(cRefs > 0);
+ DBC_Require(phStrm != NULL);
+ DBC_Require(pAttr != NULL);
+ GT_5trace(STRM_debugMask, GT_ENTER,
+ "STRM_Open: hNode: 0x%x\tuDir: 0x%x\t"
+ "uIndex: 0x%x\tpAttr: 0x%x\tphStrm: 0x%x\n",
+ hNode, uDir, uIndex, pAttr, phStrm);
+ *phStrm = NULL;
+ if (uDir != DSP_TONODE && uDir != DSP_FROMNODE) {
+ status = DSP_EDIRECTION;
+ } else {
+ /* Get the channel id from the node (set in NODE_Connect()) */
+ status = NODE_GetChannelId(hNode, uDir, uIndex, &ulChnlId);
+ }
+ if (DSP_SUCCEEDED(status))
+ status = NODE_GetStrmMgr(hNode, &hStrmMgr);
+
+ if (DSP_SUCCEEDED(status)) {
+ MEM_AllocObject(pStrm, struct STRM_OBJECT, STRM_SIGNATURE);
+ if (pStrm == NULL) {
+ status = DSP_EMEMORY;
+ GT_0trace(STRM_debugMask, GT_6CLASS,
+ "STRM_Open: MEM_AllocObject() failed!\n ");
+ } else {
+ pStrm->hStrmMgr = hStrmMgr;
+ pStrm->uDir = uDir;
+ pStrm->strmState = STREAM_IDLE;
+ pStrm->hUserEvent = pAttr->hUserEvent;
+ if (pAttr->pStreamAttrIn != NULL) {
+ pStrm->uTimeout = pAttr->pStreamAttrIn->
+ uTimeout;
+ pStrm->uNumBufs = pAttr->pStreamAttrIn->
+ uNumBufs;
+ pStrm->lMode = pAttr->pStreamAttrIn->lMode;
+ pStrm->uSegment = pAttr->pStreamAttrIn->
+ uSegment;
+ pStrm->uAlignment = pAttr->pStreamAttrIn->
+ uAlignment;
+ pStrm->uDMAChnlId = pAttr->pStreamAttrIn->
+ uDMAChnlId;
+ pStrm->uDMAPriority = pAttr->pStreamAttrIn->
+ uDMAPriority;
+ chnlAttrs.uIOReqs = pAttr->pStreamAttrIn->
+ uNumBufs;
+ } else {
+ pStrm->uTimeout = DEFAULTTIMEOUT;
+ pStrm->uNumBufs = DEFAULTNUMBUFS;
+ pStrm->lMode = STRMMODE_PROCCOPY;
+ pStrm->uSegment = 0; /* local memory */
+ pStrm->uAlignment = 0;
+ pStrm->uDMAChnlId = 0;
+ pStrm->uDMAPriority = 0;
+ chnlAttrs.uIOReqs = DEFAULTNUMBUFS;
+ }
+ chnlAttrs.hReserved1 = NULL;
+ /* DMA chnl flush timeout */
+ chnlAttrs.hReserved2 = pStrm->uTimeout;
+ chnlAttrs.hEvent = NULL;
+ if (pAttr->hUserEvent != NULL)
+ chnlAttrs.hEvent = pAttr->hUserEvent;
+
+ }
+ }
+ if (DSP_FAILED(status))
+ goto func_cont;
+
+ if ((pAttr->pVirtBase == NULL) || !(pAttr->ulVirtSize > 0))
+ goto func_cont;
+
+ DBC_Assert(pStrm->lMode != STRMMODE_LDMA); /* no System DMA */
+ /* Get the shared mem mgr for this streams dev object */
+ status = DEV_GetCmmMgr(hStrmMgr->hDev, &hCmmMgr);
+ if (DSP_FAILED(status)) {
+ GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Open: Failed to get "
+ "CMM Mgr handle: 0x%x\n", status);
+ } else {
+ /*Allocate a SM addr translator for this strm.*/
+ status = CMM_XlatorCreate(&pStrm->hXlator, hCmmMgr, NULL);
+ if (DSP_FAILED(status)) {
+ GT_1trace(STRM_debugMask, GT_6CLASS,
+ "STRM_Open: Failed to "
+ "create SM translator: 0x%x\n", status);
+ } else {
+ DBC_Assert(pStrm->uSegment > 0);
+ /* Set translators Virt Addr attributes */
+ status = CMM_XlatorInfo(pStrm->hXlator,
+ (u8 **)&pAttr->pVirtBase, pAttr->ulVirtSize,
+ pStrm->uSegment, true);
+ if (status != DSP_SOK) {
+ GT_0trace(STRM_debugMask, GT_6CLASS,
+ "STRM_Open: ERROR: "
+ "in setting CMM_XlatorInfo.\n");
+ }
+ }
+ }
+func_cont:
+ if (DSP_SUCCEEDED(status)) {
+ /* Open channel */
+ uMode = (uDir == DSP_TONODE) ?
+ CHNL_MODETODSP : CHNL_MODEFROMDSP;
+ pIntfFxns = hStrmMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnChnlOpen) (&(pStrm->hChnl),
+ hStrmMgr->hChnlMgr, uMode, ulChnlId, &chnlAttrs);
+ if (DSP_FAILED(status)) {
+ /*
+ * over-ride non-returnable status codes so we return
+ * something documented
+ */
+ if (status != DSP_EMEMORY && status !=
+ DSP_EINVALIDARG && status != DSP_EFAIL) {
+ /*
+ * We got a status that's not return-able.
+ * Assert that we got something we were
+ * expecting (DSP_EHANDLE isn't acceptable,
+ * hStrmMgr->hChnlMgr better be valid or we
+ * assert here), and then return DSP_EFAIL.
+ */
+ DBC_Assert(status == CHNL_E_OUTOFSTREAMS ||
+ status == CHNL_E_BADCHANID ||
+ status == CHNL_E_CHANBUSY ||
+ status == CHNL_E_NOIORPS);
+ status = DSP_EFAIL;
+ }
+ GT_2trace(STRM_debugMask, GT_6CLASS,
+ "STRM_Open: Channel open failed, "
+ "chnl id = %d, status = 0x%x\n", ulChnlId,
+ status);
+ }
+ }
+ if (DSP_SUCCEEDED(status))
+ *phStrm = pStrm;
+ else
+ (void)DeleteStrm(pStrm);
+
+#ifndef RES_CLEANUP_DISABLE
+ /* Return PID instead of process handle */
+ hProcess = current->pid;
+
+ res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT);
+ if (DSP_SUCCEEDED(res_status)) {
+ DRV_GetProcContext(hProcess,
+ (struct DRV_OBJECT *)hDrvObject, &pCtxt,
+ hNode, 0);
+ if (pCtxt != NULL)
+ DRV_ProcInsertSTRMResElement(*phStrm, &hSTRMRes, pCtxt);
+
+ }
+#endif
+
+ /* ensure we return a documented error code */
+ DBC_Ensure((DSP_SUCCEEDED(status) &&
+ MEM_IsValidHandle((*phStrm), STRM_SIGNATURE)) ||
+ (*phStrm == NULL && (status == DSP_EHANDLE ||
+ status == DSP_EDIRECTION || status == DSP_EVALUE ||
+ status == DSP_EFAIL)));
+ return status;
+}
+
+/*
+ * ======== STRM_Reclaim ========
+ * Purpose:
+ * Relcaims a buffer from a stream.
+ */
+DSP_STATUS STRM_Reclaim(struct STRM_OBJECT *hStrm, OUT u8 **pBufPtr,
+ u32 *pulBytes, u32 *pulBufSize, u32 *pdwArg)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct CHNL_IOC chnlIOC;
+ DSP_STATUS status = DSP_SOK;
+ void *pTmpBuf = NULL;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(pBufPtr != NULL);
+ DBC_Require(pulBytes != NULL);
+ DBC_Require(pdwArg != NULL);
+
+ GT_4trace(STRM_debugMask, GT_ENTER,
+ "STRM_Reclaim: hStrm: 0x%x\tpBufPtr: 0x%x"
+ "\tpulBytes: 0x%x\tpdwArg: 0x%x\n", hStrm, pBufPtr, pulBytes,
+ pdwArg);
+
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ goto func_end;
+ }
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+
+ status = (*pIntfFxns->pfnChnlGetIOC)(hStrm->hChnl, hStrm->uTimeout,
+ &chnlIOC);
+ if (DSP_FAILED(status)) {
+ GT_1trace(STRM_debugMask, GT_6CLASS,
+ "STRM_Reclaim: GetIOC failed! "
+ "Status = 0x%x\n", status);
+ } else {
+ *pulBytes = chnlIOC.cBytes;
+ if (pulBufSize)
+ *pulBufSize = chnlIOC.cBufSize;
+
+ *pdwArg = chnlIOC.dwArg;
+ if (!CHNL_IsIOComplete(chnlIOC)) {
+ if (CHNL_IsTimedOut(chnlIOC)) {
+ status = DSP_ETIMEOUT;
+ } else {
+ /* Allow reclaims after idle to succeed */
+ if (!CHNL_IsIOCancelled(chnlIOC))
+ status = DSP_EFAIL;
+
+ }
+ }
+ /* Translate zerocopy buffer if channel not canceled. */
+ if (DSP_SUCCEEDED(status) && (!CHNL_IsIOCancelled(chnlIOC)) &&
+ (hStrm->lMode == STRMMODE_ZEROCOPY)) {
+ /*
+ * This is a zero-copy channel so chnlIOC.pBuf
+ * contains the DSP address of SM. We need to
+ * translate it to a virtual address for the user
+ * thread to access.
+ * Note: Could add CMM_DSPPA2VA to CMM in the future.
+ */
+ pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator,
+ chnlIOC.pBuf, CMM_DSPPA2PA);
+ if (pTmpBuf != NULL) {
+ /* now convert this GPP Pa to Va */
+ pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator,
+ pTmpBuf, CMM_PA2VA);
+ }
+ if (pTmpBuf == NULL) {
+ GT_0trace(STRM_debugMask, GT_7CLASS,
+ "STRM_Reclaim: Failed "
+ "SM translation!\n");
+ status = DSP_ETRANSLATE;
+ }
+ chnlIOC.pBuf = pTmpBuf;
+ }
+ *pBufPtr = chnlIOC.pBuf;
+ }
+func_end:
+ /* ensure we return a documented return code */
+ DBC_Ensure(DSP_SUCCEEDED(status) || status == DSP_EHANDLE ||
+ status == DSP_ETIMEOUT || status == DSP_ETRANSLATE ||
+ status == DSP_EFAIL);
+ return status;
+}
+
+/*
+ * ======== STRM_RegisterNotify ========
+ * Purpose:
+ * Register to be notified on specific events for this stream.
+ */
+DSP_STATUS STRM_RegisterNotify(struct STRM_OBJECT *hStrm, u32 uEventMask,
+ u32 uNotifyType, struct DSP_NOTIFICATION
+ *hNotification)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(hNotification != NULL);
+
+ GT_4trace(STRM_debugMask, GT_ENTER,
+ "STRM_RegisterNotify: hStrm: 0x%x\t"
+ "uEventMask: 0x%x\tuNotifyType: 0x%x\thNotification: 0x%x\n",
+ hStrm, uEventMask, uNotifyType, hNotification);
+ if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ } else if ((uEventMask & ~((DSP_STREAMIOCOMPLETION) |
+ DSP_STREAMDONE)) != 0) {
+ status = DSP_EVALUE;
+ } else {
+ if (uNotifyType != DSP_SIGNALEVENT)
+ status = DSP_ENOTIMPL;
+
+ }
+ if (DSP_SUCCEEDED(status)) {
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+
+ status = (*pIntfFxns->pfnChnlRegisterNotify)(hStrm->hChnl,
+ uEventMask, uNotifyType, hNotification);
+ }
+ /* ensure we return a documented return code */
+ DBC_Ensure(DSP_SUCCEEDED(status) || status == DSP_EHANDLE ||
+ status == DSP_ETIMEOUT || status == DSP_ETRANSLATE ||
+ status == DSP_ENOTIMPL || status == DSP_EFAIL);
+ return status;
+}
+
+/*
+ * ======== STRM_Select ========
+ * Purpose:
+ * Selects a ready stream.
+ */
+DSP_STATUS STRM_Select(IN struct STRM_OBJECT **aStrmTab, u32 nStrms,
+ OUT u32 *pMask, u32 uTimeout)
+{
+ u32 uIndex;
+ struct CHNL_INFO chnlInfo;
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ struct SYNC_OBJECT **hSyncEvents = NULL;
+ u32 i;
+ DSP_STATUS status = DSP_SOK;
+
+ DBC_Require(cRefs > 0);
+ DBC_Require(aStrmTab != NULL);
+ DBC_Require(pMask != NULL);
+ DBC_Require(nStrms > 0);
+
+ GT_4trace(STRM_debugMask, GT_ENTER,
+ "STRM_Select: aStrmTab: 0x%x \tnStrms: "
+ "0x%x\tpMask: 0x%x\tuTimeout: 0x%x\n", aStrmTab,
+ nStrms, pMask, uTimeout);
+ *pMask = 0;
+ for (i = 0; i < nStrms; i++) {
+ if (!MEM_IsValidHandle(aStrmTab[i], STRM_SIGNATURE)) {
+ status = DSP_EHANDLE;
+ break;
+ }
+ }
+ if (DSP_FAILED(status))
+ goto func_end;
+
+ /* Determine which channels have IO ready */
+ for (i = 0; i < nStrms; i++) {
+ pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnChnlGetInfo)(aStrmTab[i]->hChnl,
+ &chnlInfo);
+ if (DSP_FAILED(status)) {
+ break;
+ } else {
+ if (chnlInfo.cIOCs > 0)
+ *pMask |= (1 << i);
+
+ }
+ }
+ if (DSP_SUCCEEDED(status) && uTimeout > 0 && *pMask == 0) {
+ /* Non-zero timeout */
+ hSyncEvents = (struct SYNC_OBJECT **)MEM_Alloc(nStrms *
+ sizeof(struct SYNC_OBJECT *), MEM_PAGED);
+ if (hSyncEvents == NULL) {
+ status = DSP_EMEMORY;
+ } else {
+ for (i = 0; i < nStrms; i++) {
+ pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns;
+ status = (*pIntfFxns->pfnChnlGetInfo)
+ (aStrmTab[i]->hChnl, &chnlInfo);
+ if (DSP_FAILED(status))
+ break;
+ else
+ hSyncEvents[i] = chnlInfo.hSyncEvent;
+
+ }
+ }
+ if (DSP_SUCCEEDED(status)) {
+ status = SYNC_WaitOnMultipleEvents(hSyncEvents, nStrms,
+ uTimeout, &uIndex);
+ if (DSP_SUCCEEDED(status)) {
+ /* Since we waited on the event, we have to
+ * reset it */
+ SYNC_SetEvent(hSyncEvents[uIndex]);
+ *pMask = 1 << uIndex;
+ }
+ }
+ }
+func_end:
+ if (hSyncEvents)
+ MEM_Free(hSyncEvents);
+
+ DBC_Ensure((DSP_SUCCEEDED(status) && (*pMask != 0 || uTimeout == 0)) ||
+ (DSP_FAILED(status) && *pMask == 0));
+
+ return status;
+}
+
+/*
+ * ======== DeleteStrm ========
+ * Purpose:
+ * Frees the resources allocated for a stream.
+ */
+static DSP_STATUS DeleteStrm(struct STRM_OBJECT *hStrm)
+{
+ struct WMD_DRV_INTERFACE *pIntfFxns;
+ DSP_STATUS status = DSP_SOK;
+
+ if (MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) {
+ if (hStrm->hChnl) {
+ pIntfFxns = hStrm->hStrmMgr->pIntfFxns;
+ /* Channel close can fail only if the channel handle
+ * is invalid. */
+ status = (*pIntfFxns->pfnChnlClose) (hStrm->hChnl);
+ /* Free all SM address translator resources */
+ if (DSP_SUCCEEDED(status)) {
+ if (hStrm->hXlator) {
+ /* force free */
+ (void)CMM_XlatorDelete(hStrm->hXlator,
+ true);
+ }
+ }
+ }
+ MEM_FreeObject(hStrm);
+ } else {
+ status = DSP_EHANDLE;
+ }
+ return status;
+}
+
+/*
+ * ======== DeleteStrmMgr ========
+ * Purpose:
+ * Frees stream manager.
+ */
+static void DeleteStrmMgr(struct STRM_MGR *hStrmMgr)
+{
+ if (MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE)) {
+
+ if (hStrmMgr->hSync)
+ SYNC_DeleteCS(hStrmMgr->hSync);
+
+ MEM_FreeObject(hStrmMgr);
+ }
+}
+