2020-02-04 23:05:55

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 0/7] platform/x86: intel_pmc_core: Add debugfs entries

Hi,

Tiger Lake platform supports 8 sub-states/low power modes of S0ix. Add
debugfs entries to pmc_core driver to access low power mode registers
and residencies.

Patch 1: Add debugfs entry to access sub-state residencies
Patch 2: Add debugfs entry for low power mode status registers
Patch 3: Refactor the driver by removing redundant code
Patch 4: Remove slp_s0 attributes from tgl_reg_map
Patch 5: Add an additional parameter to pmc_core_lpm_display_map()
Patch 6: Dump low power status registers on an S0ix.y failure
Patch 7: Add debugfs support to access live status registers

Changes since v1:
1) Rebased it on for-next branch to make sure patch series apply
cleanly.

Gayatri Kammela (7):
platform/x86: intel_pmc_core: Add debugfs entry to access sub-state
residencies
platform/x86: intel_pmc_core: Add debugfs entry for low power mode
status registers
platform/x86: intel_pmc_core: Refactor the driver by removing
redundant code
platform/x86: intel_pmc_core: Remove slp_s0 attributes from
tgl_reg_map
platform/x86: intel_pmc_core: Add an additional parameter to
pmc_core_lpm_display()
platform/x86: intel_pmc_core: Dump low power status registers on an
S0ix.y failure
platform/x86: intel_pmc_core: Add debugfs support to access live
status registers

drivers/platform/x86/intel_pmc_core.c | 301 +++++++++++++++++++++++---
drivers/platform/x86/intel_pmc_core.h | 28 +++
2 files changed, 302 insertions(+), 27 deletions(-)

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
--
2.17.1


2020-02-04 23:06:12

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 1/7] platform/x86: intel_pmc_core: Add debugfs entry to access sub-state residencies

Prior to Tiger Lake, the platforms that support pmc_core have no
sub-states of S0ix. Tiger Lake has 8 sub-states/low power modes of S0ix
ranging from S0i2.0-S0i2.2 and S0i3.0-S0i3.4, simply represented as
S0ix.y.

Create a debugfs entry to access residency of each sub-state.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Signed-off-by: David Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 28 +++++++++++++++++++++++++++
drivers/platform/x86/intel_pmc_core.h | 21 ++++++++++++++++++++
2 files changed, 49 insertions(+)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 144faa8bad3d..2a650dbb3bea 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -422,6 +422,8 @@ static const struct pmc_reg_map tgl_reg_map = {
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
+ .lpm_en_offset = TGL_LPM_EN_OFFSET,
+ .lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
};

static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
@@ -794,6 +796,26 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr);

