diff options
author | Santosh Shilimkar <santosh.shilimkar@ti.com> | 2009-11-07 06:59:47 +0530 |
---|---|---|
committer | Santosh Shilimkar <santosh.shilimkar@ti.com> | 2009-11-07 06:59:47 +0530 |
commit | 9e034c986287a3338c393836f27e838b8f87539e (patch) | |
tree | 2a7cdc1384ad5f3ce230310e275cf17aa35db735 /drivers/dsp/bridge/rmgr | |
parent | 8aa5e79648ce7b16943456f2578b9b68573aac9c (diff) | |
parent | 3d8b36e8e6725484d6a5d7fc258afaf37ca2db96 (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.c | 1573 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/disp.c | 916 | ||||
-rwxr-xr-x | drivers/dsp/bridge/rmgr/drv.c | 1936 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/drv_interface.c | 760 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/drv_interface.h | 40 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/dspdrv.c | 276 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/mgr.c | 491 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/nldr.c | 1967 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/node.c | 3550 | ||||
-rwxr-xr-x | drivers/dsp/bridge/rmgr/proc.c | 2111 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/pwr.c | 184 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/rmm.c | 604 | ||||
-rw-r--r-- | drivers/dsp/bridge/rmgr/strm.c | 1066 |
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); + } +} + |