Skip to content

Commit

Permalink
platform/x86:intel/pmc: Enable debugfs multiple PMC support
Browse files Browse the repository at this point in the history
Enable debugfs support for multiple PMC. These debugfs attributes
show information for all enabled PMCs.

pch_ip_power_gating_status
substate_status_registers
substate_live_status_registers
ltr_show
ltr_ignore

Signed-off-by: Xi Pardee <[email protected]>
Signed-off-by: Rajvi Jingar <[email protected]>
Reviewed-by: Ilpo Järvinen <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Hans de Goede <[email protected]>
  • Loading branch information
xpardee-create authored and jwrdegoede committed Jun 20, 2023
1 parent 1c709ae commit 2bcef45
Showing 1 changed file with 129 additions and 66 deletions.
195 changes: 129 additions & 66 deletions drivers/platform/x86/intel/pmc/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ static int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps)
}

static void pmc_core_lpm_display(struct pmc *pmc, struct device *dev,
struct seq_file *s, u32 offset,
struct seq_file *s, u32 offset, int pmc_index,
const char *str,
const struct pmc_bit_map **maps)
{
Expand All @@ -271,19 +271,19 @@ static void pmc_core_lpm_display(struct pmc *pmc, struct device *dev,

for (idx = 0; idx < arr_size; idx++) {
if (dev)
dev_info(dev, "\nLPM_%s_%d:\t0x%x\n", str, idx,
dev_info(dev, "\nPMC%d:LPM_%s_%d:\t0x%x\n", pmc_index, str, idx,
lpm_regs[idx]);
if (s)
seq_printf(s, "\nLPM_%s_%d:\t0x%x\n", str, idx,
seq_printf(s, "\nPMC%d:LPM_%s_%d:\t0x%x\n", pmc_index, str, idx,
lpm_regs[idx]);
for (index = 0; maps[idx][index].name && index < len; index++) {
bit_mask = maps[idx][index].bit_mask;
if (dev)
dev_info(dev, "%-30s %-30d\n",
dev_info(dev, "PMC%d:%-30s %-30d\n", pmc_index,
maps[idx][index].name,
lpm_regs[idx] & bit_mask ? 1 : 0);
if (s)
seq_printf(s, "%-30s %-30d\n",
seq_printf(s, "PMC%d:%-30s %-30d\n", pmc_index,
maps[idx][index].name,
lpm_regs[idx] & bit_mask ? 1 : 0);
}
Expand All @@ -300,32 +300,40 @@ static inline u8 pmc_core_reg_read_byte(struct pmc *pmc, int offset)
}

static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip,
u8 pf_reg, const struct pmc_bit_map **pf_map)
int pmc_index, u8 pf_reg, const struct pmc_bit_map **pf_map)
{
seq_printf(s, "PCH IP: %-2d - %-32s\tState: %s\n",
ip, pf_map[idx][index].name,
seq_printf(s, "PMC%d:PCH IP: %-2d - %-32s\tState: %s\n",
pmc_index, ip, pf_map[idx][index].name,
pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On");
}

static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_bit_map **maps = pmc->map->pfear_sts;
u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES];
int index, iter, idx, ip = 0;
int i;

for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
struct pmc *pmc = pmcdev->pmcs[i];
const struct pmc_bit_map **maps;
u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES];
int index, iter, idx, ip = 0;

if (!pmc)
continue;

iter = pmc->map->ppfear0_offset;
maps = pmc->map->pfear_sts;
iter = pmc->map->ppfear0_offset;

for (index = 0; index < pmc->map->ppfear_buckets &&
index < PPFEAR_MAX_NUM_ENTRIES; index++, iter++)
pf_regs[index] = pmc_core_reg_read_byte(pmc, iter);
for (index = 0; index < pmc->map->ppfear_buckets &&
index < PPFEAR_MAX_NUM_ENTRIES; index++, iter++)
pf_regs[index] = pmc_core_reg_read_byte(pmc, iter);

for (idx = 0; maps[idx]; idx++) {
for (index = 0; maps[idx][index].name &&
index < pmc->map->ppfear_buckets * 8; ip++, index++)
pmc_core_display_map(s, index, idx, ip,
pf_regs[index / 8], maps);
for (idx = 0; maps[idx]; idx++) {
for (index = 0; maps[idx][index].name &&
index < pmc->map->ppfear_buckets * 8; ip++, index++)
pmc_core_display_map(s, index, idx, ip, i,
pf_regs[index / 8], maps);
}
}

return 0;
Expand Down Expand Up @@ -454,26 +462,48 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);

int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_reg_map *map = pmc->map;
struct pmc *pmc;
const struct pmc_reg_map *map;
u32 reg;
int err = 0;
int pmc_index, ltr_index;

mutex_lock(&pmcdev->lock);
ltr_index = value;
/* For platforms with multiple pmcs, ltr index value given by user
* is based on the contiguous indexes from ltr_show output.
* pmc index and ltr index needs to be calculated from it.
*/
for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index > 0; pmc_index++) {
pmc = pmcdev->pmcs[pmc_index];

if (value > map->ltr_ignore_max) {
err = -EINVAL;
goto out_unlock;
if (!pmc)
continue;

map = pmc->map;
if (ltr_index <= map->ltr_ignore_max)
break;

/* Along with IP names, ltr_show map includes CURRENT_PLATFORM
* and AGGREGATED_SYSTEM values per PMC. Take these two index
* values into account in ltr_index calculation. Also, to start
* ltr index from zero for next pmc, subtract it by 1.
*/
ltr_index = ltr_index - (map->ltr_ignore_max + 2) - 1;
}

if (pmc_index >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0)
return -EINVAL;

pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index);

mutex_lock(&pmcdev->lock);

reg = pmc_core_reg_read(pmc, map->ltr_ignore_offset);
reg |= BIT(value);
reg |= BIT(ltr_index);
pmc_core_reg_write(pmc, map->ltr_ignore_offset, reg);

out_unlock:
mutex_unlock(&pmcdev->lock);

return err;
return 0;
}

static ssize_t pmc_core_ltr_ignore_write(struct file *file,
Expand Down Expand Up @@ -586,36 +616,44 @@ static u32 convert_ltr_scale(u32 val)

static int pmc_core_ltr_show(struct seq_file *s, void *unused)
{
struct pmc *pmc = s->private;
const struct pmc_bit_map *map = pmc->map->ltr_show_sts;
struct pmc_dev *pmcdev = s->private;
u64 decoded_snoop_ltr, decoded_non_snoop_ltr;
u32 ltr_raw_data, scale, val;
u16 snoop_ltr, nonsnoop_ltr;
int index;
int i, index, ltr_index = 0;

for (index = 0; map[index].name ; index++) {
decoded_snoop_ltr = decoded_non_snoop_ltr = 0;
ltr_raw_data = pmc_core_reg_read(pmc,
map[index].bit_mask);
snoop_ltr = ltr_raw_data & ~MTPMC_MASK;
nonsnoop_ltr = (ltr_raw_data >> 0x10) & ~MTPMC_MASK;

if (FIELD_GET(LTR_REQ_NONSNOOP, ltr_raw_data)) {
scale = FIELD_GET(LTR_DECODED_SCALE, nonsnoop_ltr);
val = FIELD_GET(LTR_DECODED_VAL, nonsnoop_ltr);
decoded_non_snoop_ltr = val * convert_ltr_scale(scale);
}
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
struct pmc *pmc = pmcdev->pmcs[i];
const struct pmc_bit_map *map;

if (FIELD_GET(LTR_REQ_SNOOP, ltr_raw_data)) {
scale = FIELD_GET(LTR_DECODED_SCALE, snoop_ltr);
val = FIELD_GET(LTR_DECODED_VAL, snoop_ltr);
decoded_snoop_ltr = val * convert_ltr_scale(scale);
}
if (!pmc)
continue;

map = pmc->map->ltr_show_sts;
for (index = 0; map[index].name; index++) {
decoded_snoop_ltr = decoded_non_snoop_ltr = 0;
ltr_raw_data = pmc_core_reg_read(pmc,
map[index].bit_mask);
snoop_ltr = ltr_raw_data & ~MTPMC_MASK;
nonsnoop_ltr = (ltr_raw_data >> 0x10) & ~MTPMC_MASK;

if (FIELD_GET(LTR_REQ_NONSNOOP, ltr_raw_data)) {
scale = FIELD_GET(LTR_DECODED_SCALE, nonsnoop_ltr);
val = FIELD_GET(LTR_DECODED_VAL, nonsnoop_ltr);
decoded_non_snoop_ltr = val * convert_ltr_scale(scale);
}
if (FIELD_GET(LTR_REQ_SNOOP, ltr_raw_data)) {
scale = FIELD_GET(LTR_DECODED_SCALE, snoop_ltr);
val = FIELD_GET(LTR_DECODED_VAL, snoop_ltr);
decoded_snoop_ltr = val * convert_ltr_scale(scale);
}

seq_printf(s, "%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n",
map[index].name, ltr_raw_data,
decoded_non_snoop_ltr,
decoded_snoop_ltr);
seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n",
ltr_index, i, map[index].name, ltr_raw_data,
decoded_non_snoop_ltr,
decoded_snoop_ltr);
ltr_index++;
}
}
return 0;
}
Expand Down Expand Up @@ -651,11 +689,19 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);
static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_bit_map **maps = pmc->map->lpm_sts;
u32 offset = pmc->map->lpm_status_offset;
int i;

