Commit b9a4fa69 authored by Shyam Sundar S K's avatar Shyam Sundar S K Committed by Hans de Goede

platform/x86: amd-pmc: Add support for logging s0ix counters

Even the FCH SSC registers provides certain level of information
about the s0ix entry and exit times which comes handy when the SMU
fails to report the statistics via the mailbox communication.

This information is captured via a new debugfs file "s0ix_stats".
A non-zero entry in this counters would mean that the system entered
the s0ix state.

If s0ix entry time and exit time don't change during suspend to idle,
the silicon has not entered the deepest state.
Signed-off-by: default avatarShyam Sundar S K <Shyam-sundar.S-k@amd.com>
Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20210629084803.248498-6-Shyam-sundar.S-k@amd.comSigned-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 76620567
...@@ -46,6 +46,15 @@ ...@@ -46,6 +46,15 @@
#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE #define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE
#define AMD_PMC_RESULT_FAILED 0xFF #define AMD_PMC_RESULT_FAILED 0xFF
/* FCH SSC Registers */
#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30
#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34
#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38
#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C
#define FCH_SSC_MAPPING_SIZE 0x800
#define FCH_BASE_PHY_ADDR_LOW 0xFED81100
#define FCH_BASE_PHY_ADDR_HIGH 0x00000000
/* SMU Message Definations */ /* SMU Message Definations */
#define SMU_MSG_GETSMUVERSION 0x02 #define SMU_MSG_GETSMUVERSION 0x02
#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 #define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04
...@@ -96,6 +105,7 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = { ...@@ -96,6 +105,7 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = {
struct amd_pmc_dev { struct amd_pmc_dev {
void __iomem *regbase; void __iomem *regbase;
void __iomem *smu_virt_addr; void __iomem *smu_virt_addr;
void __iomem *fch_virt_addr;
u32 base_addr; u32 base_addr;
u32 cpu_id; u32 cpu_id;
u32 active_ips; u32 active_ips;
...@@ -166,6 +176,29 @@ static int smu_fw_info_show(struct seq_file *s, void *unused) ...@@ -166,6 +176,29 @@ static int smu_fw_info_show(struct seq_file *s, void *unused)
} }
DEFINE_SHOW_ATTRIBUTE(smu_fw_info); DEFINE_SHOW_ATTRIBUTE(smu_fw_info);
static int s0ix_stats_show(struct seq_file *s, void *unused)
{
struct amd_pmc_dev *dev = s->private;
u64 entry_time, exit_time, residency;
entry_time = ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET);
entry_time = entry_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET);
exit_time = ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_H_OFFSET);
exit_time = exit_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_L_OFFSET);
/* It's in 48MHz. We need to convert it */
residency = (exit_time - entry_time) / 48;
seq_puts(s, "=== S0ix statistics ===\n");
seq_printf(s, "S0ix Entry Time: %lld\n", entry_time);
seq_printf(s, "S0ix Exit Time: %lld\n", exit_time);
seq_printf(s, "Residency Time: %lld\n", residency);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(s0ix_stats);
static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
{ {
debugfs_remove_recursive(dev->dbgfs_dir); debugfs_remove_recursive(dev->dbgfs_dir);
...@@ -176,6 +209,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) ...@@ -176,6 +209,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL); dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL);
debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev, debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev,
&smu_fw_info_fops); &smu_fw_info_fops);
debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev,
&s0ix_stats_fops);
} }
#else #else
static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
...@@ -353,7 +388,7 @@ static int amd_pmc_probe(struct platform_device *pdev) ...@@ -353,7 +388,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
struct amd_pmc_dev *dev = &pmc; struct amd_pmc_dev *dev = &pmc;
struct pci_dev *rdev; struct pci_dev *rdev;
u32 base_addr_lo, base_addr_hi; u32 base_addr_lo, base_addr_hi;
u64 base_addr; u64 base_addr, fch_phys_addr;
int err; int err;
u32 val; u32 val;
...@@ -405,6 +440,14 @@ static int amd_pmc_probe(struct platform_device *pdev) ...@@ -405,6 +440,14 @@ static int amd_pmc_probe(struct platform_device *pdev)
mutex_init(&dev->lock); mutex_init(&dev->lock);
/* Use FCH registers to get the S0ix stats */
base_addr_lo = FCH_BASE_PHY_ADDR_LOW;
base_addr_hi = FCH_BASE_PHY_ADDR_HIGH;
fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE);
if (!dev->fch_virt_addr)
return -ENOMEM;
/* Use SMU to get the s0i3 debug stats */ /* Use SMU to get the s0i3 debug stats */
err = amd_pmc_setup_smu_logging(dev); err = amd_pmc_setup_smu_logging(dev);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment