]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm_mpam: resctrl: Add support for csu counters
authorJames Morse <james.morse@arm.com>
Fri, 13 Mar 2026 14:46:05 +0000 (14:46 +0000)
committerJames Morse <james.morse@arm.com>
Fri, 27 Mar 2026 15:31:23 +0000 (15:31 +0000)
resctrl exposes a counter via a file named llc_occupancy. This isn't really
a counter as its value goes up and down, this is a snapshot of the cache
storage usage monitor.

Add some picking code which will only find an L3. The resctrl counter
file is called llc_occupancy but we don't check it is the last one as
it is already identified as L3.

Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Zeng Heng <zengheng4@huawei.com>
Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
Tested-by: Gavin Shan <gshan@redhat.com>
Tested-by: Jesse Chick <jessechick@os.amperecomputing.com>
Reviewed-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Co-developed-by: Dave Martin <dave.martin@arm.com>
Signed-off-by: Dave Martin <dave.martin@arm.com>
Co-developed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
drivers/resctrl/mpam_resctrl.c

index e03d0f400993c50ac015ad27184378edcbec59b7..07bb20a01b383a1a50bc63f44ff95ce85e804706 100644 (file)
@@ -311,6 +311,28 @@ static bool class_has_usable_mba(struct mpam_props *cprops)
        return mba_class_use_mbw_max(cprops);
 }
 
+static bool cache_has_usable_csu(struct mpam_class *class)
+{
+       struct mpam_props *cprops;
+
+       if (!class)
+               return false;
+
+       cprops = &class->props;
+
+       if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
+               return false;
+
+       /*
+        * CSU counters settle on the value, so we can get away with
+        * having only one.
+        */
+       if (!cprops->num_csu_mon)
+               return false;
+
+       return true;
+}
+
 /*
  * Calculate the worst-case percentage change from each implemented step
  * in the control.
@@ -630,6 +652,64 @@ static void mpam_resctrl_pick_mba(void)
        }
 }
 
+static void counter_update_class(enum resctrl_event_id evt_id,
+                                struct mpam_class *class)
+{
+       struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+
+       if (existing_class) {
+               if (class->level == 3) {
+                       pr_debug("Existing class is L3 - L3 wins\n");
+                       return;
+               }
+
+               if (existing_class->level < class->level) {
+                       pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
+                                existing_class->level, class->level);
+                       return;
+               }
+       }
+
+       mpam_resctrl_counters[evt_id].class = class;
+}
+
+static void mpam_resctrl_pick_counters(void)
+{
+       struct mpam_class *class;
+
+       lockdep_assert_cpus_held();
+
+       guard(srcu)(&mpam_srcu);
+       list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+                                srcu_read_lock_held(&mpam_srcu)) {
+               /* The name of the resource is L3... */
+               if (class->type == MPAM_CLASS_CACHE && class->level != 3) {
+                       pr_debug("class %u is a cache but not the L3", class->level);
+                       continue;
+               }
+
+               if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+                       pr_debug("class %u does not cover all CPUs",
+                                class->level);
+                       continue;
+               }
+
+               if (cache_has_usable_csu(class)) {
+                       pr_debug("class %u has usable CSU",
+                                class->level);
+
+                       /* CSU counters only make sense on a cache. */
+                       switch (class->type) {
+                       case MPAM_CLASS_CACHE:
+                               counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
 {
        struct mpam_class *class = res->class;
@@ -1264,6 +1344,9 @@ int mpam_resctrl_setup(void)
                }
        }
 
+       /* Find some classes to use for monitors */
+       mpam_resctrl_pick_counters();
+
        for_each_mpam_resctrl_mon(mon, eventid) {
                if (!mon->class)
                        continue;       // dummy resource