for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
struct pmc *pmc = pmcdev->pmcs[i];
const struct pmc_bit_map **maps;
u32 offset;

pmc_core_lpm_display(pmc, NULL, s, offset, "STATUS", maps);
if (!pmc)
continue;
maps = pmc->map->lpm_sts;
offset = pmc->map->lpm_status_offset;
pmc_core_lpm_display(pmc, NULL, s, offset, i, "STATUS", maps);
}

return 0;
}
Expand All @@ -664,11 +710,19 @@ 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;
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_bit_map **maps = pmc->map->lpm_sts;
u32 offset = pmc->map->lpm_live_status_offset;
int i;

for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
struct pmc *pmc = pmcdev->pmcs[i];
const struct pmc_bit_map **maps;
u32 offset;

pmc_core_lpm_display(pmc, NULL, s, offset, "LIVE_STATUS", maps);
if (!pmc)
continue;
maps = pmc->map->lpm_sts;
offset = pmc->map->lpm_live_status_offset;
pmc_core_lpm_display(pmc, NULL, s, offset, i, "LIVE_STATUS", maps);
}

return 0;
}
Expand Down Expand Up @@ -1005,7 +1059,7 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
&pmc_core_ltr_ignore_ops);

debugfs_create_file("ltr_show", 0444, dir, primary_pmc, &pmc_core_ltr_fops);
debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops);

debugfs_create_file("package_cstate_show", 0444, dir, primary_pmc,
&pmc_core_pkgc_fops);
Expand Down Expand Up @@ -1264,6 +1318,7 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_bit_map **maps = pmc->map->lpm_sts;
int offset = pmc->map->lpm_status_offset;
int i;

/* Check if the syspend used S0ix */
if (pm_suspend_via_firmware())
Expand All @@ -1285,10 +1340,18 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
/* 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);

if (pmc->map->slps0_dbg_maps)
pmc_core_slps0_display(pmc, dev, NULL);
if (pmc->map->lpm_sts)
pmc_core_lpm_display(pmc, dev, NULL, offset, "STATUS", maps);

for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
struct pmc *pmc = pmcdev->pmcs[i];

if (!pmc)
continue;
if (pmc->map->lpm_sts)
pmc_core_lpm_display(pmc, dev, NULL, offset, i, "STATUS", maps);
}

return 0;
}
Expand Down

0 comments on commit 2bcef45

Please sign in to comment.