On Mon, Mar 18, 2019 at 2:31 AM Somayaji, Vishwanath
<vishwanath.somay...@intel.com> wrote:
>
>
>
> >-----Original Message-----
> >From: Rajat Jain <raja...@google.com>
> >Sent: Thursday, March 14, 2019 3:51 AM
> >To: Bhardwaj, Rajneesh <rajneesh.bhard...@intel.com>; Somayaji, Vishwanath
> ><vishwanath.somay...@intel.com>; Darren Hart <dvh...@infradead.org>; Andy
> >Shevchenko <a...@infradead.org>; platform-driver-...@vger.kernel.org; linux-
> >ker...@vger.kernel.org
> >Cc: Rajat Jain <raja...@google.com>; furq...@google.com;
> >evgr...@google.com; rajatxj...@gmail.com
> >Subject: [PATCH 2/2] platform/x86: intel_pmc_core: Allow to dump debug
> >registers on S0ix failure
> >
> >Add a module parameter which when enabled, will check on resume, if the
> >last S0ix attempt was successful. If not, the driver would provide
> >helpful debug information (which gets latched during the failed suspend
> >attempt) to debug the S0ix failure.
> >
> >This information is very useful to debug S0ix failures. Specially since
> >the latched debug information will be lost (over-written) if the system
> >attempts to go into runtime (or imminent) S0ix again after that failed
> >suspend attempt.
> >
> >Signed-off-by: Rajat Jain <raja...@google.com>
> >---
> > drivers/platform/x86/intel_pmc_core.c | 86 +++++++++++++++++++++++++++
> > drivers/platform/x86/intel_pmc_core.h |  7 +++
> > 2 files changed, 93 insertions(+)
> >
> >diff --git a/drivers/platform/x86/intel_pmc_core.c
> >b/drivers/platform/x86/intel_pmc_core.c
> >index 55578d07610c..b1f4405a27ce 100644
> >--- a/drivers/platform/x86/intel_pmc_core.c
> >+++ b/drivers/platform/x86/intel_pmc_core.c
> >@@ -20,6 +20,7 @@
> > #include <linux/module.h>
> > #include <linux/pci.h>
> > #include <linux/platform_device.h>
> >+#include <linux/suspend.h>
> > #include <linux/uaccess.h>
> >
> > #include <asm/cpu_device_id.h>
> >@@ -890,9 +891,94 @@ static int pmc_core_remove(struct platform_device
> >*pdev)
> >       return 0;
> > }
> >
> >+#ifdef CONFIG_PM_SLEEP
> >+
> >+static bool warn_on_s0ix_failures;
> >+module_param(warn_on_s0ix_failures, bool, 0644);
> >+MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix
> >failures");
> >+
> >+static int pmc_core_suspend(struct device *dev)
> >+{
> >+      struct pmc_dev *pmcdev = dev_get_drvdata(dev);
> >+
> >+      /* Save PC10 and S0ix residency for checking later */
> >+      if (warn_on_s0ix_failures &&
> >+          !rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pmcdev->pc10_counter)
> >&&
> >+          !pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
> >+              pmcdev->check_counters = true;
> >+      else
> >+              pmcdev->check_counters = false;
> >+
> >+      return 0;
> >+}
> >+
> >+static inline bool pc10_failed(struct pmc_dev *pmcdev)
> >+{
> >+      u64 pc10_counter;
> >+
> >+      if (!rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pc10_counter) &&
> >+          pc10_counter == pmcdev->pc10_counter)
> >+              return true;
> >+      else
> >+              return false;
> >+}
> >+
> >+static inline bool s0ix_failed(struct pmc_dev *pmcdev)
> >+{
> >+      u64 s0ix_counter;
> >+
> >+      if (!pmc_core_dev_state_get(pmcdev, &s0ix_counter) &&
> >+          s0ix_counter == pmcdev->s0ix_counter)
> >+              return true;
> >+      else
> >+              return false;
> >+}
> >+
> >+static int pmc_core_resume(struct device *dev)
> >+{
> >+      struct pmc_dev *pmcdev = dev_get_drvdata(dev);
> >+
> >+      if (!pmcdev->check_counters)
> >+              return 0;
> >+
> >+      if (pc10_failed(pmcdev)) {
> >+              dev_info(dev, "PC10 entry had failed (PC10 cnt=0x%llx)\n",
> >+                       pmcdev->pc10_counter);
> >+      } else if (s0ix_failed(pmcdev)) {
> >+
> >+              const struct pmc_bit_map **maps = pmcdev->map-
> >>slps0_dbg_maps;
> >+              const struct pmc_bit_map *map;
> >+              int offset = pmcdev->map->slps0_dbg_offset;
> >+              u32 data;
> >+
> >+              dev_warn(dev, "S0ix entry had failed (S0ix cnt=%llu)\n",
> >+                       pmcdev->s0ix_counter);
> >+              while (*maps) {
> >+                      map = *maps;
> >+                      data = pmc_core_reg_read(pmcdev, offset);
> >+                      offset += 4;
> >+                      while (map->name) {
> >+                              dev_warn(dev, "SLP_S0_DBG: %-32s\tState:
> >%s\n",
> >+                                       map->name,
> >+                                       data & map->bit_mask ? "Yes" : "No");
> >+                              ++map;
> >+                      }
> >+                      ++maps;
> >+              }
> >+      }
> >+      return 0;
> >+}
> >+
> >+#endif
> >+
> >+const struct dev_pm_ops pmc_core_pm_ops = {
> >+      SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend,
> >pmc_core_resume)
> These PM Ops routines will be called not just in s2idle scenario, but also in 
> other suspend scenarios like s2ram, s2disk. However actual functionalities 
> served by these routines are relevant only for s2idle.
> That means we will end up having false errors in s2ram/s2disk scenarios as 
> PC10/s0ix counters wont increment in those scenarios.

