intel_soc_pmu: optimize retry logic and dump more information
authorDong Yang <dong.yang@intel.com>
Sun, 17 Jun 2012 04:12:17 +0000 (12:12 +0800)
committerbuildslave <buildslave@buildbot.tl.intel.com>
Fri, 29 Jun 2012 12:46:03 +0000 (05:46 -0700)
BZ: 42229

the pmu_pci_set_power_state() will try 3 times to wait the pmu2 get ready,
but every time issue a command to pmu2, since pmu2 is busy, this is the
wrong behavior, it should issue the interactive command only for 1 time
and wait the pmu2 to get ready for 3 times. or else it won't trigger panic
and will returned in case pmu2 busy forever.

Optimize retry logic and add longer delay in
_pmu2_wait_not_busy_yield(), use endless loop if PMU is alwasy
busy, dump all CPU call trace.

Change-Id: I4355706f95c87872e961f106ee1059eaee1590e1
Signed-off-by: Dong Yang <dong.yang@intel.com>
Signed-off-by: Illyas Mansoor <illyas.mansoor@intel.com>
Signed-off-by: Yanmin Zhang <yanmin.zhang@intel.com>
Signed-off-by: He, Bo <bo.he@intel.com>
arch/x86/platform/intel-mid/intel_soc_pmu.c
arch/x86/platform/intel-mid/intel_soc_pmu.h

