summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h9
-rw-r--r--arch/arm/mach-tegra/nv/Makefile1
-rwxr-xr-xarch/arm/mach-tegra/nv/include/linux/nvrpc_ioctl.h102
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/Makefile2
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile2
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc.c431
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc_hw_private.c165
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/Makefile2
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_module_stub.c177
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c1676
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/dispatch/Makefile4
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/dispatch/NvRm_Dispatch.c12
-rw-r--r--arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_module_dispatch.c469
-rw-r--r--arch/arm/mach-tegra/nv/nvrpc_user.c629
14 files changed, 3198 insertions, 483 deletions
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index c20a5273a684..78bf8009b0ed 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -59,9 +59,18 @@
#define TEGRA_GART_BASE 0x58000000
#define TEGRA_GART_SIZE SZ_32M
+#define TEGRA_RES_SEMA_BASE 0x60001000
+#define TEGRA_RES_SEMA_SIZE SZ_4K
+
+#define TEGRA_ARB_SEMA_BASE 0x60002000
+#define TEGRA_ARB_SEMA_SIZE SZ_4K
+
#define TEGRA_PRIMARY_ICTLR_BASE 0x60004000
#define TEGRA_PRIMARY_ICTLR_SIZE SZ_64
+#define TEGRA_ARBGNT_ICTLR_BASE 0x60004040
+#define TEGRA_ARBGNT_ICTLR_SIZE 192
+
#define TEGRA_SECONDARY_ICTLR_BASE 0x60004100
#define TEGRA_SECONDARY_ICTLR_SIZE SZ_64
diff --git a/arch/arm/mach-tegra/nv/Makefile b/arch/arm/mach-tegra/nv/Makefile
index b7a0d7019f5d..7fb51c48192f 100644
--- a/arch/arm/mach-tegra/nv/Makefile
+++ b/arch/arm/mach-tegra/nv/Makefile
@@ -11,6 +11,7 @@ ccflags-y += -Iarch/arm/mach-tegra/nv/include
obj-$(CONFIG_TEGRA_NVRM) += nvrm_user.o
+obj-$(CONFIG_TEGRA_NVRM) += nvrpc_user.o
obj-$(CONFIG_TEGRA_NVRM) += nvrm/
obj-$(CONFIG_TEGRA_NVRM) += nvreftrack/
diff --git a/arch/arm/mach-tegra/nv/include/linux/nvrpc_ioctl.h b/arch/arm/mach-tegra/nv/include/linux/nvrpc_ioctl.h
new file mode 100755
index 000000000000..594e1f5d4e94
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/include/linux/nvrpc_ioctl.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/nvrm/core/Makefile b/arch/arm/mach-tegra/nv/nvrm/core/Makefile
index 728fa0b544af..716418630a1f 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/core/Makefile
@@ -8,5 +8,5 @@ ccflags-y += -DNV_DEBUG=0
endif
ccflags-y += -Iarch/arm/mach-tegra/nv/include
-#obj-y += ap15/
+obj-y += ap15/
obj-y += common/
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile b/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
index 293e65fba4de..5d94bc4ca846 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/core/ap15/Makefile
@@ -11,3 +11,5 @@ 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_xpc.o
+obj-y += ap15rm_xpc_hw_private.o
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc.c b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc.c
new file mode 100644
index 000000000000..b0205c2110c9
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 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.
+ *
+ */
+
+/**
+ * @file
+ * @brief <b>nVIDIA Driver Development Kit:
+ * Cross Proc Communication driver </b>
+ *
+ * @b Description: Implements the interface to the NvDdk XPC.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/io.h>
+
+#include "nvrm_xpc.h"
+#include "nvrm_memmgr.h"
+#include "ap15rm_xpc_hw_private.h"
+#include "nvrm_hardware_access.h"
+#include "nvassert.h"
+#include "ap15/ararb_sema.h"
+#include "ap15/arictlr_arbgnt.h"
+#include "nvrm_avp_shrd_interrupt.h"
+
+// Minimum sdram offset required so that avp can access the address which is
+// passed.
+// AVP can not access the 0x0000:0000 to 0x0000:0040
+enum { MIN_SDRAM_OFFSET = 0x100};
+
+
+//There are only 32 arb semaphores
+#define MAX_ARB_NUM 32
+
+#define ARBSEMA_REG_READ(pArbSemaVirtAdd, reg) \
+ NV_READ32(pArbSemaVirtAdd + (ARB_SEMA_##reg##_0))
+
+#define ARBSEMA_REG_WRITE(pArbSemaVirtAdd, reg, data) \
+ NV_WRITE32(pArbSemaVirtAdd + (ARB_SEMA_##reg##_0), (data));
+
+#define ARBGNT_REG_READ(pArbGntVirtAdd, reg) \
+ NV_READ32(pArbGntVirtAdd + (ARBGNT_##reg##_0))
+
+#define ARBGNT_REG_WRITE(pArbGntVirtAdd, reg, data) \
+ NV_WRITE32(pArbGntVirtAdd + (ARBGNT_##reg##_0), (data));
+
+static int s_arbInterruptHandle = -1;
+
+// Combines the Processor Xpc system details. This contains the details of the
+// receive/send message queue and messaging system.
+typedef struct NvRmPrivXpcMessageRec
+{
+ NvRmDeviceHandle hDevice;
+
+ // Hw mail box register.
+ CpuAvpHwMailBoxReg HwMailBoxReg;
+
+} NvRmPrivXpcMessage;
+
+typedef struct NvRmPrivXpcArbSemaRec
+{
+ NvRmDeviceHandle hDevice;
+ NvU8 *pArbSemaVirtAddr;
+ NvU8 *pArbGntVirtAddr;
+ NvOsSemaphoreHandle semaphore[MAX_ARB_NUM];
+ NvOsMutexHandle mutex[MAX_ARB_NUM];
+ NvOsIntrMutexHandle hIntrMutex;
+
+} NvRmPrivXpcArbSema;
+
+static NvRmPrivXpcArbSema s_ArbSema;
+
+//Forward declarations
+static NvError InitArbSemaSystem(NvRmDeviceHandle hDevice);
+static void ArbSemaIsr(void *args);
+NvU32 GetArbIdFromRmModuleId(NvRmModuleID modId);
+/**
+ * Initialize the cpu avp hw mail box address and map the hw register address
+ * to virtual address.
+ * Thread Safety: Caller responsibility
+ */
+static NvError
+InitializeCpuAvpHwMailBoxRegister(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ NvRmPhysAddr ResourceSemaPhysAddr;
+
+ // Get base address of the hw mail box register. This register is in the set
+ // of resource semaphore module Id.
+ ResourceSemaPhysAddr = TEGRA_RES_SEMA_BASE;
+ hXpcMessage->HwMailBoxReg.BankSize = TEGRA_RES_SEMA_SIZE;
+
+ // Map the base address to the virtual address.
+ hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr =
+ IO_ADDRESS(ResourceSemaPhysAddr);
+
+ NvRmPrivXpcHwResetOutbox(&hXpcMessage->HwMailBoxReg);
+
+ return NvSuccess;
+}
+
+/**
+ * DeInitialize the cpu avp hw mail box address and unmap the hw register address
+ * virtual address.
+ * Thread Safety: Caller responsibility
+ */
+static void DeInitializeCpuAvpHwMailBoxRegister(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL;
+}
+
+/**
+ * Create the cpu-avp messaging system.
+ * This function will call other helper function to create the messaging technique
+ * used for cpu-avp communication.
+ * Thread Safety: Caller responsibility
+ */
+static NvError
+CreateCpuAvpMessagingSystem(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ NvError Error = NvSuccess;
+
+ Error = InitializeCpuAvpHwMailBoxRegister(hXpcMessage);
+
+#if NV_IS_AVP
+ hXpcMessage->HwMailBoxReg.IsCpu = NV_FALSE;
+#else
+ hXpcMessage->HwMailBoxReg.IsCpu = NV_TRUE;
+#endif
+
+ // If error found then destroy all the allocation and initialization,
+ if (Error)
+ DeInitializeCpuAvpHwMailBoxRegister(hXpcMessage);
+
+ return Error;
+}
+
+
+/**
+ * Destroy the cpu-avp messaging system.
+ * This function destroy all the allocation/initialization done for creating
+ * the cpu-avp messaging system.
+ * Thread Safety: Caller responsibility
+ */
+static void DestroyCpuAvpMessagingSystem(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ // Destroy the cpu-avp hw mail box registers.
+ DeInitializeCpuAvpHwMailBoxRegister(hXpcMessage);
+ hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL;
+ hXpcMessage->HwMailBoxReg.BankSize = 0;
+}
+
+
+NvError
+NvRmPrivXpcCreate(
+ NvRmDeviceHandle hDevice,
+ NvRmPrivXpcMessageHandle *phXpcMessage)
+{
+ NvError Error = NvSuccess;
+ NvRmPrivXpcMessageHandle hNewXpcMsgHandle = NULL;
+
+ *phXpcMessage = NULL;
+
+ // Allocates the memory for the xpc message handle.
+ hNewXpcMsgHandle = NvOsAlloc(sizeof(*hNewXpcMsgHandle));
+ if (!hNewXpcMsgHandle)
+ {
+ return NvError_InsufficientMemory;
+ }
+
+ // Initialize all the members of the xpc message handle.
+ hNewXpcMsgHandle->hDevice = hDevice;
+ hNewXpcMsgHandle->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL;
+ hNewXpcMsgHandle->HwMailBoxReg.BankSize = 0;
+
+ // Create the messaging system between the processors.
+ Error = CreateCpuAvpMessagingSystem(hNewXpcMsgHandle);
+
+ // if error the destroy all allocations done here.
+ if (Error)
+ {
+ NvOsFree(hNewXpcMsgHandle);
+ hNewXpcMsgHandle = NULL;
+ }
+
+#if NV_IS_AVP
+ Error = InitArbSemaSystem(hDevice);
+ if (Error)
+ {
+ NvOsFree(hNewXpcMsgHandle);
+ hNewXpcMsgHandle = NULL;
+ }
+#endif
+
+ // Copy the new xpc message handle into the passed parameter.
+ *phXpcMessage = hNewXpcMsgHandle;
+ return Error;
+}
+
+
+/**
+ * Destroy the Rm Xpc message handle.
+ * Thread Safety: It is provided inside the function.
+ */
+void NvRmPrivXpcDestroy(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ // If not a null pointer then destroy.
+ if (hXpcMessage)
+ {
+ // Destroy the messaging system between processor.
+ DestroyCpuAvpMessagingSystem(hXpcMessage);
+
+ // Free the allocated memory for the xpc message handle.
+ NvOsFree(hXpcMessage);
+ }
+}
+
+
+// Set the outbound mailbox with the given data. We might have to spin until
+// it's safe to send the message.
+NvError
+NvRmPrivXpcSendMessage(NvRmPrivXpcMessageHandle hXpcMessage, NvU32 data)
+{
+ NvRmPrivXpcHwSendMessageToTarget(&hXpcMessage->HwMailBoxReg, data);
+ return NvSuccess;
+}
+
+
+// Get the value currently in the inbox register. This read clears the incoming
+// interrupt.
+NvU32
+NvRmPrivXpcGetMessage(NvRmPrivXpcMessageHandle hXpcMessage)
+{
+ NvU32 data;
+ NvRmPrivXpcHwReceiveMessageFromTarget(&hXpcMessage->HwMailBoxReg, &data);
+ return data;
+}
+
+NvError NvRmXpcInitArbSemaSystem(NvRmDeviceHandle hDevice)
+{
+#if NV_IS_AVP
+ return NvSuccess;
+#else
+ return InitArbSemaSystem(hDevice);
+#endif
+}
+
+static irqreturn_t arbgnt_isr(int irq, void *data)
+{
+ ArbSemaIsr(data);
+ return IRQ_HANDLED;
+}
+
+static NvError InitArbSemaSystem(NvRmDeviceHandle hDevice)
+{
+ NvOsInterruptHandler ArbSemaHandler;
+ NvRmPhysAddr ArbSemaBase, ArbGntBase;
+ NvU32 ArbSemaSize, ArbGntSize;
+ NvU32 irq;
+ NvError e;
+ NvU32 i = 0;
+ int ret;
+
+ /* FIXME: is this the right interrupt? */
+ irq = INT_GNT_0;
+
+ ArbSemaHandler = ArbSemaIsr;
+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+ ret = request_irq(irq, arbgnt_isr, 0, "nvrm_arbgnt", hDevice);
+ if (ret < 0) {
+ printk("%s request_irq failed %d\n", __func__, ret);
+ return NvError_AccessDenied;
+ }
+ s_arbInterruptHandle = irq;
+
+ ArbSemaBase = TEGRA_ARB_SEMA_BASE;
+ ArbSemaSize = TEGRA_ARB_SEMA_SIZE;
+ ArbGntBase = TEGRA_ARBGNT_ICTLR_BASE;
+ ArbGntSize = TEGRA_ARBGNT_ICTLR_SIZE;
+
+ s_ArbSema.pArbSemaVirtAddr = IO_ADDRESS(ArbSemaBase);
+ s_ArbSema.pArbGntVirtAddr = IO_ADDRESS(ArbGntBase);
+
+ //Initialize all the semaphores and mutexes
+ for (i=0;i<MAX_ARB_NUM;i++)
+ {
+ NV_CHECK_ERROR_CLEANUP(
+ NvOsSemaphoreCreate(&s_ArbSema.semaphore[i], 0)
+ );
+
+ NV_CHECK_ERROR_CLEANUP(
+ NvOsMutexCreate(&s_ArbSema.mutex[i])
+ );
+ }
+
+ NV_CHECK_ERROR_CLEANUP(
+ NvOsIntrMutexCreate(&s_ArbSema.hIntrMutex)
+ );
+
+ enable_irq(irq);
+
+fail:
+
+ return e;
+}
+
+
+static void ArbSemaIsr(void *args)
+{
+ NvU32 int_mask, proc_int_enable, arb_gnt, i = 0;
+
+ NvOsIntrMutexLock(s_ArbSema.hIntrMutex);
+ //Check which arb semaphores have been granted to this processor
+ arb_gnt = ARBSEMA_REG_READ(s_ArbSema.pArbSemaVirtAddr, SMP_GNT_ST);
+
+ //Figure out which arb semaphores were signalled and then disable them.
+#if NV_IS_AVP
+ proc_int_enable = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, COP_ENABLE);
+ int_mask = arb_gnt & proc_int_enable;
+ ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr,
+ COP_ENABLE, (proc_int_enable & ~int_mask));
+#else
+ proc_int_enable = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE);
+ int_mask = arb_gnt & proc_int_enable;
+ ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr,
+ CPU_ENABLE, (proc_int_enable & ~int_mask));
+#endif
+
+ //Signal all the required semaphores
+ do
+ {
+ if (int_mask & 0x1)
+ {
+ NvOsSemaphoreSignal(s_ArbSema.semaphore[i]);
+ }
+ int_mask >>= 1;
+ i++;
+
+ } while (int_mask);
+
+ NvOsIntrMutexUnlock(s_ArbSema.hIntrMutex);
+}
+
+NvU32 GetArbIdFromRmModuleId(NvRmModuleID modId)
+{
+ NvU32 arbId;
+
+ switch(modId)
+ {
+ case NvRmModuleID_BseA:
+ arbId = NvRmArbSema_Bsea;
+ break;
+ case NvRmModuleID_Vde:
+ default:
+ arbId = NvRmArbSema_Vde;
+ break;
+ }
+
+ return arbId;
+}
+
+void NvRmXpcModuleAcquire(NvRmModuleID modId)
+{
+ NvU32 RequestedSemaNum;
+ NvU32 reg;
+
+ RequestedSemaNum = GetArbIdFromRmModuleId(modId);
+
+ NvOsMutexLock(s_ArbSema.mutex[RequestedSemaNum]);
+ NvOsIntrMutexLock(s_ArbSema.hIntrMutex);
+
+ //Try to grab the lock
+ ARBSEMA_REG_WRITE(s_ArbSema.pArbSemaVirtAddr, SMP_GET, 1 << RequestedSemaNum);
+
+ //Enable arb sema interrupt
+#if NV_IS_AVP
+ reg = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, COP_ENABLE);
+ reg |= (1 << RequestedSemaNum);
+ ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, COP_ENABLE, reg);
+#else
+ reg = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE);
+ reg |= (1 << RequestedSemaNum);
+ ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE, reg);
+#endif
+
+ NvOsIntrMutexUnlock(s_ArbSema.hIntrMutex);
+ NvOsSemaphoreWait(s_ArbSema.semaphore[RequestedSemaNum]);
+}
+
+void NvRmXpcModuleRelease(NvRmModuleID modId)
+{
+ NvU32 RequestedSemaNum;
+
+ RequestedSemaNum = GetArbIdFromRmModuleId(modId);
+
+ //Release the lock
+ ARBSEMA_REG_WRITE(s_ArbSema.pArbSemaVirtAddr, SMP_PUT, 1 << RequestedSemaNum);
+
+ NvOsMutexUnlock(s_ArbSema.mutex[RequestedSemaNum]);
+}
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc_hw_private.c b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc_hw_private.c
new file mode 100644
index 000000000000..ffd1dc5d6ebd
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/ap15/ap15rm_xpc_hw_private.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 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.
+ *
+ */
+
+/**
+ * @file
+ * @brief <b>nVIDIA Driver Development Kit:
+ * Cross Processor Communication driver </b>
+ *
+ * @b Description: Implements the cross processor communication Hw Access APIs
+ *
+ */
+
+#include "nvcommon.h"
+#include "nvassert.h"
+#include "nvrm_drf.h"
+#include "nvrm_hardware_access.h"
+#include "ap15rm_xpc_hw_private.h"
+#include "ap15/arres_sema.h"
+
+enum {MESSAGE_BOX_MESSAGE_LENGTH_BITS = 28};
+#define RESSEMA_REG_READ32(pResSemaHwRegVirtBaseAdd, reg) \
+ NV_READ32((pResSemaHwRegVirtBaseAdd) + (RES_SEMA_##reg##_0)/4)
+
+#define RESSEMA_REG_WRITE32(pResSemaHwRegVirtBaseAdd, reg, val) \
+ do { \
+ NV_WRITE32(((pResSemaHwRegVirtBaseAdd) + ((RES_SEMA_##reg##_0)/4)), (val)); \
+ } while(0)
+
+void NvRmPrivXpcHwResetOutbox(CpuAvpHwMailBoxReg *pHwMailBoxReg)
+{
+ NvU32 OutboxMessage;
+ NvU32 OutboxVal;
+
+ OutboxMessage = 0;
+
+ // Write Outbox in the message box
+ // Enable the Valid tag
+ // Enable interrupt
+#if NV_IS_AVP
+ OutboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_INBOX);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_STAT, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_DATA, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_CMD, 0, OutboxVal);
+ OutboxVal |= OutboxMessage;
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IE_IBE, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, TAG, 0, OutboxVal);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_INBOX, OutboxVal);
+#else
+ OutboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_OUTBOX);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_CMD, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_STAT, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_DATA, 0, OutboxVal);
+ OutboxVal |= OutboxMessage;
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, IE_OBE, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, TAG, 0, OutboxVal);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_OUTBOX, OutboxVal);
+#endif
+}
+
+
+/**
+ * Send message to the target.
+ */
+void
+NvRmPrivXpcHwSendMessageToTarget(
+ CpuAvpHwMailBoxReg *pHwMailBoxReg,
+ NvRmPhysAddr MessageAddress)
+{
+ NvU32 OutboxMessage;
+ NvU32 OutboxVal = 0;
+
+ OutboxMessage = ((NvU32)(MessageAddress)) >> (32 - MESSAGE_BOX_MESSAGE_LENGTH_BITS);
+
+ // Write Outbox in the message box
+ // Enable the Valid tag
+ // Enable interrupt
+#if NV_IS_AVP
+ // !!! not sure why this would need to be read/modify/write
+// OutboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_INBOX);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_STAT, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_DATA, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_INBOX, IN_BOX_CMD, 0, OutboxVal);
+ OutboxVal |= OutboxMessage;
+ OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_INBOX, IE_IBF, FULL, OutboxVal);
+// OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_INBOX, IE_IBE, EMPTY, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_INBOX, TAG, VALID, OutboxVal);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_INBOX, OutboxVal);
+#else
+ // !!! not sure why this would need to be read/modify/write
+// OutboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_OUTBOX);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_CMD, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_STAT, 0, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_NUM(RES_SEMA, SHRD_OUTBOX, OUT_BOX_DATA, 0, OutboxVal);
+ OutboxVal |= OutboxMessage;
+ OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_OUTBOX, IE_OBF, FULL, OutboxVal);
+// OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_OUTBOX, IE_OBE, EMPTY, OutboxVal);
+ OutboxVal = NV_FLD_SET_DRF_DEF(RES_SEMA, SHRD_OUTBOX, TAG, VALID, OutboxVal);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_OUTBOX, OutboxVal);
+#endif
+}
+
+
+
+/**
+ * Receive message from the target.
+ */
+void
+NvRmPrivXpcHwReceiveMessageFromTarget(
+ CpuAvpHwMailBoxReg *pHwMailBoxReg,
+ NvRmPhysAddr *pMessageAddress)
+{
+ NvU32 InboxMessage = 0;
+ NvU32 InboxVal;
+
+ // Read the inbox. Lower 28 bit contains the message.
+#if NV_IS_AVP
+ InboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_OUTBOX);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_OUTBOX, 0);
+#else
+ InboxVal = RESSEMA_REG_READ32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr,SHRD_INBOX);
+ RESSEMA_REG_WRITE32(pHwMailBoxReg->pHwMailBoxRegBaseVirtAddr, SHRD_INBOX, 0);
+#endif
+ if (InboxVal & NV_DRF_DEF(RES_SEMA, SHRD_INBOX, TAG, VALID))
+ {
+ pHwMailBoxReg->MailBoxData = InboxVal;
+ }
+
+ InboxVal = (pHwMailBoxReg->MailBoxData) & (0xFFFFFFFFUL >> (32 - MESSAGE_BOX_MESSAGE_LENGTH_BITS));
+ InboxMessage = (InboxVal << (32 - MESSAGE_BOX_MESSAGE_LENGTH_BITS));
+
+ *pMessageAddress = InboxMessage;
+}
+
+
+
+
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile b/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
index 44d3ba199e30..b6c0893b7cf5 100644
--- a/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/Makefile
@@ -11,3 +11,5 @@ ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core/common
ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core
obj-y += nvrm_rmctrace.o
+obj-y += nvrm_transport.o
+obj-y += nvrm_module_stub.o \ No newline at end of file
diff --git a/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_module_stub.c b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_module_stub.c
new file mode 100644
index 000000000000..eb7a63604f61
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_module_stub.c
@@ -0,0 +1,177 @@
+
+#define NV_IDL_IS_STUB
+
+/*
+ * 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/iomap.h>
+#include "nvcommon.h"
+#include "nvrm_module.h"
+
+NvError NvRmModuleGetCapabilities( NvRmDeviceHandle hDeviceHandle,
+ NvRmModuleID Module, NvRmModuleCapability * pCaps, NvU32 NumCaps,
+ void * * Capability )
+{
+ NvU32 major = 0, minor = 0;
+ unsigned i;
+
+ switch (NVRM_MODULE_ID_MODULE(Module)) {
+ case NvRmModuleID_Mpe:
+ major = 1;
+ minor = 2;
+ break;
+
+ case NvRmModuleID_BseA:
+ major = 1;
+ minor = 1;
+ break;
+
+ case NvRmModuleID_Display:
+ major = 1;
+ minor = 3;
+ break;
+
+ case NvRmModuleID_Spdif:
+ major = 1;
+ minor = 0;
+ break;
+
+ case NvRmModuleID_I2s:
+ major = 1;
+ minor = 1;
+ break;
+
+ case NvRmModuleID_Misc:
+ major = 2;
+ minor = 0;
+ break;
+
+ case NvRmModuleID_Vde:
+ major = 1;
+ minor = 2;
+ break;
+
+ case NvRmModuleID_Isp:
+ major = 1;
+ minor = 0;
+ break;
+
+ case NvRmModuleID_Vi:
+ major = 1;
+ minor = 1;
+ break;
+
+ case NvRmModuleID_3D:
+ major = 1;
+ minor = 2;
+ break;
+
+ case NvRmModuleID_2D:
+ major = 1;
+ minor = 1;
+ break;
+
+ default:
+ printk("%s module %d not implemented\n", __func__, Module);
+ }
+
+ for (i=0; i<NumCaps; i++) {
+ if (pCaps[i].MajorVersion==major &&
+ pCaps[i].MinorVersion==minor) {
+ *Capability = pCaps[i].Capability;
+ return NvSuccess;
+ }
+ }
+
+ return NvError_NotSupported;
+}
+
+NvU32 NvRmModuleGetNumInstances( NvRmDeviceHandle hRmDeviceHandle,
+ NvRmModuleID Module )
+{
+ switch (Module) {
+ case NvRmModuleID_I2s:
+ return 4;
+
+ case NvRmModuleID_Display:
+ return 2;
+
+ case NvRmModuleID_3D:
+ case NvRmModuleID_Avp:
+ case NvRmModuleID_GraphicsHost:
+ case NvRmModuleID_Vcp:
+ case NvRmModuleID_Isp:
+ case NvRmModuleID_Vi:
+ case NvRmModuleID_Epp:
+ case NvRmModuleID_2D:
+ case NvRmModuleID_Spdif:
+ case NvRmModuleID_Vde:
+ case NvRmModuleID_Mpe:
+ case NvRmModuleID_Hdcp:
+ case NvRmModuleID_Hdmi:
+ case NvRmModuleID_Tvo:
+ case NvRmModuleID_Dsi:
+ case NvRmModuleID_BseA:
+ return 1;
+
+ default:
+ printk("%s module %d not implemented\n", __func__, Module);
+ return 1;
+ }
+}
+
+void NvRmModuleGetBaseAddress( NvRmDeviceHandle hRmDeviceHandle, NvRmModuleID Module, NvRmPhysAddr * pBaseAddress, NvU32 * pSize )
+{
+ switch (NVRM_MODULE_ID_MODULE(Module)) {
+ case NvRmModuleID_GraphicsHost:
+ *pBaseAddress = 0x50000000;
+ *pSize = 144 * 1024;
+ break;
+ case NvRmModuleID_Display:
+ *pBaseAddress = 0x54200000 + (NVRM_MODULE_ID_INSTANCE(Module))*0x40000;
+ *pSize = 256 * 1024;
+ break;
+
+ case NvRmModuleID_Vi:
+ *pBaseAddress = 0x54080000;
+ *pSize = 256 * 1024;
+ break;
+
+ case NvRmModuleID_Dsi:
+ *pBaseAddress = 0x54300000;
+ *pSize = 256 * 1024;
+ break;
+
+ default:
+ *pBaseAddress = 0x0000000;
+ *pSize = 00;
+ printk("%s module %d not implemented\n", __func__, Module);
+ }
+ printk("%s module %d 0x%08x x %dK\n", __func__, Module, *pBaseAddress, *pSize / 1024);
+}
+
+void NvRmModuleReset(NvRmDeviceHandle hRmDevice, NvRmModuleID Module)
+{
+ void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+ if (NVRM_MODULE_ID_MODULE(Module) != NvRmModuleID_Avp ||
+ NVRM_MODULE_ID_INSTANCE(Module) != 0) {
+ printk("%s MOD[%lu] INST[%lu] not implemented\n", __func__,
+ NVRM_MODULE_ID_MODULE(Module),
+ NVRM_MODULE_ID_INSTANCE(Module));
+ return;
+ }
+
+ writel(1<<1, clk_rst + 0x300);
+ udelay(10);
+ writel(1<<1, clk_rst + 0x304);
+}
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
new file mode 100644
index 000000000000..6522dffe55d1
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_transport.c
@@ -0,0 +1,1676 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 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.
+ *
+ */
+
+/** @file
+ * @brief <b>NVIDIA Driver Development Kit:
+ * Transport API</b>
+ *
+ * @b Description: This is the implementation of Transport API, which
+ * implements a simple means to pass messages across a port name regardless of
+ * port exist in what processor (on same processor or other processor).
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <mach/irqs.h>
+#include "nvrm_transport.h"
+#include "nvrm_xpc.h"
+#include "nvrm_interrupt.h"
+#include "nvrm_message.h"
+#include "nvutil.h"
+#include "nvassert.h"
+#include "nvcommon.h"
+#include "avp.h"
+#include <linux/jiffies.h>
+
+#define LOOPBACK_PROFILE 0
+
+// indices where to save data for the loopback test
+#define LOOP_CPU_SEND_INDEX 0
+#define LOOP_AVP_ISR_INDEX 1
+#define LOOP_AVP_RECV_INDEX 2
+#define LOOP_AVP_SEND_INDEX 3
+#define LOOP_CPU_ISR_INDEX 4
+#define LOOP_CPU_RECV_INDEX 5
+
+#define SEMAPHORE_BASED_MUTUAL_EXCLUSION 0
+
+enum {MAX_INT_FOR_TRANSPORT = 2};
+
+// Interrupt bit index in the interrupt controller relocation table.
+enum {CPU_TRANSPORT_INT_OBE = 1};
+enum {CPU_TRANSPORT_INT_IBF = 0};
+enum {AVP_TRANSPORT_INT_OBE = 0};
+enum {AVP_TRANSPORT_INT_IBF = 1};
+
+// Some constraints parameter to develop the transport APIs.
+
+// Maximum port name length
+enum {MAX_PORT_NAME_LENGTH = 16};
+
+// Maximum possible message length between the ports
+#define MAX_COMMAND_SIZE 16
+
+// Message header size MessageCommand + port Name + message Length (24 Bytes)
+enum {MESSAGE_HEADER_SIZE = 0x20};
+
+// Maximum receive message queue depth
+enum {MAX_MESSAGE_DEPTH = 30};
+
+// Maximum time to wait for the response when open the port.
+enum {MAX_OPEN_TIMEOUT_MS = 200};
+
+// Try to resend the message after this time.
+enum {MESSAGE_RETRY_AFTER_MS = 500 };
+
+// Connection message transfer and response wait timeout.
+enum {MAX_CONNECTION_TIMEOUT_MS = 500 };
+
+
+
+// Transport Commands which uses to do the handshaking and message transfer
+// between the processor. This commands are send to the remote processor
+// when any type if transaction happens.
+typedef enum
+{
+ TransportCmd_None = 0x0,
+
+ // The first transport command from the cpu->avp will inform the
+ // avp of size of the buffer.
+ TransportCmd_SetBufferInfo,
+
+ // Transport command for staring the connection process.
+ TransportCmd_Connect,
+
+ // Transport command for disconnecting the port and deleting the port entry.
+ TransportCmd_Disconnect,
+
+ // Transport command which used for normal message transfer to the port.
+ TransportCmd_Message,
+
+ // When a command requires a response, the value in the command field will
+ // be changed by the called processor here to indicate that the response is ready.
+ TransportCmd_Response,
+
+ TransportCmd_Force32 = 0x7FFFFFFF
+
+} TransportCmd;
+
+
+
+// Ports (endpoint) state.
+typedef enum
+{
+ // Port is opened only.
+ PortState_Open = 0x1,
+
+ // Port is waiting for connection.
+ PortState_Waiting,
+
+ // Port is connected.
+ PortState_Connected,
+
+ // Port has been disconnected from other side. You can pop out messages
+ // but you can't send anymore
+ PortState_Disconnected,
+
+ // Set to destroy when there is someone waiting for a connection, but
+ // and a different thread calls to kill close the port.
+ PortState_Destroy,
+
+ PortState_Force32 = 0x7FFFFFFF
+} PortState;
+
+
+
+// Message list which will be queued in the port receive message queue.
+typedef struct RmReceiveMessageRec
+{
+ // Length of message.
+ NvU32 MessageLength;
+
+ // Fixed size message buffer where the receiving message will be store.
+ NvU8 MessageBuffer[MAX_MESSAGE_LENGTH];
+} RmReceiveMessage;
+
+
+// Combines the information for keeping the received messages to the
+// corresponding ports.
+typedef struct MessageQueueRec
+{
+ // Receive message Q details to receive the message. We make the queue 1 extra bigger than the
+ // requested size, and then we can do lockless updates because only the Recv function modifies
+ // ReadIndex, and only the ISR modifies the WriteIndex
+ RmReceiveMessage *pReceiveMsg;
+
+ volatile NvU16 ReadIndex;
+ volatile NvU16 WriteIndex;
+
+ NvU16 QueueSize;
+
+} MessageQueue;
+
+
+
+// Combines all required information for the transport port.
+// The port information contains the state, recv message q, message depth and
+// message length.
+typedef struct NvRmTransportRec
+{
+ // Name of the port, 1 exra byte for NULL termination
+ char PortName[MAX_PORT_NAME_LENGTH+1];
+
+ // The state of port whether this is open or connected or waiting for
+ // connection.
+ PortState State;
+
+ // Receive message Box which contains the receive messages for this port.
+ MessageQueue RecvMessageQueue;
+
+ // Semaphore which is signal after getting the message for that port.
+ // This is the client passed semaphore.
+ NvOsSemaphoreHandle hOnPushMsgSem;
+
+ // Pointer to the partner port. If the connect is to a remote partner,
+ // then this pointer is NULL
+ NvRmTransportHandle hConnectedPort;
+
+ // If this is a remote connection, this holds the remote ports "name"
+ NvU32 RemotePort;
+
+ // save a copy of the rm handle.
+ NvRmDeviceHandle hRmDevice;
+
+ struct NvRmTransportRec *pNext;
+
+ // unlikely to be used members at the end
+
+ // to be signalled when someone waits for a connector.
+ NvOsSemaphoreHandle hOnConnectSem;
+
+#if LOOPBACK_PROFILE
+ NvBool bLoopTest;
+#endif
+
+} NvRmTransport;
+
+
+
+// Combines the common information for keeping the transport information and
+// sending and receiving the messages.
+typedef struct NvRmPrivPortsRec
+{
+ // Device handle.
+ NvRmDeviceHandle hDevice;
+
+ // List of port names of the open ports in the system.
+ NvRmTransport *pPortHead;
+
+ // Mutex for transport
+ NvOsMutexHandle mutex;
+
+ NvRmMemHandle hMessageMem;
+ void *pTransmitMem;
+ void *pReceiveMem;
+ NvU32 MessageMemPhysAddr;
+
+ NvRmPrivXpcMessageHandle hXpc;
+
+ // if a message comes in, but the receiver's queue is full,
+ // then we don't clear the inbound message to allow another message
+ // and set this flag. We use 2 variables here, so we don't need a lock.
+ volatile NvU8 ReceiveBackPressureOn;
+ NvU8 ReceiveBackPressureOff;
+
+#if LOOPBACK_PROFILE
+ volatile NvU32 *pTimer;
+#endif
+} NvRmPrivPorts;
+
+
+// !!! Fixme, this should be part of the rm handle.
+static NvRmPrivPorts s_TransportInfo;
+
+extern NvU32 NvRmAvpPrivGetUncachedAddress(NvU32 addr);
+
+#define MESSAGE_QUEUE_SIZE_IN_BYTES ( sizeof(RmReceiveMessage) * (MAX_MESSAGE_DEPTH+1) )
+static NvU32 s_RpcAvpQueue[ (MESSAGE_QUEUE_SIZE_IN_BYTES + 3) / 4 ];
+static NvU32 s_RpcCpuQueue[ (MESSAGE_QUEUE_SIZE_IN_BYTES + 3) / 4 ];
+static struct NvRmTransportRec s_RpcAvpPortStruct;
+static struct NvRmTransportRec s_RpcCpuPortStruct;
+
+static int s_TransportInterruptHandle = -1;
+
+static NvRmTransportHandle
+FindPort(NvRmDeviceHandle hDevice, char *pPortName);
+
+static NvError NvRmPrivTransportSendMessage(NvRmDeviceHandle hDevice,
+ NvU32 *messagehdr, NvU32 MessageHdrLength,
+ NvU32 *Message, NvU32 MessageLength);
+
+static void HandleAVPResetMessage(NvRmDeviceHandle hDevice);
+
+// expect caller to handle mutex
+static char *NvRmPrivTransportUniqueName(void)
+{
+ static char UniqueName[] = "aaaaaaaa+";
+ NvU32 len = 8;
+ NvU32 i;
+
+ // this will roll a new name until we hit zzzz:zzzz
+ // it's not unbounded, but it is a lot of names...
+ // Unique names end in a '+' which won't be allowed in supplied names, to avoid
+ // collision.
+ for (i=0; i < len; ++i)
+ {
+ ++UniqueName[i];
+ if (UniqueName[i] != 'z')
+ {
+ break;
+ }
+ UniqueName[i] = 'a';
+
+ }
+
+ return UniqueName;
+}
+
+
+/* Returns NV_TRUE if the message was inserted ok
+ * Returns NV_FALSE if message was not inserted because the queue is already full
+
+ */static NvBool
+InsertMessage(NvRmTransportHandle hPort, const NvU8 *message, const NvU32 MessageSize)
+{
+ NvU32 index;
+ NvU32 NextIndex;
+
+ index = (NvU32)hPort->RecvMessageQueue.WriteIndex;
+ NextIndex = index + 1;
+ if (NextIndex == hPort->RecvMessageQueue.QueueSize)
+ NextIndex = 0;
+
+ // check for full condition
+ if (NextIndex == hPort->RecvMessageQueue.ReadIndex)
+ return NV_FALSE;
+
+ // copy in the message
+ NvOsMemcpy(hPort->RecvMessageQueue.pReceiveMsg[index].MessageBuffer,
+ message,
+ MessageSize);
+ hPort->RecvMessageQueue.pReceiveMsg[index].MessageLength = MessageSize;
+
+ hPort->RecvMessageQueue.WriteIndex = (NvU16)NextIndex;
+ return NV_TRUE;
+}
+
+
+static void
+ExtractMessage(NvRmTransportHandle hPort, NvU8 *message, NvU32 *pMessageSize, NvU32 MaxSize)
+{
+ NvU32 NextIndex;
+ NvU32 index = (NvU32)hPort->RecvMessageQueue.ReadIndex;
+ NvU32 size = hPort->RecvMessageQueue.pReceiveMsg[index].MessageLength;
+
+ NextIndex = index + 1;
+ if (NextIndex == hPort->RecvMessageQueue.QueueSize)
+ NextIndex = 0;
+
+ NV_ASSERT(index != hPort->RecvMessageQueue.WriteIndex); // assert on empty condition
+ NV_ASSERT(size <= MaxSize);
+
+ *pMessageSize = size;
+
+ // only do the copy and update if there is sufficient room, otherwise
+ // the caller will propogate an error up.
+ if (size > MaxSize)
+ {
+ return;
+ }
+ NvOsMemcpy(message,
+ hPort->RecvMessageQueue.pReceiveMsg[index].MessageBuffer,
+ size);
+
+ hPort->RecvMessageQueue.ReadIndex = (NvU16)NextIndex;
+}
+
+
+
+static void *s_TmpIsrMsgBuffer;
+
+/**
+ * Connect message
+ * [ Transport Command ]
+ * [ Remote Handle ]
+ * [ Port Name ]
+ *
+ * Response:
+ * [ Remote Handle ] <- [ Local Handle ]
+ */
+
+static void
+HandleConnectMessage(NvRmDeviceHandle hDevice, volatile NvU32 *pMessage)
+{
+ char PortName[MAX_PORT_NAME_LENGTH+1];
+ NvU32 RemotePort;
+ NvRmTransportHandle hPort;
+
+ RemotePort = pMessage[1];
+ NvOsMemcpy(PortName, (void*)&pMessage[2], MAX_PORT_NAME_LENGTH);
+ PortName[MAX_PORT_NAME_LENGTH] = 0;
+
+ // See if there is a local port with that name
+ hPort = FindPort(hDevice, PortName);
+ if (hPort && hPort->State == PortState_Waiting)
+ {
+ NvOsAtomicCompareExchange32((NvS32 *)&hPort->State, PortState_Waiting, PortState_Connected);
+ if (hPort->State == PortState_Connected)
+ {
+ hPort->RemotePort = RemotePort;
+ NvOsSemaphoreSignal(hPort->hOnConnectSem);
+ pMessage[1] = (NvU32)hPort;
+ }
+ else
+ {
+ pMessage[1] = 0;
+ }
+ }
+ else
+ {
+ pMessage[1] = 0;
+ }
+ pMessage[0] = TransportCmd_Response;
+}
+
+
+
+/**
+ * Disconnect message
+ * [ Transport Command ]
+ * [ Local Handle ]
+ *
+ * Response:
+ * [ Local Handle ] <- 0
+ */
+static void
+HandleDisconnectMessage(NvRmDeviceHandle hDevice, volatile NvU32 *pMessage)
+{
+ NvRmTransportHandle hPort;
+ hPort = (NvRmTransportHandle)pMessage[1];
+
+ // !!! For sanity we should walk the list of open ports to make sure this is a valid port!
+ if (hPort && hPort->State == PortState_Connected)
+ {
+ hPort->State = PortState_Disconnected;
+ hPort->RemotePort = 0;
+ }
+ pMessage[1] = 0;
+ pMessage[0] = TransportCmd_None;
+}
+
+
+/**
+ * Disconnect message
+ * [ Transport Command ]
+ * [ Local Handle ]
+ * [ Message Length ]
+ * [ Message ]
+ *
+ * Response:
+ * [ Message Length ] <- NvSuccess
+ * [ Transport Command ] <- When we can accept a new message
+ */
+
+static void
+HandlePortMessage(NvRmDeviceHandle hDevice, volatile NvU32 *pMessage)
+{
+ NvRmTransportHandle hPort;
+ NvU32 MessageLength;
+ NvBool bSuccess;
+
+ hPort = (NvRmTransportHandle)pMessage[1];
+ MessageLength = pMessage[2];
+
+#if LOOPBACK_PROFILE
+ if (hPort && hPort->bLoopTest)
+ {
+# if NV_IS_AVP
+ pMessage[LOOP_AVP_ISR_INDEX + 3] = *s_TransportInfo.pTimer;
+# else
+ pMessage[LOOP_CPU_ISR_INDEX + 3] = *s_TransportInfo.pTimer;
+# endif
+ }
+#endif
+
+
+ // !!! For sanity we should walk the list of open ports to make sure this is a valid port!
+ // Queue the message even if in the open state as presumably this should only have happened if
+ // due to a race condition with the transport connected messages.
+ if (hPort && (hPort->State == PortState_Connected || hPort->State == PortState_Open))
+ {
+ bSuccess = InsertMessage(hPort, (NvU8*)&pMessage[3], MessageLength);
+ if (bSuccess)
+ {
+ if (hPort->hOnPushMsgSem)
+ NvOsSemaphoreSignal(hPort->hOnPushMsgSem);
+ pMessage[0] = TransportCmd_None;
+ }
+ else
+ {
+ ++s_TransportInfo.ReceiveBackPressureOn;
+ }
+ }
+}
+
+static void
+HandleAVPResetMessage(NvRmDeviceHandle hDevice)
+{
+ NvRmTransportHandle hPort;
+
+ hPort = FindPort(hDevice,(char*)"RPC_CPU_PORT");
+ if (hPort && (hPort->State == PortState_Connected || hPort->State == PortState_Open))
+ {
+ NvU32 message;
+ message = NvRmMsg_AVP_Reset;
+ InsertMessage(hPort, (NvU8*)&message, sizeof(NvU32));
+ if (hPort->hOnPushMsgSem)
+ NvOsSemaphoreSignal(hPort->hOnPushMsgSem);
+ else
+ NV_ASSERT(0);
+ }
+ else
+ NV_ASSERT(0);
+
+}
+
+
+/**
+ * Handle the Inbox full interrupt.
+ */
+static void InboxFullIsr(void *args)
+{
+ NvRmDeviceHandle hDevice = (NvRmDeviceHandle)args;
+ NvU32 MessageData;
+ NvU32 MessageCommand;
+ volatile NvU32 *pMessage;
+
+ MessageData = NvRmPrivXpcGetMessage(s_TransportInfo.hXpc);
+ if(MessageData == AVP_WDT_RESET)
+ {
+ HandleAVPResetMessage(hDevice);
+ return;
+ }
+ // if we're on the AVP, the first message we get will configure the message info
+ if (s_TransportInfo.MessageMemPhysAddr == 0)
+ {
+ MessageData = MessageData;
+ s_TransportInfo.MessageMemPhysAddr = MessageData;
+ s_TransportInfo.pReceiveMem = (void*)MessageData;
+ s_TransportInfo.pTransmitMem = (void *) (MessageData + MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE);
+ // ack the message and return.
+ *(NvU32*)s_TransportInfo.pReceiveMem = TransportCmd_None;
+ return;
+ }
+
+ // otherwise decode and dispatch the message.
+
+
+ if (s_TransportInfo.pReceiveMem == NULL)
+ {
+ /* QT/EMUTRANS takes this path. */
+ NvRmMemRead(s_TransportInfo.hMessageMem, MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE, s_TmpIsrMsgBuffer, MAX_MESSAGE_LENGTH);
+ pMessage = s_TmpIsrMsgBuffer;
+ NvRmMemWrite(s_TransportInfo.hMessageMem, MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE, s_TmpIsrMsgBuffer, 2*sizeof(NvU32));
+ }
+ else
+ {
+ pMessage = (NvU32*)s_TransportInfo.pReceiveMem;
+ }
+
+ MessageCommand = pMessage[0];
+
+ switch (MessageCommand)
+ {
+ case TransportCmd_Connect:
+ HandleConnectMessage(hDevice, pMessage);
+ break;
+
+ case TransportCmd_Disconnect:
+ HandleDisconnectMessage(hDevice, pMessage);
+ break;
+
+ case TransportCmd_Message:
+ HandlePortMessage(hDevice, pMessage);
+ break;
+
+ default:
+ NV_ASSERT(0);
+ }
+}
+
+static irqreturn_t transport_ist(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.
+ */
+static NvError
+RegisterTransportInterrupt(NvRmDeviceHandle hDevice)
+{
+ NvU32 IrqList;
+ int ret;
+
+ if (s_TransportInterruptHandle >= 0)
+ {
+ return NvSuccess;
+ }
+
+ 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);
+ if (ret) {
+ printk("%s failed %d\n", __func__, ret);
+ return NvError_BadParameter;
+ }
+ s_TransportInterruptHandle = IrqList;
+ enable_irq(IrqList);
+ return NvSuccess;
+}
+
+// allocate buffers to be used for sending/receiving messages.
+static void
+NvRmPrivTransportAllocBuffers(NvRmDeviceHandle hRmDevice)
+{
+#if !NV_IS_AVP
+ // These buffers are always allocated on the CPU side. We'll pass the address over the AVP
+ //
+
+ NvError Error = NvSuccess;
+ NvRmMemHandle hNewMemHandle = NULL;
+
+ // Create memory handle
+ Error = NvRmMemHandleCreate(hRmDevice, &hNewMemHandle, (MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE)*2);
+ if (Error)
+ goto fail;
+
+ // Allocates the memory from the Heap
+ Error = NvRmMemAlloc(hNewMemHandle, NULL, 0,
+ XPC_MESSAGE_ALIGNMENT_SIZE, NvOsMemAttribute_Uncached);
+ if (Error)
+ goto fail;
+
+ s_TransportInfo.MessageMemPhysAddr = NvRmMemPin(hNewMemHandle);
+
+ // If it is success to create the memory handle.
+ // We have to be able to get a mapping to this, because it is used at interrupt time!
+ s_TransportInfo.hMessageMem = hNewMemHandle;
+ Error = NvRmMemMap(hNewMemHandle, 0,
+ (MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE)*2,
+ NVOS_MEM_READ_WRITE,
+ &s_TransportInfo.pTransmitMem);
+ if (Error)
+ {
+ s_TransportInfo.pTransmitMem = NULL;
+ s_TransportInfo.pReceiveMem = NULL;
+ }
+ else
+ {
+ s_TransportInfo.pReceiveMem = (void *) (((NvUPtr)s_TransportInfo.pTransmitMem) +
+ MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE);
+ }
+
+ s_TransportInfo.hMessageMem = hNewMemHandle;
+ NvRmMemWr32(hNewMemHandle, 0, 0xdeadf00d); // set this non-zero to throttle messages to the avp till avp is ready.
+ NvRmMemWr32(hNewMemHandle, MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE, 0);
+
+ NvRmPrivXpcSendMessage(s_TransportInfo.hXpc, s_TransportInfo.MessageMemPhysAddr);
+ return;
+
+
+fail:
+ NvRmMemHandleFree(hNewMemHandle);
+ s_TransportInfo.hMessageMem = NULL;
+ return;
+#else
+ return;
+#endif
+}
+
+
+static void
+NvRmPrivTransportFreeBuffers(NvRmDeviceHandle hRmDevice)
+{
+#if !NV_IS_AVP
+ NvRmMemHandleFree(s_TransportInfo.hMessageMem);
+#endif
+}
+
+static volatile NvBool s_Transport_Inited = NV_FALSE;
+
+/**
+ * Initialize the transport structures, this is callled once
+ * at NvRmOpen time.
+ */
+NvError NvRmTransportInit(NvRmDeviceHandle hRmDevice)
+{
+ NvError err;
+
+ NvOsMemset(&s_TransportInfo, 0, sizeof(s_TransportInfo));
+ s_TransportInfo.hDevice = hRmDevice;
+
+ err = NvOsMutexCreate(&s_TransportInfo.mutex);
+ if (err)
+ goto fail;
+
+#if !NVOS_IS_WINDOWS || NVOS_IS_WINDOWS_CE
+ err = NvRmPrivXpcCreate(hRmDevice, &s_TransportInfo.hXpc);
+ if (err)
+ goto fail;
+
+ NvRmPrivTransportAllocBuffers(hRmDevice);
+#endif
+
+ if (1) // Used in EMUTRANS mode where the buffers cannot be mapped.
+ {
+ s_TmpIsrMsgBuffer = NvOsAlloc(MAX_MESSAGE_LENGTH);
+ if (!s_TmpIsrMsgBuffer)
+ goto fail;
+ }
+
+#if LOOPBACK_PROFILE
+ {
+ NvU32 TimerAddr;
+ NvU32 TimerSize;
+
+ NvRmModuleGetBaseAddress(hRmDevice, NvRmModuleID_TimerUs, &TimerAddr, &TimerSize);
+ // map the us counter
+ err = NvRmPhysicalMemMap(TimerAddr, TimerSize, NVOS_MEM_READ_WRITE,
+ NvOsMemAttribute_Uncached, (void*)&s_TransportInfo.pTimer);
+ if (err)
+ goto fail;
+ }
+
+#endif
+
+#if !NVOS_IS_WINDOWS || NVOS_IS_WINDOWS_CE
+ err = RegisterTransportInterrupt(hRmDevice);
+ if (err)
+ goto fail;
+#endif
+ s_Transport_Inited = NV_TRUE;
+ return NvSuccess;
+
+
+fail:
+#if !NVOS_IS_WINDOWS || NVOS_IS_WINDOWS_CE
+ NvRmPrivXpcDestroy(s_TransportInfo.hXpc);
+ NvRmPrivTransportFreeBuffers(hRmDevice);
+#endif
+ NvOsFree(s_TmpIsrMsgBuffer);
+ NvOsMutexDestroy(s_TransportInfo.mutex);
+ return err;
+}
+
+/**
+ * DeInitialize the transport structures.
+ */
+void NvRmTransportDeInit(NvRmDeviceHandle hRmDevice)
+{
+ // Unregister the interrupts.
+#if !NVOS_IS_WINDOWS || NVOS_IS_WINDOWS_CE
+ NvRmPrivXpcDestroy(s_TransportInfo.hXpc);
+ NvRmPrivTransportFreeBuffers(hRmDevice);
+ free_irq(s_TransportInterruptHandle, hRmDevice);
+ set_irq_flags(s_TransportInterruptHandle, IRQF_VALID);
+ s_TransportInterruptHandle = -1;
+#endif
+ NvOsFree(s_TmpIsrMsgBuffer);
+ NvOsMutexDestroy(s_TransportInfo.mutex);
+}
+
+
+static void
+InsertPort(NvRmDeviceHandle hDevice, NvRmTransportHandle hPort)
+{
+ hPort->pNext = s_TransportInfo.pPortHead;
+ s_TransportInfo.pPortHead = hPort;
+}
+
+
+static NvRmTransportHandle
+FindPort(NvRmDeviceHandle hDevice, char *pPortName)
+{
+ NvRmTransportHandle hPort = NULL;
+ NvRmTransportHandle hIter = NULL;
+
+ hIter = s_TransportInfo.pPortHead;
+ while (hIter)
+ {
+ if ( NvOsStrcmp(pPortName, hIter->PortName) == 0)
+ {
+ hPort = hIter;
+ break;
+ }
+ hIter = hIter->pNext;
+ }
+
+ return hPort;
+}
+
+
+// Remove the given hPort from the list of ports
+static void
+DeletePort(NvRmDeviceHandle hRmDevice, const NvRmTransportHandle hPort)
+{
+ // Pointer to the pointer alleviates all special cases in linked list walking.
+ // I wish I was clever enough to have figured this out myself.
+
+ NvRmTransportHandle *hIter;
+
+ hIter = &s_TransportInfo.pPortHead;
+ while (*hIter)
+ {
+ if ( *hIter == hPort )
+ {
+ *hIter = (*hIter)->pNext;
+ break;
+ }
+ hIter = &(*hIter)->pNext;
+ }
+}
+
+
+
+
+/**
+ * Open the port handle with a given port name. With the same name, only two
+ * port can be open.
+ * Thread Safety: It is done inside the function.
+ */
+
+NvError
+NvRmTransportOpen(
+ NvRmDeviceHandle hRmDevice,
+ char *pPortName,
+ NvOsSemaphoreHandle RecvMessageSemaphore,
+ NvRmTransportHandle *phTransport)
+{
+ NvU32 PortNameLen;
+ NvRmTransportHandle hPartner = NULL;
+ NvRmTransportHandle hPort = NULL;
+ NvError err = NvError_InsufficientMemory;
+ char TmpName[MAX_PORT_NAME_LENGTH+1];
+
+ while (!s_Transport_Inited) {
+ // This can happen, if this API is called before avp init.
+ NvOsSleepMS(500);
+ }
+ // Look and see if this port exists anywhere.
+ if (pPortName == NULL)
+ {
+ NvOsMutexLock(s_TransportInfo.mutex);
+
+ pPortName = NvRmPrivTransportUniqueName();
+ PortNameLen = NvOsStrlen(pPortName);
+ NvOsStrncpy(TmpName, pPortName, sizeof(TmpName) );
+ pPortName = TmpName;
+
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ }
+ else
+ {
+ PortNameLen = NvOsStrlen(pPortName);
+ NV_ASSERT(PortNameLen <= MAX_PORT_NAME_LENGTH);
+ }
+
+ NvOsMutexLock(s_TransportInfo.mutex);
+ hPartner = FindPort(hRmDevice, pPortName);
+
+ if (hPartner && hPartner->hConnectedPort != NULL)
+ {
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ return NvError_TransportPortAlreadyExist;
+ }
+
+ // check if this is one of the special RPC ports used by the rm
+ if ( NvOsStrcmp(pPortName, "RPC_AVP_PORT") == 0)
+ {
+ //If someone else wants to open this port
+ //just return the one already created.
+ if (hPartner)
+ {
+ hPort = hPartner;
+ goto success;
+ }
+ else
+ {
+ hPort = &s_RpcAvpPortStruct;
+ hPort->RecvMessageQueue.pReceiveMsg = (void *)&s_RpcAvpQueue[0];
+ }
+ }
+ else if (NvOsStrcmp(pPortName, "RPC_CPU_PORT") == 0)
+ {
+ hPort = &s_RpcCpuPortStruct;
+ hPort->RecvMessageQueue.pReceiveMsg = (void *)&s_RpcCpuQueue[0];
+ }
+ else
+ {
+ // Create a new TransportPort
+ hPort = NvOsAlloc( sizeof(*hPort) );
+ if (!hPort)
+ goto fail;
+
+ NvOsMemset(hPort, 0, sizeof(*hPort) );
+
+ // Allocate the receive queue
+ hPort->RecvMessageQueue.pReceiveMsg = NvOsAlloc( sizeof(RmReceiveMessage) * (MAX_MESSAGE_DEPTH+1));
+ if (!hPort->RecvMessageQueue.pReceiveMsg)
+ goto fail;
+ }
+
+ NvOsStrncpy(hPort->PortName, pPortName, PortNameLen);
+ hPort->State = PortState_Open;
+ hPort->hConnectedPort = hPartner;
+
+ if (RecvMessageSemaphore)
+ {
+ err = NvOsSemaphoreClone(RecvMessageSemaphore, &hPort->hOnPushMsgSem);
+ if (err)
+ goto fail;
+ }
+
+ hPort->RecvMessageQueue.QueueSize = MAX_MESSAGE_DEPTH+1;
+ hPort->hRmDevice = hRmDevice;
+
+ if (hPort->hConnectedPort != NULL)
+ {
+ hPort->hConnectedPort->hConnectedPort = hPort;
+ }
+ InsertPort(hRmDevice, hPort);
+
+
+ // !!! loopback info
+#if LOOPBACK_PROFILE
+ if (NvOsStrcmp(hPort->PortName, "LOOPTEST") == 0)
+ hPort->bLoopTest = 1;
+#endif
+
+success:
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ *phTransport = hPort;
+ return NvSuccess;
+
+fail:
+ if (hPort)
+ {
+ NvOsFree(hPort->RecvMessageQueue.pReceiveMsg);
+ NvOsSemaphoreDestroy(hPort->hOnPushMsgSem);
+ NvOsFree(hPort);
+ hPort = NULL;
+ }
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ return err;
+}
+
+
+/**
+ * Close the transport handle
+ * Thread Safety: It is done inside the function.
+ */
+void NvRmTransportClose(NvRmTransportHandle hPort)
+{
+ NvU32 RemoteMessage[4];
+
+ if (!hPort)
+ return;
+
+ // Look and see if this port exists anywhere.
+ NV_ASSERT(hPort);
+
+
+ NvOsMutexLock(s_TransportInfo.mutex);
+ DeletePort(hPort->hRmDevice, hPort); // unlink this port
+
+ // Check if there is already a port waiting to connect, and if there is
+ // switch the port state to _Destroy, and signal the waiters semaphore.
+ // The "State" member is not protected by the mutex because it can be
+ // updated by the ISR.
+ while (hPort->State == PortState_Waiting)
+ {
+ NvOsAtomicCompareExchange32((NvS32*)&hPort->State, PortState_Waiting, PortState_Destroy);
+ if (hPort->State == PortState_Destroy)
+ {
+ NvOsSemaphoreSignal(hPort->hOnConnectSem);
+
+ // in this case, we can't complete the destroy, the signalled thread will
+ // have to complete. We just return now
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ return;
+ }
+ }
+
+ if (hPort->hConnectedPort)
+ {
+ // unlink this port from the other side of the connection.
+ hPort->hConnectedPort->hConnectedPort = NULL;
+ }
+
+ if (hPort->RemotePort)
+ {
+ RemoteMessage[0] = TransportCmd_Disconnect;
+ RemoteMessage[1] = hPort->RemotePort;
+ NvRmPrivTransportSendMessage(hPort->hRmDevice, RemoteMessage,
+ 2*sizeof(NvU32), NULL, 0);
+ }
+
+ NvOsSemaphoreDestroy(hPort->hOnPushMsgSem);
+
+
+ if (hPort == &s_RpcAvpPortStruct ||
+ hPort == &s_RpcCpuPortStruct)
+ {
+ // don't free these..
+ NvOsMemset(hPort, 0, sizeof(*hPort));
+ }
+ else
+ {
+ NvOsFree(hPort->RecvMessageQueue.pReceiveMsg);
+ NvOsFree(hPort);
+ }
+
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+}
+
+
+/**
+ * Wait for the connection to the other end.
+ * Thread Safety: It is done inside the function.
+ */
+NvError
+NvRmTransportWaitForConnect(
+ NvRmTransportHandle hPort,
+ NvU32 TimeoutMS)
+{
+ NvOsSemaphoreHandle hSem = NULL;
+ NvError err = NvSuccess;
+
+ NvOsMutexLock(s_TransportInfo.mutex);
+ if (hPort->State != PortState_Open)
+ {
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ err = NvError_TransportPortAlreadyExist;
+ goto exit_gracefully;
+ }
+
+ err = NvOsSemaphoreCreate(&hSem, 0);
+ if (err)
+ {
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ goto exit_gracefully;
+ }
+
+ hPort->hOnConnectSem = hSem;
+ hPort->State = PortState_Waiting;
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ err = NvOsSemaphoreWaitTimeout(hSem, TimeoutMS);
+ if (err)
+ {
+ // we have to be careful here, the ISR _might_ happen just after the semaphore
+ // times out.
+ NvOsAtomicCompareExchange32((NvS32 *)&hPort->State, PortState_Waiting, PortState_Open);
+ NV_ASSERT(hPort->State == PortState_Open || hPort->State == PortState_Connected);
+ if (hPort->State == PortState_Connected)
+ {
+ err = NvSuccess;
+ }
+ }
+
+ NvOsMutexLock(s_TransportInfo.mutex);
+ hPort->hOnConnectSem = NULL;
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ if (hPort->State == PortState_Destroy)
+ {
+ // finish the destroy process
+ NvRmTransportClose(hPort);
+ err = NvError_TransportConnectionFailed;
+ }
+
+exit_gracefully:
+ NvOsSemaphoreDestroy(hSem);
+ return err;
+}
+
+
+
+static NvError
+NvRmPrivTransportWaitResponse(NvRmDeviceHandle hDevice, NvU32 *response, NvU32 ResponseLength, NvU32 TimeoutMS)
+{
+ NvU32 CurrentTime;
+ NvU32 StartTime;
+ NvU32 Response;
+ NvBool GotResponse = NV_TRUE;
+ NvError err = NvError_Timeout;
+ volatile NvU32 *pXpcMessage = (volatile NvU32*)s_TransportInfo.pTransmitMem;
+
+ if (pXpcMessage == NULL)
+ {
+ if (!NV_IS_AVP)
+ {
+ Response = NvRmMemRd32(s_TransportInfo.hMessageMem, 0);
+ } else
+ {
+ NV_ASSERT(0);
+ return NvSuccess;
+ }
+ }
+ else
+ {
+ Response = pXpcMessage[0];
+ }
+
+ if (Response != TransportCmd_Response)
+ {
+ GotResponse = NV_FALSE;
+
+ // response is not back yet, so spin till its here.
+ StartTime = NvOsGetTimeMS();
+ CurrentTime = StartTime;
+ while ( (CurrentTime - StartTime) < TimeoutMS )
+ {
+ if ( pXpcMessage && (pXpcMessage[0] == TransportCmd_Response) )
+ {
+ GotResponse = NV_TRUE;
+ break;
+ }
+ else if ( !pXpcMessage )
+ {
+ NV_ASSERT(!"Invalid pXpcMessage pointer is accessed");
+ }
+ CurrentTime = NvOsGetTimeMS();
+ }
+ }
+
+ if ( pXpcMessage && GotResponse )
+ {
+ err = NvSuccess;
+ NvOsMemcpy(response, (void *)pXpcMessage, ResponseLength);
+ }
+
+ return err;
+}
+
+
+static NvError NvRmPrivTransportSendMessage(NvRmDeviceHandle hDevice,
+ NvU32 *MessageHdr, NvU32 MessageHdrLength,
+ NvU32 *Message, NvU32 MessageLength)
+{
+ NvU32 ReadData;
+
+ if (s_TransportInfo.pTransmitMem == NULL)
+ {
+ /* QT/EMUTRANS takes this code path */
+ if (!NV_IS_AVP)
+ {
+ ReadData = NvRmMemRd32(s_TransportInfo.hMessageMem, 0);
+ } else
+ {
+ NV_ASSERT(0);
+ return NvSuccess;
+ }
+ }
+ else
+ {
+ ReadData = ((volatile NvU32*)s_TransportInfo.pTransmitMem)[0];
+ }
+
+ // Check for clear to send
+ if ( ReadData != 0)
+ return NvError_TransportMessageBoxFull; // someone else is sending a message
+
+ if (s_TransportInfo.pTransmitMem == NULL)
+ {
+ /* QT/EMUTRANS takes this code path */
+ NvRmMemWrite(s_TransportInfo.hMessageMem, 0, MessageHdr, MessageHdrLength);
+ if (Message && MessageLength)
+ {
+ NvRmMemWrite(s_TransportInfo.hMessageMem, MessageHdrLength,
+ Message, MessageLength);
+ }
+ }
+ else
+ {
+ NvOsMemcpy(s_TransportInfo.pTransmitMem, MessageHdr, MessageHdrLength);
+ if (Message && MessageLength)
+ {
+ NvOsMemcpy(s_TransportInfo.pTransmitMem + MessageHdrLength,
+ Message, MessageLength);
+ }
+ NvOsFlushWriteCombineBuffer();
+ }
+ NvRmPrivXpcSendMessage(s_TransportInfo.hXpc, s_TransportInfo.MessageMemPhysAddr);
+ return NvSuccess;
+}
+
+NvError NvRmTransportSendMsgInLP0(NvRmTransportHandle hPort,
+ void *pMessageBuffer, NvU32 MessageSize)
+{
+ NvU32 ReadData;
+ NvU32 MessageHdr[3];
+
+ NV_ASSERT(pMessageBuffer);
+
+ MessageHdr[0] = TransportCmd_Message;
+ MessageHdr[1] = hPort->RemotePort;
+ MessageHdr[2] = MessageSize;
+
+ ReadData = ((volatile NvU32*)s_TransportInfo.pTransmitMem)[0];
+
+ // Check for clear to send
+ if ( ReadData != 0)
+ return NvError_TransportMessageBoxFull; // someone else is sending a message
+
+ NvOsMemcpy(s_TransportInfo.pTransmitMem, MessageHdr, sizeof(MessageHdr));
+ if (MessageSize) {
+ NvOsMemcpy(s_TransportInfo.pTransmitMem + sizeof(MessageHdr),
+ pMessageBuffer, MessageSize);
+ }
+ NvOsFlushWriteCombineBuffer();
+
+ NvRmPrivXpcSendMessage(s_TransportInfo.hXpc, s_TransportInfo.MessageMemPhysAddr);
+ return NvSuccess;
+}
+
+static void
+NvRmPrivTransportClearSend(NvRmDeviceHandle hDevice)
+{
+ if (s_TransportInfo.pTransmitMem == NULL)
+ {
+ /* QT/EMUTRANS take this path */
+ if (!NV_IS_AVP)
+ {
+ NvRmMemWr32(s_TransportInfo.hMessageMem, 0, TransportCmd_None);
+ } else
+ {
+ NV_ASSERT(0);
+ }
+ }
+ else
+ {
+ ((NvU32*)s_TransportInfo.pTransmitMem)[0] = TransportCmd_None;
+ }
+}
+
+/**
+ * Make the connection to the other end.
+ * Thread Safety: It is done inside the function.
+ */
+NvError NvRmTransportConnect(NvRmTransportHandle hPort, NvU32 TimeoutMS)
+{
+ NvRmTransportHandle hPartnerPort;
+ NvU32 StartTime;
+ NvU32 CurrentTime;
+ NvU32 ConnectMessage[ MAX_PORT_NAME_LENGTH/4 + 3];
+ NvError err;
+
+
+ // Look and see if there is a local port with the same name that is currently waiting, if there is
+ // mark both ports as connected.
+
+ NV_ASSERT(hPort);
+ NV_ASSERT(hPort->hRmDevice);
+ NV_ASSERT(hPort->State == PortState_Open);
+
+
+ StartTime = NvOsGetTimeMS();
+ for (;;)
+ {
+ // Someone is waiting for a connection here locally.
+ NvOsMutexLock(s_TransportInfo.mutex);
+
+ hPartnerPort = hPort->hConnectedPort;
+ if (hPartnerPort)
+ {
+ // Found a local connection
+ if (hPartnerPort->State == PortState_Waiting)
+ {
+
+ hPartnerPort->State = PortState_Connected;
+ hPartnerPort->hConnectedPort = hPort;
+
+ hPort->State = PortState_Connected;
+ NvOsSemaphoreSignal(hPartnerPort->hOnConnectSem);
+ break;
+ }
+ }
+ else if (s_TransportInfo.hMessageMem || s_TransportInfo.pReceiveMem) // if no shared buffer, then we can't create a remote connection.
+ {
+ ConnectMessage[0] = TransportCmd_Connect;
+ ConnectMessage[1] = (NvU32)hPort;
+ NvOsMemcpy(&ConnectMessage[2], hPort->PortName, MAX_PORT_NAME_LENGTH);
+
+ err = NvRmPrivTransportSendMessage(hPort->hRmDevice,
+ ConnectMessage, sizeof(ConnectMessage), NULL, 0);
+ if (!err)
+ {
+ // should send back 2 words of data. Give remote side 1000ms to respond, which should be about 100x more
+ // than it needs.
+ NvU32 WaitTime = NV_MAX(1000, TimeoutMS);
+ if (TimeoutMS == NV_WAIT_INFINITE)
+ TimeoutMS = NV_WAIT_INFINITE;
+
+ // !!! Note, we can do this without holding the mutex...
+ err = NvRmPrivTransportWaitResponse(hPort->hRmDevice, ConnectMessage, 2*sizeof(NvU32), WaitTime);
+ NvRmPrivTransportClearSend(hPort->hRmDevice);
+ if (err)
+ {
+ // the other side is not responding to messages, doh!
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ return NvError_TransportConnectionFailed;
+ }
+
+ // check the response
+ hPort->RemotePort = ConnectMessage[1];
+ if (hPort->RemotePort != 0)
+ {
+ hPort->State = PortState_Connected;
+ break;
+ }
+ }
+ }
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ NV_ASSERT(hPort->State == PortState_Open); // it better still be open
+
+ // Didn't find a connection, wait a few ms and then try again
+ CurrentTime = NvOsGetTimeMS();
+ if ( (CurrentTime - StartTime) > TimeoutMS )
+ return NvError_Timeout;
+
+ NvOsSleepMS(10);
+ }
+
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ return NvSuccess;
+}
+
+
+/**
+ * Set the queue depth and message size of the transport handle.
+ * Thread Safety: It is done inside the function.
+ */
+NvError NvRmTransportSetQueueDepth(
+ NvRmTransportHandle hPort,
+ NvU32 MaxQueueDepth,
+ NvU32 MaxMessageSize)
+{
+ RmReceiveMessage *pNewReceiveMsg = NULL;
+
+ NV_ASSERT(hPort != NULL);
+ NV_ASSERT(MaxQueueDepth != 0);
+ NV_ASSERT(MaxMessageSize != 0);
+
+ // You cannot change the queue after a connection has been opened
+ NV_ASSERT(hPort->State == PortState_Open);
+
+ // !!! FIXME
+ // Xpc does not allow changing the base message size, so we can't change the message size here (yet!)
+ // Once we have per port message buffers we can set this.
+ NV_ASSERT(MaxMessageSize <= MAX_MESSAGE_LENGTH);
+
+ // These are statically allocated ports, they cannot be modified!
+ // !!! FIXME: this is just a sanity check. Remove this and make it so that
+ // cpu/avp rpc doesn't call this function and just knows that the
+ // transport will give it a port with a large enough queue to support
+ // rpc, since rpc ports and queue are statically allocated this has to be true.
+ if (hPort == &s_RpcAvpPortStruct ||
+ hPort == &s_RpcCpuPortStruct)
+ {
+ if (MaxMessageSize <= MAX_MESSAGE_LENGTH &&
+ MaxQueueDepth <= MAX_MESSAGE_DEPTH)
+ {
+ return NvSuccess;
+ }
+
+ NV_ASSERT(!" Illegal meesage length or queue depth. ");
+ }
+
+ // Freeing default allocated message queue.
+ NvOsFree(hPort->RecvMessageQueue.pReceiveMsg);
+ hPort->RecvMessageQueue.pReceiveMsg = NULL;
+ // create a new message queue struct, one longer than requested on purpose.
+ pNewReceiveMsg = NvOsAlloc( sizeof(RmReceiveMessage) * (MaxQueueDepth+1));
+ if (pNewReceiveMsg == NULL)
+ return NvError_InsufficientMemory;
+
+ hPort->RecvMessageQueue.pReceiveMsg = pNewReceiveMsg;
+ hPort->RecvMessageQueue.QueueSize = (NvU16)(MaxQueueDepth+1);
+
+ return NvSuccess;
+}
+
+
+static NvError
+NvRmPrivTransportSendRemoteMsg(
+ NvRmTransportHandle hPort,
+ void* pMessageBuffer,
+ NvU32 MessageSize,
+ NvU32 TimeoutMS)
+{
+ NvError err;
+ NvU32 StartTime;
+ NvU32 CurrentTime;
+ NvU32 MessageHdr[3];
+ NvU32 JiffyTime = jiffies_to_msecs(1);
+
+ NV_ASSERT((MAX_MESSAGE_LENGTH) >= MessageSize);
+
+ StartTime = NvOsGetTimeMS();
+
+ MessageHdr[0] = TransportCmd_Message;
+ MessageHdr[1] = hPort->RemotePort;
+ MessageHdr[2] = MessageSize;
+
+ for (;;)
+ {
+ NvOsMutexLock(s_TransportInfo.mutex);
+ err = NvRmPrivTransportSendMessage(hPort->hRmDevice,
+ MessageHdr, sizeof(MessageHdr),
+ pMessageBuffer, MessageSize);
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ if (err == NvSuccess)
+ {
+ return NvSuccess;
+ }
+
+ // Sleep and then try again in a few ms to send again
+ CurrentTime = NvOsGetTimeMS();
+ if ( TimeoutMS != NV_WAIT_INFINITE && (CurrentTime - StartTime) > TimeoutMS )
+ return NvError_Timeout;
+ /* Sleeping for 1msec may not sleep exactly for 1msec. It depends
+ * on OS jiffy(tick) time. If jiffy time is much bigger,then this 1msec
+ * sleep would cause performance issues. At the same time, if complete
+ * polling is used, it can potentially block other threads from running.
+ * To reduce the impact of sleep in either ways, poll for one jiffy time
+ * and if operation is not complete then start sleeping.
+ */
+ if ( (CurrentTime - StartTime) > JiffyTime )
+ NvOsSleepMS(1); // try again later...
+ }
+}
+
+
+
+static NvError
+NvRmPrivTransportSendLocalMsg(
+ NvRmTransportHandle hPort,
+ void* pMessageBuffer,
+ NvU32 MessageSize,
+ NvU32 TimeoutMS)
+{
+ NvU32 CurrentTime;
+ NvU32 StartTime;
+ NvError err = NvSuccess;
+ NvU32 JiffyTime = jiffies_to_msecs(1);
+
+ NvRmTransportHandle hRemotePort;
+
+ NvOsMutexLock(s_TransportInfo.mutex);
+ hRemotePort = hPort->hConnectedPort;
+
+
+ StartTime = NvOsGetTimeMS();
+ CurrentTime = StartTime;
+
+ for (;;)
+ {
+ // try to insert into the message into the receivers queue.
+ NvBool bSuccess = InsertMessage(hRemotePort, (NvU8*)pMessageBuffer, MessageSize);
+ if (bSuccess)
+ {
+ if (hRemotePort->hOnPushMsgSem)
+ NvOsSemaphoreSignal(hRemotePort->hOnPushMsgSem);
+ break;
+ }
+
+ // The destination port is full.
+ if (TimeoutMS == 0)
+ {
+ err = NvError_TransportMessageBoxFull;
+ break;
+ }
+
+ // The user wants a timeout, so we just sleep a short time so the
+ // other thread can pop a message. It would be better to use another semaphore
+ // to indicate that the box is not full, but that just seems overkill since this
+ // should rarely happen anyhow.
+ // unlock the mutex, and wait a small amount of time.
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ /* Sleeping for 1msec may not sleep exactly for 1msec. It depends
+ * on OS jiffy(tick) time. If jiffy time is much bigger,then this 1msec
+ * sleep would cause performance issues. At the same time, if complete
+ * polling is used, it can potentially block other threads from running.
+ * To reduce the impact of sleep in either ways, poll for one jiffy time
+ * and if operation is not complete then start sleeping.
+ */
+ if ( (CurrentTime - StartTime) > JiffyTime )
+ NvOsSleepMS(1);
+ NvOsMutexLock(s_TransportInfo.mutex);
+ if (TimeoutMS != NV_WAIT_INFINITE)
+ {
+ // check for a timeout condition.
+ CurrentTime = NvOsGetTimeMS();
+ if ( (CurrentTime - StartTime) >= TimeoutMS)
+ {
+ err = NvError_Timeout;
+ break;
+ }
+ }
+ }
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ return err;
+}
+
+
+/**
+ * Send the message to the other end port.
+ * Thread Safety: It is done inside the function.
+ */
+NvError
+NvRmTransportSendMsg(
+ NvRmTransportHandle hPort,
+ void* pMessageBuffer,
+ NvU32 MessageSize,
+ NvU32 TimeoutMS)
+{
+ NvError err;
+
+ NV_ASSERT(hPort);
+ NV_ASSERT(hPort->State == PortState_Connected);
+ NV_ASSERT(pMessageBuffer);
+
+#if LOOPBACK_PROFILE
+ if (hPort->bLoopTest)
+ {
+# if NV_IS_AVP
+ ((NvU32*)pMessageBuffer)[LOOP_AVP_SEND_INDEX] = *s_TransportInfo.pTimer;
+# else
+ ((NvU32*)pMessageBuffer)[LOOP_CPU_SEND_INDEX] = *s_TransportInfo.pTimer;
+# endif
+ }
+#endif
+
+ if (hPort->hConnectedPort)
+ {
+ err = NvRmPrivTransportSendLocalMsg(hPort, pMessageBuffer, MessageSize, TimeoutMS);
+ }
+ else if (hPort->State == PortState_Connected)
+ {
+ err = NvRmPrivTransportSendRemoteMsg(hPort, pMessageBuffer, MessageSize, TimeoutMS);
+ }
+ else
+ {
+ NV_ASSERT(0); // someone did something naughty
+ err = NvError_TransportNotConnected;
+ }
+
+ return err;
+}
+
+
+
+/**
+ * Receive the message from the other end port.
+ * Thread Safety: It is done inside the function.
+ */
+NvError
+NvRmTransportRecvMsg(
+ NvRmTransportHandle hPort,
+ void* pMessageBuffer,
+ NvU32 MaxSize,
+ NvU32 *pMessageSize)
+{
+ NvU8 TmpMessage[MAX_MESSAGE_LENGTH];
+
+ NV_ASSERT(hPort);
+ NV_ASSERT( (hPort->State == PortState_Connected) || (hPort->State == PortState_Disconnected) );
+ NV_ASSERT(pMessageBuffer);
+ NV_ASSERT(pMessageSize);
+
+
+ *pMessageSize = 0;
+ NvOsMutexLock(s_TransportInfo.mutex);
+ if (hPort->RecvMessageQueue.ReadIndex == hPort->RecvMessageQueue.WriteIndex)
+ {
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ return NvError_TransportMessageBoxEmpty;
+ }
+
+ ExtractMessage(hPort, (NvU8*)pMessageBuffer, pMessageSize, MaxSize);
+ if (*pMessageSize > MaxSize)
+ {
+ // not enough room to copy the message
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+ NV_ASSERT(!" RM Transport: Illegal message size. ");
+ return NvError_InvalidSize;
+ }
+
+
+ // if there was backpressure asserted, try to handle the currently posted message, and re-enable messages
+ if (s_TransportInfo.ReceiveBackPressureOn != s_TransportInfo.ReceiveBackPressureOff)
+ {
+ NV_ASSERT( ((NvU8)s_TransportInfo.ReceiveBackPressureOn) == ((NvU8)(s_TransportInfo.ReceiveBackPressureOff+1)) );
+ ++s_TransportInfo.ReceiveBackPressureOff;
+
+ if (s_TransportInfo.pReceiveMem == NULL)
+ {
+ /* QT/EMUTRANS takes this path. */
+ NvRmMemRead(s_TransportInfo.hMessageMem,
+ MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE,
+ TmpMessage,
+ MAX_MESSAGE_LENGTH);
+ HandlePortMessage(hPort->hRmDevice, (volatile void *)TmpMessage);
+ NvRmMemWrite(s_TransportInfo.hMessageMem,
+ MAX_MESSAGE_LENGTH + MAX_COMMAND_SIZE,
+ TmpMessage,
+ 2*sizeof(NvU32) );
+ }
+ else
+ {
+ HandlePortMessage(hPort->hRmDevice, (NvU32*)s_TransportInfo.pReceiveMem);
+ }
+ }
+
+#if LOOPBACK_PROFILE
+ if (hPort->bLoopTest)
+ {
+# if NV_IS_AVP
+ ((NvU32*)pMessageBuffer)[LOOP_AVP_RECV_INDEX] = *s_TransportInfo.pTimer;
+# else
+ ((NvU32*)pMessageBuffer)[LOOP_CPU_RECV_INDEX] = *s_TransportInfo.pTimer;
+# endif
+ }
+#endif
+
+ NvOsMutexUnlock(s_TransportInfo.mutex);
+
+ return NvSuccess;
+}
+
+void
+NvRmTransportGetPortName(
+ NvRmTransportHandle hPort,
+ NvU8 *PortName,
+ NvU32 PortNameSize )
+{
+ NvU32 len;
+
+ NV_ASSERT(hPort);
+ NV_ASSERT(PortName);
+
+ len = NvOsStrlen(hPort->PortName);
+ if (len >= PortNameSize)
+ {
+ NV_ASSERT(!" RM Transport: Port Name too long. ");
+ }
+
+ NvOsStrncpy((char *)PortName, hPort->PortName, PortNameSize);
+}
diff --git a/arch/arm/mach-tegra/nv/nvrm/dispatch/Makefile b/arch/arm/mach-tegra/nv/nvrm/dispatch/Makefile
index 36cab878cc87..301c419413af 100644
--- a/arch/arm/mach-tegra/nv/nvrm/dispatch/Makefile
+++ b/arch/arm/mach-tegra/nv/nvrm/dispatch/Makefile
@@ -19,7 +19,7 @@ obj-y += NvRm_Dispatch.o
#obj-y += nvrm_init_dispatch.o
#obj-y += nvrm_interrupt_dispatch.o
#obj-y += nvrm_memmgr_dispatch.o
-#obj-y += nvrm_module_dispatch.o
+obj-y += nvrm_module_dispatch.o
#obj-y += nvrm_pinmux_dispatch.o
#obj-y += nvrm_power_dispatch.o
#obj-y += nvrm_spi_dispatch.o
@@ -27,5 +27,5 @@ obj-y += NvRm_Dispatch.o
#obj-y += nvrm_keylist_dispatch.o
#obj-y += nvrm_pcie_dispatch.o
#obj-y += nvrm_memctrl_dispatch.o
-#obj-y += nvrm_transport_dispatch.o
+obj-y += nvrm_transport_dispatch.o
#obj-y += nvrm_xpc_dispatch.o
diff --git a/arch/arm/mach-tegra/nv/nvrm/dispatch/NvRm_Dispatch.c b/arch/arm/mach-tegra/nv/nvrm/dispatch/NvRm_Dispatch.c
index 64505d65bb48..ba3a633f6712 100644
--- a/arch/arm/mach-tegra/nv/nvrm/dispatch/NvRm_Dispatch.c
+++ b/arch/arm/mach-tegra/nv/nvrm/dispatch/NvRm_Dispatch.c
@@ -84,12 +84,6 @@ NvError nvrm_xpc_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *O
return NvSuccess;
}
-NvError nvrm_transport_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- printk("NVRM: %s %d\n", __func__, function);
- return NvSuccess;
-}
-
NvError nvrm_memctrl_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
printk("NVRM: %s %d\n", __func__, function);
@@ -180,12 +174,6 @@ NvError nvrm_gpio_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *
return NvSuccess;
}
-NvError nvrm_module_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- printk("NVRM: %s %d\n", __func__, function);
- return NvSuccess;
-}
-
NvError nvrm_memmgr_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
printk("NVRM: %s %d\n", __func__, function);
diff --git a/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_module_dispatch.c b/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_module_dispatch.c
index e4038b220cbf..70a8eec1e2b8 100644
--- a/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_module_dispatch.c
+++ b/arch/arm/mach-tegra/nv/nvrm/dispatch/nvrm_module_dispatch.c
@@ -468,355 +468,6 @@ typedef struct NvRmModuleGetModuleInfo_params_t
NvRmModuleGetModuleInfo_out out;
} NvRmModuleGetModuleInfo_params;
-static NvError NvRegw08_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegw08_in *p_in;
-
- p_in = (NvRegw08_in *)InBuffer;
-
-
- NvRegw08( p_in->rm, p_in->aperture, p_in->offset, p_in->data );
-
- return err_;
-}
-
-static NvError NvRegr08_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegr08_in *p_in;
- NvRegr08_out *p_out;
-
- p_in = (NvRegr08_in *)InBuffer;
- p_out = (NvRegr08_out *)((NvU8 *)OutBuffer + OFFSET(NvRegr08_params, out) - OFFSET(NvRegr08_params, inout));
-
-
- p_out->ret_ = NvRegr08( p_in->hDeviceHandle, p_in->aperture, p_in->offset );
-
- return err_;
-}
-
-static NvError NvRegrb_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegrb_in *p_in;
- NvU32 *values = NULL;
-
- p_in = (NvRegrb_in *)InBuffer;
-
- if( p_in->num && p_in->values )
- {
- values = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !values )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- }
-
- NvRegrb( p_in->hRmDeviceHandle, p_in->aperture, p_in->num, p_in->offset, values );
-
- if(p_in->values && values)
- {
- err_ = NvOsCopyOut( p_in->values, values, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- }
- }
-clean:
- NvOsFree( values );
- return err_;
-}
-
-static NvError NvRegwb_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegwb_in *p_in;
- NvU32 *values = NULL;
-
- p_in = (NvRegwb_in *)InBuffer;
-
- if( p_in->num && p_in->values )
- {
- values = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !values )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- if( p_in->values )
- {
- err_ = NvOsCopyIn( values, p_in->values, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- goto clean;
- }
- }
- }
-
- NvRegwb( p_in->hRmDeviceHandle, p_in->aperture, p_in->num, p_in->offset, values );
-
-clean:
- NvOsFree( values );
- return err_;
-}
-
-static NvError NvRegwm_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegwm_in *p_in;
- NvU32 *offsets = NULL;
- NvU32 *values = NULL;
-
- p_in = (NvRegwm_in *)InBuffer;
-
- if( p_in->num && p_in->offsets )
- {
- offsets = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !offsets )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- if( p_in->offsets )
- {
- err_ = NvOsCopyIn( offsets, p_in->offsets, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- goto clean;
- }
- }
- }
- if( p_in->num && p_in->values )
- {
- values = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !values )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- if( p_in->values )
- {
- err_ = NvOsCopyIn( values, p_in->values, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- goto clean;
- }
- }
- }
-
- NvRegwm( p_in->hRmDeviceHandle, p_in->aperture, p_in->num, offsets, values );
-
-clean:
- NvOsFree( offsets );
- NvOsFree( values );
- return err_;
-}
-
-static NvError NvRegrm_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegrm_in *p_in;
- NvU32 *offsets = NULL;
- NvU32 *values = NULL;
-
- p_in = (NvRegrm_in *)InBuffer;
-
- if( p_in->num && p_in->offsets )
- {
- offsets = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !offsets )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- if( p_in->offsets )
- {
- err_ = NvOsCopyIn( offsets, p_in->offsets, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- goto clean;
- }
- }
- }
- if( p_in->num && p_in->values )
- {
- values = (NvU32 *)NvOsAlloc( p_in->num * sizeof( NvU32 ) );
- if( !values )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- }
-
- NvRegrm( p_in->hRmDeviceHandle, p_in->aperture, p_in->num, offsets, values );
-
- if(p_in->values && values)
- {
- err_ = NvOsCopyOut( p_in->values, values, p_in->num * sizeof( NvU32 ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- }
- }
-clean:
- NvOsFree( offsets );
- NvOsFree( values );
- return err_;
-}
-
-static NvError NvRegw_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegw_in *p_in;
-
- p_in = (NvRegw_in *)InBuffer;
-
-
- NvRegw( p_in->hDeviceHandle, p_in->aperture, p_in->offset, p_in->data );
-
- return err_;
-}
-
-static NvError NvRegr_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRegr_in *p_in;
- NvRegr_out *p_out;
-
- p_in = (NvRegr_in *)InBuffer;
- p_out = (NvRegr_out *)((NvU8 *)OutBuffer + OFFSET(NvRegr_params, out) - OFFSET(NvRegr_params, inout));
-
-
- p_out->ret_ = NvRegr( p_in->hDeviceHandle, p_in->aperture, p_in->offset );
-
- return err_;
-}
-
-static NvError NvRmGetRandomBytes_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmGetRandomBytes_in *p_in;
- NvRmGetRandomBytes_out *p_out;
- void* pBytes = NULL;
-
- p_in = (NvRmGetRandomBytes_in *)InBuffer;
- p_out = (NvRmGetRandomBytes_out *)((NvU8 *)OutBuffer + OFFSET(NvRmGetRandomBytes_params, out) - OFFSET(NvRmGetRandomBytes_params, inout));
-
- if( p_in->NumBytes && p_in->pBytes )
- {
- pBytes = (void* )NvOsAlloc( p_in->NumBytes );
- if( !pBytes )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- }
-
- p_out->ret_ = NvRmGetRandomBytes( p_in->hRmDeviceHandle, p_in->NumBytes, pBytes );
-
- if(p_in->pBytes && pBytes)
- {
- err_ = NvOsCopyOut( p_in->pBytes, pBytes, p_in->NumBytes );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- }
- }
-clean:
- NvOsFree( pBytes );
- return err_;
-}
-
-static NvError NvRmQueryChipUniqueId_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmQueryChipUniqueId_in *p_in;
- NvRmQueryChipUniqueId_out *p_out;
- void* pId = NULL;
-
- p_in = (NvRmQueryChipUniqueId_in *)InBuffer;
- p_out = (NvRmQueryChipUniqueId_out *)((NvU8 *)OutBuffer + OFFSET(NvRmQueryChipUniqueId_params, out) - OFFSET(NvRmQueryChipUniqueId_params, inout));
-
- if( p_in->IdSize && p_in->pId )
- {
- pId = (void* )NvOsAlloc( p_in->IdSize );
- if( !pId )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- }
-
- p_out->ret_ = NvRmQueryChipUniqueId( p_in->hDevHandle, p_in->IdSize, pId );
-
- if(p_in->pId && pId)
- {
- err_ = NvOsCopyOut( p_in->pId, pId, p_in->IdSize );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- }
- }
-clean:
- NvOsFree( pId );
- return err_;
-}
-
-static NvError NvRmModuleGetCapabilities_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmModuleGetCapabilities_in *p_in;
- NvRmModuleGetCapabilities_out *p_out;
- NvRmModuleCapability *pCaps = NULL;
-
- p_in = (NvRmModuleGetCapabilities_in *)InBuffer;
- p_out = (NvRmModuleGetCapabilities_out *)((NvU8 *)OutBuffer + OFFSET(NvRmModuleGetCapabilities_params, out) - OFFSET(NvRmModuleGetCapabilities_params, inout));
-
- if( p_in->NumCaps && p_in->pCaps )
- {
- pCaps = (NvRmModuleCapability *)NvOsAlloc( p_in->NumCaps * sizeof( NvRmModuleCapability ) );
- if( !pCaps )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- if( p_in->pCaps )
- {
- err_ = NvOsCopyIn( pCaps, p_in->pCaps, p_in->NumCaps * sizeof( NvRmModuleCapability ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- goto clean;
- }
- }
- }
-
- p_out->ret_ = NvRmModuleGetCapabilities( p_in->hDeviceHandle, p_in->Module, pCaps, p_in->NumCaps, &p_out->Capability );
-
-clean:
- NvOsFree( pCaps );
- return err_;
-}
-
-static NvError NvRmModuleResetWithHold_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmModuleResetWithHold_in *p_in;
-
- p_in = (NvRmModuleResetWithHold_in *)InBuffer;
-
-
- NvRmModuleResetWithHold( p_in->hRmDeviceHandle, p_in->Module, p_in->bHold );
-
- return err_;
-}
-
static NvError NvRmModuleReset_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
NvError err_ = NvSuccess;
@@ -830,135 +481,17 @@ static NvError NvRmModuleReset_dispatch_( void *InBuffer, NvU32 InSize, void *Ou
return err_;
}
-static NvError NvRmModuleGetNumInstances_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmModuleGetNumInstances_in *p_in;
- NvRmModuleGetNumInstances_out *p_out;
-
- p_in = (NvRmModuleGetNumInstances_in *)InBuffer;
- p_out = (NvRmModuleGetNumInstances_out *)((NvU8 *)OutBuffer + OFFSET(NvRmModuleGetNumInstances_params, out) - OFFSET(NvRmModuleGetNumInstances_params, inout));
-
-
- p_out->ret_ = NvRmModuleGetNumInstances( p_in->hRmDeviceHandle, p_in->Module );
-
- return err_;
-}
-
-static NvError NvRmModuleGetBaseAddress_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmModuleGetBaseAddress_in *p_in;
- NvRmModuleGetBaseAddress_out *p_out;
-
- p_in = (NvRmModuleGetBaseAddress_in *)InBuffer;
- p_out = (NvRmModuleGetBaseAddress_out *)((NvU8 *)OutBuffer + OFFSET(NvRmModuleGetBaseAddress_params, out) - OFFSET(NvRmModuleGetBaseAddress_params, inout));
-
-
- NvRmModuleGetBaseAddress( p_in->hRmDeviceHandle, p_in->Module, &p_out->pBaseAddress, &p_out->pSize );
-
- return err_;
-}
-
-static NvError NvRmModuleGetModuleInfo_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
-{
- NvError err_ = NvSuccess;
- NvRmModuleGetModuleInfo_in *p_in;
- NvRmModuleGetModuleInfo_inout *p_inout;
- NvRmModuleGetModuleInfo_out *p_out;
- NvRmModuleGetModuleInfo_inout inout;
- NvRmModuleInfo *pModuleInfo = NULL;
-
- p_in = (NvRmModuleGetModuleInfo_in *)InBuffer;
- p_inout = (NvRmModuleGetModuleInfo_inout *)((NvU8 *)InBuffer + OFFSET(NvRmModuleGetModuleInfo_params, inout));
- p_out = (NvRmModuleGetModuleInfo_out *)((NvU8 *)OutBuffer + OFFSET(NvRmModuleGetModuleInfo_params, out) - OFFSET(NvRmModuleGetModuleInfo_params, inout));
-
- (void)inout;
- inout.pNum = p_inout->pNum;
- if( p_inout->pNum && p_in->pModuleInfo )
- {
- pModuleInfo = (NvRmModuleInfo *)NvOsAlloc( p_inout->pNum * sizeof( NvRmModuleInfo ) );
- if( !pModuleInfo )
- {
- err_ = NvError_InsufficientMemory;
- goto clean;
- }
- }
-
- p_out->ret_ = NvRmModuleGetModuleInfo( p_in->hDevice, p_in->module, &inout.pNum, pModuleInfo );
-
-
- p_inout = (NvRmModuleGetModuleInfo_inout *)OutBuffer;
- p_inout->pNum = inout.pNum;
- if(p_in->pModuleInfo && pModuleInfo)
- {
- err_ = NvOsCopyOut( p_in->pModuleInfo, pModuleInfo, p_inout->pNum * sizeof( NvRmModuleInfo ) );
- if( err_ != NvSuccess )
- {
- err_ = NvError_BadParameter;
- }
- }
-clean:
- NvOsFree( pModuleInfo );
- return err_;
-}
-
NvError nvrm_module_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx );
NvError nvrm_module_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
NvError err_ = NvSuccess;
switch( function ) {
- case 15:
- err_ = NvRegw08_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 14:
- err_ = NvRegr08_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 13:
- err_ = NvRegrb_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 12:
- err_ = NvRegwb_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 11:
- err_ = NvRegwm_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 10:
- err_ = NvRegrm_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 9:
- err_ = NvRegw_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 8:
- err_ = NvRegr_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 7:
- err_ = NvRmGetRandomBytes_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 6:
- err_ = NvRmQueryChipUniqueId_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 5:
- err_ = NvRmModuleGetCapabilities_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 4:
- err_ = NvRmModuleResetWithHold_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
case 3:
err_ = NvRmModuleReset_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
break;
- case 2:
- err_ = NvRmModuleGetNumInstances_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 1:
- err_ = NvRmModuleGetBaseAddress_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
- case 0:
- err_ = NvRmModuleGetModuleInfo_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx );
- break;
default:
- err_ = NvError_BadParameter;
+ err_ = NvSuccess;
break;
}
diff --git a/arch/arm/mach-tegra/nv/nvrpc_user.c b/arch/arm/mach-tegra/nv/nvrpc_user.c
new file mode 100644
index 000000000000..874ebdc57d9a
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvrpc_user.c
@@ -0,0 +1,629 @@
+/*
+ * arch/arm/mach-tegra/nvrpc_user.c
+ *
+ * User-land access to NvRm transport APIs
+ *
+ * Copyright (c) 2008-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_DEBUG 0
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <mach/nvrm_linux.h>
+#include "linux/nvrpc_ioctl.h"
+#include "nvcommon.h"
+#include "nvassert.h"
+#include "nvos.h"
+#include "nvrm_transport.h"
+#include "nvrm_xpc.h"
+
+#define DEVICE_NAME "nvrpc"
+#define NVRPC_MAX_LOCAL_STACK 256
+#define nvrpc_stack_kzalloc(stackbuf, size, gfp) \
+ ((size) > sizeof((stackbuf)) ? kzalloc((size),(gfp)) : (stackbuf))
+#define nvrpc_stack_kfree(stackbuf, buf) \
+ do { \
+ if ((buf) && (buf)!=(void *)(stackbuf)) \
+ kfree(buf); \
+ } while (0);
+
+static int nvrpc_open(struct inode *inode, struct file *file);
+static int nvrpc_close(struct inode *inode, struct file *file);
+static long nvrpc_unlocked_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+//Ioctl functions
+static int nvrpc_ioctl_open(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_get_port_name(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_close(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_wait_for_connect(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_connect(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_set_queue_depth(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_send_msg(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_send_msg_lp0(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_recv_msg(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_init(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_acquire(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_release(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_get_msg(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_send_msg(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_destroy(struct file *filp,
+ unsigned int cmd, void __user *arg);
+static int nvrpc_ioctl_xpc_create(struct file *filp,
+ unsigned int cmd, void __user *arg);
+// local function
+static int nvrpc_make_error_code(NvError e);
+
+static const struct file_operations nvrpc_fops =
+{
+ .owner = THIS_MODULE,
+ .open = nvrpc_open,
+ .release = nvrpc_close,
+ .unlocked_ioctl = nvrpc_unlocked_ioctl,
+};
+
+static struct miscdevice nvrpc_dev =
+{
+ .name = DEVICE_NAME,
+ .fops = &nvrpc_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+};
+
+static DEFINE_MUTEX(nvrpc_device_lock);
+
+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;
+ }
+ mutex_unlock(&nvrpc_device_lock);
+
+ if (e == NvSuccess)
+ return 0;
+ else
+ return -ENODEV;
+}
+
+int nvrpc_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int nvrpc_make_error_code(NvError e)
+{
+ int error = 0;
+ if (error != NvSuccess) {
+ if (e == NvError_InvalidAddress)
+ error = -EFAULT;
+ else if (e == NvError_BadParameter)
+ error = -EINVAL;
+ else
+ error = -EIO;
+ }
+ return error;
+}
+
+static int nvrpc_ioctl_open(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ NvError e = NvSuccess;
+ int error;
+ struct nvrpc_open_params op;
+ char *p_name = NULL;
+ NvOsSemaphoreHandle recv_sem = NULL;
+ NvU32 port_name[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)];
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+
+ if (op.port_name_size) {
+ p_name = nvrpc_stack_kzalloc(port_name,
+ op.port_name_size, GFP_KERNEL);
+ if (!p_name) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ error = copy_from_user(p_name, (const void*)op.port_name,
+ op.port_name_size);
+ if (error)
+ goto fail;
+ if (p_name[op.port_name_size - 1] != 0) {
+ error = -EINVAL;
+ goto fail;
+ }
+ }
+ if (op.sem) {
+ NvOsSemaphoreHandle sem = (NvOsSemaphoreHandle) op.sem;
+ e = NvOsSemaphoreUnmarshal(sem, &recv_sem);
+ if (e != NvSuccess)
+ goto fail;
+ }
+ op.ret_val = NvRmTransportOpen(NULL, p_name, recv_sem,
+ (void *)&op.transport_handle);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ nvrpc_stack_kfree(port_name, p_name);
+ if (recv_sem)
+ NvOsSemaphoreDestroy(recv_sem);
+ if (e != NvSuccess)
+ error = nvrpc_make_error_code(e);
+ return error;
+}
+
+static int nvrpc_ioctl_get_port_name(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+
+ struct nvrpc_open_params op;
+ NvS8 *p_name = NULL;
+ NvU32 port_name[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)];
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ if (op.port_name_size && op.port_name) {
+ p_name = nvrpc_stack_kzalloc(port_name,
+ op.port_name_size, GFP_KERNEL);
+ if (!p_name) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ }
+ NvRmTransportGetPortName((NvRmTransportHandle)op.transport_handle,
+ p_name, op.port_name_size);
+
+ if (op.port_name_size && p_name) {
+ error = copy_to_user((void*)op.port_name,
+ p_name, op.port_name_size * sizeof(NvU8));
+ }
+
+fail:
+ nvrpc_stack_kfree(port_name, p_name);
+ return error;
+}
+
+static int nvrpc_ioctl_close(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ NvRmTransportClose((void*)op.handle);
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_wait_for_connect(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ NvError e = NvSuccess;
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmTransportWaitForConnect(
+ (void *)op.handle, op.param);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ if (e != NvSuccess)
+ error = nvrpc_make_error_code(e);
+ return error;
+}
+
+static int nvrpc_ioctl_connect(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ NvError e = NvSuccess;
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmTransportConnect(
+ (void *)op.handle, op.param);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ if (e != NvSuccess)
+ error = nvrpc_make_error_code(e);
+ return error;
+}
+
+static int nvrpc_ioctl_set_queue_depth(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ NvError e = NvSuccess;
+ int error;
+ struct nvrpc_set_queue_depth_params op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmTransportSetQueueDepth(
+ (NvRmTransportHandle)op.transport_handle,
+ op.max_queue_depth,
+ op.max_message_size);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ if (e != NvSuccess)
+ error = nvrpc_make_error_code(e);
+ return error;
+}
+
+static int nvrpc_ioctl_send_msg(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_msg_params op;
+ void* msg_buffer = NULL;
+ NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)];
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ if (op.msg_buffer && op.max_message_size) {
+ msg_buffer = nvrpc_stack_kzalloc(buffer,
+ op.max_message_size,
+ GFP_KERNEL);
+ if (!msg_buffer) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ error = copy_from_user(msg_buffer,
+ (void*)op.msg_buffer,
+ op.max_message_size);
+ if (error)
+ goto fail;
+ }
+
+ op.ret_val = NvRmTransportSendMsg(
+ (NvRmTransportHandle)op.transport_handle,
+ msg_buffer, op.max_message_size, op.params);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ nvrpc_stack_kfree(buffer, msg_buffer);
+ return error;
+}
+
+static int nvrpc_ioctl_send_msg_lp0(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_msg_params op;
+ void* msg_buffer = NULL;
+ NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)];
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ if (op.msg_buffer && op.max_message_size) {
+ msg_buffer = nvrpc_stack_kzalloc(buffer,
+ op.max_message_size, GFP_KERNEL);
+ if (!msg_buffer) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ error = copy_from_user(msg_buffer, (void*)op.msg_buffer,
+ op.max_message_size);
+ if (error)
+ goto fail;
+ }
+ op.ret_val = NvRmTransportSendMsgInLP0(
+ (NvRmTransportHandle)op.transport_handle,
+ msg_buffer, op.max_message_size);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ nvrpc_stack_kfree(buffer, msg_buffer);
+ return error;
+}
+
+static int nvrpc_ioctl_recv_msg(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_msg_params op;
+ void* msg_buffer = NULL;
+ NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)];
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ if (op.msg_buffer && op.max_message_size) {
+ msg_buffer = nvrpc_stack_kzalloc(buffer,
+ op.max_message_size, GFP_KERNEL);
+ if (!msg_buffer) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ } else {
+ error = -EINVAL;
+ goto fail;
+ }
+ op.ret_val = NvRmTransportRecvMsg(
+ (NvRmTransportHandle)op.transport_handle,
+ msg_buffer, op.max_message_size, &op.params);
+ error = copy_to_user(arg, &op, sizeof(op));
+ if (op.msg_buffer && msg_buffer) {
+ error = copy_to_user((void*)op.msg_buffer,
+ msg_buffer, op.max_message_size);
+ if (error)
+ goto fail;
+ }
+
+fail:
+ nvrpc_stack_kfree(buffer, msg_buffer);
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_init(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmXpcInitArbSemaSystem((void *)op.handle);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_acquire(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ NvRmXpcModuleAcquire(op.param);
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_release(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ NvRmXpcModuleRelease(op.param);
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_get_msg(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmPrivXpcGetMessage(
+ (NvRmPrivXpcMessageHandle)op.handle);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_send_msg(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmPrivXpcSendMessage(
+ (NvRmPrivXpcMessageHandle)op.handle, op.param);
+ error = copy_to_user(arg, &op, sizeof(op));
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_destroy(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ NvRmPrivXpcDestroy((NvRmPrivXpcMessageHandle)op.handle);
+
+fail:
+ return error;
+}
+
+static int nvrpc_ioctl_xpc_create(struct file *filp,
+ unsigned int cmd, void __user *arg)
+{
+ int error;
+ struct nvrpc_handle_param op;
+
+ error = copy_from_user(&op, arg, sizeof(op));
+ if (error)
+ goto fail;
+ op.ret_val = NvRmPrivXpcCreate((NvRmDeviceHandle)op.handle,
+ (void*)&op.param);
+ error = copy_to_user(&op, arg, sizeof(op));
+
+fail:
+ return error;
+}
+
+
+static long nvrpc_unlocked_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ void __user *uarg = (void __user *)arg;
+
+ if (_IOC_TYPE(cmd) != NVRPC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (err)
+ return -EFAULT;
+
+ switch (cmd) {
+ case NVRPC_IOCTL_OPEN:
+ err = nvrpc_ioctl_open(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_GET_PORTNAME:
+ err = nvrpc_ioctl_get_port_name(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_CLOSE:
+ err = nvrpc_ioctl_close(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_INIT:
+ case NVRPC_IOCTL_DEINIT:
+ break;
+
+ case NVRPC_IOCTL_WAIT_FOR_CONNECT:
+ err = nvrpc_ioctl_wait_for_connect(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_CONNECT:
+ err = nvrpc_ioctl_connect(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_SET_QUEUE_DEPTH:
+ err = nvrpc_ioctl_set_queue_depth(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_SEND_MSG:
+ err = nvrpc_ioctl_send_msg(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_SEND_MSG_LP0:
+ err = nvrpc_ioctl_send_msg_lp0(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_RECV_MSG:
+ err = nvrpc_ioctl_recv_msg(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_INIT:
+ err = nvrpc_ioctl_xpc_init(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_ACQUIRE:
+ err = nvrpc_ioctl_xpc_acquire(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_RELEASE:
+ err = nvrpc_ioctl_xpc_release(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_GET_MSG:
+ err = nvrpc_ioctl_xpc_get_msg(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_SEND_MSG:
+ err = nvrpc_ioctl_xpc_send_msg(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_DESTROY:
+ err = nvrpc_ioctl_xpc_destroy(file, cmd, uarg);
+ break;
+
+ case NVRPC_IOCTL_XPC_CREATE:
+ err = nvrpc_ioctl_xpc_create(file, cmd, uarg);
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+ return err;
+}
+
+static int __init nvrpc_init(void)
+{
+ int ret = 0;
+
+ ret = misc_register(&nvrpc_dev);
+ if (ret) {
+ pr_err("%s misc register FAILED\n", __func__);
+ }
+ return ret;
+}
+
+static void __exit nvrpc_deinit(void)
+{
+ misc_deregister(&nvrpc_dev);
+}
+
+module_init(nvrpc_init);
+module_exit(nvrpc_deinit);