diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-19 17:37:52 +0300 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-19 17:37:52 +0300 |
| commit | 91981f96d2831a73cd4dbe4383b4d7e1dcdfcc06 (patch) | |
| tree | 97b0725070b92a1551ed9b9d3133603cd545bd7b | |
| parent | f32a375eccb7b27bccc57dee45befff6e3b3d4b2 (diff) | |
| parent | 42f252f5a646866a95f025863c8b201042494ba1 (diff) | |
| download | linux-91981f96d2831a73cd4dbe4383b4d7e1dcdfcc06.tar.xz | |
Merge tag 'powerpc-7.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Madhavan Srinivasan:
- Enable GENERIC_ENTRY feature
- Add missing property in DTS for mpc83xx platform
- Enable building of DTB based on platfrom Kconfig
- Add powerpc64 JIT support for timed may_goto
- Add timeout to RTAS busy-wait loops
- Simplify cpumask api usage for cpuinfo display
- implement get_direction() in cpm1 (8xx platform)
- MAINTAINERS file update for power VMX AES entries
- Fixes to handle preempt count
- Restore KUAP registers on syscall restart exit
- define MIN_RMA in bytes rather than MB
- misc fixes and cleanups
Thanks to Aboorva Devarajan, Adriano Vero, Amit Machhiwal, Anushree
Mathur, Bartosz Golaszewski, Christophe Leroy (CS GROUP), David Gow,
Jinjie Ruan, J. Neuschäfer, Linus Walleij, Mahesh Salgaonkar, Mukesh
Kumar Chaurasiya (IBM), Ritesh Harjani (IBM), Saket Kumar Bhaskar,
Samir M, Sayali Patil, Shirisha G, Shivang Upadhyay, Shrikanth Hegde,
Sourabh Jain, Thorsten Blum, Venkat Rao Bagalkote, and Yury Norov.
* tag 'powerpc-7.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (32 commits)
powerpc/fadump: define MIN_RMA in bytes rather than MB
powerpc: Restore KUAP registers on syscall restart exit
powerpc/kexec: fix double get_cpu() imbalance in kexec_prepare_cpus
powerpc/powernv: fix preempt count leak in pnv_kexec_wait_secondaries_down
powerpc/perf: fix preempt count underflow in fsl_emb_pmu_del
powerpc/boot: Allow text relocations for pseries wrapper with binutils 2.46+
powerpc: Simplify access_ok()
powerpc/entry: Disable interrupts before irqentry_exit
powerpc/8xx: implement get_direction() in cpm1
powerpc/pseries/lparcfg: Replace deprecated strcpy in parse_system_parameter_string
powerpc: Fix indentation and replace typedef with struct name
powerpc/rtas: Replace one-element array with flexible array member
powerpc: use sysfs_emit{_at} in sysfs show functions
MAINTAINERS: powerpc: update VMX AES entries
ppc/fadump: invoke kmsg_dump in fadump panic path
powerpc/xive: Add warning if target CPU not found
powerpc/perf: Use cpumask_intersects api for checking disable path
powerpc: Simplify cpumask api usage for cpuinfo display
powerpc: Use cpumask_next_wrap instead
powerpc/fadump: Add timeout to RTAS busy-wait loops
...
82 files changed, 1242 insertions, 1068 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 16ce0c0537e8..9f4ddd4c69f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12428,13 +12428,13 @@ L: linux-crypto@vger.kernel.org S: Supported F: arch/powerpc/crypto/Kconfig F: arch/powerpc/crypto/Makefile -F: arch/powerpc/crypto/aes.c F: arch/powerpc/crypto/aes_cbc.c F: arch/powerpc/crypto/aes_ctr.c F: arch/powerpc/crypto/aes_xts.c -F: arch/powerpc/crypto/aesp8-ppc.* +F: arch/powerpc/crypto/aesp8-ppc.h F: arch/powerpc/crypto/ppc-xlate.pl F: arch/powerpc/crypto/vmx.c +F: lib/crypto/powerpc/aesp8-ppc.pl F: lib/crypto/powerpc/gf128hash.h F: lib/crypto/powerpc/ghashp8-ppc.pl diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c99fd8335ddc..f7ce5fff81f0 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -206,6 +206,7 @@ config PPC select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_VULNERABILITIES if PPC_BARRIER_NOSPEC select GENERIC_EARLY_IOREMAP + select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY select GENERIC_IDLE_POLL_SETUP select GENERIC_IOREMAP diff --git a/arch/powerpc/boot/dts/Makefile b/arch/powerpc/boot/dts/Makefile index 0cd0d8558b47..1e61a951cebe 100644 --- a/arch/powerpc/boot/dts/Makefile +++ b/arch/powerpc/boot/dts/Makefile @@ -3,3 +3,76 @@ subdir-y += fsl dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(src)/%.dts,%.dtb, $(wildcard $(src)/*.dts)) + +# PPC44x platforms +dtb-$(CONFIG_PPC44x_SIMPLE) += arches.dtb bamboo.dtb bluestone.dtb glacier.dtb +dtb-$(CONFIG_PPC44x_SIMPLE) += eiger.dtb katmai.dtb rainier.dtb redwood.dtb +dtb-$(CONFIG_PPC44x_SIMPLE) += sequoia.dtb taishan.dtb yosemite.dtb icon.dtb +dtb-$(CONFIG_EBONY) += ebony.dtb +dtb-$(CONFIG_SAM440EP) += sam440ep.dtb +dtb-$(CONFIG_WARP) += warp.dtb +dtb-$(CONFIG_ISS4xx) += iss4xx.dtb iss4xx-mpic.dtb +dtb-$(CONFIG_CANYONLANDS) += canyonlands.dtb +dtb-$(CONFIG_CURRITUCK) += currituck.dtb +dtb-$(CONFIG_AKEBONO) += akebono.dtb +dtb-$(CONFIG_FSP2) += fsp2.dtb + +# Embedded 6xx platforms +dtb-$(CONFIG_LINKSTATION) += kuroboxHG.dtb kuroboxHD.dtb +dtb-$(CONFIG_STORCENTER) += storcenter.dtb +dtb-$(CONFIG_PPC_HOLLY) += holly.dtb +dtb-$(CONFIG_GAMECUBE) += gamecube.dtb +dtb-$(CONFIG_WII) += wii.dtb +dtb-$(CONFIG_MVME5100) += mvme5100.dtb + +# MPC8xx platforms +dtb-$(CONFIG_MPC885ADS) += mpc885ads.dtb +dtb-$(CONFIG_MPC86XADS) += mpc866ads.dtb +dtb-$(CONFIG_PPC_EP88XC) += ep88xc.dtb +dtb-$(CONFIG_PPC_ADDER875) += adder875-redboot.dtb adder875-uboot.dtb +dtb-$(CONFIG_TQM8XX) += tqm8xx.dtb + +# MPC512x platforms +dtb-$(CONFIG_MPC5121_ADS) += mpc5121ads.dtb +dtb-$(CONFIG_MPC512x_GENERIC) += mpc5125twr.dtb ac14xx.dts +dtb-$(CONFIG_PDM360NG) += pdm360ng.dtb + +# MPC5200 platforms +dtb-$(CONFIG_PPC_MPC5200_SIMPLE) += a3m071.dtb a4m072.dtb charon.dtb cm5200.dtb +dtb-$(CONFIG_PPC_MPC5200_SIMPLE) += digsy_mtc.dtb motionpro.dtb mucmc52.dtb +dtb-$(CONFIG_PPC_MPC5200_SIMPLE) += o2d.dtb o2d300.dtb o2dnt2.dtb o2i.dtb +dtb-$(CONFIG_PPC_MPC5200_SIMPLE) += o2mnt.dtb o3dnt.dtb pcm030.dtb pcm032.dtb +dtb-$(CONFIG_PPC_MPC5200_SIMPLE) += tqm5200.dtb uc101.dtb +dtb-$(CONFIG_PPC_LITE5200) += lite5200.dtb lite5200b.dtb +dtb-$(CONFIG_PPC_MEDIA5200) += media5200.dtb + +# MPC82xx platforms +dtb-$(CONFIG_EP8248E) += ep8248e.dtb +dtb-$(CONFIG_MGCOGE) += mgcoge.dtb + +# MPC83xx platforms +dtb-$(CONFIG_MPC830x_RDB) += mpc8308rdb.dtb mpc8308_p1m.dtb +dtb-$(CONFIG_MPC831x_RDB) += mpc8313erdb.dtb mpc8315erdb.dtb +dtb-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.dtb +dtb-$(CONFIG_MPC834x_ITX) += mpc8349emitx.dtb mpc8349emitxgp.dtb +dtb-$(CONFIG_ASP834x) += asp834x-redboot.dtb +dtb-$(CONFIG_MPC836x_RDK) += mpc836x_rdk.dtb +dtb-$(CONFIG_KMETER1) += kmeter1.dtb +dtb-$(CONFIG_MPC837x_RDB) += mpc8377_rdb.dtb mpc8378_rdb.dtb mpc8379_rdb.dtb +dtb-$(CONFIG_MPC837x_RDB) += mpc8377_wlan.dtb + +# MPC85xx platforms +dtb-$(CONFIG_STX_GP3) += stx_gp3_8560.dtb stxssa8555.dtb +dtb-$(CONFIG_TQM85xx) += tqm8540.dtb tqm8541.dtb tqm8548.dtb +dtb-$(CONFIG_TQM85xx) += tqm8548-bigflash.dtb tqm8555.dtb tqm8560.dtb +dtb-$(CONFIG_SOCRATES) += socrates.dtb +dtb-$(CONFIG_KSI8560) += ksi8560.dtb +dtb-$(CONFIG_XES_MPC85xx) += xcalibur1501.dtb xpedite5200.dtb +dtb-$(CONFIG_XES_MPC85xx) += xpedite5200_xmon.dtb xpedite5301.dtb +dtb-$(CONFIG_XES_MPC85xx) += xpedite5330.dtb xpedite5370.dtb +dtb-$(CONFIG_PPC_P2020) += turris1x.dtb + +# Misc. platforms +dtb-$(CONFIG_PPC_MICROWATT) += microwatt.dtb +dtb-$(CONFIG_AMIGAONE) += amigaone.dtb +dtb-$(CONFIG_PPC_PS3) += ps3.dtb diff --git a/arch/powerpc/boot/dts/fsl/Makefile b/arch/powerpc/boot/dts/fsl/Makefile index d3ecdf14bc42..d2cc8e1f007e 100644 --- a/arch/powerpc/boot/dts/fsl/Makefile +++ b/arch/powerpc/boot/dts/fsl/Makefile @@ -1,3 +1,46 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(src)/%.dts,%.dtb, $(wildcard $(src)/*.dts)) + +# MPC85xx platforms +dtb-$(CONFIG_BSC9131_RDB) += bsc9131rdb.dtb +dtb-$(CONFIG_BSC9132_QDS) += bsc9132qds.dtb +dtb-$(CONFIG_C293_PCIE) += c293pcie.dtb +dtb-$(CONFIG_MPC8536_DS) += mpc8536ds.dtb mpc8536ds_36b.dtb +dtb-$(CONFIG_MPC85xx_DS) += mpc8544ds.dtb mpc8572ds_camp_core0.dtb +dtb-$(CONFIG_MPC85xx_DS) += mpc8572ds_camp_core1.dtb mpc8572ds_36b.dtb +dtb-$(CONFIG_MPC85xx_DS) += mpc8572ds.dtb +dtb-$(CONFIG_MPC85xx_MDS) += mpc8568mds.dtb mpc8569mds.dtb p1021mds.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1020mbg-pc_32b.dtb p1020mbg-pc_36b.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1020rdb_36b.dtb p1020rdb.dtb p1020rdb-pc_32b.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1020rdb-pc_36b.dtb p1020rdb-pc_camp_core0.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1020rdb-pc_camp_core1.dtb p1020rdb-pd.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1020utm-pc_32b.dtb p1020utm-pc_36b.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1021rdb-pc_32b.dtb p1021rdb-pc_36b.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1024rdb_32b.dtb p1024rdb_36b.dtb p1025rdb_32b.dtb +dtb-$(CONFIG_MPC85xx_RDB) += p1025rdb_36b.dtb +dtb-$(CONFIG_P1010_RDB) += p1010rdb-pa_36b.dtb p1010rdb-pa.dtb +dtb-$(CONFIG_P1010_RDB) += p1010rdb-pb_36b.dtb p1010rdb-pb.dtb +dtb-$(CONFIG_P1022_DS) += p1022ds_32b.dtb p1022ds_36b.dtb +dtb-$(CONFIG_P1022_RDK) += p1022rdk.dtb +dtb-$(CONFIG_P1023_RDB) += p1023rdb.dtb +dtb-$(CONFIG_PPC_P2020) += p2020ds.dtb +dtb-$(CONFIG_TWR_P102x) += p1025twr.dtb +dtb-$(CONFIG_CORENET_GENERIC) += b4420qds.dtb b4860qds.dtb cyrus_p5020.dtb +dtb-$(CONFIG_CORENET_GENERIC) += kmcent2.dtb kmcoge4.dtb oca4080.dtb +dtb-$(CONFIG_CORENET_GENERIC) += p2041rdb.dtb p3041ds.dtb p4080ds.dtb +dtb-$(CONFIG_CORENET_GENERIC) += p5020ds.dtb p5040ds.dtb t1023rdb.dtb +dtb-$(CONFIG_CORENET_GENERIC) += t1024qds.dtb t1024rdb.dtb t1040d4rdb.dtb +dtb-$(CONFIG_CORENET_GENERIC) += t1040qds.dtb t1040rdb.dtb t1040rdb-rev-a.dtb +dtb-$(CONFIG_CORENET_GENERIC) += t1042d4rdb.dtb t1042qds.dtb t1042rdb.dtb +dtb-$(CONFIG_CORENET_GENERIC) += t1042rdb_pi.dtb t2080qds.dtb t2080rdb.dtb +dtb-$(CONFIG_CORENET_GENERIC) += t2081qds.dtb t4240qds.dtb t4240rdb.dtb +dtb-$(CONFIG_PPA8548) += ppa8548.dtb +dtb-$(CONFIG_GE_IMP3A) += ge_imp3a.dtb +dtb-$(CONFIG_MVME2500) += mvme2500.dtb + +# MPC86xx platforms +dtb-$(CONFIG_GEF_SBC310) += gef_sbc310.dtb +dtb-$(CONFIG_GEF_SBC610) += gef_sbc610.dtb +dtb-$(CONFIG_GEF_PPC9A) += gef_ppc9a.dtb +dtb-$(CONFIG_MVME7100) += mvme7100.dtb diff --git a/arch/powerpc/boot/dts/mpc8308_p1m.dts b/arch/powerpc/boot/dts/mpc8308_p1m.dts index 41f917f97dab..5af945e1743c 100644 --- a/arch/powerpc/boot/dts/mpc8308_p1m.dts +++ b/arch/powerpc/boot/dts/mpc8308_p1m.dts @@ -9,6 +9,7 @@ / { compatible = "denx,mpc8308_p1m"; + model = "denx,mpc8308_p1m"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts index 39ed26fba410..7b6fd58ffafa 100644 --- a/arch/powerpc/boot/dts/mpc8308rdb.dts +++ b/arch/powerpc/boot/dts/mpc8308rdb.dts @@ -10,6 +10,7 @@ / { compatible = "fsl,mpc8308rdb"; + model = "fsl,mpc8308rdb"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 7ba1159f8803..4757f0d24a2e 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -10,6 +10,7 @@ / { compatible = "fsl,mpc8315erdb"; + model = "MPC8315E-RDB"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts index 4ff38e1a2185..d3d36fbf4e86 100644 --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts @@ -14,6 +14,7 @@ #address-cells = <1>; #size-cells = <1>; compatible = "fsl,mpc8360rdk"; + model = "fsl,mpc8360rdk"; aliases { serial0 = &serial0; diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts index fb311a7eb9f2..f4244a7a3189 100644 --- a/arch/powerpc/boot/dts/mpc8377_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts @@ -9,6 +9,7 @@ / { compatible = "fsl,mpc8377rdb"; + model = "fsl,mpc8377rdb"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc8377_wlan.dts b/arch/powerpc/boot/dts/mpc8377_wlan.dts index f736a15cceff..77ee5f8db14e 100644 --- a/arch/powerpc/boot/dts/mpc8377_wlan.dts +++ b/arch/powerpc/boot/dts/mpc8377_wlan.dts @@ -10,6 +10,7 @@ / { compatible = "fsl,mpc8377wlan"; + model = "fsl,mpc8377wlan"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts index 32c49622b404..9ae4ed5ffcf4 100644 --- a/arch/powerpc/boot/dts/mpc8378_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts @@ -9,6 +9,7 @@ / { compatible = "fsl,mpc8378rdb"; + model = "fsl,mpc8378rdb"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts index 07deb89c5a9b..214611dc6da9 100644 --- a/arch/powerpc/boot/dts/mpc8379_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts @@ -9,6 +9,7 @@ / { compatible = "fsl,mpc8379rdb"; + model = "fsl,mpc8379rdb"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/boot/hack-coff.c b/arch/powerpc/boot/hack-coff.c index a010e124ac4b..6bf0c94302f5 100644 --- a/arch/powerpc/boot/hack-coff.c +++ b/arch/powerpc/boot/hack-coff.c @@ -31,7 +31,7 @@ main(int ac, char **av) int i, nsect; int aoutsz; struct external_filehdr fhdr; - AOUTHDR aout; + struct aouthdr aout; struct external_scnhdr shdr; if (ac != 2) { diff --git a/arch/powerpc/boot/rs6000.h b/arch/powerpc/boot/rs6000.h index 16df8f3c43f1..970754a1f887 100644 --- a/arch/powerpc/boot/rs6000.h +++ b/arch/powerpc/boot/rs6000.h @@ -32,32 +32,30 @@ struct external_filehdr { /********************** AOUT "OPTIONAL HEADER" **********************/ -typedef struct -{ - unsigned char magic[2]; /* type of file */ - unsigned char vstamp[2]; /* version stamp */ - unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */ - unsigned char dsize[4]; /* initialized data " " */ - unsigned char bsize[4]; /* uninitialized data " " */ - unsigned char entry[4]; /* entry pt. */ - unsigned char text_start[4]; /* base of text used for this file */ - unsigned char data_start[4]; /* base of data used for this file */ - unsigned char o_toc[4]; /* address of TOC */ - unsigned char o_snentry[2]; /* section number of entry point */ - unsigned char o_sntext[2]; /* section number of .text section */ - unsigned char o_sndata[2]; /* section number of .data section */ - unsigned char o_sntoc[2]; /* section number of TOC */ - unsigned char o_snloader[2]; /* section number of .loader section */ - unsigned char o_snbss[2]; /* section number of .bss section */ - unsigned char o_algntext[2]; /* .text alignment */ - unsigned char o_algndata[2]; /* .data alignment */ - unsigned char o_modtype[2]; /* module type (??) */ - unsigned char o_cputype[2]; /* cpu type */ - unsigned char o_maxstack[4]; /* max stack size (??) */ - unsigned char o_maxdata[4]; /* max data size (??) */ - unsigned char o_resv2[12]; /* reserved */ -} -AOUTHDR; +struct aouthdr { + unsigned char magic[2]; /* type of file */ + unsigned char vstamp[2]; /* version stamp */ + unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */ + unsigned char dsize[4]; /* initialized data " " */ + unsigned char bsize[4]; /* uninitialized data " " */ + unsigned char entry[4]; /* entry pt. */ + unsigned char text_start[4]; /* base of text used for this file */ + unsigned char data_start[4]; /* base of data used for this file */ + unsigned char o_toc[4]; /* address of TOC */ + unsigned char o_snentry[2]; /* section number of entry point */ + unsigned char o_sntext[2]; /* section number of .text section */ + unsigned char o_sndata[2]; /* section number of .data section */ + unsigned char o_sntoc[2]; /* section number of TOC */ + unsigned char o_snloader[2]; /* section number of .loader section */ + unsigned char o_snbss[2]; /* section number of .bss section */ + unsigned char o_algntext[2]; /* .text alignment */ + unsigned char o_algndata[2]; /* .data alignment */ + unsigned char o_modtype[2]; /* module type (??) */ + unsigned char o_cputype[2]; /* cpu type */ + unsigned char o_maxstack[4]; /* max stack size (??) */ + unsigned char o_maxdata[4]; /* max data size (??) */ + unsigned char o_resv2[12]; /* reserved */ +}; #define AOUTSZ 72 #define SMALL_AOUTSZ (28) @@ -115,10 +113,10 @@ struct external_scnhdr { */ struct external_lineno { union { - char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0 */ char l_paddr[4]; /* (physical) address of line number */ } l_addr; - char l_lnno[2]; /* line number */ + char l_lnno[2]; /* line number */ }; @@ -132,20 +130,19 @@ struct external_lineno { #define E_FILNMLEN 14 /* # characters in a file name */ #define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ -struct external_syment -{ - union { - char e_name[E_SYMNMLEN]; - struct { - char e_zeroes[4]; - char e_offset[4]; - } e; - } e; - char e_value[4]; - char e_scnum[2]; - char e_type[2]; - char e_sclass[1]; - char e_numaux[1]; +struct external_syment { + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; }; @@ -187,7 +184,7 @@ union external_auxent { } x_file; struct { - char x_scnlen[4]; /* section length */ + char x_scnlen[4]; /* section length */ char x_nreloc[2]; /* # relocation entries */ char x_nlinno[2]; /* # line numbers */ } x_scn; @@ -207,7 +204,6 @@ union external_auxent { unsigned char x_stab[4]; unsigned char x_snstab[2]; } x_csect; - }; #define SYMENT struct external_syment diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 1efd1206fcab..25321ce262e8 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -262,6 +262,7 @@ pseries) if [ "$format" != "elf32ppc" ]; then link_address= pie=-pie + notext='-z notext' fi make_space=n ;; diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h new file mode 100644 index 000000000000..fc636c42e89a --- /dev/null +++ b/arch/powerpc/include/asm/entry-common.h @@ -0,0 +1,534 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_PPC_ENTRY_COMMON_H +#define _ASM_PPC_ENTRY_COMMON_H + +#include <asm/cputime.h> +#include <asm/interrupt.h> +#include <asm/runlatch.h> +#include <asm/stacktrace.h> +#include <asm/switch_to.h> +#include <asm/tm.h> + +#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG +/* + * WARN/BUG is handled with a program interrupt so minimise checks here to + * avoid recursion and maximise the chance of getting the first oops handled. + */ +#define INT_SOFT_MASK_BUG_ON(regs, cond) \ +do { \ + if ((user_mode(regs) || (TRAP(regs) != INTERRUPT_PROGRAM))) \ + BUG_ON(cond); \ +} while (0) +#else +#define INT_SOFT_MASK_BUG_ON(regs, cond) +#endif + +#ifdef CONFIG_PPC_BOOK3S_64 +extern char __end_soft_masked[]; +bool search_kernel_soft_mask_table(unsigned long addr); +unsigned long search_kernel_restart_table(unsigned long addr); + +DECLARE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); + +static inline bool is_implicit_soft_masked(struct pt_regs *regs) +{ + if (user_mode(regs)) + return false; + + if (regs->nip >= (unsigned long)__end_soft_masked) + return false; + + return search_kernel_soft_mask_table(regs->nip); +} + +static inline void srr_regs_clobbered(void) +{ + local_paca->srr_valid = 0; + local_paca->hsrr_valid = 0; +} +#else +static inline unsigned long search_kernel_restart_table(unsigned long addr) +{ + return 0; +} + +static inline bool is_implicit_soft_masked(struct pt_regs *regs) +{ + return false; +} + +static inline void srr_regs_clobbered(void) +{ +} +#endif + +static inline void nap_adjust_return(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC_970_NAP + if (unlikely(test_thread_local_flags(_TLF_NAPPING))) { + /* Can avoid a test-and-clear because NMIs do not call this */ + clear_thread_local_flags(_TLF_NAPPING); + regs_set_return_ip(regs, (unsigned long)power4_idle_nap_return); + } +#endif +} + +static __always_inline void booke_load_dbcr0(void) +{ +#ifdef CONFIG_PPC_ADV_DEBUG_REGS + unsigned long dbcr0 = current->thread.debug.dbcr0; + + if (likely(!(dbcr0 & DBCR0_IDM))) + return; + + /* + * Check to see if the dbcr0 register is set up to debug. + * Use the internal debug mode bit to do this. + */ + mtmsr(mfmsr() & ~MSR_DE); + if (IS_ENABLED(CONFIG_PPC32)) { + isync(); + global_dbcr0[smp_processor_id()] = mfspr(SPRN_DBCR0); + } + mtspr(SPRN_DBCR0, dbcr0); + mtspr(SPRN_DBSR, -1); +#endif +} + +static inline void booke_restore_dbcr0(void) +{ +#ifdef CONFIG_PPC_ADV_DEBUG_REGS + unsigned long dbcr0 = current->thread.debug.dbcr0; + + if (IS_ENABLED(CONFIG_PPC32) && unlikely(dbcr0 & DBCR0_IDM)) { + mtspr(SPRN_DBSR, -1); + mtspr(SPRN_DBCR0, global_dbcr0[smp_processor_id()]); + } +#endif +} + +static inline void check_return_regs_valid(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC_BOOK3S_64 + unsigned long trap, srr0, srr1; + static bool warned; + u8 *validp; + char *h; + + if (trap_is_scv(regs)) + return; + + trap = TRAP(regs); + // EE in HV mode sets HSRRs like 0xea0 + if (cpu_has_feature(CPU_FTR_HVMODE) && trap == INTERRUPT_EXTERNAL) + trap = 0xea0; + + switch (trap) { + case 0x980: + case INTERRUPT_H_DATA_STORAGE: + case 0xe20: + case 0xe40: + case INTERRUPT_HMI: + case 0xe80: + case 0xea0: + case INTERRUPT_H_FAC_UNAVAIL: + case 0x1200: + case 0x1500: + case 0x1600: + case 0x1800: + validp = &local_paca->hsrr_valid; + if (!READ_ONCE(*validp)) + return; + + srr0 = mfspr(SPRN_HSRR0); + srr1 = mfspr(SPRN_HSRR1); + h = "H"; + + break; + default: + validp = &local_paca->srr_valid; + if (!READ_ONCE(*validp)) + return; + + srr0 = mfspr(SPRN_SRR0); + srr1 = mfspr(SPRN_SRR1); + h = ""; + break; + } + + if (srr0 == regs->nip && srr1 == regs->msr) + return; + + /* + * A NMI / soft-NMI interrupt may have come in after we found + * srr_valid and before the SRRs are loaded. The interrupt then + * comes in and clobbers SRRs and clears srr_valid. Then we load + * the SRRs here and test them above and find they don't match. + * + * Test validity again after that, to catch such false positives. + * + * This test in general will have some window for false negatives + * and may not catch and fix all such cases if an NMI comes in + * later and clobbers SRRs without clearing srr_valid, but hopefully + * such things will get caught most of the time, statistically + * enough to be able to get a warning out. + */ + if (!READ_ONCE(*validp)) + return; + + if (!data_race(warned)) { + data_race(warned = true); + pr_warn("%sSRR0 was: %lx should be: %lx\n", h, srr0, regs->nip); + pr_warn("%sSRR1 was: %lx should be: %lx\n", h, srr1, regs->msr); + show_regs(regs); + } + + WRITE_ONCE(*validp, 0); /* fixup */ +#endif +} + +static inline void arch_interrupt_enter_prepare(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC64 + irq_soft_mask_set(IRQS_ALL_DISABLED); + + /* + * If the interrupt was taken with HARD_DIS clear, then enable MSR[EE]. + * Asynchronous interrupts get here with HARD_DIS set (see below), so + * this enables MSR[EE] for synchronous interrupts. IRQs remain + * soft-masked. The interrupt handler may later call + * interrupt_cond_local_irq_enable() to achieve a regular process + * context. + */ + if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS)) { + INT_SOFT_MASK_BUG_ON(regs, !(regs->msr & MSR_EE)); + __hard_irq_enable(); + } else { + __hard_RI_enable(); + } + /* Enable MSR[RI] early, to support kernel SLB and hash faults */ +#endif + + if (!regs_irqs_disabled(regs)) + trace_hardirqs_off(); + + if (user_mode(regs)) { + kuap_lock(); + account_cpu_user_entry(); + account_stolen_time(); + } else { + kuap_save_and_lock(regs); + /* + * CT_WARN_ON comes here via program_check_exception, + * so avoid recursion. + */ + if (TRAP(regs) != INTERRUPT_PROGRAM) + CT_WARN_ON(ct_state() != CT_STATE_KERNEL && + ct_state() != CT_STATE_IDLE); + INT_SOFT_MASK_BUG_ON(regs, is_implicit_soft_masked(regs)); + INT_SOFT_MASK_BUG_ON(regs, regs_irqs_disabled(regs) && + search_kernel_restart_table(regs->nip)); + } + INT_SOFT_MASK_BUG_ON(regs, !regs_irqs_disabled(regs) && + !(regs->msr & MSR_EE)); + + booke_restore_dbcr0(); +} + +/* + * Care should be taken to note that arch_interrupt_exit_prepare and + * arch_interrupt_async_exit_prepare do not necessarily return immediately to + * regs context (e.g., if regs is usermode, we don't necessarily return to + * user mode). Other interrupts might be taken between here and return, + * context switch / preemption may occur in the exit path after this, or a + * signal may be delivered, etc. + * + * The real interrupt exit code is platform specific, e.g., + * interrupt_exit_user_prepare / interrupt_exit_kernel_prepare for 64s. + * + * However arch_interrupt_nmi_exit_prepare does return directly to regs, because + * NMIs do not do "exit work" or replay soft-masked interrupts. + */ +static inline void arch_interrupt_exit_prepare(struct pt_regs *regs) +{ + if (user_mode(regs)) { + BUG_ON(regs_is_unrecoverable(regs)); + BUG_ON(regs_irqs_disabled(regs)); + /* + * We don't need to restore AMR on the way back to userspace for KUAP. + * AMR can only have been unlocked if we interrupted the kernel. + */ + kuap_assert_locked(); + } + + /* irqentry_exit expects to be called with interrupts disabled */ + local_irq_disable(); +} + +static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC64 + /* Ensure arch_interrupt_enter_prepare does not enable MSR[EE] */ + local_paca->irq_happened |= PACA_IRQ_HARD_DIS; +#endif + arch_interrupt_enter_prepare(regs); +#ifdef CONFIG_PPC_BOOK3S_64 + /* + * RI=1 is set by arch_interrupt_enter_prepare, so this thread flags access + * has to come afterward (it can cause SLB faults). + */ + if (cpu_has_feature(CPU_FTR_CTRL) && + !test_thread_local_flags(_TLF_RUNLATCH)) + __ppc64_runlatch_on(); +#endif +} + +static inline void arch_interrupt_async_exit_prepare(struct pt_regs *regs) +{ + /* + * Adjust at exit so the main handler sees the true NIA. This must + * come before irq_exit() because irq_exit can enable interrupts, and + * if another interrupt is taken before nap_adjust_return has run + * here, then that interrupt would return directly to idle nap return. + */ + nap_adjust_return(regs); + + arch_interrupt_exit_prepare(regs); +} + +struct interrupt_nmi_state { +#ifdef CONFIG_PPC64 + u8 irq_soft_mask; + u8 irq_happened; + u8 ftrace_enabled; + u64 softe; +#endif +}; + +static inline bool nmi_disables_ftrace(struct pt_regs *regs) +{ + /* Allow DEC and PMI to be traced when they are soft-NMI */ + if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) { + if (TRAP(regs) == INTERRUPT_DECREMENTER) + return false; + if (TRAP(regs) == INTERRUPT_PERFMON) + return false; + } + if (IS_ENABLED(CONFIG_PPC_BOOK3E_64)) { + if (TRAP(regs) == INTERRUPT_PERFMON) + return false; + } + + return true; +} + +static inline void arch_interrupt_nmi_enter_prepare(struct pt_regs *regs, + struct interrupt_nmi_state *state) +{ +#ifdef CONFIG_PPC64 + state->irq_soft_mask = local_paca->irq_soft_mask; + state->irq_happened = local_paca->irq_happened; + state->softe = regs->softe; + + /* + * Set IRQS_ALL_DISABLED unconditionally so irqs_disabled() does + * the right thing, and set IRQ_HARD_DIS. We do not want to reconcile + * because that goes through irq tracing which we don't want in NMI. + */ + local_paca->irq_soft_mask = IRQS_ALL_DISABLED; + local_paca->irq_happened |= PACA_IRQ_HARD_DIS; + + if (!(regs->msr & MSR_EE) || is_implicit_soft_masked(regs)) { + /* + * Adjust regs->softe to be soft-masked if it had not been + * reconcied (e.g., interrupt entry with MSR[EE]=0 but softe + * not yet set disabled), or if it was in an implicit soft + * masked state. This makes regs_irqs_disabled(regs) + * behave as expected. + */ + regs->softe = IRQS_ALL_DISABLED; + } + + __hard_RI_enable(); + + /* Don't do any per-CPU operations until interrupt state is fixed */ + + if (nmi_disables_ftrace(regs)) { + state->ftrace_enabled = this_cpu_get_ftrace_enabled(); + this_cpu_set_ftrace_enabled(0); + } +#endif +} + +static inline void arch_interrupt_nmi_exit_prepare(struct pt_regs *regs, + struct interrupt_nmi_state *state) +{ + /* + * nmi does not call nap_adjust_return because nmi should not create + * new work to do (must use irq_work for that). + */ + +#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC_BOOK3S + if (regs_irqs_disabled(regs)) { + unsigned long rst = search_kernel_restart_table(regs->nip); + + if (rst) + regs_set_return_ip(regs, rst); + } +#endif + + if (nmi_disables_ftrace(regs)) + this_cpu_set_ftrace_enabled(state->ftrace_enabled); + + /* Check we didn't change the pending interrupt mask. */ + WARN_ON_ONCE((state->irq_happened | PACA_IRQ_HARD_DIS) != local_paca->irq_happened); + regs->softe = state->softe; + local_paca->irq_happened = state->irq_happened; + local_paca->irq_soft_mask = state->irq_soft_mask; +#endif +} + +static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs) +{ + kuap_lock(); + + if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) + BUG_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED); + + BUG_ON(regs_is_unrecoverable(regs)); + BUG_ON(!user_mode(regs)); + BUG_ON(regs_irqs_disabled(regs)); + +#ifdef CONFIG_PPC_PKEY + if (mmu_has_feature(MMU_FTR_PKEY) && trap_is_syscall(regs)) { + unsigned long amr, iamr; + bool flush_needed = false; + /* + * When entering from userspace we mostly have the AMR/IAMR + * different from kernel default values. Hence don't compare. + */ + amr = mfspr(SPRN_AMR); + iamr = mfspr(SPRN_IAMR); + regs->amr = amr; + regs->iamr = iamr; + if (mmu_has_feature(MMU_FTR_KUAP)) { + mtspr(SPRN_AMR, AMR_KUAP_BLOCKED); + flush_needed = true; + } + if (mmu_has_feature(MMU_FTR_BOOK3S_KUEP)) { + mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED); + flush_needed = true; + } + if (flush_needed) + isync(); + } +#endif + kuap_assert_locked(); + booke_restore_dbcr0(); + account_cpu_user_entry(); + account_stolen_time(); + + /* + * This is not required for the syscall exit path, but makes the + * stack frame look nicer. If this was initialised in the first stack + * frame, or if the unwinder was taught the first stack frame always + * returns to user with IRQS_ENABLED, this store could be avoided! + */ + irq_soft_mask_regs_set_state(regs, IRQS_ENABLED); + + /* + * If system call is called with TM active, set _TIF_RESTOREALL to + * prevent RFSCV being used to return to userspace, because POWER9 + * TM implementation has problems with this instruction returning to + * transactional state. Final register values are not relevant because + * the transaction will be aborted upon return anyway. Or in the case + * of unsupported_scv SIGILL fault, the return state does not much + * matter because it's an edge case. + */ + if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && + unlikely(MSR_TM_TRANSACTIONAL(regs->msr))) + set_bits(_TIF_RESTOREALL, ¤t_thread_info()->flags); + + /* + * If the system call was made with a transaction active, doom it and + * return without performing the system call. Unless it was an + * unsupported scv vector, in which case it's treated like an illegal + * instruction. + */ +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) && + !trap_is_unsupported_scv(regs)) { + /* Enable TM in the kernel, and disable EE (for scv) */ + hard_irq_disable(); + mtmsr(mfmsr() | MSR_TM); + + /* tabort, this dooms the transaction, nothing else */ + asm volatile(".long 0x7c00071d | ((%0) << 16)" + :: "r"(TM_CAUSE_SYSCALL | TM_CAUSE_PERSISTENT)); + + /* + * Userspace will never see the return value. Execution will + * resume after the tbegin. of the aborted transaction with the + * checkpointed register state. A context switch could occur + * or signal delivered to the process before resuming the + * doomed transaction context, but that should all be handled + * as expected. + */ + return; + } +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ +} + +#define arch_enter_from_user_mode arch_enter_from_user_mode + +static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, + unsigned long ti_work) +{ + unsigned long mathflags; + + if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && IS_ENABLED(CONFIG_PPC_FPU)) { + if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && + unlikely((ti_work & _TIF_RESTORE_TM))) { + restore_tm_state(regs); + } else { + mathflags = MSR_FP; + + if (cpu_has_feature(CPU_FTR_VSX)) + mathflags |= MSR_VEC | MSR_VSX; + else if (cpu_has_feature(CPU_FTR_ALTIVEC)) + mathflags |= MSR_VEC; + + /* + * If userspace MSR has all available FP bits set, + * then they are live and no need to restore. If not, + * it means the regs were given up and restore_math + * may decide to restore them (to avoid taking an FP + * fault). + */ + if ((regs->msr & mathflags) != mathflags) + restore_math(regs); + } + } + + check_return_regs_valid(regs); +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + local_paca->tm_scratch = regs->msr; +#endif + /* Restore user access locks last */ + kuap_user_restore(regs); +} + +#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare + +static __always_inline void arch_exit_to_user_mode(void) +{ + booke_load_dbcr0(); + + account_cpu_user_exit(); +} + +#define arch_exit_to_user_mode arch_exit_to_user_mode + +#endif /* _ASM_PPC_ENTRY_COMMON_H */ diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 9cd945f2acaf..b7eee6385ae5 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -393,7 +393,7 @@ static inline void do_hard_irq_enable(void) __hard_irq_enable(); } -static inline bool arch_irq_disabled_regs(struct pt_regs *regs) +static inline bool regs_irqs_disabled(struct pt_regs *regs) { return (regs->softe & IRQS_DISABLED); } @@ -466,7 +466,7 @@ static inline bool arch_irqs_disabled(void) #define hard_irq_disable() arch_local_irq_disable() -static inline bool arch_irq_disabled_regs(struct pt_regs *regs) +static inline bool regs_irqs_disabled(struct pt_regs *regs) { return !(regs->msr & MSR_EE); } diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index eb0e4a20b818..fb42a664ae54 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -66,11 +66,9 @@ #ifndef __ASSEMBLER__ -#include <linux/context_tracking.h> -#include <linux/hardirq.h> -#include <asm/cputime.h> -#include <asm/firmware.h> -#include <asm/ftrace.h> +#include <linux/sched/debug.h> /* for show_regs */ +#include <linux/irq-entry-common.h> + #include <asm/kprobes.h> #include <asm/runlatch.h> @@ -88,308 +86,6 @@ do { \ #define INT_SOFT_MASK_BUG_ON(regs, cond) #endif -#ifdef CONFIG_PPC_BOOK3S_64 -extern char __end_soft_masked[]; -bool search_kernel_soft_mask_table(unsigned long addr); -unsigned long search_kernel_restart_table(unsigned long addr); - -DECLARE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); - -static inline bool is_implicit_soft_masked(struct pt_regs *regs) -{ - if (user_mode(regs)) - return false; - - if (regs->nip >= (unsigned long)__end_soft_masked) - return false; - - return search_kernel_soft_mask_table(regs->nip); -} - -static inline void srr_regs_clobbered(void) -{ - local_paca->srr_valid = 0; - local_paca->hsrr_valid = 0; -} -#else -static inline unsigned long search_kernel_restart_table(unsigned long addr) -{ - return 0; -} - -static inline bool is_implicit_soft_masked(struct pt_regs *regs) -{ - return false; -} - -static inline void srr_regs_clobbered(void) -{ -} -#endif - -static inline void nap_adjust_return(struct pt_regs *regs) -{ -#ifdef CONFIG_PPC_970_NAP - if (unlikely(test_thread_local_flags(_TLF_NAPPING))) { - /* Can avoid a test-and-clear because NMIs do not call this */ - clear_thread_local_flags(_TLF_NAPPING); - regs_set_return_ip(regs, (unsigned long)power4_idle_nap_return); - } -#endif -} - -static inline void booke_restore_dbcr0(void) -{ -#ifdef CONFIG_PPC_ADV_DEBUG_REGS - unsigned long dbcr0 = current->thread.debug.dbcr0; - - if (IS_ENABLED(CONFIG_PPC32) && unlikely(dbcr0 & DBCR0_IDM)) { - mtspr(SPRN_DBSR, -1); - mtspr(SPRN_DBCR0, global_dbcr0[smp_processor_id()]); - } -#endif -} - -static inline void interrupt_enter_prepare(struct pt_regs *regs) -{ -#ifdef CONFIG_PPC64 - irq_soft_mask_set(IRQS_ALL_DISABLED); - - /* - * If the interrupt was taken with HARD_DIS clear, then enable MSR[EE]. - * Asynchronous interrupts get here with HARD_DIS set (see below), so - * this enables MSR[EE] for synchronous interrupts. IRQs remain - * soft-masked. The interrupt handler may later call - * interrupt_cond_local_irq_enable() to achieve a regular process - * context. - */ - if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS)) { - INT_SOFT_MASK_BUG_ON(regs, !(regs->msr & MSR_EE)); - __hard_irq_enable(); - } else { - __hard_RI_enable(); - } - /* Enable MSR[RI] early, to support kernel SLB and hash faults */ -#endif - - if (!arch_irq_disabled_regs(regs)) - trace_hardirqs_off(); - - if (user_mode(regs)) { - kuap_lock(); - CT_WARN_ON(ct_state() != CT_STATE_USER); - user_exit_irqoff(); - - account_cpu_user_entry(); - account_stolen_time(); - } else { - kuap_save_and_lock(regs); - /* - * CT_WARN_ON comes here via program_check_exception, - * so avoid recursion. - */ - if (TRAP(regs) != INTERRUPT_PROGRAM) - CT_WARN_ON(ct_state() != CT_STATE_KERNEL && - ct_state() != CT_STATE_IDLE); - INT_SOFT_MASK_BUG_ON(regs, is_implicit_soft_masked(regs)); - INT_SOFT_MASK_BUG_ON(regs, arch_irq_disabled_regs(regs) && - search_kernel_restart_table(regs->nip)); - } - INT_SOFT_MASK_BUG_ON(regs, !arch_irq_disabled_regs(regs) && - !(regs->msr & MSR_EE)); - - booke_restore_dbcr0(); -} - -/* - * Care should be taken to note that interrupt_exit_prepare and - * interrupt_async_exit_prepare do not necessarily return immediately to - * regs context (e.g., if regs is usermode, we don't necessarily return to - * user mode). Other interrupts might be taken between here and return, - * context switch / preemption may occur in the exit path after this, or a - * signal may be delivered, etc. - * - * The real interrupt exit code is platform specific, e.g., - * interrupt_exit_user_prepare / interrupt_exit_kernel_prepare for 64s. - * - * However interrupt_nmi_exit_prepare does return directly to regs, because - * NMIs do not do "exit work" or replay soft-masked interrupts. - */ -static inline void interrupt_exit_prepare(struct pt_regs *regs) -{ -} - -static inline void interrupt_async_enter_prepare(struct pt_regs *regs) -{ -#ifdef CONFIG_PPC64 - /* Ensure interrupt_enter_prepare does not enable MSR[EE] */ - local_paca->irq_happened |= PACA_IRQ_HARD_DIS; -#endif - interrupt_enter_prepare(regs); -#ifdef CONFIG_PPC_BOOK3S_64 - /* - * RI=1 is set by interrupt_enter_prepare, so this thread flags access - * has to come afterward (it can cause SLB faults). - */ - if (cpu_has_feature(CPU_FTR_CTRL) && - !test_thread_local_flags(_TLF_RUNLATCH)) - __ppc64_runlatch_on(); -#endif - irq_enter(); -} - -static inline void interrupt_async_exit_prepare(struct pt_regs *regs) -{ - /* - * Adjust at exit so the main handler sees the true NIA. This must - * come before irq_exit() because irq_exit can enable interrupts, and - * if another interrupt is taken before nap_adjust_return has run - * here, then that interrupt would return directly to idle nap return. - */ - nap_adjust_return(regs); - - irq_exit(); - interrupt_exit_prepare(regs); -} - -struct interrupt_nmi_state { -#ifdef CONFIG_PPC64 - u8 irq_soft_mask; - u8 irq_happened; - u8 ftrace_enabled; - u64 softe; -#endif -}; - -static inline bool nmi_disables_ftrace(struct pt_regs *regs) -{ - /* Allow DEC and PMI to be traced when they are soft-NMI */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) { - if (TRAP(regs) == INTERRUPT_DECREMENTER) - return false; - if (TRAP(regs) == INTERRUPT_PERFMON) - return false; - } - if (IS_ENABLED(CONFIG_PPC_BOOK3E_64)) { - if (TRAP(regs) == INTERRUPT_PERFMON) - return false; - } - - return true; -} - -static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state) -{ -#ifdef CONFIG_PPC64 - state->irq_soft_mask = local_paca->irq_soft_mask; - state->irq_happened = local_paca->irq_happened; - state->softe = regs->softe; - - /* - * Set IRQS_ALL_DISABLED unconditionally so irqs_disabled() does - * the right thing, and set IRQ_HARD_DIS. We do not want to reconcile - * because that goes through irq tracing which we don't want in NMI. - */ - local_paca->irq_soft_mask = IRQS_ALL_DISABLED; - local_paca->irq_happened |= PACA_IRQ_HARD_DIS; - - if (!(regs->msr & MSR_EE) || is_implicit_soft_masked(regs)) { - /* - * Adjust regs->softe to be soft-masked if it had not been - * reconcied (e.g., interrupt entry with MSR[EE]=0 but softe - * not yet set disabled), or if it was in an implicit soft - * masked state. This makes arch_irq_disabled_regs(regs) - * behave as expected. - */ - regs->softe = IRQS_ALL_DISABLED; - } - - __hard_RI_enable(); - - /* Don't do any per-CPU operations until interrupt state is fixed */ - - if (nmi_disables_ftrace(regs)) { - state->ftrace_enabled = this_cpu_get_ftrace_enabled(); - this_cpu_set_ftrace_enabled(0); - } -#endif - - /* If data relocations are enabled, it's safe to use nmi_enter() */ - if (mfmsr() & MSR_DR) { - nmi_enter(); - return; - } - - /* - * But do not use nmi_enter() for pseries hash guest taking a real-mode - * NMI because not everything it touches is within the RMA limit. - */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && - firmware_has_feature(FW_FEATURE_LPAR) && - !radix_enabled()) - return; - - /* - * Likewise, don't use it if we have some form of instrumentation (like - * KASAN shadow) that is not safe to access in real mode (even on radix) - */ - if (IS_ENABLED(CONFIG_KASAN)) - return; - - /* - * Likewise, do not use it in real mode if percpu first chunk is not - * embedded. With CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK enabled there - * are chances where percpu allocation can come from vmalloc area. - */ - if (percpu_first_chunk_is_paged) - return; - - /* Otherwise, it should be safe to call it */ - nmi_enter(); -} - -static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state) -{ - if (mfmsr() & MSR_DR) { - // nmi_exit if relocations are on - nmi_exit(); - } else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && - firmware_has_feature(FW_FEATURE_LPAR) && - !radix_enabled()) { - // no nmi_exit for a pseries hash guest taking a real mode exception - } else if (IS_ENABLED(CONFIG_KASAN)) { - // no nmi_exit for KASAN in real mode - } else if (percpu_first_chunk_is_paged) { - // no nmi_exit if percpu first chunk is not embedded - } else { - nmi_exit(); - } - - /* - * nmi does not call nap_adjust_return because nmi should not create - * new work to do (must use irq_work for that). - */ - -#ifdef CONFIG_PPC64 -#ifdef CONFIG_PPC_BOOK3S - if (arch_irq_disabled_regs(regs)) { - unsigned long rst = search_kernel_restart_table(regs->nip); - if (rst) - regs_set_return_ip(regs, rst); - } -#endif - - if (nmi_disables_ftrace(regs)) - this_cpu_set_ftrace_enabled(state->ftrace_enabled); - - /* Check we didn't change the pending interrupt mask. */ - WARN_ON_ONCE((state->irq_happened | PACA_IRQ_HARD_DIS) != local_paca->irq_happened); - regs->softe = state->softe; - local_paca->irq_happened = state->irq_happened; - local_paca->irq_soft_mask = state->irq_soft_mask; -#endif -} - /* * Don't use noinstr here like x86, but rather add NOKPROBE_SYMBOL to each * function definition. The reason for this is the noinstr section is placed @@ -470,11 +166,14 @@ static __always_inline void ____##func(struct pt_regs *regs); \ \ interrupt_handler void func(struct pt_regs *regs) \ { \ - interrupt_enter_prepare(regs); \ - \ + irqentry_state_t state; \ + arch_interrupt_enter_prepare(regs); \ + state = irqentry_enter(regs); \ + instrumentation_begin(); \ ____##func (regs); \ - \ - interrupt_exit_prepare(regs); \ + instrumentation_end(); \ + arch_interrupt_exit_prepare(regs); \ + irqentry_exit(regs, state); \ } \ NOKPROBE_SYMBOL(func); \ \ @@ -504,12 +203,15 @@ static __always_inline long ____##func(struct pt_regs *regs); \ interrupt_handler long func(struct pt_regs *regs) \ { \ long ret; \ + irqentry_state_t state; \ \ - interrupt_enter_prepare(regs); \ - \ + arch_interrupt_enter_prepare(regs); \ + state = irqentry_enter(regs); \ + instrumentation_begin(); \ ret = ____##func (regs); \ - \ - interrupt_exit_prepare(regs); \ + instrumentation_end(); \ + arch_interrupt_exit_prepare(regs); \ + irqentry_exit(regs, state); \ \ return ret; \ } \ @@ -538,11 +240,16 @@ static __always_inline void ____##func(struct pt_regs *regs); \ \ interrupt_handler void func(struct pt_regs *regs) \ { \ - interrupt_async_enter_prepare(regs); \ - \ + irqentry_state_t state; \ + arch_interrupt_async_enter_prepare(regs); \ + state = irqentry_enter(regs); \ + instrumentation_begin(); \ + irq_enter_rcu(); \ ____##func (regs); \ - \ - interrupt_async_exit_prepare(regs); \ + irq_exit_rcu(); \ + instrumentation_end(); \ + arch_interrupt_async_exit_prepare(regs); \ + irqentry_exit(regs, state); \ } \ NOKPROBE_SYMBOL(func); \ \ @@ -572,14 +279,43 @@ ____##func(struct pt_regs *regs); \ \ interrupt_handler long func(struct pt_regs *regs) \ { \ - struct interrupt_nmi_state state; \ + irqentry_state_t state; \ + struct interrupt_nmi_state nmi_state; \ long ret; \ \ - interrupt_nmi_enter_prepare(regs, &state); \ - \ + arch_interrupt_nmi_enter_prepare(regs, &nmi_state); \ + if (mfmsr() & MSR_DR) { \ + /* nmi_entry if relocations are on */ \ + state = irqentry_nmi_enter(regs); \ + } else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && \ + firmware_has_feature(FW_FEATURE_LPAR) && \ + !radix_enabled()) { \ + /* no nmi_entry for a pseries hash guest \ + * taking a real mode exception */ \ + } else if (IS_ENABLED(CONFIG_KASAN)) { \ + /* no nmi_entry for KASAN in real mode */ \ + } else if (percpu_first_chunk_is_paged) { \ + /* no nmi_entry if percpu first chunk is not embedded */\ + } else { \ + state = irqentry_nmi_enter(regs); \ + } \ ret = ____##func (regs); \ - \ - interrupt_nmi_exit_prepare(regs, &state); \ + arch_interrupt_nmi_exit_prepare(regs, &nmi_state); \ + if (mfmsr() & MSR_DR) { \ + /* nmi_exit if relocations are on */ \ + irqentry_nmi_exit(regs, state); \ + } else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && \ + firmware_has_feature(FW_FEATURE_LPAR) && \ + !radix_enabled()) { \ + /* no nmi_exit for a pseries hash guest \ + * taking a real mode exception */ \ + } else if (IS_ENABLED(CONFIG_KASAN)) { \ + /* no nmi_exit for KASAN in real mode */ \ + } else if (percpu_first_chunk_is_paged) { \ + /* no nmi_exit if percpu first chunk is not embedded */ \ + } else { \ + irqentry_nmi_exit(regs, state); \ + } \ \ return ret; \ } \ @@ -661,7 +397,7 @@ void replay_soft_interrupts(void); static inline void interrupt_cond_local_irq_enable(struct pt_regs *regs) { - if (!arch_irq_disabled_regs(regs)) + if (!regs_irqs_disabled(regs)) local_irq_enable(); } diff --git a/arch/powerpc/include/asm/kasan.h b/arch/powerpc/include/asm/kasan.h index 045804a86f98..a690e7da53c2 100644 --- a/arch/powerpc/include/asm/kasan.h +++ b/arch/powerpc/include/asm/kasan.h @@ -3,14 +3,19 @@ #define __ASM_KASAN_H #if defined(CONFIG_KASAN) && !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) -#define _GLOBAL_KASAN(fn) _GLOBAL(__##fn) -#define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(__##fn) -#define EXPORT_SYMBOL_KASAN(fn) EXPORT_SYMBOL(__##fn) -#else +#define _GLOBAL_KASAN(fn) \ + _GLOBAL(fn); \ + _GLOBAL(__##fn) +#define _GLOBAL_TOC_KASAN(fn) \ + _GLOBAL_TOC(fn); \ + _GLOBAL_TOC(__##fn) +#define EXPORT_SYMBOL_KASAN(fn) \ + EXPORT_SYMBOL(__##fn) +#else /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */ #define _GLOBAL_KASAN(fn) _GLOBAL(fn) #define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(fn) #define EXPORT_SYMBOL_KASAN(fn) -#endif +#endif /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */ #ifndef __ASSEMBLER__ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index f679a11a7e7f..f4991d10d89e 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -12,12 +12,14 @@ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp. */ #include <linux/types.h> +#include <linux/sizes.h> #include <asm/firmware.h> struct device_node; struct property; -#define MIN_RMA 768 /* Minimum RMA (in MB) for CAS negotiation */ +/* Minimum RMA in bytes for CAS negotiation */ +#define MIN_RMA (768ULL * SZ_1M) #define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ #define OF_DT_END_NODE 0x2 /* End node */ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 94aa1de2b06e..fdeb97421785 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -53,6 +53,9 @@ struct pt_regs unsigned long esr; }; unsigned long result; + unsigned long exit_flags; + /* Maintain 16 byte interrupt stack alignment */ + unsigned long __pt_regs_pad[3]; }; }; #if defined(CONFIG_PPC64) || defined(CONFIG_PPC_KUAP) @@ -174,9 +177,6 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define profile_pc(regs) instruction_pointer(regs) #endif -long do_syscall_trace_enter(struct pt_regs *regs); -void do_syscall_trace_leave(struct pt_regs *regs); - static inline void set_return_regs_changed(void) { #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/arch/powerpc/include/asm/rtas-types.h b/arch/powerpc/include/asm/rtas-types.h index 9d5b16803cbb..5d40d187b965 100644 --- a/arch/powerpc/include/asm/rtas-types.h +++ b/arch/powerpc/include/asm/rtas-types.h @@ -42,8 +42,9 @@ struct rtas_error_log { */ u8 byte3; /* General event or error*/ __be32 extended_log_length; /* length in bytes */ - unsigned char buffer[1]; /* Start of extended log */ - /* Variable length. */ + + /* Start of extended log, variable length */ + unsigned char buffer[] __counted_by_be(extended_log_length); }; /* RTAS general extended event log, Version 6. The extended log starts diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h index 922d43700fb4..21af92cdb237 100644 --- a/arch/powerpc/include/asm/signal.h +++ b/arch/powerpc/include/asm/signal.h @@ -7,7 +7,6 @@ #include <uapi/asm/ptrace.h> struct pt_regs; -void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); unsigned long get_min_sigframe_size_32(void); unsigned long get_min_sigframe_size_64(void); diff --git a/arch/powerpc/include/asm/stacktrace.h b/arch/powerpc/include/asm/stacktrace.h index 6149b53b3bc8..987f2e996262 100644 --- a/arch/powerpc/include/asm/stacktrace.h +++ b/arch/powerpc/include/asm/stacktrace.h @@ -10,4 +10,10 @@ void show_user_instructions(struct pt_regs *regs); +static __always_inline bool on_thread_stack(void) +{ + return !(((unsigned long)(current->stack) ^ current_stack_pointer) + & ~(THREAD_SIZE - 1)); +} + #endif /* _ASM_POWERPC_STACKTRACE_H */ diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h index 4b3c52ed6e9d..834fcc4f7b54 100644 --- a/arch/powerpc/include/asm/syscall.h +++ b/arch/powerpc/include/asm/syscall.h @@ -139,4 +139,9 @@ static inline int syscall_get_arch(struct task_struct *task) else return AUDIT_ARCH_PPC64; } + +static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs) +{ + return false; +} #endif /* _ASM_SYSCALL_H */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 97f35f9b1a96..ee3b9adb5b67 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -57,6 +57,7 @@ struct thread_info { #ifdef CONFIG_SMP unsigned int cpu; #endif + unsigned long syscall_work; /* SYSCALL_WORK_ flags */ unsigned long local_flags; /* private flags for thread */ #ifdef CONFIG_LIVEPATCH_64 unsigned long *livepatch_sp; diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index e98c628e3899..7b8c56962c31 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -18,9 +18,35 @@ /* Threshold above which VMX copy path is used */ #define VMX_COPY_THRESHOLD 3328 +#define __access_ok __access_ok + #include <asm-generic/access_ok.h> /* + * On powerpc64, TASK_SIZE_MAX is 0x0010000000000000 then even if both ptr and size + * are TASK_SIZE_MAX we are still inside the memory gap. So make it simple. + */ +static __always_inline int __access_ok(const void __user *ptr, unsigned long size) +{ + unsigned long addr = (unsigned long)ptr; + + if (IS_ENABLED(CONFIG_PPC64)) { + BUILD_BUG_ON(!is_power_of_2(TASK_SIZE_MAX)); + BUILD_BUG_ON(TASK_SIZE_MAX > 0x0010000000000000); + + if (statically_true(size > TASK_SIZE_MAX)) + return false; + if (statically_true(size <= TASK_SIZE_MAX)) + return !(addr & ~(TASK_SIZE_MAX - 1)); + return !((size | addr) & ~(TASK_SIZE_MAX - 1)); + } else { + if (statically_true(size <= SZ_128K)) + return addr < TASK_SIZE; + return size <= TASK_SIZE && addr <= TASK_SIZE - size; + } +} + +/* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. * diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h index 01e630149d48..a393b7f2760a 100644 --- a/arch/powerpc/include/uapi/asm/ptrace.h +++ b/arch/powerpc/include/uapi/asm/ptrace.h @@ -55,6 +55,8 @@ struct pt_regs unsigned long dar; /* Fault registers */ unsigned long dsisr; /* on 4xx/Book-E used for ESR */ unsigned long result; /* Result of a system call */ + unsigned long exit_flags; /* System call exit flags */ + unsigned long __pt_regs_pad[3]; /* Maintain 16 byte interrupt stack alignment */ }; #endif /* __ASSEMBLER__ */ @@ -114,10 +116,12 @@ struct pt_regs #define PT_DAR 41 #define PT_DSISR 42 #define PT_RESULT 43 -#define PT_DSCR 44 -#define PT_REGS_COUNT 44 +#define PT_EXIT_FLAGS 44 +#define PT_PAD 47 /* 3 times */ +#define PT_DSCR 48 +#define PT_REGS_COUNT 48 -#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */ +#define PT_FPR0 (PT_REGS_COUNT + 4) /* each FP reg occupies 2 slots in this space */ #ifndef __powerpc64__ @@ -129,7 +133,7 @@ struct pt_regs #define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ -#define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */ +#define PT_VR0 (PT_FPSCR + 2) /* <82> each Vector reg occupies 2 slots in 64-bit */ #define PT_VSCR (PT_VR0 + 32*2 + 1) #define PT_VRSAVE (PT_VR0 + 33*2) @@ -137,7 +141,7 @@ struct pt_regs /* * Only store first 32 VSRs here. The second 32 VSRs in VR0-31 */ -#define PT_VSR0 150 /* each VSR reg occupies 2 slots in 64-bit */ +#define PT_VSR0 (PT_VRSAVE + 2) /* each VSR reg occupies 2 slots in 64-bit */ #define PT_VSR31 (PT_VSR0 + 2*31) #endif /* __powerpc64__ */ diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index 90d51d9b3ed2..04e5ea38bdc0 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -18,6 +18,7 @@ #include <linux/of.h> #include <linux/percpu.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <asm/cputhreads.h> #include <asm/smp.h> @@ -596,7 +597,7 @@ static ssize_t size_show(struct kobject *k, struct kobj_attribute *attr, char *b if (cache_size_kb(cache, &size_kb)) return -ENODEV; - return sprintf(buf, "%uK\n", size_kb); + return sysfs_emit(buf, "%uK\n", size_kb); } static struct kobj_attribute cache_size_attr = @@ -613,7 +614,7 @@ static ssize_t line_size_show(struct kobject *k, struct kobj_attribute *attr, ch if (cache_get_line_size(cache, &line_size)) return -ENODEV; - return sprintf(buf, "%u\n", line_size); + return sysfs_emit(buf, "%u\n", line_size); } static struct kobj_attribute cache_line_size_attr = @@ -629,7 +630,7 @@ static ssize_t nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char if (cache_nr_sets(cache, &nr_sets)) return -ENODEV; - return sprintf(buf, "%u\n", nr_sets); + return sysfs_emit(buf, "%u\n", nr_sets); } static struct kobj_attribute cache_nr_sets_attr = @@ -645,7 +646,7 @@ static ssize_t associativity_show(struct kobject *k, struct kobj_attribute *attr if (cache_associativity(cache, &associativity)) return -ENODEV; - return sprintf(buf, "%u\n", associativity); + return sysfs_emit(buf, "%u\n", associativity); } static struct kobj_attribute cache_assoc_attr = @@ -657,7 +658,7 @@ static ssize_t type_show(struct kobject *k, struct kobj_attribute *attr, char *b cache = index_kobj_to_cache(k); - return sprintf(buf, "%s\n", cache_type_string(cache)); + return sysfs_emit(buf, "%s\n", cache_type_string(cache)); } static struct kobj_attribute cache_type_attr = @@ -671,7 +672,7 @@ static ssize_t level_show(struct kobject *k, struct kobj_attribute *attr, char * index = kobj_to_cache_index_dir(k); cache = index->cache; - return sprintf(buf, "%d\n", cache->level); + return sysfs_emit(buf, "%d\n", cache->level); } static struct kobj_attribute cache_level_attr = diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c index 706e1eb95efe..b9785f105f75 100644 --- a/arch/powerpc/kernel/eeh_sysfs.c +++ b/arch/powerpc/kernel/eeh_sysfs.c @@ -9,6 +9,7 @@ #include <linux/of.h> #include <linux/pci.h> #include <linux/stat.h> +#include <linux/sysfs.h> #include <asm/ppc-pci.h> #include <asm/pci-bridge.h> @@ -31,7 +32,7 @@ static ssize_t eeh_show_##_name(struct device *dev, \ if (!edev) \ return 0; \ \ - return sprintf(buf, _format "\n", edev->_memb); \ + return sysfs_emit(buf, _format "\n", edev->_memb); \ } \ static DEVICE_ATTR(_name, 0444, eeh_show_##_name, NULL); @@ -49,8 +50,7 @@ static ssize_t eeh_pe_state_show(struct device *dev, return -ENODEV; state = eeh_ops->get_state(edev->pe, NULL); - return sprintf(buf, "0x%08x 0x%08x\n", - state, edev->pe->state); + return sysfs_emit(buf, "0x%08x 0x%08x\n", state, edev->pe->state); } static ssize_t eeh_pe_state_store(struct device *dev, @@ -87,7 +87,7 @@ static ssize_t eeh_notify_resume_show(struct device *dev, if (!edev || !edev->pe) return -ENODEV; - return sprintf(buf, "%d\n", pdn->last_allow_rc); + return sysfs_emit(buf, "%d\n", pdn->last_allow_rc); } static ssize_t eeh_notify_resume_store(struct device *dev, diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 501d43bf18f3..7f79c9aea4a9 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1422,7 +1422,7 @@ static ssize_t enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", fw_dump.fadump_enabled); + return sysfs_emit(buf, "%d\n", fw_dump.fadump_enabled); } /* @@ -1434,28 +1434,28 @@ static ssize_t hotplug_ready_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", 1); + return sysfs_emit(buf, "%d\n", 1); } static ssize_t mem_reserved_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size); + return sysfs_emit(buf, "%ld\n", fw_dump.reserve_dump_area_size); } static ssize_t registered_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", fw_dump.dump_registered); + return sysfs_emit(buf, "%d\n", fw_dump.dump_registered); } static ssize_t bootargs_append_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area)); + return sysfs_emit(buf, "%s\n", (char *)__va(fw_dump.param_area)); } static ssize_t bootargs_append_store(struct kobject *kobj, @@ -1759,10 +1759,10 @@ void __init fadump_setup_param_area(void) * 2. The range should be between MIN_RMA and RMA size (ppc64_rma_size) * 3. It must not overlap with the fadump reserved area. */ - if (ppc64_rma_size < MIN_RMA*1024*1024) + if (ppc64_rma_size < MIN_RMA) return; - range_start = MIN_RMA * 1024 * 1024; + range_start = MIN_RMA; range_end = min(ppc64_rma_size, fw_dump.boot_mem_top); } diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index e63bfde13e03..f04978080837 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <linux/context_tracking.h> +#include <linux/entry-common.h> #include <linux/err.h> #include <linux/compat.h> #include <linux/rseq.h> @@ -25,10 +26,6 @@ unsigned long global_dbcr0[NR_CPUS]; #endif -#if defined(CONFIG_PREEMPT_DYNAMIC) -DEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); -#endif - #ifdef CONFIG_PPC_BOOK3S_64 DEFINE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); static inline bool exit_must_hard_disable(void) @@ -78,181 +75,6 @@ static notrace __always_inline bool prep_irq_for_enabled_exit(bool restartable) return true; } -static notrace void booke_load_dbcr0(void) -{ -#ifdef CONFIG_PPC_ADV_DEBUG_REGS - unsigned long dbcr0 = current->thread.debug.dbcr0; - - if (likely(!(dbcr0 & DBCR0_IDM))) - return; - - /* - * Check to see if the dbcr0 register is set up to debug. - * Use the internal debug mode bit to do this. - */ - mtmsr(mfmsr() & ~MSR_DE); - if (IS_ENABLED(CONFIG_PPC32)) { - isync(); - global_dbcr0[smp_processor_id()] = mfspr(SPRN_DBCR0); - } - mtspr(SPRN_DBCR0, dbcr0); - mtspr(SPRN_DBSR, -1); -#endif -} - -static notrace void check_return_regs_valid(struct pt_regs *regs) -{ -#ifdef CONFIG_PPC_BOOK3S_64 - unsigned long trap, srr0, srr1; - static bool warned; - u8 *validp; - char *h; - - if (trap_is_scv(regs)) - return; - - trap = TRAP(regs); - // EE in HV mode sets HSRRs like 0xea0 - if (cpu_has_feature(CPU_FTR_HVMODE) && trap == INTERRUPT_EXTERNAL) - trap = 0xea0; - - switch (trap) { - case 0x980: - case INTERRUPT_H_DATA_STORAGE: - case 0xe20: - case 0xe40: - case INTERRUPT_HMI: - case 0xe80: - case 0xea0: - case INTERRUPT_H_FAC_UNAVAIL: - case 0x1200: - case 0x1500: - case 0x1600: - case 0x1800: - validp = &local_paca->hsrr_valid; - if (!READ_ONCE(*validp)) - return; - - srr0 = mfspr(SPRN_HSRR0); - srr1 = mfspr(SPRN_HSRR1); - h = "H"; - - break; - default: - validp = &local_paca->srr_valid; - if (!READ_ONCE(*validp)) - return; - - srr0 = mfspr(SPRN_SRR0); - srr1 = mfspr(SPRN_SRR1); - h = ""; - break; - } - - if (srr0 == regs->nip && srr1 == regs->msr) - return; - - /* - * A NMI / soft-NMI interrupt may have come in after we found - * srr_valid and before the SRRs are loaded. The interrupt then - * comes in and clobbers SRRs and clears srr_valid. Then we load - * the SRRs here and test them above and find they don't match. - * - * Test validity again after that, to catch such false positives. - * - * This test in general will have some window for false negatives - * and may not catch and fix all such cases if an NMI comes in - * later and clobbers SRRs without clearing srr_valid, but hopefully - * such things will get caught most of the time, statistically - * enough to be able to get a warning out. - */ - if (!READ_ONCE(*validp)) - return; - - if (!data_race(warned)) { - data_race(warned = true); - printk("%sSRR0 was: %lx should be: %lx\n", h, srr0, regs->nip); - printk("%sSRR1 was: %lx should be: %lx\n", h, srr1, regs->msr); - show_regs(regs); - } - - WRITE_ONCE(*validp, 0); /* fixup */ -#endif -} - -static notrace unsigned long -interrupt_exit_user_prepare_main(unsigned long ret, struct pt_regs *regs) -{ - unsigned long ti_flags; - -again: - ti_flags = read_thread_flags(); - while (unlikely(ti_flags & (_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM))) { - local_irq_enable(); - if (ti_flags & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) { - schedule(); - } else { - /* - * SIGPENDING must restore signal handler function - * argument GPRs, and some non-volatiles (e.g., r1). - * Restore all for now. This could be made lighter. - */ - if (ti_flags & _TIF_SIGPENDING) - ret |= _TIF_RESTOREALL; - do_notify_resume(regs, ti_flags); - } - local_irq_disable(); - ti_flags = read_thread_flags(); - } - - if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && IS_ENABLED(CONFIG_PPC_FPU)) { - if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && - unlikely((ti_flags & _TIF_RESTORE_TM))) { - restore_tm_state(regs); - } else { - unsigned long mathflags = MSR_FP; - - if (cpu_has_feature(CPU_FTR_VSX)) - mathflags |= MSR_VEC | MSR_VSX; - else if (cpu_has_feature(CPU_FTR_ALTIVEC)) - mathflags |= MSR_VEC; - - /* - * If userspace MSR has all available FP bits set, - * then they are live and no need to restore. If not, - * it means the regs were given up and restore_math - * may decide to restore them (to avoid taking an FP - * fault). - */ - if ((regs->msr & mathflags) != mathflags) - restore_math(regs); - } - } - - check_return_regs_valid(regs); - - user_enter_irqoff(); - if (!prep_irq_for_enabled_exit(true)) { - user_exit_irqoff(); - local_irq_enable(); - local_irq_disable(); - goto again; - } - -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - local_paca->tm_scratch = regs->msr; -#endif - - booke_load_dbcr0(); - - account_cpu_user_exit(); - - /* Restore user access locks last */ - kuap_user_restore(regs); - - return ret; -} - /* * This should be called after a syscall returns, with r3 the return value * from the syscall. If this function returns non-zero, the system call @@ -267,17 +89,12 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, long scv) { unsigned long ti_flags; - unsigned long ret = 0; bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv; - CT_WARN_ON(ct_state() == CT_STATE_USER); - kuap_assert_locked(); regs->result = r3; - - /* Check whether the syscall is issued inside a restartable sequence */ - rseq_syscall(regs); + regs->exit_flags = 0; ti_flags = read_thread_flags(); @@ -290,7 +107,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) { if (ti_flags & _TIF_RESTOREALL) - ret = _TIF_RESTOREALL; + regs->exit_flags = _TIF_RESTOREALL; else regs->gpr[3] = r3; clear_bits(_TIF_PERSYSCALL_MASK, ¤t_thread_info()->flags); @@ -299,18 +116,28 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, } if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) { - do_syscall_trace_leave(regs); - ret |= _TIF_RESTOREALL; + regs->exit_flags |= _TIF_RESTOREALL; } - local_irq_disable(); - ret = interrupt_exit_user_prepare_main(ret, regs); + syscall_exit_to_user_mode(regs); + +again: + user_enter_irqoff(); + if (!prep_irq_for_enabled_exit(true)) { + user_exit_irqoff(); + local_irq_enable(); + local_irq_disable(); + goto again; + } + + /* Restore user access locks last */ + kuap_user_restore(regs); #ifdef CONFIG_PPC64 - regs->exit_result = ret; + regs->exit_result = regs->exit_flags; #endif - return ret; + return regs->exit_flags; } #ifdef CONFIG_PPC64 @@ -330,13 +157,17 @@ notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *reg set_kuap(AMR_KUAP_BLOCKED); #endif - trace_hardirqs_off(); - user_exit_irqoff(); - account_cpu_user_entry(); - - BUG_ON(!user_mode(regs)); +again: + user_enter_irqoff(); + if (!prep_irq_for_enabled_exit(true)) { + user_exit_irqoff(); + local_irq_enable(); + local_irq_disable(); + goto again; + } - regs->exit_result = interrupt_exit_user_prepare_main(regs->exit_result, regs); + kuap_user_restore(regs); + regs->exit_result |= regs->exit_flags; return regs->exit_result; } @@ -347,8 +178,7 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs) unsigned long ret; BUG_ON(regs_is_unrecoverable(regs)); - BUG_ON(arch_irq_disabled_regs(regs)); - CT_WARN_ON(ct_state() == CT_STATE_USER); + BUG_ON(regs_irqs_disabled(regs)); /* * We don't need to restore AMR on the way back to userspace for KUAP. @@ -357,8 +187,21 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs) kuap_assert_locked(); local_irq_disable(); + regs->exit_flags = 0; +again: + check_return_regs_valid(regs); + user_enter_irqoff(); + if (!prep_irq_for_enabled_exit(true)) { + user_exit_irqoff(); + local_irq_enable(); + local_irq_disable(); + goto again; + } + + /* Restore user access locks last */ + kuap_user_restore(regs); - ret = interrupt_exit_user_prepare_main(0, regs); + ret = regs->exit_flags; #ifdef CONFIG_PPC64 regs->exit_result = ret; @@ -396,17 +239,10 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs) local_irq_disable(); - if (!arch_irq_disabled_regs(regs)) { + if (!regs_irqs_disabled(regs)) { /* Returning to a kernel context with local irqs enabled. */ WARN_ON_ONCE(!(regs->msr & MSR_EE)); again: - if (need_irq_preemption()) { - /* Return to preemptible kernel context */ - if (unlikely(read_thread_flags() & _TIF_NEED_RESCHED)) { - if (preempt_count() == 0) - preempt_schedule_irq(); - } - } check_return_regs_valid(regs); @@ -479,7 +315,6 @@ notrace unsigned long interrupt_exit_user_restart(struct pt_regs *regs) #endif trace_hardirqs_off(); - user_exit_irqoff(); account_cpu_user_entry(); BUG_ON(!user_mode(regs)); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index d122e8447831..ee1b5cb557c9 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/mm.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -141,7 +142,7 @@ late_initcall(fail_iommu_debugfs); static ssize_t fail_iommu_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev->archdata.fail_iommu); + return sysfs_emit(buf, "%d\n", dev->archdata.fail_iommu); } static ssize_t fail_iommu_store(struct device *dev, diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index a0e8b998c9b5..f69de08ad347 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -370,10 +370,7 @@ int irq_choose_cpu(const struct cpumask *mask) do_round_robin: raw_spin_lock_irqsave(&irq_rover_lock, flags); - irq_rover = cpumask_next(irq_rover, cpu_online_mask); - if (irq_rover >= nr_cpu_ids) - irq_rover = cpumask_first(cpu_online_mask); - + irq_rover = cpumask_next_wrap(irq_rover, cpu_online_mask); cpuid = irq_rover; raw_spin_unlock_irqrestore(&irq_rover_lock, flags); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index f26e80cbc615..53503937de0e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1061,7 +1061,7 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .virt_base = cpu_to_be32(0xffffffff), .virt_size = cpu_to_be32(0xffffffff), .load_base = cpu_to_be32(0xffffffff), - .min_rma = cpu_to_be32(MIN_RMA), + .min_rma = cpu_to_be32(MIN_RMA / SZ_1M), .min_load = cpu_to_be32(0xffffffff), /* full client load */ .min_rma_percent = 0, /* min RMA percentage of total RAM */ .max_pft_size = 48, /* max log_2(hash table size) */ diff --git a/arch/powerpc/kernel/ptrace/ptrace.c b/arch/powerpc/kernel/ptrace/ptrace.c index c6997df63287..316d4f5ead8e 100644 --- a/arch/powerpc/kernel/ptrace/ptrace.c +++ b/arch/powerpc/kernel/ptrace/ptrace.c @@ -21,9 +21,6 @@ #include <asm/switch_to.h> #include <asm/debug.h> -#define CREATE_TRACE_POINTS -#include <trace/events/syscalls.h> - #include "ptrace-decl.h" /* @@ -195,144 +192,6 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } -#ifdef CONFIG_SECCOMP -static int do_seccomp(struct pt_regs *regs) -{ - if (!test_thread_flag(TIF_SECCOMP)) - return 0; - - /* - * The ABI we present to seccomp tracers is that r3 contains - * the syscall return value and orig_gpr3 contains the first - * syscall parameter. This is different to the ptrace ABI where - * both r3 and orig_gpr3 contain the first syscall parameter. - */ - regs->gpr[3] = -ENOSYS; - - /* - * We use the __ version here because we have already checked - * TIF_SECCOMP. If this fails, there is nothing left to do, we - * have already loaded -ENOSYS into r3, or seccomp has put - * something else in r3 (via SECCOMP_RET_ERRNO/TRACE). - */ - if (__secure_computing()) - return -1; - - /* - * The syscall was allowed by seccomp, restore the register - * state to what audit expects. - * Note that we use orig_gpr3, which means a seccomp tracer can - * modify the first syscall parameter (in orig_gpr3) and also - * allow the syscall to proceed. - */ - regs->gpr[3] = regs->orig_gpr3; - - return 0; -} -#else -static inline int do_seccomp(struct pt_regs *regs) { return 0; } -#endif /* CONFIG_SECCOMP */ - -/** - * do_syscall_trace_enter() - Do syscall tracing on kernel entry. - * @regs: the pt_regs of the task to trace (current) - * - * Performs various types of tracing on syscall entry. This includes seccomp, - * ptrace, syscall tracepoints and audit. - * - * The pt_regs are potentially visible to userspace via ptrace, so their - * contents is ABI. - * - * One or more of the tracers may modify the contents of pt_regs, in particular - * to modify arguments or even the syscall number itself. - * - * It's also possible that a tracer can choose to reject the system call. In - * that case this function will return an illegal syscall number, and will put - * an appropriate return value in regs->r3. - * - * Return: the (possibly changed) syscall number. - */ -long do_syscall_trace_enter(struct pt_regs *regs) -{ - u32 flags; - - flags = read_thread_flags() & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE); - - if (flags) { - int rc = ptrace_report_syscall_entry(regs); - - if (unlikely(flags & _TIF_SYSCALL_EMU)) { - /* - * A nonzero return code from - * ptrace_report_syscall_entry() tells us to prevent - * the syscall execution, but we are not going to - * execute it anyway. - * - * Returning -1 will skip the syscall execution. We want - * to avoid clobbering any registers, so we don't goto - * the skip label below. - */ - return -1; - } - - if (rc) { - /* - * The tracer decided to abort the syscall. Note that - * the tracer may also just change regs->gpr[0] to an - * invalid syscall number, that is handled below on the - * exit path. - */ - goto skip; - } - } - - /* Run seccomp after ptrace; allow it to set gpr[3]. */ - if (do_seccomp(regs)) - return -1; - - /* Avoid trace and audit when syscall is invalid. */ - if (regs->gpr[0] >= NR_syscalls) - goto skip; - - if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_sys_enter(regs, regs->gpr[0]); - - if (!is_32bit_task()) - audit_syscall_entry(regs->gpr[0], regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); - else - audit_syscall_entry(regs->gpr[0], - regs->gpr[3] & 0xffffffff, - regs->gpr[4] & 0xffffffff, - regs->gpr[5] & 0xffffffff, - regs->gpr[6] & 0xffffffff); - - /* Return the possibly modified but valid syscall number */ - return regs->gpr[0]; - -skip: - /* - * If we are aborting explicitly, or if the syscall number is - * now invalid, set the return value to -ENOSYS. - */ - regs->gpr[3] = -ENOSYS; - return -1; -} - -void do_syscall_trace_leave(struct pt_regs *regs) -{ - int step; - - audit_syscall_exit(regs); - - if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_sys_exit(regs, regs->result); - - step = test_thread_flag(TIF_SINGLESTEP); - if (step || test_thread_flag(TIF_SYSCALL_TRACE)) - ptrace_report_syscall_exit(regs, step); -} - void __init pt_regs_check(void); /* @@ -432,6 +291,7 @@ void __init pt_regs_check(void) CHECK_REG(PT_DAR, dar); CHECK_REG(PT_DSISR, dsisr); CHECK_REG(PT_RESULT, result); + CHECK_REG(PT_EXIT_FLAGS, exit_flags); #undef CHECK_REG BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long)); diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index fbb7ebd8aa08..600596cb4ffb 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -11,6 +11,7 @@ #include <linux/nospec.h> #include <linux/prctl.h> #include <linux/seq_buf.h> +#include <linux/sysfs.h> #include <linux/debugfs.h> #include <asm/asm-prototypes.h> @@ -163,13 +164,13 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, cha } if (thread_priv) - return sprintf(buf, "Vulnerable: L1D private per thread\n"); + return sysfs_emit(buf, "Vulnerable: L1D private per thread\n"); if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) - return sprintf(buf, "Not affected\n"); + return sysfs_emit(buf, "Not affected\n"); - return sprintf(buf, "Vulnerable\n"); + return sysfs_emit(buf, "Vulnerable\n"); } ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf) @@ -352,14 +353,14 @@ ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute * default: type = "unknown"; } - return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); + return sysfs_emit(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); } if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) - return sprintf(buf, "Not affected\n"); + return sysfs_emit(buf, "Not affected\n"); - return sprintf(buf, "Vulnerable\n"); + return sysfs_emit(buf, "Vulnerable\n"); } static int ssb_prctl_get(struct task_struct *task) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 8a86b0efcb1c..67c545f61f0d 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -68,6 +68,7 @@ #include <asm/kasan.h> #include <asm/mce.h> #include <asm/systemcfg.h> +#include <linux/kmsg_dump.h> #include "setup.h" @@ -323,7 +324,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_putc(m, '\n'); /* If this is the last cpu, print the summary */ - if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids) + if (cpu_id == cpumask_last(cpu_online_mask)) show_cpuinfo_summary(m); return 0; @@ -331,10 +332,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) static void *c_start(struct seq_file *m, loff_t *pos) { - if (*pos == 0) /* just in case, cpu 0 is not the first */ - *pos = cpumask_first(cpu_online_mask); - else - *pos = cpumask_next(*pos - 1, cpu_online_mask); + *pos = cpumask_next(*pos - 1, cpu_online_mask); if ((*pos) < nr_cpu_ids) return (void *)(unsigned long)(*pos + 1); return NULL; @@ -745,6 +743,13 @@ static int ppc_panic_fadump_handler(struct notifier_block *this, hard_irq_disable(); /* + * Invoke kmsg_dump (e.g., pstore) before crash_fadump() as fadump + * runs before panic()'s kmsg_dump_desc() call. + */ + if (should_fadump_crash()) + kmsg_dump_desc(KMSG_DUMP_PANIC, (char *)ptr); + + /* * If firmware-assisted dump has been registered then trigger * its callback and let the firmware handles everything else. */ diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index aa17e62f3754..bb42a8b6c642 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -6,6 +6,7 @@ * Extracted from signal_32.c and signal_64.c */ +#include <linux/entry-common.h> #include <linux/resume_user_mode.h> #include <linux/signal.h> #include <linux/uprobes.h> @@ -292,23 +293,6 @@ static void do_signal(struct task_struct *tsk) signal_setup_done(ret, &ksig, test_thread_flag(TIF_SINGLESTEP)); } -void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) -{ - if (thread_info_flags & _TIF_UPROBE) - uprobe_notify_resume(regs); - - if (thread_info_flags & _TIF_PATCH_PENDING) - klp_update_patch_state(current); - - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) { - BUG_ON(regs != current->thread.regs); - do_signal(current); - } - - if (thread_info_flags & _TIF_NOTIFY_RESUME) - resume_user_mode_work(regs); -} - static unsigned long get_tm_stackpointer(struct task_struct *tsk) { /* When in an active transaction that takes a signal, we need to be @@ -368,3 +352,10 @@ void signal_fault(struct task_struct *tsk, struct pt_regs *regs, printk_ratelimited(regs->msr & MSR_64BIT ? fm64 : fm32, tsk->comm, task_pid_nr(tsk), where, ptr, regs->nip, regs->link); } + +void arch_do_signal_or_restart(struct pt_regs *regs) +{ + BUG_ON(regs != current->thread.regs); + regs->exit_flags |= _TIF_RESTOREALL; + do_signal(current); +} diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c index b762677f8737..a9da2af6efa8 100644 --- a/arch/powerpc/kernel/syscall.c +++ b/arch/powerpc/kernel/syscall.c @@ -3,6 +3,7 @@ #include <linux/compat.h> #include <linux/context_tracking.h> #include <linux/randomize_kstack.h> +#include <linux/entry-common.h> #include <asm/interrupt.h> #include <asm/kup.h> @@ -18,124 +19,10 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0) long ret; syscall_fn f; - kuap_lock(); - - if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) - BUG_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED); - - trace_hardirqs_off(); /* finish reconciling */ - - CT_WARN_ON(ct_state() == CT_STATE_KERNEL); - user_exit_irqoff(); - add_random_kstack_offset(); + r0 = syscall_enter_from_user_mode(regs, r0); - BUG_ON(regs_is_unrecoverable(regs)); - BUG_ON(!user_mode(regs)); - BUG_ON(arch_irq_disabled_regs(regs)); - -#ifdef CONFIG_PPC_PKEY - if (mmu_has_feature(MMU_FTR_PKEY)) { - unsigned long amr, iamr; - bool flush_needed = false; - /* - * When entering from userspace we mostly have the AMR/IAMR - * different from kernel default values. Hence don't compare. - */ - amr = mfspr(SPRN_AMR); - iamr = mfspr(SPRN_IAMR); - regs->amr = amr; - regs->iamr = iamr; - if (mmu_has_feature(MMU_FTR_KUAP)) { - mtspr(SPRN_AMR, AMR_KUAP_BLOCKED); - flush_needed = true; - } - if (mmu_has_feature(MMU_FTR_BOOK3S_KUEP)) { - mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED); - flush_needed = true; - } - if (flush_needed) - isync(); - } else -#endif - kuap_assert_locked(); - - booke_restore_dbcr0(); - - account_cpu_user_entry(); - - account_stolen_time(); - - /* - * This is not required for the syscall exit path, but makes the - * stack frame look nicer. If this was initialised in the first stack - * frame, or if the unwinder was taught the first stack frame always - * returns to user with IRQS_ENABLED, this store could be avoided! - */ - irq_soft_mask_regs_set_state(regs, IRQS_ENABLED); - - /* - * If system call is called with TM active, set _TIF_RESTOREALL to - * prevent RFSCV being used to return to userspace, because POWER9 - * TM implementation has problems with this instruction returning to - * transactional state. Final register values are not relevant because - * the transaction will be aborted upon return anyway. Or in the case - * of unsupported_scv SIGILL fault, the return state does not much - * matter because it's an edge case. - */ - if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && - unlikely(MSR_TM_TRANSACTIONAL(regs->msr))) - set_bits(_TIF_RESTOREALL, ¤t_thread_info()->flags); - - /* - * If the system call was made with a transaction active, doom it and - * return without performing the system call. Unless it was an - * unsupported scv vector, in which case it's treated like an illegal - * instruction. - */ -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) && - !trap_is_unsupported_scv(regs)) { - /* Enable TM in the kernel, and disable EE (for scv) */ - hard_irq_disable(); - mtmsr(mfmsr() | MSR_TM); - - /* tabort, this dooms the transaction, nothing else */ - asm volatile(".long 0x7c00071d | ((%0) << 16)" - :: "r"(TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)); - - /* - * Userspace will never see the return value. Execution will - * resume after the tbegin. of the aborted transaction with the - * checkpointed register state. A context switch could occur - * or signal delivered to the process before resuming the - * doomed transaction context, but that should all be handled - * as expected. - */ - return -ENOSYS; - } -#endif // CONFIG_PPC_TRANSACTIONAL_MEM - - local_irq_enable(); - - if (unlikely(read_thread_flags() & _TIF_SYSCALL_DOTRACE)) { - if (unlikely(trap_is_unsupported_scv(regs))) { - /* Unsupported scv vector */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return regs->gpr[3]; - } - /* - * We use the return value of do_syscall_trace_enter() as the - * syscall number. If the syscall was rejected for any reason - * do_syscall_trace_enter() returns an invalid syscall number - * and the test against NR_syscalls will fail and the return - * value to be used is in regs->gpr[3]. - */ - r0 = do_syscall_trace_enter(regs); - if (unlikely(r0 >= NR_syscalls)) - return regs->gpr[3]; - - } else if (unlikely(r0 >= NR_syscalls)) { + if (unlikely(r0 >= NR_syscalls)) { if (unlikely(trap_is_unsupported_scv(regs))) { /* Unsupported scv vector */ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 6b3dd6decdf9..329c1690b5ed 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -5,6 +5,7 @@ #include <linux/percpu.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/sysfs.h> #include <linux/export.h> #include <linux/nodemask.h> #include <linux/cpumask.h> @@ -63,7 +64,7 @@ static ssize_t show_smt_snooze_delay(struct device *dev, { pr_warn_once("%s (%d) read from unsupported smt_snooze_delay\n", current->comm, current->pid); - return sprintf(buf, "100\n"); + return sysfs_emit(buf, "100\n"); } static DEVICE_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, @@ -100,7 +101,7 @@ static ssize_t show_##NAME(struct device *dev, \ struct cpu *cpu = container_of(dev, struct cpu, dev); \ unsigned long val; \ smp_call_function_single(cpu->dev.id, read_##NAME, &val, 1); \ - return sprintf(buf, "%lx\n", val); \ + return sysfs_emit(buf, "%lx\n", val); \ } \ static ssize_t __used \ store_##NAME(struct device *dev, struct device_attribute *attr, \ @@ -183,7 +184,7 @@ static void add_write_permission_dev_attr(struct device_attribute *attr) static ssize_t show_dscr_default(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%lx\n", dscr_default); + return sysfs_emit(buf, "%lx\n", dscr_default); } /** @@ -272,7 +273,7 @@ static ssize_t show_pw20_state(struct device *dev, value &= PWRMGTCR0_PW20_WAIT; - return sprintf(buf, "%u\n", value ? 1 : 0); + return sysfs_emit(buf, "%u\n", value ? 1 : 0); } static void do_store_pw20_state(void *val) @@ -337,7 +338,7 @@ static ssize_t show_pw20_wait_time(struct device *dev, time = pw20_wt; } - return sprintf(buf, "%llu\n", time > 0 ? time : 0); + return sysfs_emit(buf, "%llu\n", time > 0 ? time : 0); } static void set_pw20_wait_entry_bit(void *val) @@ -394,7 +395,7 @@ static ssize_t show_altivec_idle(struct device *dev, value &= PWRMGTCR0_AV_IDLE_PD_EN; - return sprintf(buf, "%u\n", value ? 1 : 0); + return sysfs_emit(buf, "%u\n", value ? 1 : 0); } static void do_store_altivec_idle(void *val) @@ -459,7 +460,7 @@ static ssize_t show_altivec_idle_wait_time(struct device *dev, time = altivec_idle_wt; } - return sprintf(buf, "%llu\n", time > 0 ? time : 0); + return sysfs_emit(buf, "%llu\n", time > 0 ? time : 0); } static void set_altivec_idle_wait_entry_bit(void *val) @@ -746,7 +747,7 @@ static struct device_attribute pa6t_attrs[] = { #ifdef CONFIG_PPC_SVM static ssize_t show_svm(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", is_secure_guest()); + return sysfs_emit(buf, "%u\n", is_secure_guest()); } static DEVICE_ATTR(svm, 0444, show_svm, NULL); @@ -780,7 +781,7 @@ static ssize_t idle_purr_show(struct device *dev, u64 val; smp_call_function_single(cpu->dev.id, read_idle_purr, &val, 1); - return sprintf(buf, "%llx\n", val); + return sysfs_emit(buf, "%llx\n", val); } static DEVICE_ATTR(idle_purr, 0400, idle_purr_show, NULL); @@ -810,7 +811,7 @@ static ssize_t idle_spurr_show(struct device *dev, u64 val; smp_call_function_single(cpu->dev.id, read_idle_spurr, &val, 1); - return sprintf(buf, "%llx\n", val); + return sysfs_emit(buf, "%llx\n", val); } static DEVICE_ATTR(idle_spurr, 0400, idle_spurr_show, NULL); @@ -1143,7 +1144,7 @@ static ssize_t show_physical_id(struct device *dev, { struct cpu *cpu = container_of(dev, struct cpu, dev); - return sprintf(buf, "%d\n", get_hard_smp_processor_id(cpu->dev.id)); + return sysfs_emit(buf, "%d\n", get_hard_smp_processor_id(cpu->dev.id)); } static DEVICE_ATTR(physical_id, 0444, show_physical_id, NULL); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index cb8e9357383e..629f2a2d4780 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1956,7 +1956,7 @@ DEFINE_INTERRUPT_HANDLER_RAW(performance_monitor_exception) * prevent hash faults on user addresses when reading callchains (and * looks better from an irq tracing perspective). */ - if (IS_ENABLED(CONFIG_PPC64) && unlikely(arch_irq_disabled_regs(regs))) + if (IS_ENABLED(CONFIG_PPC64) && unlikely(regs_irqs_disabled(regs))) performance_monitor_exception_nmi(regs); else performance_monitor_exception_async(regs); diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c index 764001deb060..c40c69368476 100644 --- a/arch/powerpc/kernel/watchdog.c +++ b/arch/powerpc/kernel/watchdog.c @@ -376,7 +376,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt) u64 tb; /* should only arrive from kernel, with irqs disabled */ - WARN_ON_ONCE(!arch_irq_disabled_regs(regs)); + WARN_ON_ONCE(!regs_irqs_disabled(regs)); if (!cpumask_test_cpu(cpu, &wd_cpus_enabled)) return 0; diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c index 825ab8a88f18..58c13a59b93b 100644 --- a/arch/powerpc/kexec/core_64.c +++ b/arch/powerpc/kexec/core_64.c @@ -169,7 +169,7 @@ static void kexec_prepare_cpus_wait(int wait_state) int my_cpu, i, notified=-1; hw_breakpoint_disable(); - my_cpu = get_cpu(); + my_cpu = raw_smp_processor_id(); /* Make sure each CPU has at least made it to the state we need. * * FIXME: There is a (slim) chance of a problem if not all of the CPUs @@ -267,8 +267,6 @@ static void kexec_prepare_cpus(void) /* after we tell the others to go down */ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); - - put_cpu(); } #else /* ! SMP */ diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index 9dc5889d6ecb..e4fcf929cb33 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -1299,9 +1299,7 @@ static void stress_hpt_timer_fn(struct timer_list *timer) if (!firmware_has_feature(FW_FEATURE_LPAR)) tlbiel_all(); - next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask); - if (next_cpu >= nr_cpu_ids) - next_cpu = cpumask_first(cpu_online_mask); + next_cpu = cpumask_next_wrap(raw_smp_processor_id(), cpu_online_mask); stress_hpt_timer.expires = jiffies + msecs_to_jiffies(10); add_timer_on(&stress_hpt_timer, next_cpu); } diff --git a/arch/powerpc/net/Makefile b/arch/powerpc/net/Makefile index 8e60af32e51e..7f9339bacef1 100644 --- a/arch/powerpc/net/Makefile +++ b/arch/powerpc/net/Makefile @@ -3,3 +3,7 @@ # Arch-specific network modules # obj-$(CONFIG_BPF_JIT) += bpf_jit_comp.o bpf_jit_comp$(BITS).o + +ifdef CONFIG_PPC64 +obj-$(CONFIG_BPF_JIT) += bpf_timed_may_goto.o +endif diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 6351a187ca61..d4a17e18c9fb 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -517,6 +517,11 @@ bool bpf_jit_supports_subprog_tailcalls(void) return IS_ENABLED(CONFIG_PPC64); } +bool bpf_jit_supports_timed_may_goto(void) +{ + return IS_ENABLED(CONFIG_PPC64); +} + bool bpf_jit_supports_kfunc_call(void) { return IS_ENABLED(CONFIG_PPC64); diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index db364d9083e7..dab106cae22b 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -451,10 +451,28 @@ void arch_bpf_stack_walk(bool (*consume_fn)(void *, u64, u64, u64), void *cookie } } +static int bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func_addr, int reg) +{ + long reladdr = func_addr - kernel_toc_addr(); + + if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { + pr_err("eBPF: address of %ps out of range of kernel_toc.\n", (void *)func_addr); + return -ERANGE; + } + + EMIT(PPC_RAW_ADDIS(reg, _R2, PPC_HA(reladdr))); + EMIT(PPC_RAW_ADDI(reg, reg, PPC_LO(reladdr))); + EMIT(PPC_RAW_MTCTR(reg)); + EMIT(PPC_RAW_BCTRL()); + + return 0; +} + int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func) { unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0; - long reladdr; + long __maybe_unused reladdr; + int ret; /* bpf to bpf call, func is not known in the initial pass. Emit 5 nops as a placeholder */ if (!func) { @@ -507,16 +525,9 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context * EMIT(PPC_RAW_BCTRL()); #else if (core_kernel_text(func_addr)) { - reladdr = func_addr - kernel_toc_addr(); - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { - pr_err("eBPF: address of %ps out of range of kernel_toc.\n", (void *)func); - return -ERANGE; - } - - EMIT(PPC_RAW_ADDIS(_R12, _R2, PPC_HA(reladdr))); - EMIT(PPC_RAW_ADDI(_R12, _R12, PPC_LO(reladdr))); - EMIT(PPC_RAW_MTCTR(_R12)); - EMIT(PPC_RAW_BCTRL()); + ret = bpf_jit_emit_func_call(image, ctx, func_addr, _R12); + if (ret) + return ret; } else { if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V1)) { /* func points to the function descriptor */ @@ -1755,6 +1766,35 @@ emit_clear: if (ret < 0) return ret; + /* + * Call to arch_bpf_timed_may_goto() is emitted by the + * verifier and called with custom calling convention with + * first argument and return value in BPF_REG_AX (_R12). + * + * The generic helper or bpf function call emission path + * may use the same scratch register as BPF_REG_AX to + * materialize the target address. This would clobber AX + * and break timed may_goto semantics. + * + * Emit a minimal indirect call sequence here using a temp + * register and skip the normal post-call return-value move. + */ + + if (func_addr == (u64)arch_bpf_timed_may_goto) { + ret = 0; + if (!IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + ret = bpf_jit_emit_func_call(image, ctx, func_addr, + tmp1_reg); + + if (ret || IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + PPC_LI_ADDR(tmp1_reg, func_addr); + EMIT(PPC_RAW_MTCTR(tmp1_reg)); + EMIT(PPC_RAW_BCTRL()); + } + + break; + } + /* Take care of powerpc ABI requirements before kfunc call */ if (insn[i].src_reg == BPF_PSEUDO_KFUNC_CALL) { if (prepare_for_kfunc_call(fp, image, ctx, &insn[i])) diff --git a/arch/powerpc/net/bpf_timed_may_goto.S b/arch/powerpc/net/bpf_timed_may_goto.S new file mode 100644 index 000000000000..6fd8b1c9f4ac --- /dev/null +++ b/arch/powerpc/net/bpf_timed_may_goto.S @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2025 IBM Corporation, Saket Kumar Bhaskar <skb99@linux.ibm.com> */ + +#include <linux/linkage.h> +#include <asm/ppc_asm.h> + +/* + * arch_bpf_timed_may_goto() trampoline for powerpc64 + * + * Custom BPF convention (verifier/JIT): + * - input: stack offset in BPF_REG_AX (r12) + * - output: updated count in BPF_REG_AX (r12) + * + * Call bpf_check_timed_may_goto(ptr) with normal powerpc64 ABI: + * - r3 = ptr, return in r3 + * + * Preserve BPF regs R0-R5 (mapping: r8, r3-r7). + */ + +SYM_FUNC_START(arch_bpf_timed_may_goto) + /* Prologue: save LR, allocate frame */ + mflr r0 + std r0, 16(r1) + stdu r1, -112(r1) + + /* Save BPF registers R0 - R5 (r8, r3-r7) */ + std r3, 32(r1) + std r4, 40(r1) + std r5, 48(r1) + std r6, 56(r1) + std r7, 64(r1) + std r8, 72(r1) + + /* + * r3 = BPF_REG_FP + BPF_REG_AX + * BPF_REG_FP is r31; BPF_REG_AX is r12 (stack offset in bytes). + */ + add r3, r31, r12 + bl bpf_check_timed_may_goto + + /* Put return value back into AX */ + mr r12, r3 + + /* Restore BPF registers R0 - R5 (r8, r3-r7) */ + ld r3, 32(r1) + ld r4, 40(r1) + ld r5, 48(r1) + ld r6, 56(r1) + ld r7, 64(r1) + ld r8, 72(r1) + + /* Epilogue: pop frame, restore LR, return */ + addi r1, r1, 112 + ld r0, 16(r1) + mtlr r0 + blr +SYM_FUNC_END(arch_bpf_timed_may_goto) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 2e6adf5b95c4..720b1a500922 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -10,6 +10,7 @@ #include <linux/perf_event.h> #include <linux/percpu.h> #include <linux/hardirq.h> +#include <linux/sysfs.h> #include <linux/uaccess.h> #include <asm/reg.h> #include <asm/pmc.h> @@ -2204,7 +2205,7 @@ ssize_t power_events_sysfs_show(struct device *dev, pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); - return sprintf(page, "event=0x%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } static struct pmu power_pmu = { @@ -2483,7 +2484,7 @@ static void __perf_event_interrupt(struct pt_regs *regs) * will trigger a PMI after waking up from idle. Since counter values are _not_ * saved/restored in idle path, can lead to below "Can't find PMC" message. */ - if (unlikely(!found) && !arch_irq_disabled_regs(regs)) + if (unlikely(!found) && !regs_irqs_disabled(regs)) printk_ratelimited(KERN_WARNING "Can't find PMC that caused IRQ\n"); /* diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c index 7120ab20cbfe..02b5dd74c187 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -366,9 +366,10 @@ static void fsl_emb_pmu_del(struct perf_event *event, int flags) cpuhw->n_events--; + put_cpu_var(cpu_hw_events); + out: perf_pmu_enable(event->pmu); - put_cpu_var(cpu_hw_events); } static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags) diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 243c0a1c8cda..abb4cfb11fcc 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -12,6 +12,7 @@ #include <linux/rbtree.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/vmalloc.h> #include <asm/cputhreads.h> @@ -434,19 +435,19 @@ static ssize_t cpumask_show(struct device *dev, static ssize_t sockets_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", phys_sockets); + return sysfs_emit(buf, "%d\n", phys_sockets); } static ssize_t chipspersocket_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", phys_chipspersocket); + return sysfs_emit(buf, "%d\n", phys_chipspersocket); } static ssize_t coresperchip_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", phys_coresperchip); + return sysfs_emit(buf, "%d\n", phys_coresperchip); } static struct attribute *device_str_attr_create_(char *name, char *str) @@ -1061,7 +1062,7 @@ e_free: static ssize_t domains_show(struct device *dev, struct device_attribute *attr, char *page) { - int d, n, count = 0; + int d, count = 0; const char *str; for (d = 0; d < HV_PERF_DOMAIN_MAX; d++) { @@ -1069,12 +1070,7 @@ static ssize_t domains_show(struct device *dev, struct device_attribute *attr, if (!str) continue; - n = sprintf(page, "%d: %s\n", d, str); - if (n < 0) - break; - - count += n; - page += n; + count += sysfs_emit_at(page, count, "%d: %s\n", d, str); } return count; } @@ -1095,7 +1091,7 @@ static ssize_t _name##_show(struct device *dev, \ ret = -EIO; \ goto e_free; \ } \ - ret = sprintf(buf, _fmt, _expr); \ + ret = sysfs_emit(buf, _fmt, _expr); \ e_free: \ kmem_cache_free(hv_page_cache, page); \ return ret; \ diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c index 10c82cf8f5b3..7269273d3aa8 100644 --- a/arch/powerpc/perf/hv-gpci.c +++ b/arch/powerpc/perf/hv-gpci.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/perf_event.h> +#include <linux/sysfs.h> #include <asm/firmware.h> #include <asm/hvcall.h> #include <asm/io.h> @@ -85,7 +86,7 @@ static ssize_t _name##_show(struct device *dev, \ if (hret) \ return -EIO; \ \ - return sprintf(page, _format, caps._name); \ + return sysfs_emit(page, _format, caps._name); \ } \ static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name) @@ -93,7 +94,7 @@ static ssize_t kernel_version_show(struct device *dev, struct device_attribute *attr, char *page) { - return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT); + return sysfs_emit(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT); } static ssize_t cpumask_show(struct device *dev, diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index c1563b4eaa94..e3822f36c419 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -421,7 +421,6 @@ static int ppc_nest_imc_cpu_offline(unsigned int cpu) static int ppc_nest_imc_cpu_online(unsigned int cpu) { const struct cpumask *l_cpumask; - static struct cpumask tmp_mask; int res; /* Get the cpumask of this node */ @@ -431,7 +430,7 @@ static int ppc_nest_imc_cpu_online(unsigned int cpu) * If this is not the first online CPU on this node, then * just return. */ - if (cpumask_and(&tmp_mask, l_cpumask, &nest_imc_cpumask)) + if (cpumask_intersects(l_cpumask, &nest_imc_cpumask)) return 0; /* @@ -647,14 +646,13 @@ static bool is_core_imc_mem_inited(int cpu) static int ppc_core_imc_cpu_online(unsigned int cpu) { const struct cpumask *l_cpumask; - static struct cpumask tmp_mask; int ret = 0; /* Get the cpumask for this core */ l_cpumask = cpu_sibling_mask(cpu); /* If a cpu for this core is already set, then, don't do anything */ - if (cpumask_and(&tmp_mask, l_cpumask, &core_imc_cpumask)) + if (cpumask_intersects(l_cpumask, &core_imc_cpumask)) return 0; if (!is_core_imc_mem_inited(cpu)) { diff --git a/arch/powerpc/perf/kvm-hv-pmu.c b/arch/powerpc/perf/kvm-hv-pmu.c index ae264c9080ef..aa72b96b5a8c 100644 --- a/arch/powerpc/perf/kvm-hv-pmu.c +++ b/arch/powerpc/perf/kvm-hv-pmu.c @@ -16,6 +16,7 @@ #include <linux/perf_event.h> #include <linux/spinlock_types.h> #include <linux/spinlock.h> +#include <linux/sysfs.h> #include <asm/types.h> #include <asm/kvm_ppc.h> @@ -48,7 +49,7 @@ static ssize_t kvmppc_events_sysfs_show(struct device *dev, struct perf_pmu_events_attr *pmu_attr; pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); - return sprintf(page, "event=0x%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } /* Holds the hostwide stats */ diff --git a/arch/powerpc/perf/vpa-pmu.c b/arch/powerpc/perf/vpa-pmu.c index 840733468959..bff4cfab7b94 100644 --- a/arch/powerpc/perf/vpa-pmu.c +++ b/arch/powerpc/perf/vpa-pmu.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/perf_event.h> +#include <linux/sysfs.h> #include <asm/kvm_ppc.h> #include <asm/kvm_book3s_64.h> @@ -26,7 +27,7 @@ static ssize_t vpa_pmu_events_sysfs_show(struct device *dev, pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); - return sprintf(page, "event=0x%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } #define VPA_PMU_EVENT_ATTR(_name, _id) \ diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index 9b693594a5f7..c3fbec1f1d24 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -15,6 +15,7 @@ #include <linux/i2c.h> #include <linux/gpio/driver.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/kthread.h> #include <linux/property.h> #include <linux/reboot.h> @@ -77,7 +78,7 @@ static ssize_t show_status(struct device *d, return -ENODEV; mcu->reg_ctrl = ret; - return sprintf(buf, "%02x\n", ret); + return sysfs_emit(buf, "%02x\n", ret); } static DEVICE_ATTR(status, 0444, show_status, NULL); diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c index f00734f0590c..b31376bf6778 100644 --- a/arch/powerpc/platforms/8xx/cpm1.c +++ b/arch/powerpc/platforms/8xx/cpm1.c @@ -472,6 +472,18 @@ static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int cpm1_gpio16_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc); + struct cpm_ioport16 __iomem *iop = cpm1_gc->regs; + u16 pin_mask = 1 << (15 - gpio); + + if (in_be16(&iop->dir) & pin_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + int cpm1_gpiochip_add16(struct device *dev) { struct device_node *np = dev->of_node; @@ -498,6 +510,7 @@ int cpm1_gpiochip_add16(struct device *dev) gc->ngpio = 16; gc->direction_input = cpm1_gpio16_dir_in; gc->direction_output = cpm1_gpio16_dir_out; + gc->get_direction = cpm1_gpio16_get_direction; gc->get = cpm1_gpio16_get; gc->set = cpm1_gpio16_set; gc->to_irq = cpm1_gpio16_to_irq; @@ -604,6 +617,18 @@ static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int cpm1_gpio32_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc); + struct cpm_ioport32b __iomem *iop = cpm1_gc->regs; + u32 pin_mask = 1 << (31 - gpio); + + if (in_be32(&iop->dir) & pin_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + int cpm1_gpiochip_add32(struct device *dev) { struct device_node *np = dev->of_node; @@ -621,6 +646,7 @@ int cpm1_gpiochip_add32(struct device *dev) gc->ngpio = 32; gc->direction_input = cpm1_gpio32_dir_in; gc->direction_output = cpm1_gpio32_dir_out; + gc->get_direction = cpm1_gpio32_get_direction; gc->get = cpm1_gpio32_get; gc->set = cpm1_gpio32_set; gc->parent = dev; diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 0ec7b3bdda56..8452153d4650 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -20,6 +20,7 @@ #include <linux/mutex.h> #include <linux/linux_logo.h> #include <linux/syscore_ops.h> +#include <linux/sysfs.h> #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/spu_csa.h> @@ -638,8 +639,8 @@ static ssize_t spu_stat_show(struct device *dev, { struct spu *spu = container_of(dev, struct spu, dev); - return sprintf(buf, "%s %llu %llu %llu %llu " - "%llu %llu %llu %llu %llu %llu %llu %llu\n", + return sysfs_emit(buf, + "%s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", spu_state_names[spu->stats.util_state], spu_acct_time(spu, SPU_UTIL_USER), spu_acct_time(spu, SPU_UTIL_SYSTEM), diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index 6cd461f82968..33103a98cfd5 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -8,6 +8,7 @@ #include <linux/types.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/of.h> #include <linux/device.h> #include <linux/cpu.h> @@ -171,7 +172,7 @@ static u8 fastsleep_workaround_applyonce; static ssize_t show_fastsleep_workaround_applyonce(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", fastsleep_workaround_applyonce); + return sysfs_emit(buf, "%u\n", fastsleep_workaround_applyonce); } static ssize_t store_fastsleep_workaround_applyonce(struct device *dev, diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c index 2e4bffa74163..0586821d7af4 100644 --- a/arch/powerpc/platforms/powernv/opal-dump.c +++ b/arch/powerpc/platforms/powernv/opal-dump.c @@ -8,6 +8,7 @@ #include <linux/kobject.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> #include <linux/delay.h> @@ -40,7 +41,7 @@ static ssize_t dump_id_show(struct dump_obj *dump_obj, struct dump_attribute *attr, char *buf) { - return sprintf(buf, "0x%x\n", dump_obj->id); + return sysfs_emit(buf, "0x%x\n", dump_obj->id); } static const char* dump_type_to_string(uint32_t type) @@ -58,15 +59,15 @@ static ssize_t dump_type_show(struct dump_obj *dump_obj, char *buf) { - return sprintf(buf, "0x%x %s\n", dump_obj->type, - dump_type_to_string(dump_obj->type)); + return sysfs_emit(buf, "0x%x %s\n", dump_obj->type, + dump_type_to_string(dump_obj->type)); } static ssize_t dump_ack_show(struct dump_obj *dump_obj, struct dump_attribute *attr, char *buf) { - return sprintf(buf, "ack - acknowledge dump\n"); + return sysfs_emit(buf, "ack - acknowledge dump\n"); } /* @@ -114,7 +115,7 @@ static ssize_t init_dump_show(struct dump_obj *dump_obj, struct dump_attribute *attr, char *buf) { - return sprintf(buf, "1 - initiate Service Processor(FSP) dump\n"); + return sysfs_emit(buf, "1 - initiate Service Processor(FSP) dump\n"); } static int64_t dump_fips_init(uint8_t type) diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c index 2b8331922ab9..6cacd3fd3cd5 100644 --- a/arch/powerpc/platforms/powernv/opal-elog.c +++ b/arch/powerpc/platforms/powernv/opal-elog.c @@ -40,7 +40,7 @@ static ssize_t elog_id_show(struct elog_obj *elog_obj, struct elog_attribute *attr, char *buf) { - return sprintf(buf, "0x%llx\n", elog_obj->id); + return sysfs_emit(buf, "0x%llx\n", elog_obj->id); } static const char *elog_type_to_string(uint64_t type) @@ -55,16 +55,15 @@ static ssize_t elog_type_show(struct elog_obj *elog_obj, struct elog_attribute *attr, char *buf) { - return sprintf(buf, "0x%llx %s\n", - elog_obj->type, - elog_type_to_string(elog_obj->type)); + return sysfs_emit(buf, "0x%llx %s\n", elog_obj->type, + elog_type_to_string(elog_obj->type)); } static ssize_t elog_ack_show(struct elog_obj *elog_obj, struct elog_attribute *attr, char *buf) { - return sprintf(buf, "ack - acknowledge log message\n"); + return sysfs_emit(buf, "ack - acknowledge log message\n"); } static ssize_t elog_ack_store(struct elog_obj *elog_obj, diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index a3f7a2928767..5ca5f6329a2d 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c @@ -238,7 +238,7 @@ static ssize_t manage_show(struct kobject *kobj, struct manage_flash_t *const args_buf = &manage_flash_data; int rc; - rc = sprintf(buf, "%d\n", args_buf->status); + rc = sysfs_emit(buf, "%d\n", args_buf->status); /* Set status to default*/ args_buf->status = FLASH_NO_OP; return rc; @@ -321,7 +321,7 @@ static ssize_t update_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct update_flash_t *const args_buf = &update_flash_data; - return sprintf(buf, "%d\n", args_buf->status); + return sysfs_emit(buf, "%d\n", args_buf->status); } /* diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c index 9bb73cb42a65..bf18b333281e 100644 --- a/arch/powerpc/platforms/powernv/opal-powercap.c +++ b/arch/powerpc/platforms/powernv/opal-powercap.c @@ -10,6 +10,7 @@ #include <linux/of.h> #include <linux/kobject.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <asm/opal.h> @@ -56,16 +57,11 @@ static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr, goto out; } ret = opal_error_code(opal_get_async_rc(msg)); - if (!ret) { - ret = sprintf(buf, "%u\n", be32_to_cpu(pcap)); - if (ret < 0) - ret = -EIO; - } + if (!ret) + ret = sysfs_emit(buf, "%u\n", be32_to_cpu(pcap)); break; case OPAL_SUCCESS: - ret = sprintf(buf, "%u\n", be32_to_cpu(pcap)); - if (ret < 0) - ret = -EIO; + ret = sysfs_emit(buf, "%u\n", be32_to_cpu(pcap)); break; default: ret = opal_error_code(ret); diff --git a/arch/powerpc/platforms/powernv/opal-psr.c b/arch/powerpc/platforms/powernv/opal-psr.c index 24d0a894d965..19228181cb6f 100644 --- a/arch/powerpc/platforms/powernv/opal-psr.c +++ b/arch/powerpc/platforms/powernv/opal-psr.c @@ -10,6 +10,7 @@ #include <linux/of.h> #include <linux/kobject.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <asm/opal.h> @@ -50,16 +51,11 @@ static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr, goto out; } ret = opal_error_code(opal_get_async_rc(msg)); - if (!ret) { - ret = sprintf(buf, "%u\n", be32_to_cpu(psr)); - if (ret < 0) - ret = -EIO; - } + if (!ret) + ret = sysfs_emit(buf, "%u\n", be32_to_cpu(psr)); break; case OPAL_SUCCESS: - ret = sprintf(buf, "%u\n", be32_to_cpu(psr)); - if (ret < 0) - ret = -EIO; + ret = sysfs_emit(buf, "%u\n", be32_to_cpu(psr)); break; default: ret = opal_error_code(ret); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 4dbb47ddbdcc..06ed5e2aa265 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -396,7 +396,8 @@ static void pnv_kexec_wait_secondaries_down(void) { int my_cpu, i, notified = -1; - my_cpu = get_cpu(); + /* Called with interrupts disabled, so the CPU is pinned. */ + my_cpu = raw_smp_processor_id(); for_each_online_cpu(i) { uint8_t status; diff --git a/arch/powerpc/platforms/powernv/subcore.c b/arch/powerpc/platforms/powernv/subcore.c index 393e747541fb..f7668ef1ac1f 100644 --- a/arch/powerpc/platforms/powernv/subcore.c +++ b/arch/powerpc/platforms/powernv/subcore.c @@ -12,6 +12,7 @@ #include <linux/gfp.h> #include <linux/smp.h> #include <linux/stop_machine.h> +#include <linux/sysfs.h> #include <asm/cputhreads.h> #include <asm/cpuidle.h> @@ -409,7 +410,7 @@ out: static ssize_t show_subcores_per_core(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%x\n", subcores_per_core); + return sysfs_emit(buf, "%x\n", subcores_per_core); } static DEVICE_ATTR(subcores_per_core, 0644, diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 150c09b58ae8..ca2608a70f4d 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/fs.h> #include <linux/root_dev.h> +#include <linux/sysfs.h> #include <linux/console.h> #include <linux/export.h> #include <linux/memblock.h> @@ -183,7 +184,7 @@ static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx) static ssize_t ps3_fw_version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%s", ps3_firmware_version_str); + return sysfs_emit(buf, "%s\n", ps3_firmware_version_str); } static int __init ps3_setup_sysfs(void) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 8d83df12430f..38e22125b96f 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -18,6 +18,7 @@ #include <linux/sched.h> #include <linux/stringify.h> #include <linux/swap.h> +#include <linux/sysfs.h> #include <linux/device.h> #include <linux/balloon.h> #include <asm/firmware.h> @@ -333,7 +334,7 @@ static int cmm_thread(void *dummy) struct device_attribute *attr, \ char *buf) \ { \ - return sprintf(buf, format, ##args); \ + return sysfs_emit(buf, format, ##args); \ } \ static DEVICE_ATTR(name, 0444, show_##name, NULL) @@ -343,7 +344,7 @@ CMM_SHOW(loaned_target_kb, "%lu\n", PAGES2KB(loaned_pages_target)); static ssize_t show_oom_pages(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%lu\n", PAGES2KB(oom_freed_pages)); + return sysfs_emit(buf, "%lu\n", PAGES2KB(oom_freed_pages)); } static ssize_t store_oom_pages(struct device *dev, diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index a7c451c2507d..f4d33b8dffd8 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/cpu.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/of.h> #include "of_helpers.h" @@ -798,7 +799,7 @@ dlpar_store_out: static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", "memory,cpu,dt"); + return sysfs_emit(buf, "%s\n", "memory,cpu,dt"); } static CLASS_ATTR_RW(dlpar); diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index cad2deb7e70d..2d0f991da2c8 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -46,6 +46,7 @@ #include <linux/of.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/sysfs.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <asm/ibmebus.h> @@ -399,7 +400,7 @@ static ssize_t devspec_show(struct device *dev, struct platform_device *ofdev; ofdev = to_platform_device(dev); - return sprintf(buf, "%pOF\n", ofdev->dev.of_node); + return sysfs_emit(buf, "%pOF\n", ofdev->dev.of_node); } static DEVICE_ATTR_RO(devspec); @@ -409,7 +410,7 @@ static ssize_t name_show(struct device *dev, struct platform_device *ofdev; ofdev = to_platform_device(dev); - return sprintf(buf, "%pOFn\n", ofdev->dev.of_node); + return sysfs_emit(buf, "%pOFn\n", ofdev->dev.of_node); } static DEVICE_ATTR_RO(name); diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index 8821c378bfff..54b7ecf375b5 100644 --- a/arch/powerpc/platforms/pseries/lparcfg.c +++ b/arch/powerpc/platforms/pseries/lparcfg.c @@ -22,6 +22,7 @@ #include <asm/papr-sysparm.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/string.h> #include <linux/uaccess.h> #include <linux/hugetlb.h> #include <asm/lppaca.h> @@ -431,17 +432,18 @@ static void parse_system_parameter_string(struct seq_file *m) w_idx = 0; } else if (local_buffer[idx] == '=') { /* code here to replace workbuffer contents - with different keyword strings */ - if (0 == strcmp(workbuffer, "MaxEntCap")) { - strcpy(workbuffer, - "partition_max_entitled_capacity"); - w_idx = strlen(workbuffer); - } - if (0 == strcmp(workbuffer, "MaxPlatProcs")) { - strcpy(workbuffer, - "system_potential_processors"); - w_idx = strlen(workbuffer); - } + * with different keyword strings. Truncation + * by strscpy is deliberately ignored because + * SPLPAR_MAXLENGTH >= maximum string size. + */ + if (!strcmp(workbuffer, "MaxEntCap")) + w_idx = strscpy(workbuffer, + "partition_max_entitled_capacity", + SPLPAR_MAXLENGTH); + if (!strcmp(workbuffer, "MaxPlatProcs")) + w_idx = strscpy(workbuffer, + "system_potential_processors", + SPLPAR_MAXLENGTH); } } kfree(workbuffer); diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 63eca4ebb5e5..75da96c08cdd 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -8,6 +8,7 @@ #include <linux/ioport.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/ndctl.h> #include <linux/sched.h> #include <linux/libnvdimm.h> @@ -1062,8 +1063,8 @@ static ssize_t health_bitmap_inject_show(struct device *dev, struct nvdimm *dimm = to_nvdimm(dev); struct papr_scm_priv *p = nvdimm_provider_data(dimm); - return sprintf(buf, "%#llx\n", - READ_ONCE(p->health_bitmap_inject_mask)); + return sysfs_emit(buf, "%#llx\n", + READ_ONCE(p->health_bitmap_inject_mask)); } static DEVICE_ATTR_ADMIN_RO(health_bitmap_inject); diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c index 3676cb297767..7b9dfe829f25 100644 --- a/arch/powerpc/platforms/pseries/power.c +++ b/arch/powerpc/platforms/pseries/power.c @@ -11,6 +11,7 @@ #include <linux/kobject.h> #include <linux/string.h> +#include <linux/sysfs.h> #include <linux/errno.h> #include <linux/init.h> #include <asm/machdep.h> @@ -22,7 +23,7 @@ unsigned long rtas_poweron_auto; /* default and normal state is 0 */ static ssize_t auto_poweron_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%lu\n", rtas_poweron_auto); + return sysfs_emit(buf, "%lu\n", rtas_poweron_auto); } static ssize_t auto_poweron_store(struct kobject *kobj, diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c index 2c661b798235..fdaf85ecd39b 100644 --- a/arch/powerpc/platforms/pseries/pseries_energy.c +++ b/arch/powerpc/platforms/pseries/pseries_energy.c @@ -12,6 +12,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/sysfs.h> #include <linux/device.h> #include <linux/cpu.h> #include <linux/of.h> @@ -242,7 +243,7 @@ static ssize_t get_best_energy_data(struct device *dev, if (rc != H_SUCCESS) return -EINVAL; - return sprintf(page, "%lu\n", retbuf[1] >> 32); + return sysfs_emit(page, "%lu\n", retbuf[1] >> 32); } /* Wrapper functions */ diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c index eceb3289383e..3bb4ac2ab6cc 100644 --- a/arch/powerpc/platforms/pseries/rtas-fadump.c +++ b/arch/powerpc/platforms/pseries/rtas-fadump.c @@ -179,9 +179,42 @@ static u64 rtas_fadump_get_bootmem_min(void) return RTAS_FADUMP_MIN_BOOT_MEM; } +/* + * Helper to make an ibm,configure-kernel-dump RTAS call with a bounded + * busy-wait loop. Returns the RTAS return code on completion, or + * -ETIMEDOUT if firmware keeps returning a busy status beyond + * RTAS_FADUMP_MAX_WAIT_MS milliseconds. + */ +static int rtas_fadump_call(struct fw_dump *fadump_conf, int operation, + void *fdm_ptr, unsigned int fdm_size, + const char *op_name) +{ + unsigned int wait_time, total_wait = 0; + int rc; + + do { + rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1, + NULL, operation, fdm_ptr, fdm_size); + wait_time = rtas_busy_delay_time(rc); + if (wait_time) { + pr_debug("Firmware busy during fadump %s, waiting %ums (total %ums)\n", + op_name, wait_time, total_wait); + if (total_wait >= RTAS_FADUMP_MAX_WAIT_MS) { + pr_err("Timed out waiting for firmware to complete fadump %s\n", + op_name); + return -ETIMEDOUT; + } + total_wait += wait_time; + mdelay(wait_time); + } + } while (wait_time); + + return rc; +} + static int rtas_fadump_register(struct fw_dump *fadump_conf) { - unsigned int wait_time, fdm_size; + unsigned int fdm_size; int rc, err = -EIO; /* @@ -192,16 +225,10 @@ static int rtas_fadump_register(struct fw_dump *fadump_conf) fdm_size = sizeof(struct rtas_fadump_section_header); fdm_size += be16_to_cpu(fdm.header.dump_num_sections) * sizeof(struct rtas_fadump_section); - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1, - NULL, FADUMP_REGISTER, &fdm, fdm_size); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - - } while (wait_time); + rc = rtas_fadump_call(fadump_conf, FADUMP_REGISTER, &fdm, fdm_size, + "register"); + if (rc == -ETIMEDOUT) + return -ETIMEDOUT; switch (rc) { case 0: @@ -234,19 +261,12 @@ static int rtas_fadump_register(struct fw_dump *fadump_conf) static int rtas_fadump_unregister(struct fw_dump *fadump_conf) { - unsigned int wait_time; int rc; - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1, - NULL, FADUMP_UNREGISTER, &fdm, - sizeof(struct rtas_fadump_mem_struct)); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - } while (wait_time); + rc = rtas_fadump_call(fadump_conf, FADUMP_UNREGISTER, &fdm, + sizeof(struct rtas_fadump_mem_struct), "unregister"); + if (rc == -ETIMEDOUT) + return -ETIMEDOUT; if (rc) { pr_err("Failed to un-register - unexpected error(%d).\n", rc); @@ -259,19 +279,13 @@ static int rtas_fadump_unregister(struct fw_dump *fadump_conf) static int rtas_fadump_invalidate(struct fw_dump *fadump_conf) { - unsigned int wait_time; int rc; - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1, - NULL, FADUMP_INVALIDATE, fdm_active, - sizeof(struct rtas_fadump_mem_struct)); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - } while (wait_time); + rc = rtas_fadump_call(fadump_conf, FADUMP_INVALIDATE, + (void *)fdm_active, + sizeof(struct rtas_fadump_mem_struct), "invalidate"); + if (rc == -ETIMEDOUT) + return -ETIMEDOUT; if (rc) { pr_err("Failed to invalidate - unexpected error (%d).\n", rc); diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h index c109abf6befd..65fdab7b5b8d 100644 --- a/arch/powerpc/platforms/pseries/rtas-fadump.h +++ b/arch/powerpc/platforms/pseries/rtas-fadump.h @@ -41,6 +41,12 @@ #define MAX_SECTIONS 10 #define RTAS_FADUMP_MAX_BOOT_MEM_REGS 7 +/* + * Maximum time to wait for firmware to respond to an + * ibm,configure-kernel-dump RTAS call before giving up. + */ +#define RTAS_FADUMP_MAX_WAIT_MS 60000U + /* Kernel Dump section info */ struct rtas_fadump_section { __be32 request_flag; diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index c51db63d3e88..a9928d75624a 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -7,6 +7,7 @@ #include <linux/delay.h> #include <linux/suspend.h> #include <linux/stat.h> +#include <linux/sysfs.h> #include <asm/firmware.h> #include <asm/hvcall.h> #include <asm/machdep.h> @@ -121,7 +122,7 @@ static ssize_t show_hibernate(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", KERN_DT_UPDATE); + return sysfs_emit(buf, "%d\n", KERN_DT_UPDATE); } static DEVICE_ATTR(hibernate, 0644, show_hibernate, store_hibernate); diff --git a/arch/powerpc/platforms/pseries/vas-sysfs.c b/arch/powerpc/platforms/pseries/vas-sysfs.c index 4f6fbbb672ae..00c6ffd3ef39 100644 --- a/arch/powerpc/platforms/pseries/vas-sysfs.c +++ b/arch/powerpc/platforms/pseries/vas-sysfs.c @@ -10,6 +10,7 @@ #include <linux/miscdevice.h> #include <linux/kobject.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/mm.h> #include "vas.h" @@ -58,7 +59,7 @@ static ssize_t update_total_credits_store(struct vas_cop_feat_caps *caps, #define sysfs_caps_entry_read(_name) \ static ssize_t _name##_show(struct vas_cop_feat_caps *caps, char *buf) \ { \ - return sprintf(buf, "%d\n", atomic_read(&caps->_name)); \ + return sysfs_emit(buf, "%d\n", atomic_read(&caps->_name)); \ } struct vas_sysfs_entry { diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 08e2add48adb..572bdf42335e 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/delay.h> #include <linux/stat.h> +#include <linux/sysfs.h> #include <linux/device.h> #include <linux/init.h> #include <linux/slab.h> @@ -942,14 +943,14 @@ static ssize_t cmo_##name##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return sprintf(buf, "%lu\n", to_vio_dev(dev)->cmo.name); \ + return sysfs_emit(buf, "%lu\n", to_vio_dev(dev)->cmo.name); \ } static ssize_t cmo_allocs_failed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viodev = to_vio_dev(dev); - return sprintf(buf, "%d\n", atomic_read(&viodev->cmo.allocs_failed)); + return sysfs_emit(buf, "%d\n", atomic_read(&viodev->cmo.allocs_failed)); } static ssize_t cmo_allocs_failed_store(struct device *dev, @@ -998,7 +999,7 @@ static DEVICE_ATTR_RW(cmo_allocs_failed); #define viobus_cmo_rd_attr(name) \ static ssize_t cmo_bus_##name##_show(const struct bus_type *bt, char *buf) \ { \ - return sprintf(buf, "%lu\n", vio_cmo.name); \ + return sysfs_emit(buf, "%lu\n", vio_cmo.name); \ } \ static struct bus_attribute bus_attr_cmo_bus_##name = \ __ATTR(cmo_##name, S_IRUGO, cmo_bus_##name##_show, NULL) @@ -1007,7 +1008,7 @@ static struct bus_attribute bus_attr_cmo_bus_##name = \ static ssize_t \ cmo_##name##_##var##_show(const struct bus_type *bt, char *buf) \ { \ - return sprintf(buf, "%lu\n", vio_cmo.name.var); \ + return sysfs_emit(buf, "%lu\n", vio_cmo.name.var); \ } \ static BUS_ATTR_RO(cmo_##name##_##var) @@ -1022,7 +1023,7 @@ viobus_cmo_pool_rd_attr(excess, free); static ssize_t cmo_high_show(const struct bus_type *bt, char *buf) { - return sprintf(buf, "%lu\n", vio_cmo.high); + return sysfs_emit(buf, "%lu\n", vio_cmo.high); } static ssize_t cmo_high_store(const struct bus_type *bt, const char *buf, @@ -1535,7 +1536,7 @@ machine_device_initcall(pseries, vio_device_init); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", to_vio_dev(dev)->name); + return sysfs_emit(buf, "%s\n", to_vio_dev(dev)->name); } static DEVICE_ATTR_RO(name); @@ -1544,7 +1545,7 @@ static ssize_t devspec_show(struct device *dev, { struct device_node *of_node = dev->of_node; - return sprintf(buf, "%pOF\n", of_node); + return sysfs_emit(buf, "%pOF\n", of_node); } static DEVICE_ATTR_RO(devspec); @@ -1556,17 +1557,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, const char *cp; dn = dev->of_node; - if (!dn) { - strcpy(buf, "\n"); - return strlen(buf); - } + if (!dn) + return sysfs_emit(buf, "\n"); cp = of_get_property(dn, "compatible", NULL); - if (!cp) { - strcpy(buf, "\n"); - return strlen(buf); - } + if (!cp) + return sysfs_emit(buf, "\n"); - return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp); + return sysfs_emit(buf, "vio:T%sS%s\n", vio_dev->type, cp); } static DEVICE_ATTR_RO(modalias); diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c index f9e64f54dc14..f63b89adf9f3 100644 --- a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c +++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c @@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -61,7 +62,7 @@ static ssize_t fsl_timer_wakeup_show(struct device *dev, } mutex_unlock(&sysfs_lock); - return sprintf(buf, "%lld\n", interval); + return sysfs_emit(buf, "%lld\n", interval); } static ssize_t fsl_timer_wakeup_store(struct device *dev, diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index c120be73d149..dadd1f46ec93 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -564,6 +564,7 @@ static int xive_find_target_in_mask(const struct cpumask *mask, return cpu; } + WARN_ONCE(1, "target CPU not found in mask: %*pbl\n", cpumask_pr_args(mask)); return -1; } |
