[ARM] tegra: stingray: CPU-AVP RPC in kernel
authorKaz Fukuoka <kfukuoka@nvidia.com>
Fri, 30 Jul 2010 20:13:01 +0000 (13:13 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:41 +0000 (16:33 -0700)
- /dev/nvfw ioctl interface to load AVP firmware.
- Use request_firmware() for AVP modules
- /dev/nvrpc ioctl interface to call RPC on AVP.
- Server thread to serve RPC from AVP.

Change-Id: I1694dc49d69b677cd225f8b68a4f84edf9bf0a23
Signed-off-by: Dima Zavin <dima@android.com>
17 files changed:
arch/arm/mach-tegra/nv/include/mach/nvrpc.h [new file with mode: 0755]
arch/arm/mach-tegra/nv/include/nvfw.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/include/nvrm_moduleloader.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_avp_service.c [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_cpu_rpc.c [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_swi_registry.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_graphics_private.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_init_stub.c [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader_private.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_rpc.h [new file with mode: 0644]
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c
arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c
arch/arm/mach-tegra/nv/nvrpc_user.c

diff --git a/arch/arm/mach-tegra/nv/include/mach/nvrpc.h b/arch/arm/mach-tegra/nv/include/mach/nvrpc.h
new file mode 100755 (executable)
index 0000000..594e1f5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * arch/arm/mach-tegra/include/linux/nvrpc_ioctl.h
+ *
+ * structure declarations for nvrpc user-space ioctls
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#if !defined(__KERNEL__)
+#define __user
+#endif
+
+#ifndef _MACH_TEGRA_NVRPC_IOCTL_H_
+#define _MACH_TEGRA_NVRPC_IOCTL_H_
+
+struct nvrpc_handle_param {
+       __u32 handle;
+       __u32 param;
+       __u32 ret_val;              /* operation status */
+};
+
+struct nvrpc_open_params {
+       __u32 rm_handle;            /* rm device handle */
+       __u32 port_name_size;       /* port name buffer size */
+       __u32 sem;                  /* receive semaphore handle */
+       __u32 transport_handle;     /* transport handle */
+       __u32 ret_val;              /* operation status */
+       unsigned long port_name;    /* port name */
+};
+
+struct nvrpc_set_queue_depth_params {
+       __u32 transport_handle;     /* transport handle */
+       __u32 max_queue_depth;      /* maximum number of message in Queue */
+       __u32 max_message_size;     /* maximum size of the message in bytes */
+       __u32 ret_val;              /* operation status */
+};
+
+struct nvrpc_msg_params {
+       __u32 transport_handle;     /* transport handle */
+       __u32 max_message_size;     /* maximum size of the message in bytes */
+       __u32 params;               /* timeout in ms */
+       __u32 ret_val;              /* operation status */
+       unsigned long msg_buffer;
+};
+
+#define NVRPC_IOC_MAGIC 'N'
+
+#define NVRPC_IOCTL_INIT                    \
+       _IOWR(NVRPC_IOC_MAGIC, 0x30, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_OPEN                    \
+       _IOWR(NVRPC_IOC_MAGIC, 0x31, struct nvrpc_open_params)
+#define NVRPC_IOCTL_GET_PORTNAME            \
+       _IOWR(NVRPC_IOC_MAGIC, 0x32, struct nvrpc_open_params)
+#define NVRPC_IOCTL_CLOSE                   \
+       _IOWR(NVRPC_IOC_MAGIC, 0x33, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_DEINIT                   \
+       _IOWR(NVRPC_IOC_MAGIC, 0x34, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_WAIT_FOR_CONNECT        \
+       _IOWR(NVRPC_IOC_MAGIC, 0x35, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_CONNECT                 \
+       _IOWR(NVRPC_IOC_MAGIC, 0x36, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_SET_QUEUE_DEPTH         \
+       _IOWR(NVRPC_IOC_MAGIC, 0x37, struct nvrpc_set_queue_depth_params)
+#define NVRPC_IOCTL_SEND_MSG                \
+       _IOWR(NVRPC_IOC_MAGIC, 0x38, struct nvrpc_msg_params)
+#define NVRPC_IOCTL_SEND_MSG_LP0            \
+       _IOWR(NVRPC_IOC_MAGIC, 0x39, struct nvrpc_msg_params)
+#define NVRPC_IOCTL_RECV_MSG           \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3A, struct nvrpc_msg_params)
+#define NVRPC_IOCTL_XPC_INIT                \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3B, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_ACQUIRE             \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3C, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_RELEASE             \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3D, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_GET_MSG             \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3E, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_SEND_MSG            \
+       _IOWR(NVRPC_IOC_MAGIC, 0x3F, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_DESTROY             \
+       _IOWR(NVRPC_IOC_MAGIC, 0x40, struct nvrpc_handle_param)
+#define NVRPC_IOCTL_XPC_CREATE              \
+       _IOWR(NVRPC_IOC_MAGIC, 0x41, struct nvrpc_handle_param)
+
+#endif
diff --git a/arch/arm/mach-tegra/nv/include/nvfw.h b/arch/arm/mach-tegra/nv/include/nvfw.h
new file mode 100644 (file)
index 0000000..e6b496b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/mach-tegra/include/linux/nvfw_ioctl.h
+ *
+ * structure declarations for nvfw ioctls
+ *
+ * Copyright (c) 2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/ioctl.h>
+
+#if !defined(__KERNEL__)
+#define __user
+#endif
+
+#ifndef _MACH_TEGRA_NVFW_IOCTL_H_
+#define _MACH_TEGRA_NVFW_IOCTL_H_
+
+struct nvfw_load_handle {
+       const char *filename;
+       int length;
+       void *args;
+       int argssize;
+       int greedy;
+       void *handle;
+};
+
+struct nvfw_get_proc_address_handle {
+       const char *symbolname;
+       int length;
+       void *address;
+       void *handle;
+};
+
+#define NVFW_IOC_MAGIC 'N'
+#define NVFW_IOC_LOAD_LIBRARY     _IOWR(NVFW_IOC_MAGIC, 0x50, struct nvfw_load_handle)
+#define NVFW_IOC_LOAD_LIBRARY_EX  _IOWR(NVFW_IOC_MAGIC, 0x51, struct nvfw_load_handle)
+#define NVFW_IOC_FREE_LIBRARY     _IOW (NVFW_IOC_MAGIC, 0x52, struct nvfw_load_handle)
+#define NVFW_IOC_GET_PROC_ADDRESS _IOWR(NVFW_IOC_MAGIC, 0x53, struct nvfw_load_handle)
+
+#endif
diff --git a/arch/arm/mach-tegra/nv/include/nvrm_moduleloader.h b/arch/arm/mach-tegra/nv/include/nvrm_moduleloader.h
new file mode 100644 (file)
index 0000000..ab8761c
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * arch/arm/mach-tegra/include/nvrm_moduleloader.h
+ *
+ *
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef INCLUDED_nvrm_moduleloader_H
+#define INCLUDED_nvrm_moduleloader_H
+
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#include "nvrm_init.h"
+
+#include "nvcommon.h"
+#include "nvos.h"
+
+/**
+ * NvRmLibraryHandle is an opaque handle to the Module Loader interface
+ *
+ * @ingroup nvrm_moduleloader
+ */
+
+typedef struct NvRmLibraryRec *NvRmLibraryHandle;
+
+/**
+ * @brief Defines the pin state
+ */
+
+typedef enum
+{
+    NvRmModuleLoaderReason_Attach = 0,
+    NvRmModuleLoaderReason_Detach,
+    NvRmModuleLoaderReason_Num,
+    NvRmModuleLoaderReason_Force32 = 0x7FFFFFFF
+} NvRmModuleLoaderReason;
+
+/**
+ * Loads the segments of requested library name.
+ * This method will parse the ELF dynamic library, relocate the address,
+ * resolve the symbols and load the segments accordingly.
+ * A successful load should return a valid handle.
+ *
+ * If some of the parameters passed are not valid assert
+ * encountered in debug mode.
+ *
+ * @ingroup nvrm_moduleloader
+ *
+ * @param hDevice The handle to the RM device
+ * @param pLibName The library to be loaded.
+ * @param pArgs The arguments to be passed.
+ * @param sizeOfArgs The size of arguments passed.
+ * @param hLibHandle The handle to the loaded library
+ *
+ * @retval NvSuccess Load library operation completed successfully
+ * @retval NvError_FileReadFailed Indicates that the fileoffset read failed
+ * @retval NvError_LibraryNotFound Indicates the given library could not be found
+ * @retval NvError_InsufficientMemory Indicates memory allocation failed
+ * @retval NvError_InvalidElfFormat Indicates the ELF file is not valid
+ */
+
+ NvError NvRmLoadLibrary(
+    NvRmDeviceHandle hDevice,
+    const char * pLibName,
+    void* pArgs,
+    NvU32 sizeOfArgs,
+    NvRmLibraryHandle * hLibHandle );
+
+/**
+ * Loads the segments of requested library name.This method will parse the ELF dynamic
+ * library, relocate the address, resolve the symbols and load the segments depending
+ * on the conservative or greedy approach. In both the approaches the the IRAM_MAND
+ * sections are loaded in IRAM and DRAM_MAND sections are loaded in DRAM. In conservative
+ * approach  the IRAM_PREF sections are always loaded in SDRAM. In greedy approach
+ * the IRAM_PREF sections are first laoded in IRAM. If IRAM allocation fails for an IRAM_PREF
+ * section, it would fallback to DRAM. A successful load should return a valid handle.
+ *
+ * IRAM_MAND_ADDR = 0x40000000
+ * DRAM_MAND_ADDR = 0x10000000
+ * Then
+ *    If (vaddr < DRAM_MAND_ADDR)
+ *       IRAM_PREF Section
+ *   Else (vaddr >= IRAM_MAND_ADDR)
+ *       IRAM_MAND Section
+ *   Else
+ *       DRAM_MAND Section
+ *
+ * If some of the parameters passed are not valid assert
+ * encountered in debug mode.
+ *
+ * @ingroup nvrm_moduleloader
+ *
+ * @param hDevice The handle to the RM device
+ * @param pLibName The library to be loaded.
+ * @param pArgs The arguments to be passed.
+ * @param sizeOfArgs The size of arguments passed.
+ * @param IsApproachGreedy The approach used to load the segments.
+ * @param hLibHandle The handle to the loaded library
+ *
+ * @retval NvSuccess Load library operation completed successfully
+ * @retval NvError_FileReadFailed Indicates that the fileoffset read failed
+ * @retval NvError_LibraryNotFound Indicates the given library could not be found
+ * @retval NvError_InsufficientMemory Indicates memory allocation failed
+ * @retval NvError_InvalidElfFormat Indicates the ELF file is not valid
+ */
+
+ NvError NvRmLoadLibraryEx(
+    NvRmDeviceHandle hDevice,
+    const char * pLibName,
+    void* pArgs,
+    NvU32 sizeOfArgs,
+    NvBool IsApproachGreedy,
+    NvRmLibraryHandle * hLibHandle );
+
+/**
+ * Get symbol address for a given symbol name and handle.
+ *
+ * Client will request for symbol address for a export function by
+ * sending down the symbol name and handle to the loaded library.
+ *
+ * Assert encountered if some of the parameters passed are not valid
+ *
+ * NOTE: This function is currently only used to obtain the entry
+ * point address (ie, the address of "main"). It should be noted
+ * that the entry point must ALWAYS be in THUMB mode! Using ARM
+ * mode will cause the module to crash.
+ *
+ * @ingroup nvrm_moduleloader
+ *
+ * @param hLibHandle Library handle which is returned by NvRmLoadLibrary().
+ * @param pSymbolName pointer to a symbol name to be looked up
+ * @param pSymAddress pointer to a symbol address
+ *
+ * @retval NvSuccess Symbol address is obtained successfully.
+ * @retval NvError_SymbolNotFound Indicates the symbol requested is not found
+ */
+
+ NvError NvRmGetProcAddress(
+    NvRmLibraryHandle hLibHandle,
+    const char * pSymbolName,
+    void* * pSymAddress );
+
+/**
+ * Free the losded memory of the corresponding library handle.
+ *
+ * This API will use the handle to get the base loaded address and free the memory
+ *
+ * @param hLibHandle The handle which is returned by NvRmLoadLibrary().
+ *
+ * @retval NvSuccess Successfuly unloaded the library memory.
+ */
+
+ NvError NvRmFreeLibrary(
+    NvRmLibraryHandle hLibHandle );
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
index 5d94bc4ca8463cdadd8d423b960b39c5debf5f6f..b5e63bd493e1e0d46dd45f572310d60caa70cc99 100644 (file)
@@ -11,5 +11,6 @@ ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core/common
 ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core
 
 #obj-y += ap15rm_init.o
+obj-y += ap15rm_avp_service.o
 obj-y += ap15rm_xpc.o
 obj-y += ap15rm_xpc_hw_private.o
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_avp_service.c b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_avp_service.c
new file mode 100644 (file)
index 0000000..53f5032
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_avp_service.c
+ *
+ * AVP service to handle AVP messages.
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/** @file
+ * @brief <b>NVIDIA Driver Development Kit:
+ *              Testcases for the xpc </b>
+ *
+ * @b Description: This file implements the AVP service to handle AVP messages.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+
+#include "nvcommon.h"
+#include "nvassert.h"
+#include "nvrm_drf.h"
+#include "nvrm_init.h"
+#include "nvrm_message.h"
+#include "nvrm_rpc.h"
+#include "nvrm_moduleloader_private.h"
+#include "nvrm_graphics_private.h"
+#include "ap15/arres_sema.h"
+#include "ap15/arflow_ctlr.h"
+#include "ap15/arapbpm.h"
+#include "nvrm_avp_swi_registry.h"
+#include "ap15/arevp.h"
+#include "nvrm_hardware_access.h"
+#include "mach/io.h"
+#include "mach/iomap.h"
+
+static NvU32 s_AvpInitialized = NV_FALSE;
+static NvRmLibraryHandle s_hAvpLibrary = NULL;
+
+#define NV_USE_AOS 1
+
+#define AVP_EXECUTABLE_NAME "nvrm_avp.axf"
+
+void NvRmPrivProcessMessage(NvRmRPCHandle hRPCHandle, char *pRecvMessage, int messageLength)
+{
+    NvError Error = NvSuccess;
+    NvRmMemHandle hMem;
+
+    switch ((NvRmMsg)*pRecvMessage) {
+
+    case NvRmMsg_MemHandleCreate:
+    {
+        NvRmMessage_HandleCreat *msgHandleCreate = NULL;
+        NvRmMessage_HandleCreatResponse msgRHandleCreate;
+
+        msgHandleCreate = (NvRmMessage_HandleCreat*)pRecvMessage;
+
+        msgRHandleCreate.msg = NvRmMsg_MemHandleCreate;
+        Error = NvRmMemHandleCreate(hRPCHandle->hRmDevice,&hMem, msgHandleCreate->size);
+        if (!Error) {
+            msgRHandleCreate.hMem = hMem;
+        }
+        msgRHandleCreate.msg = NvRmMsg_MemHandleCreate_Response;
+        msgRHandleCreate.error = Error;
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgRHandleCreate,
+                           sizeof(msgRHandleCreate));
+    }
+    break;
+    case NvRmMsg_MemHandleOpen:
+        break;
+    case NvRmMsg_MemHandleFree:
+    {
+        NvRmMessage_HandleFree *msgHandleFree = NULL;
+        msgHandleFree = (NvRmMessage_HandleFree*)pRecvMessage;
+        NvRmMemHandleFree(msgHandleFree->hMem);
+    }
+    break;
+    case NvRmMsg_MemAlloc:
+    {
+        NvRmMessage_MemAlloc *msgMemAlloc = NULL;
+        NvRmMessage_Response msgResponse;
+        msgMemAlloc = (NvRmMessage_MemAlloc*)pRecvMessage;
+
+        Error = NvRmMemAlloc(msgMemAlloc->hMem,
+                    (msgMemAlloc->NumHeaps == 0) ? NULL : msgMemAlloc->Heaps,
+                    msgMemAlloc->NumHeaps,
+                    msgMemAlloc->Alignment,
+                    msgMemAlloc->Coherency);
+        msgResponse.msg = NvRmMsg_MemAlloc_Response;
+        msgResponse.error = Error;
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_MemPin:
+    {
+        NvRmMessage_Pin *msgHandleFree = NULL;
+        NvRmMessage_PinResponse msgResponse;
+        msgHandleFree = (NvRmMessage_Pin*)pRecvMessage;
+
+        msgResponse.address = NvRmMemPin(msgHandleFree->hMem);
+        msgResponse.msg = NvRmMsg_MemPin_Response;
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_MemUnpin:
+    {
+        NvRmMessage_HandleFree *msgHandleFree = NULL;
+        NvRmMessage_Response msgResponse;
+        msgHandleFree = (NvRmMessage_HandleFree*)pRecvMessage;
+
+        NvRmMemUnpin(msgHandleFree->hMem);
+
+        msgResponse.msg = NvRmMsg_MemUnpin_Response;
+        msgResponse.error = NvSuccess;
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_MemGetAddress:
+    {
+        NvRmMessage_GetAddress *msgGetAddress = NULL;
+        NvRmMessage_GetAddressResponse msgGetAddrResponse;
+
+        msgGetAddress = (NvRmMessage_GetAddress*)pRecvMessage;
+
+        msgGetAddrResponse.msg     = NvRmMsg_MemGetAddress_Response;
+        msgGetAddrResponse.address = NvRmMemGetAddress(msgGetAddress->hMem,msgGetAddress->Offset);
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgGetAddrResponse, sizeof(msgGetAddrResponse));
+    }
+    break;
+    case NvRmMsg_HandleFromId :
+    {
+        NvRmMessage_HandleFromId *msgHandleFromId = NULL;
+        NvRmMessage_Response msgResponse;
+        NvRmMemHandle hMem;
+
+        msgHandleFromId = (NvRmMessage_HandleFromId*)pRecvMessage;
+
+        msgResponse.msg     = NvRmMsg_HandleFromId_Response;
+        msgResponse.error = NvRmMemHandleFromId(msgHandleFromId->id, &hMem);
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(NvRmMessage_Response));
+    }
+    break;
+    case NvRmMsg_PowerModuleClockControl:
+    {
+        NvRmMessage_Module *msgPMCC;
+        NvRmMessage_Response msgPMCCR;
+        msgPMCC = (NvRmMessage_Module*)pRecvMessage;
+
+        msgPMCCR.msg = NvRmMsg_PowerModuleClockControl_Response;
+        msgPMCCR.error = NvRmPowerModuleClockControl(hRPCHandle->hRmDevice,
+                                                     msgPMCC->ModuleId,
+                                                     msgPMCC->ClientId,
+                                                     msgPMCC->Enable);
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgPMCCR, sizeof(msgPMCCR));
+    }
+    break;
+    case NvRmMsg_ModuleReset:
+    {
+        NvRmMessage_Module *msgPMCC;
+        NvRmMessage_Response msgPMCCR;
+        msgPMCC = (NvRmMessage_Module*)pRecvMessage;
+
+        msgPMCCR.msg = NvRmMsg_ModuleReset_Response;
+
+        NvRmModuleReset(hRPCHandle->hRmDevice, msgPMCC->ModuleId);
+        /// Send response since clients to this call needs to wait
+        /// for some time before they can start using the HW module
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgPMCCR, sizeof(msgPMCCR));
+    }
+    break;
+
+    case NvRmMsg_PowerRegister:
+    {
+        NvRmMessage_PowerRegister *msgPower;
+        NvRmMessage_PowerRegister_Response msgResponse;
+
+        msgPower = (NvRmMessage_PowerRegister*)pRecvMessage;
+
+        msgResponse.msg   = NvRmMsg_PowerResponse;
+        msgResponse.error = NvSuccess;
+        msgResponse.clientId = msgPower->clientId;
+
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+
+    }
+    break;
+
+    case NvRmMsg_PowerUnRegister:
+        break;
+    case NvRmMsg_PowerStarvationHint:
+    case NvRmMsg_PowerBusyHint:
+    {
+        NvRmMessage_Response msgResponse;
+        msgResponse.msg   = NvRmMsg_PowerResponse;
+        msgResponse.error = NvSuccess;
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_PowerBusyMultiHint:
+        break;
+    case NvRmMsg_PowerDfsGetState:
+    {
+        NvRmMessage_PowerDfsGetState_Response msgResponse;
+        msgResponse.msg = NvRmMsg_PowerDfsGetState_Response;
+        msgResponse.state = NvRmDfsRunState_Stopped;
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_PowerModuleGetMaxFreq:
+    {
+        NvRmMessage_PowerModuleGetMaxFreq_Response msgResponse;
+        msgResponse.msg = NvRmMsg_PowerModuleGetMaxFreq;
+        msgResponse.freqKHz = 0;
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_PowerDfsGetClockUtilization:
+    {
+        NvRmMessage_PowerDfsGetClockUtilization_Response msgResponse;
+        NvRmDfsClockUsage ClockUsage = { 0, 0, 0, 0, 0, 0 };
+
+        msgResponse.msg = NvRmMsg_PowerDfsGetClockUtilization_Response;
+        msgResponse.error = NvSuccess;
+        NvOsMemcpy(&msgResponse.clockUsage, &ClockUsage, sizeof(ClockUsage));
+        NvRmPrivRPCSendMsg(hRPCHandle, &msgResponse, sizeof(msgResponse));
+    }
+    break;
+    case NvRmMsg_InitiateLP0:
+    {
+        //Just for testing purposes.
+    }
+    break;
+    case NvRmMsg_RemotePrintf:
+    {
+        NvRmMessage_RemotePrintf *msg;
+
+        msg = (NvRmMessage_RemotePrintf*)pRecvMessage;
+        NvOsDebugPrintf("AVP: %s", msg->string);
+    }
+    break;
+    case NvRmMsg_AVP_Reset:
+        NvOsDebugPrintf("AVP has been reset by WDT\n");
+        break;
+    default:
+        NV_ASSERT( !"AVP Service::ProcessMessage: bad message" );
+        break;
+    }
+}
+
+NvError
+NvRmPrivInitAvp(NvRmDeviceHandle hDevice)
+{
+    NvError err = NvSuccess;
+    void* avpExecutionJumpAddress;
+    NvU32 RegVal, resetVector;
+
+    // Do this only once.
+    if (s_AvpInitialized) return NvSuccess;
+
+    NvOsDebugPrintf("%s <kernel impl>: called\n", __func__);
+
+    err = NvRmPrivLoadKernelLibrary(hDevice, AVP_EXECUTABLE_NAME, &s_hAvpLibrary);
+    if (err != NvSuccess) {
+        NV_DEBUG_PRINTF(("AVP executable file not found\n"));
+        NV_ASSERT(!"AVP executable file not found");
+    }
+
+    err = NvRmGetProcAddress(s_hAvpLibrary, "main", &avpExecutionJumpAddress);
+    NV_ASSERT(err == NvSuccess);
+    NvOsDebugPrintf("%s <kernel impl>: avpExecutionJumpAddress=%x\n", __func__, avpExecutionJumpAddress);
+
+    resetVector = (NvU32)avpExecutionJumpAddress & 0xFFFFFFFE;
+
+    NV_WRITE32(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) +  EVP_COP_RESET_VECTOR_0, resetVector);
+    RegVal = NV_READ32(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) +  EVP_COP_RESET_VECTOR_0);
+    NV_ASSERT( RegVal == resetVector );
+
+    NvRmModuleReset(hDevice, NvRmModuleID_Avp);
+
+    /// Resume AVP
+    RegVal = NV_DRF_DEF(FLOW_CTLR, HALT_COP_EVENTS, MODE, FLOW_MODE_NONE);
+    NV_WRITE32(IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) +  FLOW_CTLR_HALT_COP_EVENTS_0, RegVal);
+
+    s_AvpInitialized = NV_TRUE;
+
+    err = NvRmPrivInitService(hDevice);
+    if (err) return err;
+
+    err = NvRmPrivInitModuleLoaderRPC(hDevice);
+    if (err) return err;
+
+    return err;
+}
index e57ea8d3dec97393a98172605dbde3cab0861c81..eb84beed8bdda73c53cb3d769f552b02d99ea4eb 100644 (file)
@@ -10,7 +10,11 @@ ccflags-y += -Iarch/arm/mach-tegra/nv/include
 ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core/common
 ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core
 
+obj-y += nvrm_avp_cpu_rpc.o
+obj-y += nvrm_moduleloader.o
 obj-y += nvrm_rmctrace.o
 obj-y += nvrm_transport.o
 obj-y += nvrm_module_stub.o
-obj-y += nvrm_power.o
\ No newline at end of file
+obj-y += nvrm_power.o
+obj-y += nvrm_init_stub.o
+
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_cpu_rpc.c b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_cpu_rpc.c
new file mode 100644 (file)
index 0000000..60c259d
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_avp_cpu_rpc.c
+ *
+ * Transport API
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/** @file
+ * @brief <b>NVIDIA Driver Development Kit:
+ *          Transport API</b>
+ *
+ * @b Description: This is the wrapper implementation of Transport API.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "nvrm_transport.h"
+#include "nvrm_xpc.h"
+#include "nvrm_rpc.h"
+#include "nvrm_interrupt.h"
+#include "nvassert.h"
+#include "nvrm_graphics_private.h"
+
+/* global variable passed from nvrpc_user.c */
+extern NvRmTransportHandle g_hTransportAvp;
+extern NvRmTransportHandle g_hTransportCpu;
+extern NvOsSemaphoreHandle g_hTransportAvpSem;
+extern NvOsSemaphoreHandle g_hTransportCpuSem;
+extern int g_hTransportAvpIsConnected;
+extern int g_hTransportCpuIsConnected;
+
+/* local variables for handles */
+static NvOsThreadHandle s_RecvThreadId_Service;
+static NvRmRPCHandle gs_hRPCHandle = NULL;
+volatile static int s_ContinueProcessing = 1;
+
+#if !NV_IS_AVP
+#define  PORT_NAME  "RPC_CPU_PORT"
+#else
+#define  PORT_NAME  "RPC_AVP_PORT"
+#endif
+/* Receive message port thread */
+static void ServiceThread( void *args );
+static void ServiceThread( void *args )
+{
+       NvError Error = NvSuccess;
+       static NvU8 ReceiveMessage[MAX_MESSAGE_LENGTH];
+       NvU32 MessageLength = 0;
+
+       NvOsDebugPrintf("%s: started\n", __func__);
+
+       Error = NvRmPrivRPCWaitForConnect(gs_hRPCHandle);
+       if (Error)
+       {
+               goto exit_gracefully;
+       }
+       while (s_ContinueProcessing)
+       {
+               Error = NvRmPrivRPCRecvMsg(gs_hRPCHandle, ReceiveMessage,
+                                       &MessageLength);
+               if (Error == NvError_InvalidState)
+               {
+                       break;
+               }
+               if (!Error)
+               {
+                       ReceiveMessage[MessageLength] = '\0';
+               }
+               NvRmPrivProcessMessage(gs_hRPCHandle, (char*)ReceiveMessage,
+                               MessageLength);
+       }
+
+exit_gracefully:
+        return;
+}
+
+NvError NvRmPrivRPCInit(NvRmDeviceHandle hDeviceHandle, char* portName,
+                       NvRmRPCHandle *hRPCHandle )
+{
+       NvError Error = NvSuccess;
+
+       NvOsDebugPrintf("%s: portName=%s\n", __func__, portName);
+
+       *hRPCHandle = NvOsAlloc(sizeof(NvRmRPC));
+       if (!*hRPCHandle)
+       {
+               Error = NvError_InsufficientMemory;
+               return Error;
+       }
+
+       Error = NvOsMutexCreate(&(*hRPCHandle)->RecvLock);
+       if( Error != NvSuccess)
+       {
+               goto clean_up;
+       }
+
+       if (! portName) {
+               panic("%s: No port name.\n", __func__);
+       }
+       if (! strcmp(portName, "RPC_AVP_PORT")) {
+               if (g_hTransportAvp) panic("%s: g_hTransportAvp is already set.\n", __func__);
+               NvOsDebugPrintf("%s: creating RPC_AVP_PORT.\n", __func__);
+
+               Error = NvOsSemaphoreCreate(&g_hTransportAvpSem, 0);
+               if (Error != NvSuccess) panic(__func__);
+
+               Error = NvRmTransportOpen(hDeviceHandle, portName, g_hTransportAvpSem,
+                                       &g_hTransportAvp);
+               if (Error != NvSuccess) panic(__func__);
+
+               (*hRPCHandle)->svcTransportHandle = g_hTransportAvp;
+               (*hRPCHandle)->TransportRecvSemId = g_hTransportAvpSem;
+               (*hRPCHandle)->isConnected = g_hTransportAvpIsConnected;
+               NvOsDebugPrintf("%s: isConnected=%d\n", __func__, g_hTransportAvpIsConnected);
+       }
+       if (! strcmp(portName, "RPC_CPU_PORT")) {
+               if (g_hTransportCpu) panic("%s: g_hTransportCpu is already set.\n", __func__);
+               NvOsDebugPrintf("%s: creating RPC_CPU_PORT.\n", __func__);
+
+               Error = NvOsSemaphoreCreate(&g_hTransportCpuSem, 0);
+               if (Error != NvSuccess) panic(__func__);
+
+               Error = NvRmTransportOpen(hDeviceHandle, portName, g_hTransportCpuSem,
+                                       &g_hTransportCpu);
+               if (Error != NvSuccess) panic(__func__);
+
+               (*hRPCHandle)->svcTransportHandle = g_hTransportCpu;
+               (*hRPCHandle)->TransportRecvSemId = g_hTransportCpuSem;
+               (*hRPCHandle)->isConnected = g_hTransportCpuIsConnected;
+               NvOsDebugPrintf("%s: isConnected=%d\n", __func__, g_hTransportCpuIsConnected);
+       }
+       (*hRPCHandle)->hRmDevice = hDeviceHandle;
+
+clean_up:
+       return Error;
+}
+
+void NvRmPrivRPCDeInit( NvRmRPCHandle hRPCHandle )
+{
+       if(hRPCHandle != NULL)
+       {
+               if(hRPCHandle->svcTransportHandle != NULL)
+               {
+                       NvOsSemaphoreDestroy(hRPCHandle->TransportRecvSemId);
+                       NvOsMutexDestroy(hRPCHandle->RecvLock);
+                       NvRmTransportClose(hRPCHandle->svcTransportHandle);
+                       hRPCHandle->svcTransportHandle = NULL;
+                       hRPCHandle->isConnected = NV_FALSE;
+               }
+               NvOsFree(hRPCHandle);
+       }
+}
+
+void NvRmPrivRPCSendMsg(NvRmRPCHandle hRPCHandle,
+                       void* pMessageBuffer,
+                       NvU32 MessageSize)
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(hRPCHandle->svcTransportHandle != NULL);
+
+       NvOsMutexLock(hRPCHandle->RecvLock);
+       Error = NvRmTransportSendMsg(hRPCHandle->svcTransportHandle,
+                               pMessageBuffer, MessageSize, NV_WAIT_INFINITE);
+       NvOsMutexUnlock(hRPCHandle->RecvLock);
+       if(Error)
+               NV_ASSERT(Error == NvSuccess);
+}
+
+void NvRmPrivRPCSendMsgWithResponse( NvRmRPCHandle hRPCHandle,
+                               void* pRecvMessageBuffer,
+                               NvU32 MaxSize,
+                               NvU32 * pMessageSize,
+                               void* pSendMessageBuffer,
+                               NvU32 MessageSize)
+{
+       NvError Error = NvSuccess;
+       NvOsDebugPrintf("%s: started\n", __func__);
+       NV_ASSERT(hRPCHandle->svcTransportHandle != NULL);
+
+       NvOsMutexLock(hRPCHandle->RecvLock);
+       NvOsDebugPrintf("%s: calling NvRmTransportSendMsg\n", __func__);
+       Error = NvRmTransportSendMsg(hRPCHandle->svcTransportHandle,
+                               pSendMessageBuffer, MessageSize, NV_WAIT_INFINITE);
+       if (Error)
+       {
+               // TODO: Determine cause of error and pass appropriate error to caller.
+               NvOsDebugPrintf("%s: error in NvRmTransportSendMsg\n", __func__);
+               goto clean_up;
+       }
+       NvOsDebugPrintf("%s: returned from NvRmTransportSendMsg\n", __func__);
+
+       NvOsDebugPrintf("%s: NvOsSemaphoreWait(TransportRecvSemId=%x)\n", __func__,hRPCHandle->TransportRecvSemId);
+       NvOsSemaphoreWait(hRPCHandle->TransportRecvSemId);
+
+       NvOsDebugPrintf("%s: calling NvRmTransportRecvMsg\n", __func__);
+       Error = NvRmTransportRecvMsg(hRPCHandle->svcTransportHandle,
+                               pRecvMessageBuffer, MaxSize, pMessageSize);
+       if (Error)
+       {
+               NvOsDebugPrintf("%s: error in NvRmTransportRecvMsg\n", __func__);
+               goto clean_up;
+       }
+       NvOsDebugPrintf("%s: returned from NvRmTransportRecvMsg\n", __func__);
+
+clean_up:
+       NV_ASSERT(Error == NvSuccess);
+       NvOsMutexUnlock(hRPCHandle->RecvLock);
+}
+
+NvError NvRmPrivRPCWaitForConnect( NvRmRPCHandle hRPCHandle )
+{
+       NvError Error = NvSuccess;
+
+       NV_ASSERT(hRPCHandle != NULL);
+       NV_ASSERT(hRPCHandle->svcTransportHandle != NULL);
+
+       if (hRPCHandle->isConnected) panic("%s: line=%d\n", __func__, __LINE__);
+       if(hRPCHandle->isConnected == NV_FALSE)
+       {
+               Error = NvRmTransportSetQueueDepth(hRPCHandle->svcTransportHandle,
+                                               MAX_QUEUE_DEPTH, MAX_MESSAGE_LENGTH);
+               if (Error)
+               {
+                       goto clean_up;
+               }
+               Error = NvError_InvalidState;
+               // Connect to the other end
+               while (s_ContinueProcessing)
+               {
+                       /* NvOsDebugPrintf("%s: NvRmTransportWaitForConnect(handle=%x)\n", __func__, hRPCHandle->svcTransportHandle); */
+                       Error = NvRmTransportWaitForConnect(
+                               hRPCHandle->svcTransportHandle, 100 );
+                       /* NvOsDebugPrintf("%s: NvRmTransportWaitForConnect=%d\n", __func__, Error); */
+                       if (Error == NvSuccess)
+                       {
+                               hRPCHandle->isConnected = NV_TRUE;
+                               break;
+                       }
+                       // if there is some other issue than a timeout, then bail out.
+                       if (Error != NvError_Timeout)
+                       {
+                               goto clean_up;
+                       }
+               }
+       }
+
+clean_up:
+       return Error;
+}
+
+NvError NvRmPrivRPCConnect( NvRmRPCHandle hRPCHandle )
+{
+       NvError Error = NvSuccess;
+
+       NV_ASSERT(hRPCHandle != NULL);
+       NV_ASSERT(hRPCHandle->svcTransportHandle != NULL);
+
+       /* if (hRPCHandle->isConnected) panic("%s: line=%d\n", __func__, __LINE__); */
+       NvOsMutexLock(hRPCHandle->RecvLock);
+       if(hRPCHandle->isConnected == NV_TRUE)
+       {
+               goto clean_up;
+       }
+       Error = NvRmTransportSetQueueDepth(hRPCHandle->svcTransportHandle,
+                                       MAX_QUEUE_DEPTH, MAX_MESSAGE_LENGTH);
+       if (Error)
+       {
+               goto clean_up;
+       }
+       Error = NvError_InvalidState;
+
+#define CONNECTION_TIMEOUT (20 * 1000)
+
+       // Connect to the other end with a large timeout
+       // Timeout value has been increased to suit slow enviornments like
+       // emulation FPGAs
+       NvOsDebugPrintf("%s: NvRmTransportConnect(handle=%x)\n", __func__, hRPCHandle->svcTransportHandle);
+       Error = NvRmTransportConnect(hRPCHandle->svcTransportHandle,
+                               CONNECTION_TIMEOUT );
+       NvOsDebugPrintf("%s: NvRmTransportConnect=%d\n", __func__, Error);
+       if(Error == NvSuccess)
+       {
+               NvOsDebugPrintf("%s: Connected.\n", __func__);
+               hRPCHandle->isConnected = NV_TRUE;
+       }
+       else
+       {
+               NvOsDebugPrintf("%s: Not connected.\n", __func__);
+       }
+
+#undef CONNECTION_TIMEOUT
+
+clean_up:
+       NvOsMutexUnlock(hRPCHandle->RecvLock);
+       return Error;
+}
+
+NvError NvRmPrivRPCRecvMsg( NvRmRPCHandle hRPCHandle, void* pMessageBuffer,
+                       NvU32 * pMessageSize )
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(hRPCHandle->svcTransportHandle != NULL);
+
+       if (s_ContinueProcessing == 0)
+       {
+               Error = NvError_InvalidState;
+               goto clean_up;
+       }
+
+       NvOsSemaphoreWait(hRPCHandle->TransportRecvSemId);
+       if(s_ContinueProcessing != 0)
+       {
+
+               Error = NvRmTransportRecvMsg(hRPCHandle->svcTransportHandle,
+                                       pMessageBuffer, MAX_MESSAGE_LENGTH, pMessageSize);
+       }
+       else
+       {
+               Error = NvError_InvalidState;
+       }
+clean_up:
+       return Error;
+}
+
+void NvRmPrivRPCClose( NvRmRPCHandle hRPCHandle )
+{
+       // signal the thread to exit
+       s_ContinueProcessing = 0;
+       if(hRPCHandle && hRPCHandle->svcTransportHandle != NULL)
+       {
+               if (hRPCHandle->TransportRecvSemId)
+                       NvOsSemaphoreSignal(hRPCHandle->TransportRecvSemId);
+       }
+}
+
+NvError NvRmPrivInitService(NvRmDeviceHandle hDeviceHandle)
+{
+       NvError Error = NvSuccess;
+
+       NvOsDebugPrintf("%s <kernel>: called\n", __func__);
+       Error = NvRmPrivRPCInit(hDeviceHandle, PORT_NAME, &gs_hRPCHandle);
+       if( Error != NvSuccess)
+       {
+               goto exit_gracefully;
+       }
+       NV_ASSERT(gs_hRPCHandle != NULL);
+
+#if !NV_IS_AVP
+       Error = NvOsInterruptPriorityThreadCreate(ServiceThread, NULL,
+                                               &s_RecvThreadId_Service);
+       NvOsDebugPrintf("%s: s_RecvThreadId_Service=%p\n", __func__, s_RecvThreadId_Service);
+#else
+       Error = NvOsThreadCreate(ServiceThread, NULL, &s_RecvThreadId_Service);
+#endif
+
+exit_gracefully:
+       return Error;
+}
+
+void NvRmPrivServiceDeInit()
+{
+       NvRmPrivRPCClose(gs_hRPCHandle);
+       NvOsThreadJoin(s_RecvThreadId_Service);
+       NvRmPrivRPCDeInit(gs_hRPCHandle);
+}
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_swi_registry.h b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_swi_registry.h
new file mode 100644 (file)
index 0000000..712bca9
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_avp_swi_registry.h
+ *
+ *
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef INCLUDED_NVRM_AVP_SWI_REGISTRY_H
+#define INCLUDED_NVRM_AVP_SWI_REGISTRY_H
+
+#include "nvcommon.h"
+#include "nvos.h"
+#include "nvrm_power.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+enum {MAX_CLIENTS = 5};
+enum {MAX_SWI_PER_CLIENT = 32};
+enum {CLIENT_SWI_NUM_START = 0xD0};
+
+typedef NvError (*AvpClientSwiHandler) (int *pRegs);
+
+typedef enum
+{
+    AvpSwiClientType_None = 0,
+    AvpSwiClientType_NvMM,
+    AvpSwiClientType_Force32 = 0x7fffffff
+} AvpSwiClientType;
+
+typedef enum {
+    AvpSwiClientSwiNum_NvMM = 0xD0,
+    AvpSwiClientSwiNum_Force32 = 0x7fffffff
+} AvpSwiClientSwiNum;
+
+typedef struct AvpSwiClientRec
+{
+    AvpClientSwiHandler ClientSwiHandler[MAX_SWI_PER_CLIENT];
+    AvpSwiClientType ClientId;
+    AvpSwiClientSwiNum SwiNum;
+} AvpSwiClient;
+
+typedef struct AvpSwiClientRegistryRec
+{
+    AvpSwiClient SwiClient[MAX_CLIENTS];
+    NvU32 RefCount;
+    NvOsMutexHandle Mutex;
+}AvpSwiClientRegistry;
+
+NvError
+NvRmAvpClientSwiHandlerRegister(
+    AvpSwiClientType ClientId,
+    AvpClientSwiHandler pClinetSwiFunc,
+    NvU32 *pClientIndex);
+
+NvError
+NvRmAvpClientSwiHandlerUnRegister(
+    AvpSwiClientType ClientId,
+    NvU32 ClientIndex);
+
+NvError
+NvRmAvpHandleClientSwi(
+    NvU32 SwiNum,
+    NvU32 ClientIndex,
+    int *pRegs);
+
+typedef struct{
+    NvRmDfsClockId clockId;
+    NvU32 clientId;
+    NvU32 boostDurationMS;
+    NvRmFreqKHz boostKHz;
+}NvRm_PowerBusyHint;
+
+/** NvRmRegisterLibraryCall - Register a library call with the AVP RM
+ *
+ *  @param id The user id to associate with the function
+ *  @param pEntry The function to be registered
+ *  @param pOwnerKey A special unique key to use when unregistering.
+ *
+ *  @returns InsufficientMemory or AlreadyAllocated on failure.
+ */
+NvError
+NvRmRegisterLibraryCall(NvU32 Id, void *pEntry, NvU32 *pOwnerKey);
+
+/** NvRmUnregisterLibraryCall - Unregister a library call
+ *
+ *  @param id The user id associated with the function
+ *  @param pOwnerKey A special unique key. Used to ensure that the correct owner
+ *  unregisters a function.
+ *
+ */
+void
+NvRmUnregisterLibraryCall(NvU32 Id, NvU32 OwnerKey);
+
+/** NvRmGetLibraryCall - Obtain a registered function from the AVP RM
+ *
+ *  @param id The user id associated with the desired library function
+ *
+ *  @returns NULL on failure. The function pointer on success
+ */
+void *NvRmGetLibraryCall(NvU32 Id);
+
+/** NvRmRemoteDebugPrintf - Routes client prints to the CPU.
+ *
+ *  NOTE: This does *not* route kernel prints. ONLY AVP client prints will
+ *  be routed.
+ *  @param string The debug string to print to console
+ *
+ */
+void *NvRmRemoteDebugPrintf(const char *string);
+
+/** NvOsAVPThreadCreate - Creates threads on the AVP with an optional stackPtr argument.
+ *
+ *  AVP clients can use this function to allocate thread stacks wherever they desire (like in
+ *  IRAM, for instance). It is the clients responsibility to allocate this pointer and free it.
+ *  NOTE: The client must free this pointer only after the thread has been joined.
+ *
+ *  @param function The thread entry point
+ *  @param args The thread args
+ *  @param thread The result thread id structure (out param)
+ *  @param stackPtr The optional pointer to a user allocated stack (Can be NULL)
+ *  @param stackSize The size of the associated stackPtr.
+ *
+ */
+NvError NvOsAVPThreadCreate(NvOsThreadFunction function,
+                            void *args,
+                            NvOsThreadHandle *thread,
+                            void *stackPtr,
+                            NvU32 stackSize);
+
+/** NvOsAVPSetIdle - This function is used to force the AVP kernel to save its state
+ *
+ *  When the PMC_SCRATCH22 register has a non-zero value, the AVP has finished saving all its state.
+ *  @param iramSourceAddress The address at which the IRAM aperture begins
+ *  @param iramBufferAddress The address of the buffer into which the AVP will save all IRAM state.
+ *  @param iramSize The size of the iram aperture.
+ *
+ */
+void NvOsAVPSetIdle(NvU32 iramSourceAddress,
+                    NvU32 iramBufferAddress,
+                    NvU32 iramSize);
+
+/** NvRmPowerBusyMultiHint - Provide hints to multiple modules. Saves on messaging overhead.
+ *
+ *  @param multiHint The array of hints
+ *  @param numHints The number of hints
+ */
+void NvRmPowerBusyMultiHint(NvRm_PowerBusyHint *multiHint, NvU32 numHints);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_graphics_private.h b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_graphics_private.h
new file mode 100644 (file)
index 0000000..3953b36
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_graphics_private.h
+ *
+ *
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef NVRM_GRAPHICS_PRIVATE_H
+#define NVRM_GRAPHICS_PRIVATE_H
+
+#define NVRM_TRANSPORT_IN_KERNEL 1
+
+/**
+ * Initialize all graphics stuff
+ *
+ * @param hDevice The RM instance
+ */
+NvError
+NvRmGraphicsOpen( NvRmDeviceHandle rm );
+
+/**
+ * Deinitialize all graphics stuff
+ *
+ * @param hDevice The RM instance
+ */
+void
+NvRmGraphicsClose( NvRmDeviceHandle rm );
+
+/**
+ * Initialize the channels.
+ *
+ * @param hDevice The RM instance
+ */
+NvError
+NvRmPrivChannelInit( NvRmDeviceHandle hDevice );
+
+/**
+ * Deinitialize the channels.
+ *
+ * @param hDevice The RM instance
+ */
+void
+NvRmPrivChannelDeinit( NvRmDeviceHandle hDevice );
+
+/**
+ * Initialize the graphics host, including interrupts.
+ */
+void
+NvRmPrivHostInit( NvRmDeviceHandle rm );
+
+void
+NvRmPrivHostShutdown( NvRmDeviceHandle rm );
+
+#if (NVRM_TRANSPORT_IN_KERNEL == 0)
+NvError
+NvRmPrivTransportInit(NvRmDeviceHandle hRmDevice);
+
+void
+NvRmPrivTransportDeInit(NvRmDeviceHandle hRmDevice);
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_init_stub.c b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_init_stub.c
new file mode 100644 (file)
index 0000000..481ebd4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2009 NVIDIA Corporation.  All rights reserved.
+ *
+ * NVIDIA Corporation and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto.  Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA Corporation is strictly prohibited.
+ */
+
+#include "nvcommon.h"
+#include "nvos.h"
+#include "nvassert.h"
+#include "nvidlcmd.h"
+#include "nvrm_init.h"
+
+void NvRmClose(NvRmDeviceHandle hDevice)
+{
+}
+
+NvError NvRmOpenNew(NvRmDeviceHandle *pHandle)
+{
+    *pHandle = (void *)1;
+    return NvSuccess;
+}
+
+void NvRmInit(NvRmDeviceHandle *pHandle)
+{
+}
+
+NvError NvRmOpen(NvRmDeviceHandle *pHandle, NvU32 DeviceId)
+{
+    return NvRmOpenNew(pHandle);
+}
index e32033f6aa056b950bf34cbf880a5b4f00702e67..0fe59dbf293a944f52c8aa8eafb867bb9a925a66 100644 (file)
@@ -1,33 +1,23 @@
 /*
- * Copyright (c) 2010 NVIDIA Corporation.
- * All rights reserved.
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_message.h
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
  *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
  *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
+ * Copyright (c) 2010, NVIDIA Corporation.
  *
- * Neither the name of the NVIDIA Corporation nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
  *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 #ifndef INCLUDED_NVRM_MESSAGE_H
@@ -43,16 +33,16 @@ extern "C"
 {
 #endif  /* __cplusplus */
 
-// Maximum message queue depth
+/* Maximum message queue depth */
 enum {MAX_QUEUE_DEPTH = 5};
-// Maximum message length
+/* Maximum message length */
 enum {MAX_MESSAGE_LENGTH = 256};
-// Maximum argument size
+/* Maximum argument size */
 enum {MAX_ARGS_SIZE = 220};
-// Max String length
+/* Max String length */
 enum {MAX_STRING_LENGTH = 200};
 
-typedef struct NvRmRPCRec 
+typedef struct NvRmRPCRec
 {
     NvRmTransportHandle svcTransportHandle;
     NvOsSemaphoreHandle TransportRecvSemId;
@@ -86,11 +76,11 @@ typedef enum
     NvRmMsg_ModuleReset,
     NvRmMsg_ModuleReset_Response,
     NvRmMsg_PowerRegister,
-    NvRmMsg_PowerUnRegister,    
+    NvRmMsg_PowerUnRegister,
     NvRmMsg_PowerStarvationHint,
     NvRmMsg_PowerBusyHint,
     NvRmMsg_PowerBusyMultiHint,
-    NvRmMsg_PowerDfsGetState,    
+    NvRmMsg_PowerDfsGetState,
     NvRmMsg_PowerDfsGetState_Response,
     NvRmMsg_PowerResponse,
     NvRmMsg_PowerModuleGetMaxFreq,
@@ -102,6 +92,8 @@ typedef enum
     NvRmMsg_DetachModule,
     NvRmMsg_DetachModule_Response,
     NvRmMsg_AVP_Reset,
+    NvRmMsg_PowerDfsGetClockUtilization,
+    NvRmMsg_PowerDfsGetClockUtilization_Response,
     NvRmMsg_Force32 = 0x7FFFFFFF
 }NvRmMsg;
 
@@ -171,11 +163,11 @@ typedef struct{
 typedef struct{
     NvRmMsg msg;
     NvU32 clientId;
-    NvOsSemaphoreHandle eventSema;    
+    NvOsSemaphoreHandle eventSema;
 }NvRmMessage_PowerRegister;
 
 typedef struct{
-    NvRmMsg msg;    
+    NvRmMsg msg;
     NvU32 clientId;
 }NvRmMessage_PowerUnRegister;
 
@@ -225,6 +217,18 @@ typedef struct{
     NvRmFreqKHz freqKHz;
 }NvRmMessage_PowerModuleGetMaxFreq_Response;
 
+typedef struct{
+    NvRmMsg msg;
+    NvError error;
+    NvRmDfsClockId clockId;
+}NvRmMessage_PowerDfsGetClockUtilization;
+
+typedef struct{
+    NvRmMsg msg;
+    NvError error;
+    NvRmDfsClockUsage clockUsage;
+}NvRmMessage_PowerDfsGetClockUtilization_Response;
+
 typedef struct{
     NvRmMsg msg;
     NvU32 sourceAddr;
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c
new file mode 100644 (file)
index 0000000..6de25c6
--- /dev/null
@@ -0,0 +1,1651 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_moduleloader.c
+ *
+ * AVP firmware module loader
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#define NV_ENABLE_DEBUG_PRINTS 0
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/uaccess.h>
+#include <asm/io.h>
+
+#include "nvcommon.h"
+#include "nvassert.h"
+#include "nvos.h"
+#include "nvutil.h"
+#include "nvrm_hardware_access.h"
+#include "nvrm_message.h"
+#include "nvrm_rpc.h"
+#include "nvrm_moduleloader.h"
+#include "nvrm_moduleloader_private.h"
+#include "nvrm_graphics_private.h"
+#include "nvrm_structure.h"
+#include "nvfw.h"
+
+#define DEVICE_NAME "nvfw"
+
+static const struct firmware *s_FwEntry;
+static NvRmRPCHandle s_RPCHandle = NULL;
+static NvError SendMsgDetachModule(NvRmLibraryHandle  hLibHandle);
+static NvError SendMsgAttachModule(NvRmLibraryHandle *hLibHandle,
+                               void* pArgs,
+                               NvU32 sizeOfArgs);
+NvU32 NvRmModuleGetChipId(NvRmDeviceHandle hDevice);
+NvError NvRmPrivInitModuleLoaderRPC(NvRmDeviceHandle hDevice);
+void NvRmPrivDeInitModuleLoaderRPC(void);
+
+#define ADD_MASK                   0x00000001
+#define SUB_MASK                   0xFFFFFFFD
+// For the elf to be relocatable, we need atleast 2 program segments
+// Although even elfs with more than 1 program segment may not be relocatable.
+#define MIN_SEGMENTS_FOR_DYNAMIC_LOADING    2
+
+static int nvfw_open(struct inode *inode, struct file *file);
+static int nvfw_close(struct inode *inode, struct file *file);
+static long nvfw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+static ssize_t nvfw_write(struct file *, const char __user *, size_t, loff_t *);
+
+static const struct file_operations nvfw_fops =
+{
+       .owner          = THIS_MODULE,
+       .open           = nvfw_open,
+       .release        = nvfw_close,
+       .write          = nvfw_write,
+       .unlocked_ioctl = nvfw_ioctl,
+};
+
+static struct miscdevice nvfw_dev =
+{
+       .name   = DEVICE_NAME,
+       .fops   = &nvfw_fops,
+       .minor  = MISC_DYNAMIC_MINOR,
+};
+
+// FIXME: This function is just for debugging.
+ssize_t nvfw_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
+{
+       NvRmDeviceHandle hRmDevice;
+       NvRmLibraryHandle hRmLibHandle;
+       char filename[100];
+       int error;
+
+       printk(KERN_INFO "%s: entry\n", __func__);
+
+       error = copy_from_user(filename, buff, count);
+       if (error)
+               panic("%s: line=%d\n", __func__, __LINE__);
+       filename[count] = 0;
+       printk(KERN_INFO "%s: filename=%s\n", __func__, filename);
+
+       error = NvRmOpen( &hRmDevice, 0 );
+       if (error)
+               panic("%s: line=%d\n", __func__, __LINE__);
+
+       error = NvRmLoadLibrary(hRmDevice, filename, NULL, 0, &hRmLibHandle);
+       if (error)
+               panic("%s: line=%d\n", __func__, __LINE__);
+
+       printk(KERN_INFO "%s: return\n", __func__);
+       return count;
+}
+
+int nvfw_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+int nvfw_close(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int nvfw_ioctl_load_library(struct file *filp, void __user *arg)
+{
+       struct nvfw_load_handle op;
+       NvRmDeviceHandle hRmDevice;
+       NvRmLibraryHandle hRmLibHandle;
+       char *filename = NULL;
+       void *args = NULL;
+       int error;
+
+       error = copy_from_user(&op, arg, sizeof(op));
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       filename = NvOsAlloc(op.length + 1);
+       error = copy_from_user(filename, op.filename, op.length + 1);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+       printk(KERN_INFO "%s: filename=%s\n", __func__, filename);
+
+       args = NvOsAlloc(op.argssize);
+       error = copy_from_user(args, op.args, op.argssize);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmOpen( &hRmDevice, 0 );
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmLoadLibrary(hRmDevice, filename, args, op.argssize, &hRmLibHandle);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       op.handle = hRmLibHandle;
+       error = copy_to_user(arg, &op, sizeof(op));
+
+error_exit:
+       NvOsFree(filename);
+       NvOsFree(args);
+       return error;
+}
+
+static int nvfw_ioctl_load_library_ex(struct file *filp, void __user *arg)
+{
+       struct nvfw_load_handle op;
+       NvRmDeviceHandle hRmDevice;
+       NvRmLibraryHandle hRmLibHandle;
+       char *filename = NULL;
+       void *args = NULL;
+       int error;
+
+       error = copy_from_user(&op, arg, sizeof(op));
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       filename = NvOsAlloc(op.length + 1);
+       error = copy_from_user(filename, op.filename, op.length + 1);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+       printk(KERN_INFO "%s: filename=%s\n", __func__, filename);
+
+       args = NvOsAlloc(op.argssize);
+       error = copy_from_user(args, op.args, op.argssize);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmOpen( &hRmDevice, 0 );
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmLoadLibraryEx(hRmDevice, filename, args, op.argssize, op.greedy, &hRmLibHandle);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       op.handle = hRmLibHandle;
+       error = copy_to_user(arg, &op, sizeof(op));
+
+error_exit:
+       NvOsFree(filename);
+       NvOsFree(args);
+       return error;
+}
+
+static int nvfw_ioctl_free_library(struct file *filp, void __user *arg)
+{
+       struct nvfw_load_handle op;
+       NvRmDeviceHandle hRmDevice;
+       int error;
+
+       error = copy_from_user(&op, arg, sizeof(op));
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmOpen( &hRmDevice, 0 );
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmFreeLibrary(op.handle);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+error_exit:
+       return error;
+}
+
+static int nvfw_ioctl_get_proc_address(struct file *filp, void __user *arg)
+{
+       struct nvfw_get_proc_address_handle op;
+       NvRmDeviceHandle hRmDevice;
+       char *symbolname;
+       int error;
+
+       error = copy_from_user(&op, arg, sizeof(op));
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       symbolname = NvOsAlloc(op.length + 1);
+       error = copy_from_user(symbolname, op.symbolname, op.length + 1);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+       printk(KERN_INFO "%s: symbolname=%s\n", __func__, symbolname);
+
+       error = NvRmOpen( &hRmDevice, 0 );
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = NvRmGetProcAddress(op.handle, symbolname, &op.address);
+       if (error) panic("%s: line=%d\n", __func__, __LINE__);
+       if (error) goto error_exit;
+
+       error = copy_to_user(arg, &op, sizeof(op));
+
+error_exit:
+       NvOsFree(symbolname);
+       return error;
+}
+
+static long nvfw_ioctl(struct file *filp,
+       unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       void __user *uarg = (void __user *)arg;
+
+       switch (cmd) {
+       case NVFW_IOC_LOAD_LIBRARY:
+               err = nvfw_ioctl_load_library(filp, uarg);
+               break;
+       case NVFW_IOC_LOAD_LIBRARY_EX:
+               err = nvfw_ioctl_load_library_ex(filp, uarg);
+               break;
+       case NVFW_IOC_FREE_LIBRARY:
+               err = nvfw_ioctl_free_library(filp, uarg);
+               break;
+       case NVFW_IOC_GET_PROC_ADDRESS:
+               err = nvfw_ioctl_get_proc_address(filp, uarg);
+               break;
+       default:
+               return -ENOTTY;
+       }
+       return err;
+}
+
+static NvError
+PrivateOsFopen(const char *filename, NvU32 flags, PrivateOsFileHandle *file)
+{
+       PrivateOsFileHandle hFile;
+
+       hFile = NvOsAlloc(sizeof(PrivateOsFile));
+       if (hFile == NULL) {
+               return NvError_InsufficientMemory;
+       }
+
+       NvOsDebugPrintf("%s <kernel impl>: file=%s\n", __func__, filename);
+       NvOsDebugPrintf("%s <kernel impl>: calling request_firmware()\n", __func__);
+       if (request_firmware(&s_FwEntry, filename, nvfw_dev.this_device) != 0) {
+               printk(KERN_ERR "%s: Cannot read firmware '%s'\n", __func__, filename);
+               return NvError_FileReadFailed;
+       }
+       NvOsDebugPrintf("%s <kernel impl>: back from request_firmware()\n", __func__);
+       hFile->pstart = s_FwEntry->data;
+       hFile->pread = s_FwEntry->data;
+       hFile->pend = s_FwEntry->data + s_FwEntry->size;
+
+       *file = hFile;
+
+       return NvError_Success;
+}
+
+static void
+PrivateOsFclose(PrivateOsFileHandle hFile)
+{
+       release_firmware(s_FwEntry);
+       NV_ASSERT(hFile);
+       NvOsFree(hFile);
+}
+
+static NvError
+PrivateOsFread(
+       PrivateOsFileHandle hFile,
+       void *ptr,
+       size_t size,
+       size_t *bytes)
+{
+       size_t nBytesRead = size;
+       NvError err = NvError_Success;
+
+       if (hFile->pread >= hFile->pend) {
+               nBytesRead = 0;
+               err = NvError_EndOfFile;
+               goto epilogue;
+       }
+
+       else if (hFile->pread + size > hFile->pend) {
+               nBytesRead = hFile->pend - hFile->pread;
+               NvOsMemcpy(ptr, hFile->pread, nBytesRead);
+               err = NvError_EndOfFile;
+               goto epilogue;
+       }
+
+       else {
+               NvOsMemcpy(ptr, hFile->pread, nBytesRead);
+               goto epilogue;
+       }
+
+epilogue:
+       hFile->pread += nBytesRead;
+       *bytes = nBytesRead;
+       return err;
+}
+
+static NvError
+PrivateOsFseek(PrivateOsFileHandle file, NvS64 offset, NvOsSeekEnum whence)
+{
+       NV_ASSERT(whence == NvOsSeek_Set);
+       file->pread = file->pstart + (NvU32)offset;
+
+       return NvError_Success;
+}
+
+NvError
+NvRmPrivLoadKernelLibrary(NvRmDeviceHandle hDevice,
+                       const char *pLibName,
+                       NvRmLibraryHandle *hLibHandle)
+{
+       NvError Error = NvSuccess;
+
+       NvOsDebugPrintf("%s <kernel impl>: file=%s\n", __func__, pLibName);
+       if ((Error = NvRmPrivLoadLibrary(hDevice, pLibName, 0, NV_FALSE,
+                                                       hLibHandle)) != NvSuccess)
+       {
+               return Error;
+       }
+       return Error;
+}
+
+NvError
+NvRmLoadLibrary(NvRmDeviceHandle hDevice,
+                const char *pLibName,
+                void* pArgs,
+                NvU32 sizeOfArgs,
+                NvRmLibraryHandle *hLibHandle)
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(sizeOfArgs <= MAX_ARGS_SIZE);
+
+       NvOsDebugPrintf("%s <kernel impl>: file=%s\n", __func__, pLibName);
+       Error = NvRmLoadLibraryEx(hDevice, pLibName, pArgs, sizeOfArgs, NV_FALSE,
+                               hLibHandle);
+       return Error;
+}
+
+NvError
+NvRmLoadLibraryEx(NvRmDeviceHandle hDevice,
+                const char *pLibName,
+                void* pArgs,
+                NvU32 sizeOfArgs,
+                NvBool IsApproachGreedy,
+                NvRmLibraryHandle *hLibHandle)
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(sizeOfArgs <= MAX_ARGS_SIZE);
+
+       NvOsDebugPrintf("%s <kernel impl>: file=%s\n", __func__, pLibName);
+
+       /* NvRmPrivInitModuleLoaderRPC(hDevice); */
+       if ((Error = NvRmPrivInitAvp(hDevice)) != NvSuccess)
+       {
+               return Error;
+       }
+
+       if ((Error = NvRmPrivLoadLibrary(hDevice, pLibName, 0, IsApproachGreedy,
+                                                       hLibHandle)) != NvSuccess)
+       {
+               return Error;
+       }
+
+       if ((Error = NvRmPrivRPCConnect(s_RPCHandle)) == NvSuccess)
+       {
+               Error = SendMsgAttachModule(hLibHandle, pArgs, sizeOfArgs);
+       }
+       else
+       {
+               NvOsDebugPrintf("RPCConnect timedout during NvRmLoadLibraryEx\r\n");
+       }
+       if (Error)
+       {
+               NvRmPrivFreeLibrary(*hLibHandle);
+       }
+       return Error;
+}
+
+NvError
+NvRmGetProcAddress(NvRmLibraryHandle Handle,
+               const char *pSymbol,
+               void **pSymAddress)
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(Handle);
+       Error = NvRmPrivGetProcAddress(Handle, pSymbol, pSymAddress);
+       return Error;
+}
+
+NvError NvRmFreeLibrary(NvRmLibraryHandle hLibHandle)
+{
+       NvError Error = NvSuccess;
+       NV_ASSERT(hLibHandle);
+       if((Error = NvRmPrivRPCConnect(s_RPCHandle)) == NvSuccess)
+       {
+               Error = SendMsgDetachModule(hLibHandle);
+       }
+       if (Error == NvSuccess)
+       {
+               Error = NvRmPrivFreeLibrary(hLibHandle);
+       }
+
+       return Error;
+}
+
+NvU32 NvRmModuleGetChipId(NvRmDeviceHandle hDevice)
+{
+       typedef struct
+       {
+               NvU32 Id;
+       }Capabilities;
+
+       NvError Error = NvSuccess;
+       NvRmModuleCapability caps[3];
+       Capabilities Cap15, Cap20,Cap16,*capabilities;
+
+       // for AP20
+       Cap20.Id = 0x20;
+       caps[0].MajorVersion = 1;
+       caps[0].MinorVersion = 1;
+       caps[0].EcoLevel = 0;
+       caps[0].Capability = (void *)&Cap20;
+
+       //for AP15 A01
+       Cap15.Id = 0x15;
+       caps[1].MajorVersion = 1;
+       caps[1].MinorVersion = 0;
+       caps[1].EcoLevel = 0;
+       caps[1].Capability = (void *)&Cap15;
+
+       //for AP15 A02
+       Cap16.Id = 0x15;
+       caps[2].MajorVersion = 1;
+       caps[2].MinorVersion = 1;
+       caps[2].EcoLevel = 0;
+       caps[2].Capability = (void *)&Cap16;
+
+       Error = NvRmModuleGetCapabilities(hDevice, NvRmModuleID_BseA, caps, 3, (void **)&capabilities);
+
+       return capabilities->Id;
+}
+
+//before unloading loading send message to avp with args and entry point via transport
+static NvError SendMsgDetachModule(NvRmLibraryHandle hLibHandle)
+{
+       NvError Error = NvSuccess;
+       NvU32 RecvMsgSize;
+       NvRmMessage_DetachModule Msg;
+       NvRmMessage_DetachModuleResponse MsgR;
+       void *address = NULL;
+
+       Msg.msg = NvRmMsg_DetachModule;
+
+       if ((Error = NvRmGetProcAddress(hLibHandle, "main", &address)) != NvSuccess)
+       {
+               goto exit_gracefully;
+       }
+       Msg.msg = NvRmMsg_DetachModule;
+       Msg.reason = NvRmModuleLoaderReason_Detach;
+       Msg.entryAddress = (NvU32)address;
+       RecvMsgSize = sizeof(NvRmMessage_DetachModuleResponse);
+       NvRmPrivRPCSendMsgWithResponse(s_RPCHandle,
+                               &MsgR,
+                               RecvMsgSize,
+                               &RecvMsgSize,
+                               &Msg,
+                               sizeof(Msg));
+
+       Error = MsgR.error;
+       if (Error)
+       {
+               goto exit_gracefully;
+       }
+exit_gracefully:
+       return Error;
+}
+
+//after successful loading send message to avp with args and entry point via transport
+static NvError SendMsgAttachModule(NvRmLibraryHandle *hLibHandle,
+                               void* pArgs,
+                               NvU32 sizeOfArgs)
+{
+       NvError Error = NvSuccess;
+       NvU32 RecvMsgSize;
+       NvRmMessage_AttachModule *MsgPtr=NULL;
+       NvRmMessage_AttachModuleResponse MsgR;
+       void *address = NULL;
+
+       MsgPtr = NvOsAlloc(sizeof(*MsgPtr));
+       if(MsgPtr==NULL)
+       {
+               Error = NvError_InsufficientMemory;
+               goto exit_gracefully;
+       }
+       MsgPtr->msg = NvRmMsg_AttachModule;
+
+       if(pArgs)
+       {
+               NvOsMemcpy(MsgPtr->args, pArgs, sizeOfArgs);
+       }
+
+       MsgPtr->size = sizeOfArgs;
+       if ((Error = NvRmGetProcAddress(*hLibHandle, "main", &address)) != NvSuccess)
+       {
+               goto exit_gracefully;
+       }
+       MsgPtr->entryAddress = (NvU32)address;
+       MsgPtr->reason = NvRmModuleLoaderReason_Attach;
+       RecvMsgSize = sizeof(NvRmMessage_AttachModuleResponse);
+       NvRmPrivRPCSendMsgWithResponse(s_RPCHandle,
+                               &MsgR,
+                               RecvMsgSize,
+                               &RecvMsgSize,
+                               MsgPtr,
+                               sizeof(*MsgPtr));
+
+       Error = MsgR.error;
+       if (Error)
+       {
+               goto exit_gracefully;
+       }
+exit_gracefully:
+       NvOsFree(MsgPtr);
+       return Error;
+}
+
+
+NvError NvRmPrivInitModuleLoaderRPC(NvRmDeviceHandle hDevice)
+{
+       NvError err = NvSuccess;
+
+       // Run only once.
+       if (s_RPCHandle) return NvError_Success;
+
+       NvOsDebugPrintf("%s <kernel impl>: NvRmPrivRPCInit(RPC_AVP_PORT)\n", __func__);
+       err = NvRmPrivRPCInit(hDevice, "RPC_AVP_PORT", &s_RPCHandle);
+       if (err) panic("%s: NvRmPrivRPCInit FAILED\n", __func__);
+
+       return err;
+}
+
+void NvRmPrivDeInitModuleLoaderRPC()
+{
+       NvRmPrivRPCDeInit(s_RPCHandle);
+}
+
+SegmentNode* AddToSegmentList(SegmentNode *pList,
+                       NvRmMemHandle pRegion,
+                       Elf32_Phdr Phdr,
+                       NvU32 Idx,
+                       NvU32 PhysAddr,
+                       void* MapAddress)
+{
+       SegmentNode *TempRec = NULL;
+       SegmentNode *CurrentRec = NULL;
+
+       TempRec = NvOsAlloc(sizeof(SegmentNode));
+       if (TempRec != NULL)
+       {
+               TempRec->pLoadRegion = pRegion;
+               TempRec->Index = Idx;
+               TempRec->VirtualAddr = Phdr.p_vaddr;
+               TempRec->MemorySize = Phdr.p_memsz;
+               TempRec->FileOffset = Phdr.p_offset;
+               TempRec->FileSize = Phdr.p_filesz;
+               TempRec->LoadAddress = PhysAddr;
+               TempRec->MapAddr = MapAddress;
+               TempRec->Next = NULL;
+
+               CurrentRec = pList;
+               if (CurrentRec == NULL)
+               {
+                       pList = TempRec;
+               }
+               else
+               {
+                       while (CurrentRec->Next != NULL)
+                       {
+                               CurrentRec = CurrentRec->Next;
+                       }
+                       CurrentRec->Next = TempRec;
+               }
+       }
+       return pList;
+}
+void RemoveRegion(SegmentNode *pList)
+{
+       if (pList != NULL)
+       {
+               SegmentNode *pCurrentRec;
+               SegmentNode *pTmpRec;
+               pCurrentRec = pList;
+               while (pCurrentRec != NULL)
+               {
+                       NvRmMemUnpin(pCurrentRec->pLoadRegion);
+                       NvRmMemHandleFree(pCurrentRec->pLoadRegion);
+                       pCurrentRec->pLoadRegion = NULL;
+                       pTmpRec = pCurrentRec;
+                       pCurrentRec = pCurrentRec->Next;
+                       NvOsFree( pTmpRec );
+               }
+               pList = NULL;
+       }
+}
+
+void UnMapRegion(SegmentNode *pList)
+{
+       if (pList != NULL)
+       {
+               SegmentNode *pCurrentRec;
+               pCurrentRec = pList;
+               while (pCurrentRec != NULL && pCurrentRec->MapAddr )
+               {
+                       NvRmMemUnmap(pCurrentRec->pLoadRegion, pCurrentRec->MapAddr,
+                               pCurrentRec->MemorySize);
+                       pCurrentRec = pCurrentRec->Next;
+               }
+       }
+}
+
+NvError
+ApplyRelocation(SegmentNode *pList,
+                NvU32 FileOffset,
+                NvU32 SegmentOffset,
+                NvRmMemHandle pRegion,
+                const Elf32_Rel *pRel)
+{
+       NvError Error = NvSuccess;
+       NvU8 Type = 0;
+       NvU32 SymIndex = 0;
+       Elf32_Word Word = 0;
+       SegmentNode *pCur;
+       NvU32 TargetVirtualAddr = 0;
+       NvU32 LoadAddress = 0;
+       NV_ASSERT(NULL != pRel);
+
+       NvRmMemRead(pRegion, SegmentOffset,&Word, sizeof(Word));
+       NV_DEBUG_PRINTF(("NvRmMemRead: SegmentOffset 0x%04x, word %p\r\n",
+                                       SegmentOffset, Word));
+       Type = ELF32_R_TYPE(pRel->r_info);
+
+       switch (Type)
+       {
+       case R_ARM_NONE:
+               break;
+       case R_ARM_CALL:
+               break;
+       case R_ARM_RABS32:
+               SymIndex = ELF32_R_SYM(pRel->r_info);
+               if (pList != NULL)
+               {
+                       pCur = pList;
+                       while (pCur != NULL)
+                       {
+                               if (pCur->Index == (SymIndex - 1))
+                               {
+                                       TargetVirtualAddr = pCur->VirtualAddr;
+                                       LoadAddress = pCur->LoadAddress;
+                               }
+                               pCur = pCur->Next;
+                       }
+                       if (LoadAddress > TargetVirtualAddr)
+                       {
+                               Word = Word + (LoadAddress - TargetVirtualAddr);
+                       }
+                       else //handle negative displacement
+                       {
+                               Word = Word - (TargetVirtualAddr - LoadAddress);
+                       }
+                       NV_DEBUG_PRINTF(("NvRmMemWrite: SegmentOffset 0x%04x, word %p\r\n",
+                                                       SegmentOffset, Word));
+                       NvRmMemWrite(pRegion, SegmentOffset, &Word, sizeof(Word));
+               }
+               break;
+       default:
+               Error = NvError_NotSupported;
+               NV_DEBUG_PRINTF(("This relocation type is not handled = %d\r\n", Type));
+               break;
+       }
+       return Error;
+}
+
+NvError
+GetSpecialSectionName(Elf32_Word SectionType,
+               Elf32_Word SectionFlags,
+               const char** SpecialSectionName)
+{
+       const char *unknownSection = "Unknown\r\n";
+       *SpecialSectionName = unknownSection;
+       /// Mask off the high 16 bits for now
+       switch (SectionFlags & 0xffff)
+       {
+       case SHF_ALLOC|SHF_WRITE:
+               if (SectionType == SHT_NOBITS)
+                       *SpecialSectionName = ".bss\r\n";
+               else if (SectionType == SHT_PROGBITS)
+                       *SpecialSectionName = ".data\r\n";
+               else if (SectionType == SHT_FINI_ARRAY)
+                       *SpecialSectionName = ".fini_array\r\n";
+               else if (SectionType == SHT_INIT_ARRAY)
+                       *SpecialSectionName = ".init_array\r\n";
+               break;
+       case SHF_ALLOC|SHF_EXECINSTR:
+               if (SectionType == SHT_PROGBITS)
+                       *SpecialSectionName = ".init or fini \r\n";
+
+               break;
+       case SHF_ALLOC:
+               if (SectionType == SHT_STRTAB)
+                       *SpecialSectionName = ".dynstr\r\n";
+               else if (SectionType == SHT_DYNSYM)
+                       *SpecialSectionName = ".dynsym\r\n";
+               else if (SectionType == SHT_HASH)
+                       *SpecialSectionName = ".hash\r\n";
+               else if (SectionType == SHT_PROGBITS)
+                       *SpecialSectionName = ".rodata\r\n";
+               else
+                       *SpecialSectionName = unknownSection;
+               break;
+       default:
+               if (SectionType == SHT_PROGBITS)
+                       *SpecialSectionName = ".comment\r\n";
+               else
+                       *SpecialSectionName = unknownSection;
+               break;
+       }
+       return NvSuccess;
+}
+
+NvError
+ParseDynamicSegment(SegmentNode *pList,
+               const char* pSegmentData,
+               size_t SegmentSize,
+               NvU32 DynamicSegmentOffset)
+{
+       NvError Error = NvSuccess;
+       Elf32_Dyn* pDynSeg = NULL;
+       NvU32  Counter = 0;
+       NvU32 RelocationTableAddressOffset = 0;
+       NvU32 RelocationTableSize = 0;
+       NvU32 RelocationEntrySize = 0;
+       const Elf32_Rel* RelocationTablePtr = NULL;
+       NvU32 SymbolTableAddressOffset = 0;
+       NvU32 SymbolTableEntrySize = 0;
+       NvU32 SymbolTableSize = 0;
+       NvU32 SegmentOffset = 0;
+       NvU32 FileOffset = 0;
+       SegmentNode *node;
+#if NV_ENABLE_DEBUG_PRINTS
+       // Strings for interpreting ELF header e_type field.
+       static const char * s_DynSecTypeText[] =
+               {
+                       "DT_NULL",
+                       "DT_NEEDED",
+                       "DT_PLTRELSZ",
+                       "DT_PLTGOT",
+                       "DT_HASH",
+//        "DT_STRTAB",
+                       "String Table Address",
+//        "DT_SYMTAB",
+                       "Symbol Table Address",
+//        "DT_RELA",
+                       "Relocation Table Address",
+//        "DT_RELASZ",
+                       "Relocation Table Size",
+//        "DT_RELAENT",
+                       "Relocation Entry Size",
+//        "DT_STRSZ",
+                       "String Table Size",
+//        "DT_SYMENT",
+                       "Symbol Table Entry Size",
+                       "DT_INIT",
+                       "DT_FINI",
+                       "DT_SONAME",
+                       "DT_RPATH",
+                       "DT_SYMBOLIC",
+//        "DT_REL",
+                       "Relocation Table Address",
+//        "DT_RELSZ",
+                       "Relocation Table Size",
+//        "DT_RELENT",
+                       "Relocation Entry Size",
+                       "DT_PLTREL",
+                       "DT_DEBUG",
+                       "DT_TEXTREL",
+                       "DT_JMPREL",
+                       "DT_BIND_NOW",
+                       "DT_INIT_ARRAY",
+                       "DT_FINI_ARRAY",
+                       "DT_INIT_ARRAYSZ",
+                       "DT_FINI_ARRAYSZ",
+                       "DT_RUNPATH",
+                       "DT_FLAGS",
+                       "DT_ENCODING",
+                       "DT_PREINIT_ARRAY",
+                       "DT_PREINIT_ARRAYSZ",
+                       "DT_NUM",
+                       "DT_OS-specific",
+                       "DT_PROC-specific",
+                       ""
+               };
+#else
+#define s_DynSecTypeText ((char**)0)
+#endif
+
+       pDynSeg = (Elf32_Dyn*)pSegmentData;
+       do
+       {
+               if (pDynSeg->d_tag < DT_NUM)
+               {
+                       NV_DEBUG_PRINTF(("Entry %d with Tag %s %d\r\n",
+                                                       Counter++, s_DynSecTypeText[pDynSeg->d_tag], pDynSeg->d_val));
+               }
+               else
+               {
+                       NV_DEBUG_PRINTF(("Entry %d Special Compatibility Range %x %d\r\n",
+                                                       Counter++, pDynSeg->d_tag, pDynSeg->d_val));
+               }
+               if (pDynSeg->d_tag == DT_NULL)
+                       break;
+               if ((pDynSeg->d_tag == DT_REL) || (pDynSeg->d_tag == DT_RELA))
+                       RelocationTableAddressOffset = pDynSeg->d_un.d_val;
+               if ((pDynSeg->d_tag == DT_RELENT) || (pDynSeg->d_tag == DT_RELAENT))
+                       RelocationEntrySize = pDynSeg->d_un.d_val;
+               if ((pDynSeg->d_tag == DT_RELSZ) || (pDynSeg->d_tag == DT_RELASZ))
+                       RelocationTableSize = pDynSeg->d_un.d_val;
+               if (pDynSeg->d_tag == DT_SYMTAB)
+                       SymbolTableAddressOffset = pDynSeg->d_un.d_val;
+               if (pDynSeg->d_tag == DT_SYMENT)
+                       SymbolTableEntrySize = pDynSeg->d_un.d_val;
+               if (pDynSeg->d_tag == DT_ARM_RESERVED1)
+                       SymbolTableSize = pDynSeg->d_un.d_val;
+               pDynSeg++;
+
+       }while ((Counter*sizeof(Elf32_Dyn)) < SegmentSize);
+
+       if (RelocationTableAddressOffset && RelocationTableSize && RelocationEntrySize)
+       {
+               RelocationTablePtr = (const Elf32_Rel*)&pSegmentData[RelocationTableAddressOffset];
+
+               for (Counter = 0; Counter < (RelocationTableSize/RelocationEntrySize); Counter++)
+               {
+                       //calculate the actual offset of the reloc entry
+                       NV_DEBUG_PRINTF(("Reloc %d offset is %x RType %d SymIdx %d \r\n",
+                                                       Counter, RelocationTablePtr->r_offset,
+                                                       ELF32_R_TYPE(RelocationTablePtr->r_info),
+                                                       ELF32_R_SYM(RelocationTablePtr->r_info)));
+
+                       node = pList;
+                       while (node != NULL)
+                       {
+                               if ( (RelocationTablePtr->r_offset > node->VirtualAddr) &&
+                                       (RelocationTablePtr->r_offset <=
+                                               (node->VirtualAddr + node->MemorySize)))
+                               {
+                                       FileOffset = node->FileOffset +
+                                               (RelocationTablePtr->r_offset - node->VirtualAddr);
+
+                                       NV_DEBUG_PRINTF(("File offset to be relocated %d \r\n", FileOffset));
+
+                                       SegmentOffset = (RelocationTablePtr->r_offset - node->VirtualAddr);
+
+                                       NV_DEBUG_PRINTF(("Segment offset to be relocated %d \r\n", SegmentOffset));
+
+                                       Error = ApplyRelocation(pList, FileOffset, SegmentOffset,
+                                                               node->pLoadRegion, RelocationTablePtr);
+
+                               }
+                               node = node->Next;
+                       }
+                       RelocationTablePtr++;
+               }
+
+       }
+       if (SymbolTableAddressOffset && SymbolTableSize && SymbolTableEntrySize)
+       {
+#if 0
+               const Elf32_Sym* SymbolTablePtr = NULL;
+               SymbolTablePtr = (const Elf32_Sym*)&pSegmentData[SymbolTableAddressOffset];
+               for (Counter = 0; Counter <SymbolTableSize/SymbolTableEntrySize; Counter++)
+               {
+
+                       NvOsDebugPrintf("Symbol name %x, value %x, size %x, info %x, other %x, shndx %x\r\n",
+                                       SymbolTablePtr->st_name, SymbolTablePtr->st_value,
+                                       SymbolTablePtr->st_size, SymbolTablePtr->st_info,
+                                       SymbolTablePtr->st_other, SymbolTablePtr->st_shndx);
+                       NV_DEBUG_PRINTF(("Symbol name %x, value %x, size %x, info %x, other %x, shndx %x\r\n",
+                                                       SymbolTablePtr->st_name, SymbolTablePtr->st_value,
+                                                       SymbolTablePtr->st_size, SymbolTablePtr->st_info,
+                                                       SymbolTablePtr->st_other, SymbolTablePtr->st_shndx));
+
+                       SymbolTablePtr++;
+               }
+#endif
+       }
+       return Error;
+}
+
+NvError
+LoadLoadableProgramSegment(PrivateOsFileHandle elfSourceHandle,
+                       NvRmDeviceHandle hDevice,
+                       NvRmLibraryHandle hLibHandle,
+                       Elf32_Phdr Phdr,
+                       Elf32_Ehdr Ehdr,
+                       const NvRmHeap * Heaps,
+                       NvU32 NumHeaps,
+                       NvU32 loop,
+                       const char *Filename,
+                       SegmentNode **segmentList)
+{
+       NvError Error = NvSuccess;
+       NvRmMemHandle pLoadRegion = NULL;
+       void* pLoadAddress = NULL;
+       NvU32 offset = 0;
+       NvU32 addr;  // address of pLoadRegion
+       size_t bytesRead = 0;
+
+       Error = NvRmMemHandleCreate(hDevice,
+                                &pLoadRegion,
+                                Phdr.p_memsz);
+
+       if (Error != NvSuccess)
+               goto CleanUpExit;
+
+       Error = NvRmMemAlloc(pLoadRegion,
+                       Heaps,
+                       NumHeaps,
+                       NV_MAX(16, Phdr.p_align),
+                       NvOsMemAttribute_Uncached);
+
+       if (Error != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("Memory Allocation %d Failed\r\n",Error));
+               NvRmMemHandleFree(pLoadRegion);
+               pLoadRegion = NULL;
+               goto CleanUpExit;
+       }
+       addr = NvRmMemPin(pLoadRegion);
+
+       Error = NvRmMemMap(pLoadRegion, 0, Phdr.p_memsz,
+                       NVOS_MEM_READ_WRITE, &pLoadAddress);
+       if (Error != NvSuccess)
+       {
+               pLoadAddress = NULL;
+       }
+
+       // This will initialize ZI to zero
+       if( pLoadAddress )
+       {
+               NvOsMemset(pLoadAddress, 0, Phdr.p_memsz);
+       }
+       else
+       {
+               NvU8 *tmp = NvOsAlloc( Phdr.p_memsz );
+               if( !tmp )
+               {
+                       goto CleanUpExit;
+               }
+               NvOsMemset( tmp, 0, Phdr.p_memsz );
+               NvRmMemWrite( pLoadRegion, 0, tmp, Phdr.p_memsz );
+               NvOsFree( tmp );
+       }
+
+       if(Phdr.p_filesz)
+       {
+               if( pLoadAddress )
+               {
+                       if ((Error = PrivateOsFread(elfSourceHandle, pLoadAddress,
+                                                               Phdr.p_filesz, &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+               }
+               else
+               {
+                       NvU8 *tmp = NvOsAlloc( Phdr.p_filesz );
+                       if( !tmp )
+                       {
+                               goto CleanUpExit;
+                       }
+
+                       Error = PrivateOsFread( elfSourceHandle, tmp, Phdr.p_filesz,
+                                       &bytesRead );
+                       if( Error != NvSuccess )
+                       {
+                               NvOsFree( tmp );
+                               goto CleanUpExit;
+                       }
+
+                       NvRmMemWrite( pLoadRegion, 0, tmp, Phdr.p_filesz );
+
+                       NvOsFree( tmp );
+               }
+       }
+       if ((Ehdr.e_entry >= Phdr.p_vaddr)
+               && (Ehdr.e_entry < (Phdr.p_vaddr + Phdr.p_memsz)))
+       {
+               // Odd address indicates entry point is Thumb code.
+               // The address needs to be masked with LSB before being invoked.
+               if (addr > Phdr.p_vaddr)
+               {
+                       offset = (addr - Phdr.p_vaddr) | ADD_MASK;
+                       hLibHandle->EntryAddress = (void*)(Ehdr.e_entry + offset);
+               }
+               else
+               {
+                       offset = ((Phdr.p_vaddr - addr) | (ADD_MASK)) & (SUB_MASK);
+                       hLibHandle->EntryAddress = (void*)(Ehdr.e_entry - offset);
+               }
+               NV_DEBUG_PRINTF(("Load Address for %s segment %d:%x\r\n",
+                                               Filename, loop, addr));
+               NvOsDebugPrintf("Load Address for %s segment %d:%x\r\n",
+                               Filename, loop, addr);
+       }
+
+       *segmentList = AddToSegmentList((*segmentList), pLoadRegion, Phdr, loop,
+                                       addr, pLoadAddress);
+
+CleanUpExit:
+       if (Error != NvSuccess)
+       {
+               if(pLoadRegion != NULL)
+               {
+                       if( pLoadAddress )
+                       {
+                               NvRmMemUnmap(pLoadRegion, pLoadAddress, Phdr.p_memsz);
+                       }
+
+                       NvRmMemUnpin(pLoadRegion);
+                       NvRmMemHandleFree(pLoadRegion);
+               }
+       }
+       return Error;
+}
+
+NvError
+NvRmPrivLoadLibrary(NvRmDeviceHandle hDevice,
+               const char *Filename,
+               NvU32 Address,
+               NvBool IsApproachGreedy,
+               NvRmLibraryHandle *hLibHandle)
+{
+       NvError Error = NvSuccess;
+       PrivateOsFileHandle elfSourceHandle = 0;
+       size_t bytesRead = 0;
+       Elf32_Ehdr elf;
+       Elf32_Phdr progHeader;
+       NvU32 loop = 0;
+       char *dynamicSegementBuffer = NULL;
+       int dynamicSegmentOffset = 0;
+       int lastFileOffset = 0;
+       SegmentNode *segmentList = NULL;
+       NvRmHeap HeapProperty[2];
+       NvU32 HeapSize = 0;
+
+       NV_ASSERT(NULL != Filename);
+       *hLibHandle = NULL;
+
+       NvOsDebugPrintf("%s <kernel impl>: file=%s\n", __func__, Filename);
+       if ((Error = PrivateOsFopen(Filename, NVOS_OPEN_READ,
+                                               &elfSourceHandle)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("Elf source file Not found Error = %d\r\n", Error));
+               NvOsDebugPrintf("Failed to load library %s, NvError=%d."
+                               " Make sure it is present on the device\r\n", Filename, Error);
+               return Error;
+       }
+       if ((Error = PrivateOsFread(elfSourceHandle, &elf,
+                                               sizeof(elf), &bytesRead)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("File Read size mismatch %d\r\n", bytesRead));
+               goto CleanUpExit;
+       }
+       // Parse the elf headers and display information
+       parseElfHeader(&elf);
+       /// Parse the Program Segment Headers and display information
+       if ((Error = parseProgramSegmentHeaders(elfSourceHandle, elf.e_phoff, elf.e_phnum)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("parseProgramSegmentHeaders failed %d\r\n", Error));
+               goto CleanUpExit;
+       }
+       /// Parse the section Headers and display information
+       if ((Error = parseSectionHeaders(elfSourceHandle, &elf)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("parseSectionHeaders failed %d\r\n", Error));
+               goto CleanUpExit;
+       }
+       // allocate memory for handle....
+       *hLibHandle = NvOsAlloc(sizeof(NvRmLibHandle));
+       if (!*hLibHandle)
+       {
+               Error = NvError_InsufficientMemory;
+               goto CleanUpExit;
+       }
+
+       if (elf.e_phnum && elf.e_phnum < MIN_SEGMENTS_FOR_DYNAMIC_LOADING)
+       {
+               if ((Error = loadSegmentsInFixedMemory(elfSourceHandle,
+                                                               &elf, 0, &(*hLibHandle)->pLibBaseAddress)) != NvSuccess)
+               {
+                       NV_DEBUG_PRINTF(("LoadSegmentsInFixedMemory Failed %d\r\n", Error));
+                       goto CleanUpExit;
+               }
+               (*hLibHandle)->EntryAddress = (*hLibHandle)->pLibBaseAddress;
+               return Error;
+       }
+       else if (elf.e_phnum)
+       {
+               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                       elf.e_phoff, NvOsSeek_Set)) != NvSuccess)
+               {
+                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                       goto CleanUpExit;
+               }
+               lastFileOffset = elf.e_phoff;
+               // load the IRAM mandatory  and DRAM mandatory sections first...
+               for (loop = 0; loop < elf.e_phnum; loop++)
+               {
+                       if ((Error = PrivateOsFread(elfSourceHandle, &progHeader,
+                                                               sizeof(Elf32_Phdr), &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+                       lastFileOffset += bytesRead;
+                       if (progHeader.p_type == PT_LOAD)
+                       {
+                               NV_DEBUG_PRINTF(("Found load segment %d\r\n",loop));
+                               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                                       progHeader.p_offset, NvOsSeek_Set)) != NvSuccess)
+                               {
+                                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                                       goto CleanUpExit;
+                               }
+                               if (progHeader.p_vaddr >= DRAM_MAND_ADDRESS && progHeader.p_vaddr < IRAM_PREF_EXT_ADDRESS)
+                               {
+
+
+                                       if (progHeader.p_vaddr >= DRAM_MAND_ADDRESS && progHeader.p_vaddr < IRAM_MAND_ADDRESS)
+                                       {
+                                               HeapProperty[0] = NvRmHeap_ExternalCarveOut;
+                                       }
+                                       else if (progHeader.p_vaddr >= IRAM_MAND_ADDRESS)
+                                       {
+                                               HeapProperty[0] = NvRmHeap_IRam;
+                                       }
+                                       Error = LoadLoadableProgramSegment(elfSourceHandle, hDevice, (*hLibHandle),
+                                                                        progHeader, elf, HeapProperty, 1, loop,
+                                                                        Filename, &segmentList);
+                                       if (Error != NvSuccess)
+                                       {
+                                               NV_DEBUG_PRINTF(("Unable to load segment %d \r\n", loop));
+                                               goto CleanUpExit;
+                                       }
+                               }
+                               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                                       lastFileOffset, NvOsSeek_Set)) != NvSuccess)
+                               {
+                                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                                       goto CleanUpExit;
+                               }
+                       }
+               }
+
+               // now load the preferred and dynamic sections
+               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                       elf.e_phoff, NvOsSeek_Set)) != NvSuccess)
+               {
+                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                       goto CleanUpExit;
+               }
+               lastFileOffset = elf.e_phoff;
+               for (loop = 0; loop < elf.e_phnum; loop++)
+               {
+                       if ((Error = PrivateOsFread(elfSourceHandle, &progHeader,
+                                                               sizeof(Elf32_Phdr), &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+                       lastFileOffset += bytesRead;
+                       if (progHeader.p_type == PT_LOAD)
+                       {
+                               NV_DEBUG_PRINTF(("Found load segment %d\r\n",loop));
+                               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                                       progHeader.p_offset, NvOsSeek_Set)) != NvSuccess)
+                               {
+                                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                                       goto CleanUpExit;
+                               }
+                               if (progHeader.p_vaddr < DRAM_MAND_ADDRESS)
+                               {
+                                       if (IsApproachGreedy == NV_FALSE)
+                                       {
+                                               HeapSize = 1;
+                                               //conservative allocation - IRAM_PREF sections in DRAM.
+                                               HeapProperty[0] = NvRmHeap_ExternalCarveOut;
+                                       }
+                                       else
+                                       {
+                                               // greedy allocation - IRAM_PREF sections in IRAM, otherwise fallback to DRAM
+                                               HeapSize = 2;
+                                               HeapProperty[0] = NvRmHeap_IRam;
+                                               HeapProperty[1] = NvRmHeap_ExternalCarveOut;
+                                       }
+                                       Error = LoadLoadableProgramSegment(elfSourceHandle, hDevice,
+                                                                        (*hLibHandle), progHeader, elf,
+                                                                        HeapProperty, HeapSize, loop,
+                                                                        Filename, &segmentList);
+                                       if (Error != NvSuccess)
+                                       {
+                                               NV_DEBUG_PRINTF(("Unable to load segment %d \r\n", loop));
+                                               goto CleanUpExit;
+                                       }
+                               }
+                               else if (progHeader.p_vaddr >= IRAM_PREF_EXT_ADDRESS)
+                               {
+                                       NvU32 Chipid = NvRmModuleGetChipId(hDevice);
+                                       if(Chipid == 0x15 || Chipid == 0x16)
+                                       {
+                                               HeapSize = 1;
+                                               //conservative allocation - IRAM_PREF_EXT sections in DRAM for AP15.
+                                               HeapProperty[0] = NvRmHeap_ExternalCarveOut;
+                                       }
+                                       else if(Chipid >= 0x20)
+                                       {
+                                               if (IsApproachGreedy == NV_FALSE)
+                                               {
+                                                       HeapSize = 1;
+                                                       //conservative allocation - IRAM_PREF sections in DRAM.
+                                                       HeapProperty[0] = NvRmHeap_ExternalCarveOut;
+                                               }
+                                               else
+                                               {
+                                                       // greedy allocation - IRAM_PREF sections in IRAM, otherwise fallback to DRAM
+                                                       HeapSize = 2;
+                                                       HeapProperty[0] = NvRmHeap_IRam;
+                                                       HeapProperty[1] = NvRmHeap_ExternalCarveOut;
+                                               }
+                                       }
+                                       Error = LoadLoadableProgramSegment(elfSourceHandle, hDevice,
+                                                                        (*hLibHandle), progHeader, elf,
+                                                                        HeapProperty, HeapSize, loop,
+                                                                        Filename, &segmentList);
+                                       if (Error != NvSuccess)
+                                       {
+                                               NV_DEBUG_PRINTF(("Unable to load segment %d \r\n", loop));
+                                               goto CleanUpExit;
+                                       }
+                               }
+                               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                                       lastFileOffset, NvOsSeek_Set)) != NvSuccess)
+                               {
+                                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                                       goto CleanUpExit;
+                               }
+                       }
+                       if (progHeader.p_type != PT_DYNAMIC)
+                               continue;
+                       dynamicSegmentOffset = progHeader.p_offset;
+                       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                               dynamicSegmentOffset, NvOsSeek_Set)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+                       dynamicSegementBuffer = NvOsAlloc(progHeader.p_filesz);
+                       if (dynamicSegementBuffer == NULL)
+                       {
+                               NV_DEBUG_PRINTF(("Memory Allocation %d Failed\r\n", progHeader.p_filesz));
+                               goto CleanUpExit;
+                       }
+                       if ((Error = PrivateOsFread(elfSourceHandle, dynamicSegementBuffer,
+                                                               progHeader.p_filesz, &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+                       if ((Error = ParseDynamicSegment(
+                                               segmentList,
+                                               dynamicSegementBuffer,
+                                               progHeader.p_filesz,
+                                               dynamicSegmentOffset)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("Parsing and relocation of segment failed \r\n"));
+                               goto CleanUpExit;
+                       }
+                       (*hLibHandle)->pList = segmentList;
+                       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                               lastFileOffset, NvOsSeek_Set)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                               goto CleanUpExit;
+                       }
+               }
+       }
+
+CleanUpExit:
+       {
+               if (Error == NvSuccess)
+               {
+                       UnMapRegion(segmentList);
+                       NvOsFree(dynamicSegementBuffer);
+                       PrivateOsFclose(elfSourceHandle);
+               }
+               else
+               {
+                       RemoveRegion(segmentList);
+                       NvOsFree(dynamicSegementBuffer);
+                       PrivateOsFclose(elfSourceHandle);
+                       NvOsFree(*hLibHandle);
+               }
+       }
+       return Error;
+}
+
+NvError NvRmPrivFreeLibrary(NvRmLibHandle *hLibHandle)
+{
+       NvError Error = NvSuccess;
+       RemoveRegion(hLibHandle->pList);
+       NvOsFree(hLibHandle);
+       return Error;
+}
+
+void parseElfHeader(Elf32_Ehdr *elf)
+{
+       if (elf->e_ident[0] == ELF_MAG0)
+       {
+               NV_DEBUG_PRINTF(("File is elf Object File with Identification %c%c%c\r\n",
+                                               elf->e_ident[1], elf->e_ident[2], elf->e_ident[3]));
+               NV_DEBUG_PRINTF(("Type of ELF is %x\r\n", elf->e_type));
+               //An object file conforming to this specification must have
+               //the value EM_ARM (40, 0x28).
+               NV_DEBUG_PRINTF(("Machine type of the file is %x\r\n", elf->e_machine));
+               //Address of entry point for this file. bit 1:0
+               //indicates if entry point is ARM or thum mode
+               NV_DEBUG_PRINTF(("Entry point for this axf is %x\r\n", elf->e_entry));
+               NV_DEBUG_PRINTF(("Version of the ELF is %d\r\n", elf->e_version));
+               NV_DEBUG_PRINTF(("Program Table Header Offset %d\r\n", elf->e_phoff));
+               NV_DEBUG_PRINTF(("Section Table Header Offset %d\r\n", elf->e_shoff));
+               NV_DEBUG_PRINTF(("Elf Header size %d\r\n", elf->e_ehsize));
+               NV_DEBUG_PRINTF(("Section Header's Size %d\r\n", elf->e_shentsize));
+               NV_DEBUG_PRINTF(("Number of Section Headers %d\r\n", elf->e_shnum));
+               NV_DEBUG_PRINTF(("String Table Section Header Index %d\r\n", elf->e_shstrndx));
+               NV_DEBUG_PRINTF(("\r\n"));
+       }
+}
+
+NvError parseProgramSegmentHeaders(PrivateOsFileHandle elfSourceHandle,
+                               NvU32 segmentHeaderOffset,
+                               NvU32 segmentCount)
+{
+       Elf32_Phdr progHeader;
+       size_t bytesRead = 0;
+       NvU32 loop = 0;
+       NvError Error = NvSuccess;
+       if (segmentCount)
+       {
+               NV_DEBUG_PRINTF(("Program Headers Found %d\r\n", segmentCount));
+               if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                       segmentHeaderOffset, NvOsSeek_Set)) != NvSuccess)
+               {
+                       NV_DEBUG_PRINTF(("File Seek failed %d\r\n", Error));
+                       return Error;
+               }
+
+               for (loop = 0; loop < segmentCount; loop++)
+               {
+                       if ((Error = PrivateOsFread(elfSourceHandle, &progHeader,
+                                                               sizeof(progHeader), &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               return Error;
+                       }
+
+                       NV_DEBUG_PRINTF(("Program %d Header type %d\r\n",
+                                                       loop, progHeader.p_type));
+                       NV_DEBUG_PRINTF(("Program %d Header offset %d\r\n",
+                                                       loop, progHeader.p_offset));
+                       NV_DEBUG_PRINTF(("Program %d Header Virtual Address %x\r\n",
+                                                       loop, progHeader.p_vaddr));
+                       NV_DEBUG_PRINTF(("Program %d Header Physical Address %x\r\n",
+                                                       loop, progHeader.p_paddr));
+                       NV_DEBUG_PRINTF(("Program %d Header Filesize %d\r\n",
+                                                       loop, progHeader.p_filesz));
+                       NV_DEBUG_PRINTF(("Program %d Header Memory Size %d\r\n",
+                                                       loop, progHeader.p_memsz));
+                       NV_DEBUG_PRINTF(("Program %d Header Flags %x\r\n",
+                                                       loop, progHeader.p_flags));
+                       NV_DEBUG_PRINTF(("Program %d Header alignment %d\r\n",
+                                                       loop, progHeader.p_align));
+                       NV_DEBUG_PRINTF(("\r\n"));
+               }
+       }
+       return NvSuccess;
+}
+
+NvError
+parseSectionHeaders(PrivateOsFileHandle elfSourceHandle, Elf32_Ehdr *elf)
+{
+       NvError Error = NvSuccess;
+       NvU32 stringTableOffset = 0;
+       Elf32_Shdr sectionHeader;
+       size_t bytesRead = 0;
+       NvU32 loop = 0;
+       char* stringTable = NULL;
+       const char *specialNamePtr = NULL;
+
+       // Try to get to the string table so that we can get section names
+       stringTableOffset = elf->e_shoff + (elf->e_shentsize * elf->e_shstrndx);
+
+       NV_DEBUG_PRINTF(("String Table File Offset is %d\r\n", stringTableOffset));
+
+       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                               stringTableOffset, NvOsSeek_Set)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+               return Error;
+       }
+       if ((Error = PrivateOsFread(elfSourceHandle, &sectionHeader,
+                                               sizeof(sectionHeader), &bytesRead)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+               return Error;
+       }
+       if (sectionHeader.sh_type == SHT_STRTAB)
+       {
+               NV_DEBUG_PRINTF(("Found Section is string Table\r\n"));
+               if (sectionHeader.sh_size)
+               {
+                       stringTable = NvOsAlloc(sectionHeader.sh_size);
+                       if (stringTable == NULL)
+                       {
+                               NV_DEBUG_PRINTF(("String table mem allocation failed for %d\r\n",
+                                                               sectionHeader.sh_size));
+                               return  NvError_InsufficientMemory;
+                       }
+                       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                                               sectionHeader.sh_offset, NvOsSeek_Set)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+                               goto CleanUpExit_parseSectionHeaders;
+                       }
+                       if ((Error = PrivateOsFread(elfSourceHandle, stringTable,
+                                                               sectionHeader.sh_size, &bytesRead)) != NvSuccess)
+                       {
+                               NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                               goto CleanUpExit_parseSectionHeaders;
+                       }
+               }
+       }
+       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                               elf->e_shoff, NvOsSeek_Set)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("File Seek failed %d\r\n", bytesRead));
+               goto CleanUpExit_parseSectionHeaders;
+       }
+       for (loop = 0; loop < elf->e_shnum; loop++)
+       {
+               if ((Error = PrivateOsFread(elfSourceHandle, &sectionHeader,
+                                                       sizeof(sectionHeader), &bytesRead)) != NvSuccess)
+               {
+                       NV_DEBUG_PRINTF(("File Read failed %d\r\n", bytesRead));
+                       goto CleanUpExit_parseSectionHeaders;
+               }
+
+               NV_DEBUG_PRINTF(("Section %d is named %s\r\n",
+                                               loop, &stringTable[sectionHeader.sh_name]));
+               NV_DEBUG_PRINTF(("Section %d Type %d\r\n",
+                                               loop, sectionHeader.sh_type));
+               NV_DEBUG_PRINTF(("Section %d Flags %x\r\n",
+                                               loop, sectionHeader.sh_flags));
+
+               GetSpecialSectionName(sectionHeader.sh_type,
+                               sectionHeader.sh_flags, &specialNamePtr);
+
+               NV_DEBUG_PRINTF(("Section %d Special Name is %s",
+                                               loop, specialNamePtr));
+               NV_DEBUG_PRINTF(("Section %d Address %x\r\n",
+                                               loop, sectionHeader.sh_addr));
+               NV_DEBUG_PRINTF(("Section %d File Offset %d\r\n",
+                                               loop, sectionHeader.sh_offset));
+               NV_DEBUG_PRINTF(("Section %d Size %d \r\n",
+                                               loop, sectionHeader.sh_size));
+               NV_DEBUG_PRINTF(("Section %d Link %d \r\n",
+                                               loop, sectionHeader.sh_link));
+               NV_DEBUG_PRINTF(("Section %d Info %d\r\n",
+                                               loop, sectionHeader.sh_info));
+               NV_DEBUG_PRINTF(("Section %d alignment %d\r\n",
+                                               loop, sectionHeader.sh_addralign));
+               NV_DEBUG_PRINTF(("Section %d Fixed Entry Size %d\r\n",
+                                               loop, sectionHeader.sh_entsize));
+               NV_DEBUG_PRINTF(("\r\n"));
+
+       }
+CleanUpExit_parseSectionHeaders:
+       if (stringTable)
+               NvOsFree(stringTable);
+       return Error;
+}
+
+
+NvError
+loadSegmentsInFixedMemory(PrivateOsFileHandle elfSourceHandle,
+                       Elf32_Ehdr *elf, NvU32 segmentIndex, void **loadaddress)
+{
+       NvError Error = NvSuccess;
+       size_t bytesRead = 0;
+       Elf32_Phdr progHeader;
+
+       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                               elf->e_phoff + (segmentIndex * sizeof(progHeader)), NvOsSeek_Set)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("loadSegmentsInFixedMemory File Seek failed %d\r\n", bytesRead));
+               return Error;
+       }
+
+       if ((Error = PrivateOsFread(elfSourceHandle, &progHeader,
+                                               sizeof(Elf32_Phdr), &bytesRead)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF((" loadSegmentsInFixedMemory File Read failed %d\r\n", bytesRead));
+               return Error;
+       }
+       NV_ASSERT(progHeader.p_type == PT_LOAD);
+       if ((Error = PrivateOsFseek(elfSourceHandle,
+                                               progHeader.p_offset, NvOsSeek_Set)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("loadSegmentsInFixedMemory File Seek failed %d\r\n", Error));
+               return Error;
+       }
+
+       /* if((Error = NvRmPhysicalMemMap(progHeader.p_vaddr, */
+       /*                                      progHeader.p_memsz, NVOS_MEM_READ_WRITE, */
+       /*                                      NvOsMemAttribute_Uncached, loadaddress)) != NvSuccess) */
+       /* { */
+       /*      NV_DEBUG_PRINTF(("loadSegmentsInFixedMemory Failed trying to Mem Map %x\r\n", progHeader.p_vaddr)); */
+       /*      return Error; */
+       /* } */
+       // This will initialize ZI to zero
+       *loadaddress = ioremap_nocache(progHeader.p_vaddr, progHeader.p_memsz);
+
+       NvOsMemset(*loadaddress, 0, progHeader.p_memsz);
+       if ((Error = PrivateOsFread(elfSourceHandle, *loadaddress,
+                                               progHeader.p_filesz, &bytesRead)) != NvSuccess)
+       {
+               NV_DEBUG_PRINTF(("loadSegmentsInFixedMemory File Read failed %d\r\n", bytesRead));
+               return Error;
+       }
+       // Load address need to be reset to the physical address as this is passed to the AVP as the entry point.
+       *loadaddress = (void *)progHeader.p_vaddr;
+
+       return Error;
+}
+
+NvError NvRmPrivGetProcAddress(NvRmLibraryHandle Handle,
+                       const char *pSymbol,
+                       void **pSymAddress)
+{
+       NvError Error = NvSuccess;
+       // In phase 1, this API will just return the load address as entry address
+       NvRmLibHandle *hHandle = Handle;
+
+       //NOTE: The EntryAddress is pointing to a THUMB function
+       //(LSB is set). The Entry Function must be in THUMB mode.
+       if (hHandle->EntryAddress != NULL)
+       {
+               *pSymAddress = hHandle->EntryAddress;
+       }
+       else
+       {
+               Error = NvError_SymbolNotFound;
+       }
+       return Error;
+}
+
+static int __init nvfw_init(void)
+{
+       int ret = 0;
+
+       NvOsDebugPrintf("%s: called\n", __func__);
+       ret = misc_register(&nvfw_dev);
+       if (ret) panic("%s: misc_register FAILED\n", __func__);
+
+       return ret;
+}
+
+static void __exit nvfw_deinit(void)
+{
+       misc_deregister(&nvfw_dev);
+}
+
+module_init(nvfw_init);
+module_exit(nvfw_deinit);
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader_private.h b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader_private.h
new file mode 100644 (file)
index 0000000..becb53c
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_moduleloader_private.h
+ *
+ * AVP firmware module loader
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef INCLUDED_NVRM_MODULELOADER_PRIVATE_H
+#define INCLUDED_NVRM_MODULELOADER_PRIVATE_H
+
+#include "nvrm_moduleloader.h"
+#include "nvrm_memmgr.h"
+
+typedef struct PrivateOsFileRec
+{
+    const NvU8 *pstart;
+    const NvU8 *pread;
+    const NvU8 *pend;
+} PrivateOsFile;
+
+typedef struct PrivateOsFileRec *PrivateOsFileHandle;
+
+#define LOAD_ADDRESS        0x11001000
+#define IRAM_PREF_EXT_ADDRESS   0x50000000
+#define IRAM_MAND_ADDRESS   0x40000000
+#define DRAM_MAND_ADDRESS   0x10000000
+#define DT_ARM_SYMTABSZ     0x70000001
+#define DT_ARM_RESERVED1    0x70000000
+
+/// ELF magic number
+enum
+{
+    ELF_MAG0 = 0x7F
+};
+
+/// ELF section header entry types.
+enum
+{
+    SHT_INIT_ARRAY = 12,             ///< Code initialization array
+    SHT_FINI_ARRAY,             ///< Code finalization array
+    SHT_PREINIT_ARRAY,          ///< Code pre-inialization array
+    SHT_GROUP,                  ///< Group
+    SHT_SYMTAB_SHNDX,           ///< Symbol table index
+};
+#define SHT_LOPROC 0x70000000    ///< Start of processor-specific
+#define SHT_HIPROC 0x7fffffff    ///< End of processor-specific
+#define SHT_LOUSER 0x80000000    ///< Start of application-specific
+#define SHT_HIUSER 0xffffffff     ///< End of application-specific
+
+/// ELF dynamic section type flags
+enum
+{
+    DT_NUM              = 34,           ///< Number used
+};
+
+/// ARM specific relocation codes
+enum
+{
+    R_ARM_RABS32 = 253,
+};
+
+/// A linked list of load segment records
+typedef struct SegmentRec SegmentNode;
+
+struct SegmentRec
+{
+    NvRmMemHandle pLoadRegion;
+    NvU32 LoadAddress;
+    NvU32 Index;
+    NvU32 VirtualAddr;
+    NvU32 MemorySize;
+    NvU32 FileOffset;
+    NvU32 FileSize;
+    void* MapAddr;
+    SegmentNode *Next;
+};
+
+/// ModuleLoader handle structure
+typedef struct NvRmLibraryRec
+{
+    void* pLibBaseAddress;
+    void* EntryAddress;
+    SegmentNode *pList;
+} NvRmLibHandle;
+
+NvError
+NvRmPrivLoadKernelLibrary(NvRmDeviceHandle hDevice,
+                      const char *pLibName,
+                      NvRmLibraryHandle *hLibHandle);
+
+/// Add a load region to the segment list
+SegmentNode* AddToSegmentList(SegmentNode *pList,
+                      NvRmMemHandle pRegion,
+                      Elf32_Phdr Phdr,
+                      NvU32 Idx,
+                      NvU32 PhysAddr,
+                      void* MapAddr);
+
+/// Apply the relocation code based on relocation info from relocation table
+NvError
+ApplyRelocation(SegmentNode *pList,
+                NvU32 FileOffset,
+                NvU32 SegmentOffset,
+                NvRmMemHandle pRegion,
+                const Elf32_Rel *pRel);
+
+/// Get the special section name for a given section type and flag
+NvError
+GetSpecialSectionName(Elf32_Word SectionType,
+                      Elf32_Word SectionFlags,
+                      const char** SpecialSectionName);
+
+/// Parse the dynamic segment of ELF to extract the relocation table
+ NvError
+ParseDynamicSegment(SegmentNode *pList,
+                    const char* pSegmentData,
+                    size_t SegmentSize,
+                    NvU32 DynamicSegmentOffset);
+
+/// Parse ELF library and load the relocated library segments for a given library name
+NvError NvRmPrivLoadLibrary(NvRmDeviceHandle hDevice,
+                                                            const char *Filename,
+                                                            NvU32 Address,
+                                                            NvBool IsApproachGreedy,
+                                                            NvRmLibraryHandle *hLibHandle);
+
+/// Get the symbol address. In phase1, this api will return the entry point address of the module
+NvError
+NvRmPrivGetProcAddress(NvRmLibraryHandle Handle,
+               const char *pSymbol,
+               void **pSymAddress);
+/// Free the ELF library by unloading the library from memory
+NvError NvRmPrivFreeLibrary(NvRmLibHandle *hLibHandle);
+
+NvError NvRmPrivInitModuleLoaderRPC(NvRmDeviceHandle hDevice);
+NvError NvRmPrivInitAvp(NvRmDeviceHandle hDevice);
+
+/// Unmap memory segments
+void UnMapRegion(SegmentNode *pList);
+/// Unload segments
+void RemoveRegion(SegmentNode *pList);
+
+void parseElfHeader(Elf32_Ehdr *elf);
+
+NvError
+LoadLoadableProgramSegment(PrivateOsFileHandle elfSourceHandle,
+            NvRmDeviceHandle hDevice,
+            NvRmLibraryHandle hLibHandle,
+            Elf32_Phdr Phdr,
+            Elf32_Ehdr Ehdr,
+            const NvRmHeap * Heaps,
+            NvU32 NumHeaps,
+            NvU32 loop,
+            const char *Filename,
+            SegmentNode **segmentList);
+
+NvError
+parseProgramSegmentHeaders(PrivateOsFileHandle elfSourceHandle,
+            NvU32 segmentHeaderOffset,
+            NvU32 segmentCount);
+
+ NvError
+parseSectionHeaders(PrivateOsFileHandle elfSourceHandle,
+            Elf32_Ehdr *elf);
+
+NvError
+loadSegmentsInFixedMemory(PrivateOsFileHandle elfSourceHandle,
+                        Elf32_Ehdr *elf, NvU32 segmentIndex, void **loadaddress);
+#endif
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_rpc.h b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_rpc.h
new file mode 100644 (file)
index 0000000..b38e8a1
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * arch/arm/mach-tegra/nvrm/core/common/nvrm_rpc.h
+ *
+ * communication between processors (cpu and avp)
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef NVRM_RPC_H
+#define NVRM_RPC_H
+
+/*
+ * nvrm_cpu_avp_rpc_private.h defines the private implementation functions to facilitate
+ * communication between processors (cpu and avp).
+ */
+
+#include "nvcommon.h"
+#include "nvos.h"
+#include "nvrm_init.h"
+#include "nvrm_message.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif  /* __cplusplus */
+
+
+/**
+ * Initialize RPC
+ *
+ * Init the RPC.  Both the service and client
+ * to the service must call this API before calling to create each endpoint of the connection
+ * via NvRmPrivRPCConnect
+ *
+ * If PortName is too long or does not exist debug mode
+ * assert is encountered.
+ *
+ * @param hDeviceHandle rm device handle
+ * @param rpcPortName the port name
+ * @param hRPCHandle the RPC transport handle
+ *
+ * @retval NvError_SemaphoreCreateFailed Creaion of semaphore failed.
+ */
+ NvError NvRmPrivRPCInit( NvRmDeviceHandle hDeviceHandle, char* rpcPortName, NvRmRPCHandle *hRPCHandle );
+/**
+ * De-intialize the RPC and other resources.
+ * @param hRPCHandle the RPC transport handle
+ *
+ */
+void NvRmPrivRPCDeInit( NvRmRPCHandle hRPCHandle );
+
+/**
+ * Connect to RPC port
+ *
+ * Creates one end of a RPC connection.  Both the service and client
+ * to the service must call this API to create each endpoint of the connection
+ * through a specified port
+ *
+ * If PortName is too long or does not exist debug mode
+ * assert is encountered.
+ *
+ * @param hRPCHandle the RPC transport handle
+ *
+ * @retval NvSuccess Transport endpoint successfully allocated
+ * @retval NvError_InsufficientMemory Not enough memory to allocate endpoint
+ * @retval NvError_MutexCreateFailed Creaion of mutex failed.
+ * @retval NvError_SemaphoreCreateFailed Creaion of semaphore failed.
+ * @retval NvError_SharedMemAllocFailed Creaion of shared memory allocation
+ * failed.
+ * @retval NvError_NotInitialized The transport is not able to initialzed the
+ * threads.
+ */
+ NvError NvRmPrivRPCConnect( NvRmRPCHandle hRPCHandle );
+
+ /**
+ * Connect to RPC port
+ *
+ * Creates one end of a RPC connection.  Both the service and client
+ * to the service must call this API to create each endpoint of the connection
+ * through a specified port
+ *
+ * If PortName is too long or does not exist debug mode
+ * assert is encountered.
+ *
+ * @param hRPCHandle the RPC transport handle
+ *
+ * @retval NvSuccess Transport endpoint successfully allocated
+ * @retval NvError_InsufficientMemory Not enough memory to allocate endpoint
+ * @retval NvError_MutexCreateFailed Creaion of mutex failed.
+ * @retval NvError_SemaphoreCreateFailed Creaion of semaphore failed.
+ * @retval NvError_SharedMemAllocFailed Creaion of shared memory allocation
+ * failed.
+ * @retval NvError_NotInitialized The transport is not able to initialzed the
+ * threads.
+ */
+ NvError NvRmPrivRPCWaitForConnect( NvRmRPCHandle hRPCHandle );
+ /**
+ * Receive the message from the port. This will read the message if it is
+ * available for this port otherwise it will return the
+ * NvError_TransportMessageBoxEmpty error.
+ *
+ * @param hRPCHandle the RPC transport handle
+ * @param pMessageBuffer The pointer to the receive message buffer where the
+ * received message will be copied.
+ * @param pMessageSize Pointer to the variable where the length of the message
+ * will be stored.
+ *
+ * @retval NvSuccess Message received successfully.
+ * @retval NvError_NotInitialized hTransport is not open.
+ * @retval NvError_InvalidState The port is not connection state.
+ * @retval NvError_TransportMessageBoxEmpty The message box empty and not able
+ * to receive the message.
+ * @retval NvError_TransportIncompleteMessage The received message for this
+ * port is longer than the configured message length for this port. It copied
+ * the maximm size of the configured length of the message for this port and
+ * return the incomplete message buffer.
+ * @retval NvError_TransportMessageOverflow The port receives the message more
+ * than the configured queue depth count for this port and hence message
+ * overflow has been ocuured.
+ */
+
+ NvError NvRmPrivRPCRecvMsg( NvRmRPCHandle hRPCHandle, void* pMessageBuffer, NvU32 * pMessageSize );
+
+ /**
+ * Send Message.
+ *
+ * Sends a message to the other port which is connected to this port.
+ * Its a wrapper to rm transport send message
+ *
+ * @param hRPCHandle the RPC transport handle
+ * @param pMessageBuffer The pointer to the message buffer where message which
+ * need to be send is available.
+ * @param MessageSize Specifies the size of the message.
+ *
+ */
+void
+NvRmPrivRPCSendMsg(NvRmRPCHandle hRPCHandle,
+                   void* pMessageBuffer,
+                   NvU32 MessageSize);
+
+/**
+ * Send and Recieve message.
+ *
+ * Send and Recieve a message between port.
+ * Its a wrapper to rm transport send message with response
+ *
+ * @param hRPCHandle the RPC transport handle
+ * @param pRecvMessageBuffer The pointer to the receive message buffer where the
+ * received message will be copied.
+ * @param MaxSize The maximum size in bytes that may be copied to the buffer
+ * @param pMessageSize Pointer to the variable where the length of the message
+ * will be stored.
+ * @param pSendMessageBuffer The pointer to the message buffer where message which
+ * need to be send is available.
+ * @param MessageSize Specifies the size of the message.
+ *
+ */
+void
+NvRmPrivRPCSendMsgWithResponse(NvRmRPCHandle hRPCHandle,
+                               void* pRecvMessageBuffer,
+                               NvU32 MaxSize,
+                               NvU32 *pMessageSize,
+                               void* pSendMessageBuffer,
+                               NvU32 MessageSize);
+
+
+/**
+ * Closes a transport connection.  Proper closure of this connection requires
+ * that both the client and service call this API.  Therefore, it is expected
+ * that the client and service message one another to coordinate the close.
+ *
+ */
+void NvRmPrivRPCClose(NvRmRPCHandle hRPCHandle);
+
+NvError  NvRmPrivInitService(NvRmDeviceHandle hDeviceHandle);
+
+void NvRmPrivServiceDeInit(void);
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+
+
+#endif
index 6522dffe55d1a021a39ceeec4280c85cbdf82775..8227b9f2ca45a9914c34667988ed3c18030e8dc1 100644 (file)
@@ -578,32 +578,12 @@ static void InboxFullIsr(void *args)
     }
 }
 