+static int pmc_core_substate_res_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+ u32 offset = pmcdev->map->lpm_residency_offset;
+ u32 lpm_en;
+ int index;
+
+ lpm_en = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_en_offset);
+ seq_printf(s, "status substate residency\n");
+ for (index = 0; lpm_modes[index]; index++) {
+ seq_printf(s, "%7s %7s %-15u\n",
+ BIT(index) & lpm_en ? "Enabled" : " ",
+ lpm_modes[index], pmc_core_reg_read(pmcdev, offset));
+ offset += 4;
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);
+
static int pmc_core_pkgc_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
@@ -859,6 +881,12 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
debugfs_create_bool("slp_s0_dbg_latch", 0644,
dir, &slps0_dbg_latch);
}
+
+ if (pmcdev->map->lpm_en_offset) {
+ debugfs_create_file("substate_residencies", 0444,
+ pmcdev->dbgfs_dir, pmcdev,
+ &pmc_core_substate_res_fops);
+ }
}
#else
static inline void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index f1a0792b3f91..ff1b2645d9b4 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -188,6 +188,24 @@ enum ppfear_regs {

#define TGL_NUM_IP_IGN_ALLOWED 22

+/*
+ * Tigerlake Power Management Controller register offsets
+ */
+#define TGL_LPM_EN_OFFSET 0x1C78
+#define TGL_LPM_RESIDENCY_OFFSET 0x1C80
+
+const char *lpm_modes[] = {
+ "S0i2.0",
+ "S0i2.1",
+ "S0i2.2",
+ "S0i3.0",
+ "S0i3.1",
+ "S0i3.2",
+ "S0i3.3",
+ "S0i3.4",
+ NULL
+};
+
struct pmc_bit_map {
const char *name;
u32 bit_mask;
@@ -231,6 +249,9 @@ struct pmc_reg_map {
const u32 slps0_dbg_offset;
const u32 ltr_ignore_max;
const u32 pm_vric1_offset;
+ /* Low Power Mode registers */
+ const u32 lpm_en_offset;
+ const u32 lpm_residency_offset;
};

/**
--
2.17.1

2020-02-04 23:06:14

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 6/7] platform/x86: intel_pmc_core: Dump low power status registers on an S0ix.y failure

Platforms prior to Tiger Lake has no sub-states of S0ix and accessing
device PM states that are latched whenever there is a PC10 entry is
possible with the help of slp_s0_debug_status and slp_s0_dbg_latch
debugfs entries.

If a platform has sub-states of S0ix, no such entries are created.
Hence, dump low power status registers on resume When any attempt to
enter any low power state was unsuccessful.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Suggested-by: David Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 41426d4af887..62cce906755e 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -1284,6 +1284,8 @@ static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
static int pmc_core_resume(struct device *dev)
{
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
+ const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
+ int offset = pmcdev->map->lpm_status_offset;

if (!pmcdev->check_counters)
return 0;
@@ -1303,6 +1305,8 @@ static int pmc_core_resume(struct device *dev)
pmcdev->s0ix_counter);
if (pmcdev->map->slps0_dbg_maps)
pmc_core_slps0_display(pmcdev, dev, NULL);
+ if (pmcdev->map->lpm_sts)
+ pmc_core_lpm_display(pmcdev, dev, NULL, "STATUS", offset, maps);

return 0;
}
--
2.17.1

2020-02-04 23:06:11

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 2/7] platform/x86: intel_pmc_core: Add debugfs entry for low power mode status registers

Tiger Lake has 6 status registers that are memory mapped. These
registers show the status of the low power mode requirements. The
registers are latched on every C10 entry or exit and on every s0ix.y
entry/exit. Accessing these registers is useful for debugging any low
power related activities.

Thus, add debugfs entry to access low power mode status registers.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Signed-off-by: David Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 188 ++++++++++++++++++++++++++
drivers/platform/x86/intel_pmc_core.h | 5 +
2 files changed, 193 insertions(+)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 2a650dbb3bea..fc4da7c33dbf 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -408,6 +408,152 @@ static const struct pmc_reg_map icl_reg_map = {
.ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
};

+static const struct pmc_bit_map tgl_lpm0_map[] = {
+ {"USB2PLL_OFF_STS", BIT(18)},
+ {"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)},
+ {"PCIe_Gen3PLL_OFF_STS", BIT(20)},
+ {"OPIOPLL_OFF_STS", BIT(21)},
+ {"OCPLL_OFF_STS", BIT(22)},
+ {"AudioPLL_OFF_STS", BIT(23)},
+ {"MIPIPLL_OFF_STS", BIT(24)},
+ {"Fast_XTAL_Osc_OFF_STS", BIT(25)},
+ {"AC_Ring_Osc_OFF_STS", BIT(26)},
+ {"MC_Ring_Osc_OFF_STS", BIT(27)},
+ {"SATAPLL_OFF_STS", BIT(29)},
+ {"XTAL_USB2PLL_OFF_STS", BIT(31)},
+ {}
+};
+
+static const struct pmc_bit_map tgl_lpm1_map[] = {
+ {"SPI_PG_STS", BIT(2)},
+ {"xHCI_PG_STS", BIT(3)},
+ {"PCIe_Ctrller_A_PG_STS", BIT(4)},
+ {"PCIe_Ctrller_B_PG_STS", BIT(5)},
+ {"PCIe_Ctrller_C_PG_STS", BIT(6)},
+ {"GBE_PG_STS", BIT(7)},
+ {"SATA_PG_STS", BIT(8)},
+ {"HDA0_PG_STS", BIT(9)},
+ {"HDA1_PG_STS", BIT(10)},
+ {"HDA2_PG_STS", BIT(11)},
+ {"HDA3_PG_STS", BIT(12)},
+ {"PCIe_Ctrller_D_PG_STS", BIT(13)},
+ {"ISIO_PG_STS", BIT(14)},
+ {"SMB_PG_STS", BIT(16)},
+ {"ISH_PG_STS", BIT(17)},
+ {"ITH_PG_STS", BIT(19)},
+ {"SDX_PG_STS", BIT(20)},
+ {"xDCI_PG_STS", BIT(25)},
+ {"DCI_PG_STS", BIT(26)},
+ {"CSME0_PG_STS", BIT(27)},
+ {"CSME_KVM_PG_STS", BIT(28)},
+ {"CSME1_PG_STS", BIT(29)},
+ {"CSME_CLINK_PG_STS", BIT(30)},
+ {"CSME2_PG_STS", BIT(31)},
+ {}
+};
+
+static const struct pmc_bit_map tgl_lpm2_map[] = {
+ {"ADSP_D3_STS", BIT(0)},
+ {"SATA_D3_STS", BIT(1)},
+ {"xHCI0_D3_STS", BIT(2)},
+ {"xDCI1_D3_STS", BIT(5)},
+ {"SDX_D3_STS", BIT(6)},
+ {"EMMC_D3_STS", BIT(7)},
+ {"IS_D3_STS", BIT(8)},
+ {"THC0_D3_STS", BIT(9)},
+ {"THC1_D3_STS", BIT(10)},
+ {"GBE_D3_STS", BIT(11)},
+ {"GBE_TSN_D3_STS", BIT(12)},
+ {}
+};
+
+static const struct pmc_bit_map tgl_lpm3_map[] = {
+ {"GPIO_COM0_VNN_REQ_STS", BIT(1)},
+ {"GPIO_COM1_VNN_REQ_STS", BIT(2)},
+ {"GPIO_COM2_VNN_REQ_STS", BIT(3)},
+ {"GPIO_COM3_VNN_REQ_STS", BIT(4)},
+ {"GPIO_COM4_VNN_REQ_STS", BIT(5)},
+ {"GPIO_COM5_VNN_REQ_STS", BIT(6)},
+ {"Audio_VNN_REQ_STS", BIT(7)},
+ {"ISH_VNN_REQ_STS", BIT(8)},
+ {"CNVI_VNN_REQ_STS", BIT(9)},
+ {"eSPI_VNN_REQ_STS", BIT(10)},
+ {"Display_VNN_REQ_STS", BIT(11)},
+ {"DTS_VNN_REQ_STS", BIT(12)},
+ {"SMBUS_VNN_REQ_STS", BIT(14)},
+ {"CSME_VNN_REQ_STS", BIT(15)},
+ {"SMLINK0_VNN_REQ_STS", BIT(16)},
+ {"SMLINK1_VNN_REQ_STS", BIT(17)},
+ {"CLINK_VNN_REQ_STS", BIT(20)},
+ {"DCI_VNN_REQ_STS", BIT(21)},
+ {"ITH_VNN_REQ_STS", BIT(22)},
+ {"CSME_VNN_REQ_STS", BIT(24)},
+ {"GBE_VNN_REQ_STS", BIT(25)},
+ {}
+};
+
+static const struct pmc_bit_map tgl_lpm4_map[] = {
+ {"CPU_C10_REQ_STS_0", BIT(0)},
+ {"PCIe_LPM_En_REQ_STS_3", BIT(3)},
+ {"ITH_REQ_STS_5", BIT(5)},
+ {"CNVI_REQ_STS_6", BIT(6)},
+ {"ISH_REQ_STS_7", BIT(7)},
+ {"USB2_SUS_PG_Sys_REQ_STS_10", BIT(10)},
+ {"PCIe_Clk_REQ_STS_12", BIT(12)},
+ {"MPHY_Core_DL_REQ_STS_16", BIT(16)},
+ {"Break-even_En_REQ_STS_17", BIT(17)},
+ {"Auto-demo_En_REQ_STS_18", BIT(18)},
+ {"MPHY_SUS_REQ_STS_22", BIT(22)},
+ {"xDCI_attached_REQ_STS_24", BIT(24)},
+ {}
+};
+
+static const struct pmc_bit_map tgl_lpm5_map[] = {
+ {"LSX_Wake0_En_STS", BIT(0)},
+ {"LSX_Wake0_Pol_STS", BIT(1)},
+ {"LSX_Wake1_En_STS", BIT(2)},
+ {"LSX_Wake1_Pol_STS", BIT(3)},
+ {"LSX_Wake2_En_STS", BIT(4)},
+ {"LSX_Wake2_Pol_STS", BIT(5)},
+ {"LSX_Wake3_En_STS", BIT(6)},
+ {"LSX_Wake3_Pol_STS", BIT(7)},
+ {"LSX_Wake4_En_STS", BIT(8)},
+ {"LSX_Wake4_Pol_STS", BIT(9)},
+ {"LSX_Wake5_En_STS", BIT(10)},
+ {"LSX_Wake5_Pol_STS", BIT(11)},
+ {"LSX_Wake6_En_STS", BIT(12)},
+ {"LSX_Wake6_Pol_STS", BIT(13)},
+ {"LSX_Wake7_En_STS", BIT(14)},
+ {"LSX_Wake7_Pol_STS", BIT(15)},
+ {"Intel_Se_IO_Wake0_En_STS", BIT(16)},
+ {"Intel_Se_IO_Wake0_Pol_STS", BIT(17)},
+ {"Intel_Se_IO_Wake1_En_STS", BIT(18)},
+ {"Intel_Se_IO_Wake1_Pol_STS", BIT(19)},
+ {"Int_Timer_SS_Wake0_En_STS", BIT(20)},
+ {"Int_Timer_SS_Wake0_Pol_STS", BIT(21)},
+ {"Int_Timer_SS_Wake1_En_STS", BIT(22)},
+ {"Int_Timer_SS_Wake1_Pol_STS", BIT(23)},
+ {"Int_Timer_SS_Wake2_En_STS", BIT(24)},
+ {"Int_Timer_SS_Wake2_Pol_STS", BIT(25)},
+ {"Int_Timer_SS_Wake3_En_STS", BIT(26)},
+ {"Int_Timer_SS_Wake3_Pol_STS", BIT(27)},
+ {"Int_Timer_SS_Wake4_En_STS", BIT(28)},
+ {"Int_Timer_SS_Wake4_Pol_STS", BIT(29)},
+ {"Int_Timer_SS_Wake5_En_STS", BIT(30)},
+ {"Int_Timer_SS_Wake5_Pol_STS", BIT(31)},
+ {}
+};
+
+static const struct pmc_bit_map *tgl_lpm_maps[] = {
+ tgl_lpm0_map,
+ tgl_lpm1_map,
+ tgl_lpm2_map,
+ tgl_lpm3_map,
+ tgl_lpm4_map,
+ tgl_lpm5_map,
+ NULL
+};
+
static const struct pmc_reg_map tgl_reg_map = {
.pfear_sts = ext_tgl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
@@ -424,6 +570,8 @@ static const struct pmc_reg_map tgl_reg_map = {
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
.lpm_en_offset = TGL_LPM_EN_OFFSET,
.lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
+ .lpm_sts = tgl_lpm_maps,
+ .lpm_status_offset = TGL_LPM_STATUS_OFFSET,
};

static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
@@ -816,6 +964,40 @@ static int pmc_core_substate_res_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);

+static void pmc_core_lpm_display(struct pmc_dev *pmcdev, struct seq_file *s,
+ u32 offset, const char *str,
+ const struct pmc_bit_map **maps)
+{
+ u32 lpm_regs[ARRAY_SIZE(tgl_lpm_maps)-1];
+ int index, idx, len = 32, bit_mask;
+
+ for (index = 0; tgl_lpm_maps[index]; index++) {
+ lpm_regs[index] = pmc_core_reg_read(pmcdev, offset);
+ offset += 4;
+ }
+
+ for (idx = 0; maps[idx]; idx++) {
+ seq_printf(s, "\nLPM_%s_%d:\t0x%x\n", str, idx, lpm_regs[idx]);
+ for (index = 0; maps[idx][index].name && index < len; index++) {
+ bit_mask = maps[idx][index].bit_mask;
+ seq_printf(s, "%-30s %-30d\n", maps[idx][index].name,
+ lpm_regs[idx] & bit_mask ? 1 : 0);
+ }
+ }
+}
+
+static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+ const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
+ u32 offset = pmcdev->map->lpm_status_offset;
+
+ pmc_core_lpm_display(pmcdev, s, offset, "STATUS", maps);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs);
+
static int pmc_core_pkgc_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
@@ -887,6 +1069,12 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
pmcdev->dbgfs_dir, pmcdev,
&pmc_core_substate_res_fops);
}
+
+ if (pmcdev->map->lpm_status_offset) {
+ debugfs_create_file("substate_status_registers", 0444,
+ pmcdev->dbgfs_dir, pmcdev,
+ &pmc_core_substate_sts_regs_fops);
+ }
}
#else
static inline void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index ff1b2645d9b4..3fdf4735c56f 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -194,6 +194,9 @@ enum ppfear_regs {
#define TGL_LPM_EN_OFFSET 0x1C78
#define TGL_LPM_RESIDENCY_OFFSET 0x1C80

+/* Tigerlake Low Power Mode debug registers */
+#define TGL_LPM_STATUS_OFFSET 0x1C3C
+
const char *lpm_modes[] = {
"S0i2.0",
"S0i2.1",
@@ -239,6 +242,7 @@ struct pmc_reg_map {
const struct pmc_bit_map **slps0_dbg_maps;
const struct pmc_bit_map *ltr_show_sts;
const struct pmc_bit_map *msr_sts;
+ const struct pmc_bit_map **lpm_sts;
const u32 slp_s0_offset;
const u32 ltr_ignore_offset;
const int regmap_length;
@@ -252,6 +256,7 @@ struct pmc_reg_map {
/* Low Power Mode registers */
const u32 lpm_en_offset;
const u32 lpm_residency_offset;
+ const u32 lpm_status_offset;
};

/**
--
2.17.1

2020-02-04 23:06:16

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 7/7] platform/x86: intel_pmc_core: Add debugfs support to access live status registers

Just like status registers, Tiger Lake has another set of 6 registers
that help with status of the low power mode requirements. They are
latched on every PC10 entry/exit and S0ix.y entry/exit as well.

Though status and live status registers show the status of same list
of requirements, live status registers show the status of the low power
mode requirements at the time of reading.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David E. Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 19 +++++++++++++++++++
drivers/platform/x86/intel_pmc_core.h | 2 ++
2 files changed, 21 insertions(+)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 62cce906755e..19e02319fd0e 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -570,6 +570,7 @@ static const struct pmc_reg_map tgl_reg_map = {
.lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
.lpm_sts = tgl_lpm_maps,
.lpm_status_offset = TGL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET,
};

static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
@@ -1019,6 +1020,18 @@ static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs);

+static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+ const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
+ u32 offset = pmcdev->map->lpm_live_status_offset;
+
+ pmc_core_lpm_display(pmcdev, NULL, s, offset, "LIVE_STATUS", maps);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs);
+
static int pmc_core_pkgc_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
@@ -1096,6 +1109,12 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
pmcdev->dbgfs_dir, pmcdev,
&pmc_core_substate_sts_regs_fops);
}
+
+ if (pmcdev->map->lpm_status_offset) {
+ debugfs_create_file("substate_live_status_registers", 0444,
+ pmcdev->dbgfs_dir, pmcdev,
+ &pmc_core_substate_l_sts_regs_fops);
+ }
}
#else
static inline void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index 3fdf4735c56f..1bbdffe80bde 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -196,6 +196,7 @@ enum ppfear_regs {

/* Tigerlake Low Power Mode debug registers */
#define TGL_LPM_STATUS_OFFSET 0x1C3C
+#define TGL_LPM_LIVE_STATUS_OFFSET 0x1C5C

const char *lpm_modes[] = {
"S0i2.0",
@@ -257,6 +258,7 @@ struct pmc_reg_map {
const u32 lpm_en_offset;
const u32 lpm_residency_offset;
const u32 lpm_status_offset;
+ const u32 lpm_live_status_offset;
};

/**
--
2.17.1

2020-02-04 23:06:29

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 5/7] platform/x86: intel_pmc_core: Add an additional parameter to pmc_core_lpm_display()

Add a device pointer of type struct device as an additional parameter to
pmc_core_lpm_display(), so that the driver can re-use it to dump the
debug registers in resume for an S0ix failure.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index a7394cfc4906..41426d4af887 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -973,8 +973,9 @@ static int pmc_core_substate_res_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);

-static void pmc_core_lpm_display(struct pmc_dev *pmcdev, struct seq_file *s,
- u32 offset, const char *str,
+static void pmc_core_lpm_display(struct pmc_dev *pmcdev, struct device *dev,
+ struct seq_file *s, u32 offset,
+ const char *str,
const struct pmc_bit_map **maps)
{
u32 lpm_regs[ARRAY_SIZE(tgl_lpm_maps)-1];
@@ -986,11 +987,22 @@ static void pmc_core_lpm_display(struct pmc_dev *pmcdev, struct seq_file *s,
}

for (idx = 0; maps[idx]; idx++) {
- seq_printf(s, "\nLPM_%s_%d:\t0x%x\n", str, idx, lpm_regs[idx]);
+ if (dev)
+ dev_dbg(dev, "\nLPM_%s_%d:\t0x%x\n", str, idx,
+ lpm_regs[idx]);
+ if (s)
+ seq_printf(s, "\nLPM_%s_%d:\t0x%x\n", str, idx,
+ lpm_regs[idx]);
for (index = 0; maps[idx][index].name && index < len; index++) {
bit_mask = maps[idx][index].bit_mask;
- seq_printf(s, "%-30s %-30d\n", maps[idx][index].name,
- lpm_regs[idx] & bit_mask ? 1 : 0);
+ if (dev)
+ dev_dbg(dev, "%-30s %-30d\n",
+ maps[idx][index].name,
+ lpm_regs[idx] & bit_mask ? 1 : 0);
+ if (s)
+ seq_printf(s, "%-30s %-30d\n",
+ maps[idx][index].name,
+ lpm_regs[idx] & bit_mask ? 1 : 0);
}
}
}
@@ -1001,7 +1013,7 @@ static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
u32 offset = pmcdev->map->lpm_status_offset;

- pmc_core_lpm_display(pmcdev, s, offset, "STATUS", maps);
+ pmc_core_lpm_display(pmcdev, NULL, s, offset, "STATUS", maps);

return 0;
}
--
2.17.1

2020-02-04 23:06:52

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 3/7] platform/x86: intel_pmc_core: Refactor the driver by removing redundant code

pmc_core_slps0_dbg_show() is responsible for displaying debug registers
through slp_s0_debug_status entry. The driver uses the same but
redundant code to dump these debug registers for an S0ix failure.

Hence, refactor the driver by removing redundant code and reuse the
same function that both dumps registers through slp_s0_debug_status
entry and in resume for an S0ix failure.

The changes in this patch are preparatory, so platforms that support low
power sub-states can dump the debug registers when the attempt to enter
low power states are unsuccessful.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Suggested-by: Andy Shevchenko <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 48 +++++++++++++--------------
1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index fc4da7c33dbf..9c66f253cf2b 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -845,30 +845,41 @@ static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset)
mutex_unlock(&pmcdev->lock);
}

-static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused)
+static void pmc_core_slps0_display(struct pmc_dev *pmcdev, struct device *dev,
+ struct seq_file *s)
{
- struct pmc_dev *pmcdev = s->private;
const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
const struct pmc_bit_map *map;
- int offset;
+ int offset = pmcdev->map->slps0_dbg_offset;
u32 data;

- pmc_core_slps0_dbg_latch(pmcdev, false);
- offset = pmcdev->map->slps0_dbg_offset;
while (*maps) {
map = *maps;
data = pmc_core_reg_read(pmcdev, offset);
offset += 4;
while (map->name) {
- seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n",
- map->name,
- data & map->bit_mask ?
- "Yes" : "No");
+ if (dev)
+ dev_dbg(dev, "SLP_S0_DBG: %-32s\tState: %s\n",
+ map->name,
+ data & map->bit_mask ? "Yes" : "No");
+ if (s)
+ seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n",
+ map->name,
+ data & map->bit_mask ? "Yes" : "No");
++map;
}
++maps;
}
+}
+
+static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+
+ pmc_core_slps0_dbg_latch(pmcdev, false);
+ pmc_core_slps0_display(pmcdev, NULL, s);
pmc_core_slps0_dbg_latch(pmcdev, true);
+
return 0;
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg);
@@ -1263,10 +1274,6 @@ static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
static int pmc_core_resume(struct device *dev)
{
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
- const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
- int offset = pmcdev->map->slps0_dbg_offset;
- const struct pmc_bit_map *map;
- u32 data;

if (!pmcdev->check_counters)
return 0;
@@ -1284,18 +1291,9 @@ static int pmc_core_resume(struct device *dev)
/* The real interesting case - S0ix failed - lets ask PMC why. */
dev_warn(dev, "CPU did not enter SLP_S0!!! (S0ix cnt=%llu)\n",
pmcdev->s0ix_counter);
- while (*maps) {
- map = *maps;
- data = pmc_core_reg_read(pmcdev, offset);
- offset += 4;
- while (map->name) {
- dev_dbg(dev, "SLP_S0_DBG: %-32s\tState: %s\n",
- map->name,
- data & map->bit_mask ? "Yes" : "No");
- map++;
- }
- maps++;
- }
+ if (pmcdev->map->slps0_dbg_maps)
+ pmc_core_slps0_display(pmcdev, dev, NULL);
+
return 0;
}

--
2.17.1

2020-02-04 23:07:06

by Kammela, Gayatri

[permalink] [raw]
Subject: [PATCH v2 4/7] platform/x86: intel_pmc_core: Remove slp_s0 attributes from tgl_reg_map

If platforms such as Tiger Lake has sub-states of S0ix, then both
slp_s0_debug_status and slp_s0_dbg_latch entries become invalid. Thus,
remove slp_s0_offset and slp_s0_dbg_maps attributes from tgl_reg_map, so
that both the entries are not created.

Cc: Srinivas Pandruvada <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: David Box <[email protected]>
Suggested-by: David Box <[email protected]>
Signed-off-by: Gayatri Kammela <[email protected]>
---
drivers/platform/x86/intel_pmc_core.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 9c66f253cf2b..a7394cfc4906 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -556,8 +556,6 @@ static const struct pmc_bit_map *tgl_lpm_maps[] = {

static const struct pmc_reg_map tgl_reg_map = {
.pfear_sts = ext_tgl_pfear_map,
- .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slps0_dbg_maps = cnp_slps0_dbg_maps,
.ltr_show_sts = cnp_ltr_show_map,
.msr_sts = msr_map,
.slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
--
2.17.1