summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/nv
diff options
context:
space:
mode:
authorKaz Fukuoka <kfukuoka@nvidia.com>2010-07-30 13:13:01 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2010-10-13 14:17:45 -0700
commitefdc89684c62a400eb9543a18bd4fb5de16e7ae6 (patch)
treef2f621f575e2fc9e03a622bdc6fd806587d8afa7 /arch/arm/mach-tegra/nv
parentc9743d7eae9200438ec737a43df9e3267761bbec (diff)
[ARM] tegra: CPU-AVP RPC in kernel
- /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>
Diffstat (limited to 'arch/arm/mach-tegra/nv')
-rwxr-xr-xarch/arm/mach-tegra/nv/include/mach/nvrpc.h102
-rw-r--r--arch/arm/mach-tegra/nv/include/nvfw.h54
-rw-r--r--arch/arm/mach-tegra/nv/include/nvrm_moduleloader.h179
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile1
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_avp_service.c319
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/Makefile6
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_cpu_rpc.c381
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_swi_registry.h171
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_graphics_private.h77
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_init_stub.c34
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h68
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c1651
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader_private.h184
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_rpc.h198
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c29
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c2
-rw-r--r--arch/arm/mach-tegra/nv/nvrpc_user.c68
17 files changed, 3457 insertions, 67 deletions
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
index 000000000000..594e1f5d4e94
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/include/mach/nvrpc.h
@@ -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
index 000000000000..e6b496b5d6e0
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/include/nvfw.h
@@ -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
index 000000000000..ab8761c970c3
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/include/nvrm_moduleloader.h
@@ -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
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile b/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
index 5d94bc4ca846..b5e63bd493e1 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
@@ -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
index 000000000000..53f503210cb8
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_avp_service.c
@@ -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;
+}
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile b/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
index e57ea8d3dec9..eb84beed8bdd 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
@@ -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
index 000000000000..60c259db00cd
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_cpu_rpc.c
@@ -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
index 000000000000..712bca98efde
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_avp_swi_registry.h
@@ -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
index 000000000000..3953b3665d3d
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_graphics_private.h
@@ -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
index 000000000000..481ebd43260f
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_init_stub.c
@@ -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);
+}
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h
index e32033f6aa05..0fe59dbf293a 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_message.h
@@ -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;
@@ -227,6 +219,18 @@ typedef struct{
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;
NvU32 bufferAddr;
NvU32 bufferSize;
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
index 000000000000..6de25c61608e
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c
@@ -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
index 000000000000..becb53c978f3
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader_private.h
@@ -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
index 000000000000..b38e8a1b1f3a
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_rpc.h
@@ -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
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c
index 6522dffe55d1..8227b9f2ca45 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c
@@ -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;
}
diff --git a/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c b/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c
index 952fcd77c05a..fd80efcb642f 100644
--- a/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c
+++ b/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_power_dispatch.c
@@ -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;
diff --git a/arch/arm/mach-tegra/nv/nvrpc_user.c b/arch/arm/mach-tegra/nv/nvrpc_user.c
index 874ebdc57d9a..19ac6c540759 100644
--- a/arch/arm/mach-tegra/nv/nvrpc_user.c
+++ b/arch/arm/mach-tegra/nv/nvrpc_user.c
@@ -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__);