[PATCH v3 30/47] arm_mpam: resctrl: Pre-allocate free running monitors

Ben Horgan posted 47 patches 4 weeks ago
There is a newer version of this series
[PATCH v3 30/47] arm_mpam: resctrl: Pre-allocate free running monitors
Posted by Ben Horgan 4 weeks ago
From: James Morse <james.morse@arm.com>

When there are enough monitors, the resctrl mbm local and total files can
be exposed. These need all the monitors that resctrl may use to be
allocated up front.

Add helpers to do this.

If a different candidate class is discovered, the old array should be
free'd and the allocated monitors returned to the driver.

Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since v2:
Code flow tidying (Jonathan)
---
 drivers/resctrl/mpam_internal.h |  8 +++-
 drivers/resctrl/mpam_resctrl.c  | 81 ++++++++++++++++++++++++++++++++-
 2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1c5492008fe8..89f9d374ded0 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -360,7 +360,13 @@ struct mpam_resctrl_res {
 struct mpam_resctrl_mon {
 	struct mpam_class	*class;
 
-	/* per-class data that resctrl needs will live here */
+	/*
+	 * Array of allocated MBWU monitors, indexed by (closid, rmid).
+	 * When ABMC is not in use, this array directly maps (closid, rmid)
+	 * to the allocated monitor. Otherwise this array is sparse, and
+	 * un-assigned (closid, rmid) are -1.
+	 */
+	int			*mbwu_idx_to_mon;
 };
 
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 14a8dcaf1366..3af12ad77fba 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -572,10 +572,58 @@ static void mpam_resctrl_pick_mba(void)
 	}
 }
 
+static void __free_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		if (array[i] < 0)
+			continue;
+
+		mpam_free_mbwu_mon(class, array[i]);
+		array[i] = ~0;
+	}
+}
+
+static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		int mbwu_mon = mpam_alloc_mbwu_mon(class);
+
+		if (mbwu_mon < 0) {
+			__free_mbwu_mon(class, array, num_mbwu_mon);
+			return mbwu_mon;
+		}
+		array[i] = mbwu_mon;
+	}
+
+	return 0;
+}
+
+static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
+{
+	int err;
+	size_t array_size = num_mbwu_mon * sizeof(int);
+	int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
+
+	if (!array)
+		return ERR_PTR(-ENOMEM);
+
+	memset(array, -1, array_size);
+
+	err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
+	if (err)
+		return ERR_PTR(err);
+	return_ptr(array);
+}
+
 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;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evt_id];
+	struct mpam_class *existing_class = mon->class;
+	u16 num_mbwu_mon = class->props.num_mbwu_mon;
+	int *new_array, *existing_array = mon->mbwu_idx_to_mon;
 
 	if (existing_class) {
 		if (class->level == 3) {
@@ -590,8 +638,37 @@ static void counter_update_class(enum resctrl_event_id evt_id,
 		}
 	}
 
-	mpam_resctrl_counters[evt_id].class = class;
+	pr_debug("Updating event %u to use class %u\n", evt_id, class->level);
+
+	/* Might not need all the monitors */
+	num_mbwu_mon = __mpam_monitors_free_running(num_mbwu_mon);
+
+	if ((evt_id != QOS_L3_OCCUP_EVENT_ID) && num_mbwu_mon) {
+		/*
+		 * This is the pre-allocated free-running monitors path. It always
+		 * allocates one monitor per PARTID * PMG.
+		 */
+		WARN_ON_ONCE(num_mbwu_mon != resctrl_arch_system_num_rmid_idx());
+
+		new_array = __alloc_mbwu_array(class, num_mbwu_mon);
+		if (IS_ERR(new_array)) {
+			pr_debug("Failed to allocate MBWU array\n");
+			return;
+		}
+		mon->mbwu_idx_to_mon = new_array;
+
+		if (existing_array) {
+			pr_debug("Releasing previous class %u's monitors\n",
+				 existing_class->level);
+			__free_mbwu_mon(existing_class, existing_array, num_mbwu_mon);
+			kfree(existing_array);
+		}
+	} else if (evt_id != QOS_L3_OCCUP_EVENT_ID) {
+		pr_debug("Not pre-allocating free-running counters\n");
+	}
+
 	exposed_mon_capable = true;
+	mon->class = class;
 }
 
 static void mpam_resctrl_pick_counters(void)
