powerpc: fix regression of per-CPU DSCR setting
Subsystems (2)
cover powerpc: fix regression of per-CPU DSCR setting
Hello,
This patch corrects a regression on PowerPC CPUs that causes their per-CPU DSCR SPR value (exposed via /sys/devices/system/cpuN/dscr) to be quickly lost during context switching, effectively meaning that the DSCR can no longer be set on a per-CPU basis.
My intent is to restore the functionality of the per-CPU value in a way that is compatible with the newer global default and task-specific DSCR setting system. Users of either the old or new systems should now get pretty much what they expect.
A couple of notes:
I've split an existing "ifdef CONFIG_PPC_STD_MMU_64" block in paca_struct into two parts because it allows dscr_default to be placed into a cache line hole. (This seems be the case even without CONFIG_PPC_STD_MMU_64 being defined.) Comments or ideas on alternative placements are welcome.
PowerPC context switching is touched but there should not be any performance cost; if anything it should get slightly faster due to the per-CPU value being easier to access than the old global default.
Sam Bobroff (3):
powerpc: Split __SYSFS_SPRSETUP macro
powerpc: fix regression of per-CPU DSCR setting
powerpc: Document sysfs DSCR interface
Documentation/ABI/stable/sysfs-devices-system-cpu | 25 ++++++++++ arch/powerpc/include/asm/paca.h | 3 ++ arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/entry_64.S | 9 +--- arch/powerpc/kernel/sysfs.c | 51 +++++++++++++-------- arch/powerpc/kernel/tm.S | 16 ++----- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 3 +- 7 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 Documentation/ABI/stable/sysfs-devices-system-cpu
Signature · 1 line
1.7.10.4
PATCH 1/3 powerpc: Split __SYSFS_SPRSETUP macro
Split the __SYSFS_SPRSETUP macro into two parts so that registers requiring custom read and write functions can use common code for their show and store functions.
--- arch/powerpc/kernel/sysfs.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
arch/powerpc/kernel/sysfs.c +13 -6
@@ -404,7 +404,7 @@ void ppc_enable_pmcs(void) }EXPORT_SYMBOL (ppc_enable_pmcs); -#define __SYSFS_SPRSETUP (NAME ,ADDRESS ,EXTRA ) \ +#define __SYSFS_SPRSETUP_READ_WRITE (NAME ,ADDRESS ,EXTRA ) \ static void read_##NAME(void *val) \ { \ *(unsigned long *)val = mfspr(ADDRESS); \
@@ -413,7 +413,9 @@ static void write_##NAME(void *val) \ { \EXTRA ; \mtspr (ADDRESS , *(unsigned long *)val); \ -} \ +} + +#define __SYSFS_SPRSETUP_SHOW_STORE (NAME ) \ static ssize_t show_##NAME(struct device *dev, \ struct device_attribute *attr, \ char *buf) \
@@ -436,10 +438,15 @@ static ssize_t __used \return count; \ } -#define SYSFS_PMCSETUP (NAME ,ADDRESS ) \ - __SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs()) -#define SYSFS_SPRSETUP (NAME ,ADDRESS ) \ - __SYSFS_SPRSETUP(NAME, ADDRESS, ) +#define SYSFS_PMCSETUP (NAME ,ADDRESS ) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ppc_enable_pmcs()) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) +#define SYSFS_SPRSETUP (NAME ,ADDRESS ) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) + +#define SYSFS_SPRSETUP_SHOW_STORE (NAME ) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME)/* Let's define all possible registers, we'll only hook up the ones * that are implemented on the current processor
Signature · 1 line
1.7.10.4
Re: [PATCH 1/3] powerpc: Split __SYSFS_SPRSETUP macro
Quoted 44 lines · Sam Bobroff
Split the
__SYSFS_SPRSETUPmacro into two parts so that registers requiring custom read and write functions can use common code for their show and store functions.Signed-off-by Sam Bobroff <[email protected]>--- arch/powerpc/kernel/sysfs.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)arch/powerpc/kernel/sysfs.c +6
-6@@ -404,7 +404,7 @@ void ppc_enable_pmcs(void) }EXPORT_SYMBOL (ppc_enable_pmcs); -#define __SYSFS_SPRSETUP (NAME ,ADDRESS ,EXTRA ) \ +#define __SYSFS_SPRSETUP_READ_WRITE (NAME ,ADDRESS ,EXTRA ) \ static void read_##NAME(void *val) \ { \ *(unsigned long *)val = mfspr(ADDRESS); \@@ -413,7 +413,9 @@ static void write_##NAME(void *val) \ { \EXTRA ; \mtspr (ADDRESS , *(unsigned long *)val); \ -} \ +} + +#define __SYSFS_SPRSETUP_SHOW_STORE (NAME ) \ static ssize_t show_##NAME(struct device *dev, \ struct device_attribute *attr, \ char *buf) \@@ -436,10 +438,15 @@ static ssize_t __used \return count; \ } -#define SYSFS_PMCSETUP (NAME ,ADDRESS ) \ - __SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs()) -#define SYSFS_SPRSETUP (NAME ,ADDRESS ) \ - __SYSFS_SPRSETUP(NAME, ADDRESS, ) +#define SYSFS_PMCSETUP (NAME ,ADDRESS ) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ppc_enable_pmcs()) \
arch/powerpc/kernel/sysfs.c static ssize_t __used \ · line 452
Quoted 10 lines
arch/powerpc/kernel/sysfs.c +7
-0+ __SYSFS_SPRSETUP_SHOW_STORE(NAME) +#define SYSFS_SPRSETUP (NAME ,ADDRESS ) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) + +#define SYSFS_SPRSETUP_SHOW_STORE (NAME ) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME)/* Let's define all possible registers, we'll only hook up the ones * that are implemented on the current processor
PATCH 2/3 powerpc: fix regression of per-CPU DSCR setting
In reply to Sam BobroffSince commit "efcac65 powerpc: Per process DSCR + some fixes (try#4)" it is no longer possible to set the DSCR on a per-CPU basis.
The old behaviour was to minipulate the DSCR SPR directly but this is no longer sufficient: the value is quickly overwritten by context switching.
This patch stores the per-CPU DSCR value in a kernel variable rather than directly in the SPR and it is used whenever a process has not set the DSCR itself. The sysfs interface (/sys/devices/system/cpu/cpuN/dscr) is unchanged.
Writes to the old global default (/sys/devices/system/cpu/dscr_default) now set all of the per-CPU values and reads return the last written value.
The new per-CPU default is added to the paca_struct and is used everywhere outside of sysfs.c instead of the old global default.
--- arch/powerpc/include/asm/paca.h | 3 +++ arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/entry_64.S | 9 +-------- arch/powerpc/kernel/sysfs.c | 32 ++++++++++++++++++------------- arch/powerpc/kernel/tm.S | 16 ++++------------ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 3 +-- 6 files changed, 29 insertions(+), 35 deletions(-)
arch/powerpc/include/asm/paca.h +3 -0
@@ -92,7 +92,10 @@ struct paca_struct {struct slb_shadow *slb_shadow_ptr;struct dtl_entry *dispatch_log;struct dtl_entry *dispatch_log_end; +#endif /* CONFIG_PPC_STD_MMU_64 */ +u64 dscr_default;/* per-CPU default DSCR */ +#ifdef CONFIG_PPC_STD_MMU_64 /* * Now, starting in cacheline 2, the exception save areas */
arch/powerpc/kernel/asm-offsets.c +1 -0
@@ -247,6 +247,7 @@ int main(void)#endif DEFINE (PACAHWCPUID , offsetof(struct paca_struct , hw_cpu_id));DEFINE (PACAKEXECSTATE , offsetof(struct paca_struct , kexec_state)); +DEFINE (PACA_DSCR , offsetof(struct paca_struct , dscr_default));DEFINE (PACA_STARTTIME , offsetof(struct paca_struct , starttime));DEFINE (PACA_STARTTIME_USER , offsetof(struct paca_struct , starttime_user));DEFINE (PACA_USER_TIME , offsetof(struct paca_struct , user_time));
arch/powerpc/kernel/entry_64.S +1 -8
@@ -387,12 +387,6 @@ _GLOBAL(ret_from_kernel_thread) li r3,0 b syscall_exit - .section ".toc","aw" -DSCR_DEFAULT: - .tc dscr_default[TC],dscr_default - - .section ".text" - /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state
@@ -577,11 +571,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #ifdef CONFIG_PPC64 BEGIN_FTR_SECTION lwz r6,THREAD_DSCR_INHERIT(r4) - ld r7,DSCR_DEFAULT@toc(2) ld r0,THREAD_DSCR(r4) cmpwi r6,0 bne 1f - ld r0,0(r7) + ld r0,PACA_DSCR(r13) 1: BEGIN_FTR_SECTION_NESTED(70) mfspr r8, SPRN_FSCR
arch/powerpc/kernel/sysfs.c +19 -13
@@ -484,7 +484,6 @@ SYSFS_PMCSETUP(pmc8, SPRN_PMC8);SYSFS_PMCSETUP (mmcra,SPRN_MMCRA );SYSFS_SPRSETUP (purr,SPRN_PURR );SYSFS_SPRSETUP (spurr,SPRN_SPURR ); -SYSFS_SPRSETUP (dscr,SPRN_DSCR );SYSFS_SPRSETUP (pir,SPRN_PIR );/*
@@ -494,12 +493,27 @@ SYSFS_SPRSETUP(pir, SPRN_PIR);*/ static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static DEVICE_ATTR(spurr, 0400, show_spurr, NULL); -static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr); static DEVICE_ATTR(purr, 0400, show_purr, store_purr); static DEVICE_ATTR(pir, 0400, show_pir, NULL); -unsigned long dscr_default =0 ; -EXPORT_SYMBOL (dscr_default); +static unsigned long dscr_default; + +static void read_dscr (void *val) +{ + *(unsigned long *)val =get_paca ()->dscr_default; +} + +static void write_dscr (void *val) +{ +get_paca ()->dscr_default = *(unsigned long *)val; +if (!current->thread.dscr_inherit) { + current->thread.dscr = *(unsigned long *)val; +mtspr (SPRN_DSCR , *(unsigned long *)val); + } +} + +SYSFS_SPRSETUP_SHOW_STORE (dscr); +static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);static void add_write_permission_dev_attr (struct device_attribute *attr) {
@@ -512,14 +526,6 @@ static ssize_t show_dscr_default(struct device *dev,return sprintf (buf,"%lx\n" , dscr_default); } -static void update_dscr (void *dummy) -{ -if (!current->thread.dscr_inherit) { - current->thread.dscr = dscr_default; -mtspr (SPRN_DSCR , dscr_default); - } -} -static ssize_t __used store_dscr_default (struct device *dev,struct device_attribute *attr,const char *buf,size_t count)
@@ -532,7 +538,7 @@ static ssize_t __used store_dscr_default(struct device *dev,return -EINVAL ; dscr_default = val; -on_each_cpu (update_dscr,NULL ,1 ); +on_each_cpu (write_dscr, &val,1 );return count; }
arch/powerpc/kernel/tm.S +4 -12
@@ -78,12 +78,6 @@ _GLOBAL(tm_abort) TABORT(R3) blr - .section ".toc","aw" -DSCR_DEFAULT: - .tc dscr_default[TC],dscr_default - - .section ".text" - /* void tm_reclaim(struct thread_struct *thread, * unsigned long orig_msr, * uint8_t cause)
@@ -298,9 +292,8 @@ dont_backup_fp: mtlr r0 ld r2, STK_GOT(r1) - /* Load system default DSCR */ - ld r4, DSCR_DEFAULT@toc(r2) - ld r0, 0(r4) + /* Load CPU's default DSCR */ + ld r0, PACA_DSCR(r13) mtspr SPRN_DSCR, r0 blr
@@ -479,9 +472,8 @@ restore_gprs: mtlr r0 ld r2, STK_GOT(r1) - /* Load system default DSCR */ - ld r4, DSCR_DEFAULT@toc(r2) - ld r0, 0(r4) + /* Load CPU's default DSCR */ + ld r0, PACA_DSCR(r13) mtspr SPRN_DSCR, r0 blr
arch/powerpc/kvm/book3s_hv_rmhandlers.S +1 -2
@@ -286,8 +286,7 @@ kvm_start_guest: beq kvm_no_guest /* Set HSTATE_DSCR(r13) to something sensible */ - LOAD_REG_ADDR(r6, dscr_default) - ld r6, 0(r6) + ld r6, PACA_DSCR(r13) std r6, HSTATE_DSCR(r13) bl kvmppc_hv_entry
Signature · 1 line
1.7.10.4
Quoted 142 lines · Sam Bobroff
Since commit "efcac65 powerpc: Per process DSCR + some fixes (try#4)" it is no longer possible to set the DSCR on a per-CPU basis.
The old behaviour was to minipulate the DSCR SPR directly but this is no longer sufficient: the value is quickly overwritten by context switching.
This patch stores the per-CPU DSCR value in a kernel variable rather than directly in the SPR and it is used whenever a process has not set the DSCR itself. The sysfs interface (
/sys/devices/system/cpu/cpuN/dscr) is unchanged.Writes to the old global default (
/sys/devices/system/cpu/dscr_default) now set all of the per-CPU values and reads return the last written value.The new per-CPU default is added to the
paca_structand is used everywhere outside ofsysfs.cinstead of the old global default.Signed-off-by Sam Bobroff <[email protected]>--- arch/powerpc/include/asm/paca.h | 3 +++ arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/entry_64.S | 9 +-------- arch/powerpc/kernel/sysfs.c | 32 ++++++++++++++++++------------- arch/powerpc/kernel/tm.S | 16 ++++------------ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 3 +-- 6 files changed, 29 insertions(+), 35 deletions(-)arch/powerpc/include/asm/paca.h +3
-0@@ -92,7 +92,10 @@ struct paca_struct {struct slb_shadow *slb_shadow_ptr;struct dtl_entry *dispatch_log;struct dtl_entry *dispatch_log_end; +#endif /* CONFIG_PPC_STD_MMU_64 */ +u64 dscr_default;/* per-CPU default DSCR */ +#ifdef CONFIG_PPC_STD_MMU_64 /* * Now, starting in cacheline 2, the exception save areas */ arch/powerpc/kernel/asm-offsets.c +1
-0@@ -247,6 +247,7 @@ int main(void)#endif DEFINE (PACAHWCPUID , offsetof(struct paca_struct , hw_cpu_id));DEFINE (PACAKEXECSTATE , offsetof(struct paca_struct , kexec_state)); +DEFINE (PACA_DSCR , offsetof(struct paca_struct , dscr_default));DEFINE (PACA_STARTTIME , offsetof(struct paca_struct , starttime));DEFINE (PACA_STARTTIME_USER , offsetof(struct paca_struct , starttime_user));DEFINE (PACA_USER_TIME , offsetof(struct paca_struct , user_time));arch/powerpc/kernel/entry_64.S +1
-8@@ -387,12 +387,6 @@ _GLOBAL(ret_from_kernel_thread) li r3,0 b syscall_exit - .section ".toc","aw" -DSCR_DEFAULT: - .tc dscr_default[TC],dscr_default - - .section ".text" - /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state@@ -577,11 +571,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #ifdef CONFIG_PPC64 BEGIN_FTR_SECTION lwz r6,THREAD_DSCR_INHERIT(r4) - ld r7,DSCR_DEFAULT@toc(2) ld r0,THREAD_DSCR(r4) cmpwi r6,0 bne 1f - ld r0,0(r7) + ld r0,PACA_DSCR(r13) 1: BEGIN_FTR_SECTION_NESTED(70) mfspr r8, SPRN_FSCRarch/powerpc/kernel/sysfs.c +18
-12@@ -484,7 +484,6 @@ SYSFS_PMCSETUP(pmc8, SPRN_PMC8);SYSFS_PMCSETUP (mmcra,SPRN_MMCRA );SYSFS_SPRSETUP (purr,SPRN_PURR );SYSFS_SPRSETUP (spurr,SPRN_SPURR ); -SYSFS_SPRSETUP (dscr,SPRN_DSCR );SYSFS_SPRSETUP (pir,SPRN_PIR );/* @@ -494,12 +493,27 @@ SYSFS_SPRSETUP(pir, SPRN_PIR);*/ static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static DEVICE_ATTR(spurr, 0400, show_spurr, NULL); -static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr); static DEVICE_ATTR(purr, 0400, show_purr, store_purr); static DEVICE_ATTR(pir, 0400, show_pir, NULL); -unsigned long dscr_default =0 ; -EXPORT_SYMBOL (dscr_default); +static unsigned long dscr_default; + +static void read_dscr (void *val) +{ + *(unsigned long *)val =get_paca ()->dscr_default; +} + +static void write_dscr (void *val) +{ +get_paca ()->dscr_default = *(unsigned long *)val; +if (!current->thread.dscr_inherit) { + current->thread.dscr = *(unsigned long *)val; +mtspr (SPRN_DSCR , *(unsigned long *)val); + } +} + +SYSFS_SPRSETUP_SHOW_STORE (dscr); +static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);static void add_write_permission_dev_attr (struct device_attribute *attr) {@@ -512,14 +526,6 @@ static ssize_t show_dscr_default(struct device *dev,return sprintf (buf,"%lx\n" , dscr_default); } -static void update_dscr (void *dummy) -{ -if (!current->thread.dscr_inherit) { - current->thread.dscr = dscr_default; -mtspr (SPRN_DSCR , dscr_default); - } -} -static ssize_t __used store_dscr_default (struct device *dev,struct device_attribute *attr,const char *buf,size_t count)
arch/powerpc/kernel/sysfs.c static ssize_t __used store_dscr_default(struct device *dev, · line 544
Quoted 8 lines
arch/powerpc/kernel/sysfs.c +1
-1@@ -532,7 +538,7 @@ static ssize_t __used store_dscr_default(struct device *dev,return -EINVAL ; dscr_default = val; -on_each_cpu (update_dscr,NULL ,1 ); +on_each_cpu (write_dscr, &val,1 );return count; }
Quoted 56 lines
arch/powerpc/kernel/tm.S +4
-12@@ -78,12 +78,6 @@ _GLOBAL(tm_abort) TABORT(R3) blr - .section ".toc","aw" -DSCR_DEFAULT: - .tc dscr_default[TC],dscr_default - - .section ".text" - /* void tm_reclaim(struct thread_struct *thread, * unsigned long orig_msr, * uint8_t cause)@@ -298,9 +292,8 @@ dont_backup_fp: mtlr r0 ld r2, STK_GOT(r1) - /* Load system default DSCR */ - ld r4, DSCR_DEFAULT@toc(r2) - ld r0, 0(r4) + /* Load CPU's default DSCR */ + ld r0, PACA_DSCR(r13) mtspr SPRN_DSCR, r0 blr@@ -479,9 +472,8 @@ restore_gprs: mtlr r0 ld r2, STK_GOT(r1) - /* Load system default DSCR */ - ld r4, DSCR_DEFAULT@toc(r2) - ld r0, 0(r4) + /* Load CPU's default DSCR */ + ld r0, PACA_DSCR(r13) mtspr SPRN_DSCR, r0 blrarch/powerpc/kvm/book3s_hv_rmhandlers.S +1
-2@@ -286,8 +286,7 @@ kvm_start_guest: beq kvm_no_guest /* Set HSTATE_DSCR(r13) to something sensible */ - LOAD_REG_ADDR(r6, dscr_default) - ld r6, 0(r6) + ld r6, PACA_DSCR(r13) std r6, HSTATE_DSCR(r13) bl kvmppc_hv_entry
PATCH 3/3 powerpc: Document sysfs DSCR interface
In reply to Sam BobroffAdd some documentation about ...
/sys/devices/system/cpu/dscr_default/sys/devices/system/cpu/cpuN/dscr
... to Documentation/ABI/stable.
--- Documentation/ABI/stable/sysfs-devices-system-cpu | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/ABI/stable/sysfs-devices-system-cpu
Documentation/ABI/stable/sysfs-devices-system-cpu new file +25 -0
@@ -0,0 +1,25 @@ +What: /sys/devices/system/cpu/dscr_default +Date: 13-May-2014 +KernelVersion: v3.15.0 +Contact: +Description: Writes are equivalent to writing to + /sys/devices/system/cpu/cpuN/dscr on all CPUs. + Reads return the last written value or 0. + This value is not a global default: it is a way to set + all per-CPU defaults at the same time. +Values: 64 bit unsigned integer (bit field) + +What: /sys/devices/system/cpu/cpu[0-9]+/dscr +Date: 13-May-2014 +KernelVersion: v3.15.0 +Contact: +Description: Default value for the Data Stream Control Register (DSCR) on + a CPU. + This default value is used when the kernel is executing and + for any process that has not set the DSCR itself. + If a process ever sets the DSCR (via direct access to the + SPR) that value will be persisted for that process and used + on any CPU where it executes (overriding the value described + here). + If set by a process it will be inherited by child processes. +Values: 64 bit unsigned integer (bit field)
Signature · 1 line
1.7.10.4