platform/x86/intel/pmc: Display LPM requirements for multiple PMCs
authorRajvi Jingar <rajvi.jingar@linux.intel.com>
Wed, 29 Nov 2023 22:21:28 +0000 (14:21 -0800)
committerHans de Goede <hdegoede@redhat.com>
Mon, 4 Dec 2023 13:53:43 +0000 (14:53 +0100)
Update the substate_requirements attribute to display the requirements for
all the PMCs on a package.

Signed-off-by: Rajvi Jingar <rajvi.jingar@linux.intel.com>
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20231129222132.2331261-17-david.e.box@linux.intel.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/intel/pmc/core.c

index 3894119d61b0fb29676b9f6e318002ffbc026087..9d3a1b6ef6223ce11a8339b7746b831778dcc8da 100644 (file)
@@ -728,7 +728,7 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
 }
 DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs);
 
-static void pmc_core_substate_req_header_show(struct seq_file *s)
+static void pmc_core_substate_req_header_show(struct seq_file *s, int pmc_index)
 {
        struct pmc_dev *pmcdev = s->private;
        int i, mode;
@@ -743,68 +743,81 @@ static void pmc_core_substate_req_header_show(struct seq_file *s)
 static int pmc_core_substate_req_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;
-       const struct pmc_bit_map *map;
-       const int num_maps = pmc->map->lpm_num_maps;
-       u32 sts_offset = pmc->map->lpm_status_offset;
-       u32 *lpm_req_regs = pmc->lpm_req_regs;
-       int mp;
+       u32 sts_offset;
+       u32 *lpm_req_regs;
+       int num_maps, mp, pmc_index;
 
-       /* Display the header */
-       pmc_core_substate_req_header_show(s);
+       for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) {
+               struct pmc *pmc = pmcdev->pmcs[pmc_index];
+               const struct pmc_bit_map **maps;
 
-       /* Loop over maps */
-       for (mp = 0; mp < num_maps; mp++) {
-               u32 req_mask = 0;
-               u32 lpm_status;
-               int mode, idx, i, len = 32;
+               if (!pmc)
+                       continue;
+
+               maps = pmc->map->lpm_sts;
+               num_maps = pmc->map->lpm_num_maps;
+               sts_offset = pmc->map->lpm_status_offset;
+               lpm_req_regs = pmc->lpm_req_regs;
 
                /*
-                * Capture the requirements and create a mask so that we only
-                * show an element if it's required for at least one of the
-                * enabled low power modes
+                * When there are multiple PMCs, though the PMC may exist, the
+                * requirement register discovery could have failed so check
+                * before accessing.
                 */
-               pmc_for_each_mode(idx, mode, pmcdev)
-                       req_mask |= lpm_req_regs[mp + (mode * num_maps)];
-
-               /* Get the last latched status for this map */
-               lpm_status = pmc_core_reg_read(pmc, sts_offset + (mp * 4));
-
-               /*  Loop over elements in this map */
-               map = maps[mp];
-               for (i = 0; map[i].name && i < len; i++) {
-                       u32 bit_mask = map[i].bit_mask;
-
-                       if (!(bit_mask & req_mask))
-                               /*
-                                * Not required for any enabled states
-                                * so don't display
-                                */
-                               continue;
-
-                       /* Display the element name in the first column */
-                       seq_printf(s, "%30s |", map[i].name);
-
-                       /* Loop over the enabled states and display if required */
-                       pmc_for_each_mode(idx, mode, pmcdev) {
-                               if (lpm_req_regs[mp + (mode * num_maps)] & bit_mask)
-                                       seq_printf(s, " %9s |",
-                                                  "Required");
-                               else
-                                       seq_printf(s, " %9s |", " ");
-                       }
-
-                       /* In Status column, show the last captured state of this agent */
-                       if (lpm_status & bit_mask)
-                               seq_printf(s, " %9s |", "Yes");
-                       else
-                               seq_printf(s, " %9s |", " ");
+               if (!lpm_req_regs)
+                       continue;
 
-                       seq_puts(s, "\n");
+               /* Display the header */
+               pmc_core_substate_req_header_show(s, pmc_index);
+
+               /* Loop over maps */
+               for (mp = 0; mp < num_maps; mp++) {
+                       u32 req_mask = 0;
+                       u32 lpm_status;
+                       const struct pmc_bit_map *map;
+                       int mode, idx, i, len = 32;
+
+                       /*
+                        * Capture the requirements and create a mask so that we only
+                        * show an element if it's required for at least one of the
+                        * enabled low power modes
+                        */
+                       pmc_for_each_mode(idx, mode, pmcdev)
+                               req_mask |= lpm_req_regs[mp + (mode * num_maps)];
+
+                       /* Get the last latched status for this map */
+                       lpm_status = pmc_core_reg_read(pmc, sts_offset + (mp * 4));
+
+                       /*  Loop over elements in this map */
+                       map = maps[mp];
+                       for (i = 0; map[i].name && i < len; i++) {
+                               u32 bit_mask = map[i].bit_mask;
+
+                               if (!(bit_mask & req_mask)) {
+                                       /*
+                                        * Not required for any enabled states
+                                        * so don't display
+                                        */
+                                       continue;
+                               }
+
+                               /* Display the element name in the first column */
+                               seq_printf(s, "pmc%d: %26s |", pmc_index, map[i].name);
+
+                               /* Loop over the enabled states and display if required */
+                               pmc_for_each_mode(idx, mode, pmcdev) {
+                                       bool required = lpm_req_regs[mp + (mode * num_maps)] &
+                                                       bit_mask;
+                                       seq_printf(s, " %9s |", required ? "Required" : " ");
+                               }
+
+                               /* In Status column, show the last captured state of this agent */
+                               seq_printf(s, " %9s |", lpm_status & bit_mask ? "Yes" : " ");
+
+                               seq_puts(s, "\n");
+                       }
                }
        }
-
        return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_req_regs);