-- 
2.43.0
Re: [PATCH v3 30/47] arm_mpam: resctrl: Pre-allocate free running monitors
Posted by Gavin Shan 3 weeks ago
Hi Ben,

On 1/13/26 12:58 AM, Ben Horgan wrote:
> From: James Morse <james.morse@arm.com>
> 
> When there are enough monitors, the resctrl mbm local and total files can
> be exposed. These need all the monitors that resctrl may use to be
> allocated up front.
> 
> Add helpers to do this.
> 
> If a different candidate class is discovered, the old array should be
> free'd and the allocated monitors returned to the driver.
> 
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since v2:
> Code flow tidying (Jonathan)
> ---
>   drivers/resctrl/mpam_internal.h |  8 +++-
>   drivers/resctrl/mpam_resctrl.c  | 81 ++++++++++++++++++++++++++++++++-
>   2 files changed, 86 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index 1c5492008fe8..89f9d374ded0 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -360,7 +360,13 @@ struct mpam_resctrl_res {
>   struct mpam_resctrl_mon {
>   	struct mpam_class	*class;
>   
> -	/* per-class data that resctrl needs will live here */
> +	/*
> +	 * Array of allocated MBWU monitors, indexed by (closid, rmid).
> +	 * When ABMC is not in use, this array directly maps (closid, rmid)
> +	 * to the allocated monitor. Otherwise this array is sparse, and
> +	 * un-assigned (closid, rmid) are -1.
> +	 */
> +	int			*mbwu_idx_to_mon;
>   };
>   
>   static inline int mpam_alloc_csu_mon(struct mpam_class *class)
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 14a8dcaf1366..3af12ad77fba 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -572,10 +572,58 @@ static void mpam_resctrl_pick_mba(void)
>   	}
>   }
>   
> +static void __free_mbwu_mon(struct mpam_class *class, int *array,
> +			    u16 num_mbwu_mon)
> +{
> +	for (int i = 0; i < num_mbwu_mon; i++) {
> +		if (array[i] < 0)
> +			continue;
> +
> +		mpam_free_mbwu_mon(class, array[i]);
> +		array[i] = ~0;
> +	}
> +}
> +
> +static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
> +			    u16 num_mbwu_mon)
> +{
> +	for (int i = 0; i < num_mbwu_mon; i++) {
> +		int mbwu_mon = mpam_alloc_mbwu_mon(class);
> +
> +		if (mbwu_mon < 0) {
> +			__free_mbwu_mon(class, array, num_mbwu_mon);
> +			return mbwu_mon;
> +		}
> +		array[i] = mbwu_mon;
> +	}
> +
> +	return 0;
> +}
> +
> +static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
> +{
> +	int err;
> +	size_t array_size = num_mbwu_mon * sizeof(int);
> +	int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
> +

A warning reported by checkpatch.pl as below.

WARNING: Missing a blank line after declarations
#84: FILE: drivers/resctrl/mpam_resctrl.c:607:
+	size_t array_size = num_mbwu_mon * sizeof(int);
+	int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);


