[PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values

Ben Horgan posted 47 patches 4 weeks ago
There is a newer version of this series
[PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
Posted by Ben Horgan 4 weeks ago
From: James Morse <james.morse@arm.com>

Care must be taken when modifying the PARTID and PMG of a task in any
per-task structure as writing these values may race with the task being
scheduled in, and reading the modified values.

Add helpers to set the task properties, and the CPU default value.  These
use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval() to
avoid causing torn values.

CC: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since rfc:
Keep comment attached to mpam_get_regval()
Add internal helper, __mpam_regval() (Jonathan)
---
 arch/arm64/include/asm/mpam.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 7b3d3abad162..c9b73f1af7ce 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -4,6 +4,7 @@
 #ifndef __ASM__MPAM_H
 #define __ASM__MPAM_H
 
+#include <linux/bitfield.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 #include <linux/sched.h>
@@ -22,6 +23,22 @@ DECLARE_PER_CPU(u64, arm64_mpam_current);
  */
 extern u64 arm64_mpam_global_default;
 
+static inline u64 __mpam_regval(u16 partid_d, u16 partid_i, u8 pmg_d, u8 pmg_i)
+{
+	return FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d) |
+		FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i) |
+		FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d) |
+		FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
+}
+
+static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
+					 u8 pmg_d, u8 pmg_i)
+{
+	u64 default_val = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
+
+	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
+}
+
 /*
  * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
  * which may race with reads in mpam_thread_switch(). Ensure only one of the old
@@ -36,6 +53,17 @@ static inline u64 mpam_get_regval(struct task_struct *tsk)
 	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
 }
 
+static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
+					    u16 partid_d, u16 partid_i,
+					    u8 pmg_d, u8 pmg_i)
+{
+#ifdef CONFIG_ARM64_MPAM
+	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
+
+	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
+#endif
+}
+
 static inline void mpam_thread_switch(struct task_struct *tsk)
 {
 	u64 oldregval;
-- 
2.43.0
Re: [PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
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>
> 
> Care must be taken when modifying the PARTID and PMG of a task in any
> per-task structure as writing these values may race with the task being
> scheduled in, and reading the modified values.
> 
> Add helpers to set the task properties, and the CPU default value.  These
> use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval() to
> avoid causing torn values.
> 
> CC: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since rfc:
> Keep comment attached to mpam_get_regval()
> Add internal helper, __mpam_regval() (Jonathan)
> ---
>   arch/arm64/include/asm/mpam.h | 28 ++++++++++++++++++++++++++++
>   1 file changed, 28 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> index 7b3d3abad162..c9b73f1af7ce 100644
> --- a/arch/arm64/include/asm/mpam.h
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -4,6 +4,7 @@
>   #ifndef __ASM__MPAM_H
>   #define __ASM__MPAM_H
>   
> +#include <linux/bitfield.h>
>   #include <linux/jump_label.h>
>   #include <linux/percpu.h>
>   #include <linux/sched.h>
> @@ -22,6 +23,22 @@ DECLARE_PER_CPU(u64, arm64_mpam_current);
>    */
>   extern u64 arm64_mpam_global_default;
>   
> +static inline u64 __mpam_regval(u16 partid_d, u16 partid_i, u8 pmg_d, u8 pmg_i)
> +{
> +	return FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d) |
> +		FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i) |
> +		FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d) |
> +		FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
> +}

Nitpick: Alignment issues in the lines for 2nd/3rd/4th FIELD_PREP().

	return FIELD_PREP(...) |
	       FIELD_PREP(...) |
                FIELD_PREP(...) |
                FIELD_PREP(...);

> +
> +static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
> +					 u8 pmg_d, u8 pmg_i)
> +{
> +	u64 default_val = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
> +
> +	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
> +}
> +

per_cpu(arm64_mpam_default) won't be reachable until CONFIG_ARM64_MPAM is set.
So I think both mpam_set_cpu_defaults() and __mpam_regval() need to be protected
by '#ifdef CONFIG_ARM64_MPAM ... #endif'.

