]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
platform/x86/intel/pmc: Enable PkgC LTR blocking counter
authorXi Pardee <xi.pardee@linux.intel.com>
Tue, 5 May 2026 04:33:33 +0000 (21:33 -0700)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 8 May 2026 18:38:45 +0000 (21:38 +0300)
Enable the Package C-state LTR blocking counter in the PMT telemetry
region. This counter records how many times any Package C-state entry
is blocked for the specified reasons.

Add pmc_core_pkgc_counters_show() as a common helper to display
package C-state blocking counters from the telemetry region.

Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
Link: https://patch.msgid.link/20260505043342.2573556-3-xi.pardee@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/intel/pmc/core.c
drivers/platform/x86/intel/pmc/core.h

index c8a92d62352032a59cecede454355b6e7b05c8c2..7681c444f4bdfe34ffb5f1bb5de2e7271525de18 100644 (file)
@@ -1071,6 +1071,34 @@ static int pmc_core_die_c6_us_show(struct seq_file *s, void *unused)
 }
 DEFINE_SHOW_ATTRIBUTE(pmc_core_die_c6_us);
 
+static int pmc_core_pkgc_counters_show(struct seq_file *s,
+                                      struct telem_endpoint *ep,
+                                      u32 offset, const char **counters)
+{
+       unsigned int i;
+       u32 counter;
+       int ret;
+
+       for (i = 0; counters[i]; i++) {
+               ret = pmt_telem_read32(ep, offset + i, &counter, 1);
+               if (ret)
+                       return ret;
+               seq_printf(s, "%-30s %-30u\n", counters[i], counter);
+       }
+
+       return 0;
+}
+
+static int pmc_core_pkgc_ltr_blocker_show(struct seq_file *s, void *unused)
+{
+       struct pmc_dev *pmcdev = s->private;
+
+       return pmc_core_pkgc_counters_show(s, pmcdev->pc_ep,
+                                          pmcdev->pkgc_ltr_blocker_offset,
+                                          pmcdev->pkgc_ltr_blocker_counters);
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_ltr_blocker);
+
 static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
 {
        struct pmc_dev *pmcdev = s->private;
@@ -1322,7 +1350,7 @@ static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev,
        return ERR_PTR(-ENODEV);
 }
 
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
 {
        struct telem_endpoint *ep;
 
@@ -1333,16 +1361,32 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
                return;
        }
 
-       ep = pmc_core_register_endpoint(pcidev, guids);
-       if (IS_ERR(ep)) {
-               dev_err(&pmcdev->pdev->dev,
-                       "pmc_core: couldn't get DMU telem endpoint %ld",
-                       PTR_ERR(ep));
-               return;
+       if (pmc_dev_info->dmu_guids) {
+               ep = pmc_core_register_endpoint(pcidev, pmc_dev_info->dmu_guids);
+               if (IS_ERR(ep)) {
+                       dev_err(&pmcdev->pdev->dev,
+                               "pmc_core: couldn't get DMU telem endpoint %ld",
+                               PTR_ERR(ep));
+                       return;
+               }
+
+               pmcdev->punit_ep = ep;
+               pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
        }
 
-       pmcdev->punit_ep = ep;
-       pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
+       if (pmc_dev_info->pc_guid) {
+               ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, pmc_dev_info->pc_guid, 0);
+               if (IS_ERR(ep)) {
+                       dev_err(&pmcdev->pdev->dev,
+                               "pmc_core: couldn't get Package C-state telem endpoint %ld",
+                               PTR_ERR(ep));
+                       return;
+               }
+
+               pmcdev->pc_ep = ep;
+               pmcdev->pkgc_ltr_blocker_counters = pmc_dev_info->pkgc_ltr_blocker_counters;
+               pmcdev->pkgc_ltr_blocker_offset = pmc_dev_info->pkgc_ltr_blocker_offset;
+       }
 }
 
 void pmc_core_set_device_d3(unsigned int device)
@@ -1466,6 +1510,13 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
                                    pmcdev->dbgfs_dir, pmcdev,
                                    &pmc_core_die_c6_us_fops);
        }