-static irqreturn_t transport_ist(int irq, void *data)
+static irqreturn_t transport_isr(int irq, void *data)
 {
     InboxFullIsr(data);
-    enable_irq(irq);
     return IRQ_HANDLED;
 }
 
-static irqreturn_t transport_isr(int irq, void *data)
-{
-    disable_irq_nosync(irq);
-    return IRQ_WAKE_THREAD;
-}
-
-
-/**
- * Handle the outbox empty interrupt.
- */
-
-static void
-NvRmPrivProcIdGetProcessorInfo(
-    NvRmDeviceHandle hDevice,
-    NvRmModuleID *pProcModuleId)
-{
-    *pProcModuleId = NvRmModuleID_Cpu;
-}
-
 /**
  * Register for the transport interrupts.
  */
@@ -620,15 +600,14 @@ RegisterTransportInterrupt(NvRmDeviceHandle hDevice)
     
     IrqList = INT_SHR_SEM_INBOX_IBF;
 
-    set_irq_flags(IrqList, IRQF_VALID | IRQF_NOAUTOEN);
-    ret = request_threaded_irq(IrqList, transport_isr, transport_ist, 0,
-                              "nvrm_transport", hDevice);
+    set_irq_flags(IrqList, IRQF_VALID);
+    ret = request_irq(IrqList, transport_isr, 0,
+                      "nvrm_transport", hDevice);
     if (ret) {
       printk("%s failed %d\n", __func__, ret);
       return NvError_BadParameter;
     }
     s_TransportInterruptHandle = IrqList;
