diff options
author | tkasivajhula <tkasivajhula@nvidia.com> | 2010-05-15 23:52:18 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-17 11:29:37 -0700 |
commit | b8a0f3f1d92e521fb517219daa5083363a4a57e0 (patch) | |
tree | e4b07f324ecea5df60bf6b59fc8a81aa66565c60 | |
parent | e8e7b1c392c8cf7bec7a959ec0625f9bdf4e109d (diff) |
tegra power: Workaround for daemon crash.
Put the AVP suspend operation in the kernel. It appears
that someone in userspace is still active after nvrm_graphics
has suspended.
Change-Id: Ie3b67478d502c8af5fd25a141d362409f737ffc3
Reviewed-on: http://git-master/r/1404
Reviewed-by: Trivikram Kasivajhula <tkasivajhula@nvidia.com>
Tested-by: Trivikram Kasivajhula <tkasivajhula@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/common/nvrm_transport.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm_user.c | 85 |
2 files changed, 85 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_transport.c b/arch/arm/mach-tegra/nvrm/core/common/nvrm_transport.c index 4504b8a01819..6f376e757062 100644 --- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_transport.c +++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_transport.c @@ -1688,4 +1688,3 @@ NvRmTransportGetPortName( NvOsStrncpy((char *)PortName, hPort->PortName, PortNameSize); } - diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c index f649754da469..d8e5f94502fc 100644 --- a/arch/arm/mach-tegra/nvrm_user.c +++ b/arch/arm/mach-tegra/nvrm_user.c @@ -42,6 +42,7 @@ #include "nvos.h" #include "nvrm_memmgr.h" #include "nvrm_ioctls.h" +#include "nvrm_message.h" #include "mach/nvrm_linux.h" #include "linux/nvos_ioctl.h" #include "nvrm_power_private.h" @@ -63,6 +64,11 @@ static long nvrm_unlocked_ioctl(struct file *file, static int nvrm_mmap(struct file *file, struct vm_area_struct *vma); extern void reset_cpu(unsigned int cpu, unsigned int reset); +//Variables for AVP suspend operation +extern NvRmDeviceHandle s_hRmGlobal; +static NvRmMemHandle s_IramMemHandle; +static NvRmTransportHandle s_AvpSuspendPort; + static NvOsThreadHandle s_DfsThread = NULL; static NvRtHandle s_RtHandle = NULL; @@ -459,8 +465,87 @@ static int nvrm_remove(struct platform_device *pdev) return 0; } +NvError NvRmAvpSuspend(NvRmDeviceHandle hRmDeviceHandle) +{ + NvRmMessage_InitiateLP0 Msg; + NvError e = NvSuccess; + NvRmHeap Heaps[2]; + NvU32 iramSize, iramAddr, numInstances, instSize; + volatile NvU32 *syncVal = NULL; + volatile NvU32 *bar; + + if (!s_AvpSuspendPort) + { + e = NvRmTransportOpen(hRmDeviceHandle, "RPC_AVP_PORT", + NULL, &s_AvpSuspendPort); + if (e) + goto fail; + } + + Heaps[0] = NvRmHeap_ExternalCarveOut; + + NvRmModuleGetBaseAddress(hRmDeviceHandle, + NVRM_MODULE_ID(NvRmPrivModuleID_Iram, 0),&iramAddr, &instSize); + + numInstances = NvRmModuleGetNumInstances(hRmDeviceHandle, + NVRM_MODULE_ID(NvRmPrivModuleID_Iram, 0)); + + iramSize = instSize * numInstances; + if (s_IramMemHandle == NULL) + { + NV_CHECK_ERROR_CLEANUP( + NvRmMemHandleCreate(hRmDeviceHandle, &s_IramMemHandle, + iramSize + sizeof(NvU32)) + ); + + NV_CHECK_ERROR_CLEANUP( + NvRmMemAlloc(s_IramMemHandle, Heaps, 1, 16, + NvOsMemAttribute_Uncached) + ); + } + + Msg.msg = NvRmMsg_InitiateLP0; + Msg.sourceAddr = iramAddr; + Msg.bufferAddr = NvRmMemPin(s_IramMemHandle); + Msg.bufferSize = iramSize; + + NV_CHECK_ERROR_CLEANUP( + NvRmMemMap(s_IramMemHandle, iramSize, + sizeof(NvU32), NVOS_MEM_READ_WRITE, (void**)&syncVal) + ); + + *syncVal = 0; + + //Make sure write lands in memory before AVP reads it. + bar = (volatile NvU32*)syncVal; + (void)(*bar); + + //SendMsgInLP0 should never return an error in this scenario. + //If it does, something is seriously wrong with LP0. + //(No one else should be talking to the AVP at this moment) + NV_CHECK_ERROR_CLEANUP( + NvRmTransportSendMsgInLP0(s_AvpSuspendPort, &Msg, sizeof(Msg)) + ); + + //Wait for the AVP to acknowledge that LP0 call + while (!*syncVal); + + return NvSuccess; +fail: + if (s_IramMemHandle) + { + NvRmMemHandleFree(s_IramMemHandle); + s_IramMemHandle = NULL; + } + + return e; +} + static int nvrm_suspend(struct platform_device *pdev, pm_message_t state) { + if (NvRmAvpSuspend(s_hRmGlobal)) + return -1; + if(NvRmKernelPowerSuspend(s_hRmGlobal)) { printk(KERN_INFO "%s : FAILED\n", __func__); return -1; |