[ARM] tegra: nvrm_transport: handshake AVP reset with kernel
authorGary King <gking@nvidia.com>
Wed, 1 Sep 2010 20:19:38 +0000 (13:19 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:50:41 +0000 (16:50 -0700)
the AVP kernel modifies the AVP reset vector after it starts to its
own value; poll this register to verify that the AVP kernel has
started properly.

Change-Id: I5d9f36dd2763c0df28576f3cb86de20f6aae0ef2
Signed-off-by: Gary King <gking@nvidia.com>
arch/arm/mach-tegra/nv/nvrm/core/common/nvrm_moduleloader.c

index 22241b72a70e94c84bd7b28cfa53b19273c33376..695216c8fed3a3f11d474cc3b2ee1864d29e7105 100644 (file)
@@ -516,6 +516,7 @@ static void NvRmPrivResetAvp(NvRmDeviceHandle hRm, unsigned long reset_va)
     u32 *stub_va = &_tegra_avp_launcher_stub_data[AVP_LAUNCHER_START_VA];
     unsigned long stub_addr = virt_to_phys(_tegra_avp_launcher_stub);
     unsigned int tmp;
+    unsigned long timeout;
 
     *stub_va = reset_va;
     __cpuc_flush_dcache_area(stub_va, sizeof(*stub_va));
@@ -526,8 +527,18 @@ static void NvRmPrivResetAvp(NvRmDeviceHandle hRm, unsigned long reset_va)
     barrier();
     NvRmModuleReset(hRm, NvRmModuleID_Avp);
     writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + FLOW_CTRL_HALT_COP);
+
     barrier();
-    writel(tmp, _TEGRA_AVP_RESET_VECTOR_ADDR);
+    timeout = jiffies + HZ;
+    /* the AVP firmware will reprogram its reset vector as the kernel
+     * starts, so a dead kernel can be detected by polling this value */
+    while (time_before(jiffies, timeout)) {
+        if (readl(_TEGRA_AVP_RESET_VECTOR_ADDR) != stub_addr)
+            break;
+        cpu_relax();
+    }
+
+    WARN_ON(readl(_TEGRA_AVP_RESET_VECTOR_ADDR) == stub_addr);
 }
 
 void NvRmPrivXpcSendMsgAddress(void);