index 101c74e..231c7f4 100644 (file)
@@ -353,9 +353,9 @@ int _pmu2_wait_not_busy(void)
 
 static int _pmu2_wait_not_busy_yield(void)
 {
-       int pmu_busy_retry = 20;
+       int pmu_busy_retry = 50000; /* 500msec minimum */
 
-       /* wait 10ms that the latest pmu command finished */
+       /* wait for the latest pmu command finished */
        do {
                usleep_range(10, 500);
 
@@ -1248,7 +1248,8 @@ int __ref pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
        int pmu_num;
        struct pmu_ss_states cur_pmssc;
        int status = 0;
-       int retry_count = 3;
+       int retry_times = 0;
+       ktime_t calltime, delta, rettime;
 
        /* Ignore callback from devices until we have initialized */
        if (unlikely((!pmu_initialized)))
@@ -1317,90 +1318,67 @@ int __ref pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
        cur_pmssc.pmu2_states[2] &= ~IGNORE_SSS2;
        cur_pmssc.pmu2_states[3] &= ~IGNORE_SSS3;
 
-       do {
-               /* Issue the pmu command to PMU 2
-                * flag is needed to distinguish between
-                * S0ix vs interactive command in pmu_sc_irq()
-                */
-               status = pmu_issue_interactive_command(&cur_pmssc, false);
-
-               if (unlikely(status != PMU_SUCCESS)) {
-                       dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
-                                "Failed to Issue a PM command to PMU2\n");
-                       goto unlock;
-               }
+       /* Issue the pmu command to PMU 2
+        * flag is needed to distinguish between
+        * S0ix vs interactive command in pmu_sc_irq()
+        */
+       status = pmu_issue_interactive_command(&cur_pmssc, false);
 
-               /*
-                * Wait for interactive command to complete.
-                * If we dont wait, there is a possibility that
-                * the driver may access the device before its
-                * powered on in SCU.
-                *
-                */
-               status = _pmu2_wait_not_busy_yield();
+       if (unlikely(status != PMU_SUCCESS)) {
+               dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
+                        "Failed to Issue a PM command to PMU2\n");
+               goto unlock;
+       }
 
-               if (likely(!status))
-                       break;
+       calltime = ktime_get();
+retry:
+       /*
+        * Wait for interactive command to complete.
+        * If we dont wait, there is a possibility that
+        * the driver may access the device before its
+        * powered on in SCU.
+        *
+        */
+       status = _pmu2_wait_not_busy_yield();
+       if (unlikely(status)) {
+               rettime = ktime_get();
+               delta = ktime_sub(rettime, calltime);
+               retry_times++;
 
                printk(KERN_CRIT "%s: D0ix transition failure:"
                                " %04x %04X %s %20s:\n", __func__,
                                pdev->vendor, pdev->device,
                                dev_name(&pdev->dev),
                                dev_driver_string(&pdev->dev));
+               printk(KERN_CRIT "interrupt pending = %d\n",
+                               pmu_interrupt_pending());
                printk(KERN_CRIT "pmu_busy_status = %d\n",
-               _pmu_read_status(PMU_BUSY_STATUS));
+                               _pmu_read_status(PMU_BUSY_STATUS));
                printk(KERN_CRIT "suspend_started = %d\n",
                                mid_pmu_cxt->suspend_started);
                printk(KERN_CRIT "shutdown_started = %d\n",
                                mid_pmu_cxt->shutdown_started);
-               printk(KERN_CRIT "Retrying... attempt(%d):\n",
-                               retry_count);
-       } while (--retry_count);
-
-       if (unlikely(status)) {
-               struct pmu_ss_states new_pmsss;
-               u32 post_transition_val;
-
-               /*
-                * Check if the power transition
-                * indeed happend, if yes continue, else BUG
-                */
-               new_value &=
-                       (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
-               pmu_read_sss(&new_pmsss);
-               post_transition_val =
-                       (new_pmsss.pmu2_states[sub_sys_index] &
-                       (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS)));
-
-               if (new_value != post_transition_val) {
-                       printk(KERN_CRIT "%s: D0ix transition failure:"
-                               " %04x %04X %s %20s:\n", __func__,
-                               pdev->vendor, pdev->device,
-                               dev_name(&pdev->dev),
-                               dev_driver_string(&pdev->dev));
-                       printk(KERN_CRIT "interrupt pending = %d\n",
-                               pmu_interrupt_pending());
-                       printk(KERN_CRIT "pmu_busy_status = %d\n",
-                       _pmu_read_status(PMU_BUSY_STATUS));
-                       printk(KERN_CRIT "suspend_started = %d\n",
-                                       mid_pmu_cxt->suspend_started);
-                       printk(KERN_CRIT "shutdown_started = %d\n",
-                                       mid_pmu_cxt->shutdown_started);
-                       printk(KERN_CRIT "interactive_cmd_sent = %d\n",
+               printk(KERN_CRIT "interactive_cmd_sent = %d\n",
                                (int)mid_pmu_cxt->interactive_cmd_sent);
-                       printk(KERN_CRIT "camera_off = %d"
-                       " display_off = %d\n", mid_pmu_cxt->camera_off,
-                                       mid_pmu_cxt->display_off);
-                       printk(KERN_CRIT "s0ix_possible = 0x%x\n",
-                                       mid_pmu_cxt->s0ix_possible);
-                       printk(KERN_CRIT "s0ix_entered = 0x%x\n",
-                                       mid_pmu_cxt->s0ix_entered);
-                       printk(KERN_CRIT "pmu_current_state = %d\n",
-                                       mid_pmu_cxt->pmu_current_state);
-                       pmu_dump_logs();
+               printk(KERN_CRIT "camera_off = %d"
+                               " display_off = %d\n", mid_pmu_cxt->camera_off,
+                               mid_pmu_cxt->display_off);
+               printk(KERN_CRIT "s0ix_possible = 0x%x\n",
+                               mid_pmu_cxt->s0ix_possible);
+               printk(KERN_CRIT "s0ix_entered = 0x%x\n",
+                               mid_pmu_cxt->s0ix_entered);
+               printk(KERN_CRIT "pmu_current_state = %d\n",
+                               mid_pmu_cxt->pmu_current_state);
+               printk(KERN_CRIT "PMU is BUSY! retry_times[%d] "
+                               "total_delay[%lli]ms. Retry ...\n",
+                               retry_times, (long long) ktime_to_ms(delta));
+               pmu_dump_logs();
 
+               trigger_all_cpu_backtrace();
+               if (retry_times < 60)
+                       goto retry;
+               else
                        BUG();
-               }
        }
 
        pmu_set_s0ix_possible(state);
index f6342b0..db0c530 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/jhash.h>
 #include <linux/suspend.h>
 #include <linux/wakelock.h>
+#include <linux/nmi.h>
 #include <asm/apic.h>
 #include <asm/intel_scu_ipc.h>
 #include <linux/intel_mid_pm.h>