+
+       if (pmcdev->pc_ep) {
+               debugfs_create_file("pkgc_ltr_blocker_show", 0444,
+                                   pmcdev->dbgfs_dir, pmcdev,
+                                   &pmc_core_pkgc_ltr_blocker_fops);
+       }
+
 }
 
 /*
@@ -1716,8 +1767,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
        }
 
        pmc_core_get_low_power_modes(pmcdev);
-       if (pmc_dev_info->dmu_guids)
-               pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids);
+       if (pmc_dev_info->dmu_guids || pmc_dev_info->pc_guid)
+               pmc_core_punit_pmt_init(pmcdev, pmc_dev_info);
 
        if (ssram) {
                ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info);
@@ -1738,6 +1789,9 @@ unmap_regbase:
        if (pmcdev->punit_ep)
                pmt_telem_unregister_endpoint(pmcdev->punit_ep);
 
+       if (pmcdev->pc_ep)
+               pmt_telem_unregister_endpoint(pmcdev->pc_ep);
+
        return ret;
 }
 
@@ -1834,6 +1888,9 @@ static void pmc_core_clean_structure(struct platform_device *pdev)
        if (pmcdev->punit_ep)
                pmt_telem_unregister_endpoint(pmcdev->punit_ep);
 
+       if (pmcdev->pc_ep)
+               pmt_telem_unregister_endpoint(pmcdev->pc_ep);
+
        platform_set_drvdata(pdev, NULL);
 }
 
index 118c8740ad3aafbd32ac6ea8cb9729e0ed59001e..a20aab73c14094441ab24f0170490afe21e40550 100644 (file)
@@ -453,6 +453,9 @@ struct pmc {
  * @suspend:           Function to perform platform specific suspend
  * @resume:            Function to perform platform specific resume
  *
+ * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
+ * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
+ *
  * pmc_dev contains info about power management controller device.
  */
 struct pmc_dev {
@@ -471,8 +474,12 @@ struct pmc_dev {
        u8 num_of_pkgc;
 
        u32 die_c6_offset;
+       struct telem_endpoint *pc_ep;
        struct telem_endpoint *punit_ep;
        struct pmc_info *regmap_list;
+
+       const char **pkgc_ltr_blocker_counters;
+       u32 pkgc_ltr_blocker_offset;
 };
 
 enum pmc_index {
@@ -486,12 +493,15 @@ enum pmc_index {
  * struct pmc_dev_info - Structure to keep PMC device info
  * @pci_func:          Function number of the primary PMC
  * @dmu_guids:         List of Die Management Unit GUID
+ * @pc_guid:           GUID for telemetry region to read PKGC blocker info
+ * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
  * @regmap_list:       Pointer to a list of pmc_info structure that could be
  *                     available for the platform. When set, this field implies
  *                     SSRAM support.
  * @map:               Pointer to a pmc_reg_map struct that contains platform
  *                     specific attributes of the primary PMC
  * @sub_req_show:      File operations to show substate requirements
+ * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
  * @suspend:           Function to perform platform specific suspend
  * @resume:            Function to perform platform specific resume
  * @init:              Function to perform platform specific init action
@@ -500,9 +510,12 @@ enum pmc_index {
 struct pmc_dev_info {
        u8 pci_func;
        u32 *dmu_guids;
+       u32 pc_guid;
+       u32 pkgc_ltr_blocker_offset;
        struct pmc_info *regmap_list;
        const struct pmc_reg_map *map;
        const struct file_operations *sub_req_show;
+       const char **pkgc_ltr_blocker_counters;
        void (*suspend)(struct pmc_dev *pmcdev);
        int (*resume)(struct pmc_dev *pmcdev);
        int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
@@ -535,7 +548,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
 
 int pmc_core_resume_common(struct pmc_dev *pmcdev);
 int get_primary_reg_base(struct pmc *pmc);
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids);
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
 void pmc_core_set_device_d3(unsigned int device);
 
 int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);