Yes, you are right. Currently there is no API for a driver to know
whether the *current suspend* attempt is targeting S0ix or S3. I was
hoping that the pm_suspend_via_s2idle() might tell us that but that is
not true. Note that this issue is mitigated by the expectation that
this parameter (warn_on_s0ix_failures) will only be enabled only on
platforms that use S0ix.

However, if this is a concern and there is a string sentiment around
it, I am happy to throw in a patch that adds such an API in the pm
core and uses it (I have a patch ready).

Thanks,

Rajat

>
> Vishwa
> >+};
> >+
> > static struct platform_driver pmc_core_driver = {
> >       .driver = {
> >               .name = "pmc_core",
> >+              .pm = &pmc_core_pm_ops
> >       },
> >       .probe = pmc_core_probe,
> >       .remove = pmc_core_remove,
> >diff --git a/drivers/platform/x86/intel_pmc_core.h
> >b/drivers/platform/x86/intel_pmc_core.h
> >index 88d9c0653a5f..fdee5772e532 100644
> >--- a/drivers/platform/x86/intel_pmc_core.h
> >+++ b/drivers/platform/x86/intel_pmc_core.h
> >@@ -241,6 +241,9 @@ struct pmc_reg_map {
> >  * @pmc_xram_read_bit:        flag to indicate whether PMC XRAM shadow
> >registers
> >  *                    used to read MPHY PG and PLL status are available
> >  * @mutex_lock:               mutex to complete one transcation
> >+ * @check_counters:   On resume, check if counters are getting incremented
> >+ * @pc10_counter:     PC10 residency counter
> >+ * @s0ix_counter:     S0ix residency (step adjusted)
> >  *
> >  * pmc_dev contains info about power management controller device.
> >  */
> >@@ -253,6 +256,10 @@ struct pmc_dev {
> > #endif /* CONFIG_DEBUG_FS */
> >       int pmc_xram_read_bit;
> >       struct mutex lock; /* generic mutex lock for PMC Core */
> >+
> >+      bool check_counters; /* Check for counter increments on resume */
> >+      u64 pc10_counter;
> >+      u64 s0ix_counter;
> > };
> >
> > #endif /* PMC_CORE_H */
> >--
> >2.21.0.360.g471c308f928-goog
>

Reply via email to