> +	if (!array)
> +		return ERR_PTR(-ENOMEM);
> +
> +	memset(array, -1, array_size);
> +
> +	err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
> +	if (err)
> +		return ERR_PTR(err);
> +	return_ptr(array);
> +}
> +
>   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;
> +	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evt_id];
> +	struct mpam_class *existing_class = mon->class;
> +	u16 num_mbwu_mon = class->props.num_mbwu_mon;
> +	int *new_array, *existing_array = mon->mbwu_idx_to_mon;
>   
>   	if (existing_class) {
>   		if (class->level == 3) {
> @@ -590,8 +638,37 @@ static void counter_update_class(enum resctrl_event_id evt_id,
>   		}
>   	}
>   
> -	mpam_resctrl_counters[evt_id].class = class;
> +	pr_debug("Updating event %u to use class %u\n", evt_id, class->level);
> +
> +	/* Might not need all the monitors */
> +	num_mbwu_mon = __mpam_monitors_free_running(num_mbwu_mon);
> +
> +	if ((evt_id != QOS_L3_OCCUP_EVENT_ID) && num_mbwu_mon) {
> +		/*
> +		 * This is the pre-allocated free-running monitors path. It always
> +		 * allocates one monitor per PARTID * PMG.
> +		 */
> +		WARN_ON_ONCE(num_mbwu_mon != resctrl_arch_system_num_rmid_idx());
> +
> +		new_array = __alloc_mbwu_array(class, num_mbwu_mon);
> +		if (IS_ERR(new_array)) {
> +			pr_debug("Failed to allocate MBWU array\n");
> +			return;
> +		}
> +		mon->mbwu_idx_to_mon = new_array;
> +
> +		if (existing_array) {
> +			pr_debug("Releasing previous class %u's monitors\n",
> +				 existing_class->level);
> +			__free_mbwu_mon(existing_class, existing_array, num_mbwu_mon);
> +			kfree(existing_array);
> +		}
> +	} else if (evt_id != QOS_L3_OCCUP_EVENT_ID) {
> +		pr_debug("Not pre-allocating free-running counters\n");
> +	}
> +
>   	exposed_mon_capable = true;
> +	mon->class = class;
>   }
>   
>   static void mpam_resctrl_pick_counters(void)

Thanks,
Gavin
Re: [PATCH v3 30/47] arm_mpam: resctrl: Pre-allocate free running monitors
Posted by Ben Horgan 2 weeks, 6 days ago
Hi Gavin,

On 1/19/26 11:57, Gavin Shan wrote:
> Hi Ben,
> 
> On 1/13/26 12:58 AM, Ben Horgan wrote:
>> From: James Morse <james.morse@arm.com>
>>
>> When there are enough monitors, the resctrl mbm local and total files can
>> be exposed. These need all the monitors that resctrl may use to be
>> allocated up front.
>>
>> Add helpers to do this.
>>
>> If a different candidate class is discovered, the old array should be
>> free'd and the allocated monitors returned to the driver.
>>
>> Signed-off-by: James Morse <james.morse@arm.com>
>> Signed-off-by: Ben Horgan <ben.horgan@arm.com>

>> +
>> +static int *__alloc_mbwu_array(struct mpam_class *class, u16
>> num_mbwu_mon)
>> +{
>> +    int err;
>> +    size_t array_size = num_mbwu_mon * sizeof(int);
>> +    int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
>> +
> 
> A warning reported by checkpatch.pl as below.
> 
> WARNING: Missing a blank line after declarations
> #84: FILE: drivers/resctrl/mpam_resctrl.c:607:
> +    size_t array_size = num_mbwu_mon * sizeof(int);
> +    int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
> 

Similarly to the other blank line checkpatch.pl warning I expect this is
to do with how it handles the __free() annotation. I'm not intending to
change this code unless there is some style guideline that I've missed
or other reason to do so.

Thanks,

Ben

Re: [PATCH v3 30/47] arm_mpam: resctrl: Pre-allocate free running monitors
Posted by Jonathan Cameron 3 weeks, 6 days ago
On Mon, 12 Jan 2026 16:58:57 +0000
Ben Horgan <ben.horgan@arm.com> wrote:

> From: James Morse <james.morse@arm.com>
> 
> When there are enough monitors, the resctrl mbm local and total files can
> be exposed. These need all the monitors that resctrl may use to be
> allocated up front.
> 
> Add helpers to do this.
> 
> If a different candidate class is discovered, the old array should be
> free'd and the allocated monitors returned to the driver.
> 
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>