-    enable_irq(IrqList);
     return NvSuccess;
 }
 
index 952fcd77c05ab1f90e138afda3ef81f7d60f7198..fd80efcb642f108d01c44d1bdbf4c7ac28696885 100644 (file)
@@ -225,7 +225,7 @@ NvError nvrm_power_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void
     switch( function ) {
     case 9:
         err_ = NvRmPowerVoltageControl_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
-        break; 
+        break;
     case 8:
         err_ = NvRmPowerModuleClockControl_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
         break;
index 874ebdc57d9ae6ef49bafe6abb9e31cfd73f00e7..19ac6c5407593afd407c37269433af319b9f20ce 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <mach/nvrm_linux.h>
-#include "linux/nvrpc_ioctl.h"
+#include <mach/nvrpc.h>
 #include "nvcommon.h"
 #include "nvassert.h"
 #include "nvos.h"
@@ -102,15 +102,17 @@ static struct miscdevice nvrpc_dev =
 
 static DEFINE_MUTEX(nvrpc_device_lock);
 
+static NvBool s_init_done = NV_FALSE;
+NvRmDeviceHandle s_hRmGlobal = NULL;
+
 int nvrpc_open(struct inode *inode, struct file *file)
 {
        NvError e = NvSuccess;
-       static NvBool init_done = NV_FALSE;
 
        mutex_lock(&nvrpc_device_lock);
-       if (init_done == NV_FALSE) {
-               e = NvRmTransportInit(NULL);
-               init_done = NV_TRUE;
+       if (s_init_done == NV_FALSE) {
+               e = NvRmTransportInit(s_hRmGlobal);
+               s_init_done = NV_TRUE;
        }
        mutex_unlock(&nvrpc_device_lock);
 
@@ -139,6 +141,13 @@ static int nvrpc_make_error_code(NvError e)
        return error;
 }
 
+NvRmTransportHandle g_hTransportAvp = NULL;
+NvRmTransportHandle g_hTransportCpu = NULL;
+NvOsSemaphoreHandle g_hTransportAvpSem = NULL;
+NvOsSemaphoreHandle g_hTransportCpuSem = NULL;
+int g_hTransportAvpIsConnected = 0;
+int g_hTransportCpuIsConnected = 0;
+
 static int nvrpc_ioctl_open(struct file *filp,
                            unsigned int cmd, void __user *arg)
 {
@@ -175,12 +184,29 @@ static int nvrpc_ioctl_open(struct file *filp,
                if (e != NvSuccess)
                        goto fail;
        }
-       op.ret_val = NvRmTransportOpen(NULL, p_name, recv_sem,
+       printk(KERN_ERR "%s: NvRmTransportOpen\n", __func__);
+       op.ret_val = NvRmTransportOpen(s_hRmGlobal, p_name, recv_sem,
                                       (void *)&op.transport_handle);
        error = copy_to_user(arg, &op, sizeof(op));
+       if (p_name && ! strcmp(p_name, "RPC_CPU_PORT")) {
+           if (g_hTransportCpu) {
+                   panic("%s: g_hTransportCpu=%p is already assigned.\n", __func__, g_hTransportCpu);
+           }
+           g_hTransportCpu = (NvRmTransportHandle)op.transport_handle;
+           g_hTransportCpuSem = (NvOsSemaphoreHandle) op.sem;
+           printk(KERN_ERR "%s: g_hTransportCpu=%p\n", __func__, g_hTransportCpu);
+       }
+       if (p_name && ! strcmp(p_name, "RPC_AVP_PORT")) {
+           if (g_hTransportAvp) {
+                   panic("%s: g_hTransportAvp=%p is already assigned.\n", __func__, g_hTransportAvp);
+           }
+           g_hTransportAvp = (NvRmTransportHandle)op.transport_handle;
+           g_hTransportAvpSem = (NvOsSemaphoreHandle) op.sem;
+           printk(KERN_ERR "%s: g_hTransportAvp=%p\n", __func__, g_hTransportAvp);
+       }
 
 fail:
-       nvrpc_stack_kfree(port_name, p_name);
+       nvrpc_stack_kfree((char*)port_name, p_name);
        if (recv_sem)
                NvOsSemaphoreDestroy(recv_sem);
        if (e != NvSuccess)
@@ -217,7 +243,7 @@ static int nvrpc_ioctl_get_port_name(struct file *filp,
        }
 
 fail:
-       nvrpc_stack_kfree(port_name, p_name);
+       nvrpc_stack_kfree((NvS8*)port_name, p_name);
        return error;
 }
 
@@ -262,14 +288,28 @@ static int nvrpc_ioctl_connect(struct file *filp,
        NvError e = NvSuccess;
        int error;
        struct nvrpc_handle_param op;
+       NvU8 port_name[NVRPC_MAX_LOCAL_STACK];
 
        error = copy_from_user(&op, arg, sizeof(op));
        if (error)
                goto fail;
+
+       NvRmTransportGetPortName((void *)op.handle,
+                                port_name, sizeof(port_name));
+       printk(KERN_INFO "%s: port_name=%s\n", __func__, port_name);
+
+
        op.ret_val = NvRmTransportConnect(
                (void *)op.handle, op.param);
        error = copy_to_user(arg, &op, sizeof(op));
 
+       if (! strcmp(port_name, "RPC_AVP_PORT")) {
+           g_hTransportAvpIsConnected = 1;
+       }
+       if (! strcmp(port_name, "RPC_CPU_PORT")) {
+           g_hTransportCpuIsConnected = 1;
+       }
+
 fail:
        if (e != NvSuccess)
                error = nvrpc_make_error_code(e);
@@ -613,6 +653,18 @@ static int __init nvrpc_init(void)
 {
        int ret = 0;
 
+       NvRmDeviceHandle handle;
+       NvRmInit(&handle);
+
+       if (s_init_done == NV_FALSE) {
+               NvError e;
+
+               printk(KERN_INFO "%s: NvRmTransportInit\n", __func__);
+               e = NvRmOpen(&s_hRmGlobal, 0);
+               e = NvRmTransportInit(s_hRmGlobal);
+               s_init_done = NV_TRUE;
+       }
+
        ret = misc_register(&nvrpc_dev);
        if (ret) {
                pr_err("%s misc register FAILED\n", __func__);