>   /*
>    * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
>    * which may race with reads in mpam_thread_switch(). Ensure only one of the old
> @@ -36,6 +53,17 @@ static inline u64 mpam_get_regval(struct task_struct *tsk)
>   	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>   }
>   
> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
> +					    u16 partid_d, u16 partid_i,
> +					    u8 pmg_d, u8 pmg_i)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
> +
> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
> +#endif
> +}
> +
>   static inline void mpam_thread_switch(struct task_struct *tsk)
>   {
>   	u64 oldregval;

Thanks,
Gavin
Re: [PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
Posted by Ben Horgan 3 weeks ago
Hi Gavin,

On 1/19/26 07:01, Gavin Shan wrote:
> Hi Ben,
> 
> On 1/13/26 12:58 AM, Ben Horgan wrote:
>> From: James Morse <james.morse@arm.com>
>>
>> Care must be taken when modifying the PARTID and PMG of a task in any
>> per-task structure as writing these values may race with the task being
>> scheduled in, and reading the modified values.
>>
>> Add helpers to set the task properties, and the CPU default value.  These
>> use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval() to
>> avoid causing torn values.
>>
>> CC: Dave Martin <Dave.Martin@arm.com>
>> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
>> Signed-off-by: James Morse <james.morse@arm.com>
>> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
>> ---
>> Changes since rfc:
>> Keep comment attached to mpam_get_regval()
>> Add internal helper, __mpam_regval() (Jonathan)
>> ---
>>   arch/arm64/include/asm/mpam.h | 28 ++++++++++++++++++++++++++++
>>   1 file changed, 28 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/
>> mpam.h
>> index 7b3d3abad162..c9b73f1af7ce 100644
>> --- a/arch/arm64/include/asm/mpam.h
>> +++ b/arch/arm64/include/asm/mpam.h
>> @@ -4,6 +4,7 @@
>>   #ifndef __ASM__MPAM_H
>>   #define __ASM__MPAM_H
>>   +#include <linux/bitfield.h>
>>   #include <linux/jump_label.h>
>>   #include <linux/percpu.h>
>>   #include <linux/sched.h>
>> @@ -22,6 +23,22 @@ DECLARE_PER_CPU(u64, arm64_mpam_current);
>>    */
>>   extern u64 arm64_mpam_global_default;
>>   +static inline u64 __mpam_regval(u16 partid_d, u16 partid_i, u8
>> pmg_d, u8 pmg_i)
>> +{
>> +    return FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d) |
>> +        FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i) |
>> +        FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d) |
>> +        FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
>> +}
> 
> Nitpick: Alignment issues in the lines for 2nd/3rd/4th FIELD_PREP().
> 
>     return FIELD_PREP(...) |
>            FIELD_PREP(...) |
>                FIELD_PREP(...) |
>                FIELD_PREP(...);

Sure, I'll align these.

> 
>> +
>> +static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16
>> partid_i,
>> +                     u8 pmg_d, u8 pmg_i)
>> +{
>> +    u64 default_val = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
>> +
>> +    WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
>> +}
>> +
> 
> per_cpu(arm64_mpam_default) won't be reachable until CONFIG_ARM64_MPAM
> is set.
> So I think both mpam_set_cpu_defaults() and __mpam_regval() need to be
> protected
> by '#ifdef CONFIG_ARM64_MPAM ... #endif'.

I'll move the #ifdef CONFIG_ARM64_MPAM up to cover these.

> 
>>   /*
>>    * The resctrl filesystem writes to the partid/pmg values for
>> threads and CPUs,
>>    * which may race with reads in mpam_thread_switch(). Ensure only
>> one of the old
>> @@ -36,6 +53,17 @@ static inline u64 mpam_get_regval(struct
>> task_struct *tsk)
>>       return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>>   }
>>   +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
>> +                        u16 partid_d, u16 partid_i,
>> +                        u8 pmg_d, u8 pmg_i)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +    u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
>> +
>> +    WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
>> +#endif
>> +}
>> +
>>   static inline void mpam_thread_switch(struct task_struct *tsk)
>>   {
>>       u64 oldregval;
> 
> Thanks,
> Gavin
> 

Thanks,

Ben

Re: [PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
Posted by Catalin Marinas 3 weeks, 4 days ago
On Mon, Jan 12, 2026 at 04:58:38PM +0000, Ben Horgan wrote:
> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
> +					    u16 partid_d, u16 partid_i,
> +					    u8 pmg_d, u8 pmg_i)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
> +
> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
> +#endif
> +}

Isn't this function, together with mpam_thread_switch(), in an enclosing
#ifdef already?

> +
>  static inline void mpam_thread_switch(struct task_struct *tsk)
>  {
>  	u64 oldregval;
> -- 
> 2.43.0
> 

-- 
Catalin
Re: [PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
Posted by Ben Horgan 3 weeks ago
Hi Catalin,

On 1/15/26 19:13, Catalin Marinas wrote:
> On Mon, Jan 12, 2026 at 04:58:38PM +0000, Ben Horgan wrote:
>> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
>> +					    u16 partid_d, u16 partid_i,
>> +					    u8 pmg_d, u8 pmg_i)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
>> +
>> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
>> +#endif
>> +}
> 
> Isn't this function, together with mpam_thread_switch(), in an enclosing
> #ifdef already?

Yes, I'll remove the inner #ifdef.

Thanks,

Ben
Re: [PATCH v3 11/47] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
Posted by Gavin Shan 3 weeks ago
On 1/16/26 3:13 AM, Catalin Marinas wrote:
> On Mon, Jan 12, 2026 at 04:58:38PM +0000, Ben Horgan wrote:
>> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
>> +					    u16 partid_d, u16 partid_i,
>> +					    u8 pmg_d, u8 pmg_i)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
>> +
>> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
>> +#endif
>> +}
> 
> Isn't this function, together with mpam_thread_switch(), in an enclosing
> #ifdef already?
> 

I think Catalin is correct that this ifdef inside mpam_set_task_partid_pmg()
can be dropped.

>> +
>>   static inline void mpam_thread_switch(struct task_struct *tsk)
>>   {
>>   	u64 oldregval;
>> -- 
>> 2.43.0
>>

Thanks,
Gavin